QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 
20 #include "processing/models/qgsprocessingmodelalgorithm.h"
21 #include "qgsprocessingoutputs.h"
24 #include "qgsspinbox.h"
25 #include "qgsdoublespinbox.h"
26 #include "qgsprocessingcontext.h"
27 #include "qgsauthconfigselect.h"
28 #include "qgsapplication.h"
29 #include "qgsfilewidget.h"
30 #include "qgssettings.h"
31 #include "qgsexpressionlineedit.h"
35 #include "qgslayoutmanager.h"
36 #include "qgsproject.h"
37 #include "qgslayoutcombobox.h"
38 #include "qgslayoutitemcombobox.h"
39 #include "qgsprintlayout.h"
40 #include "qgsscalewidget.h"
41 #include "qgssnapindicator.h"
42 #include "qgsmapmouseevent.h"
43 #include "qgsfilterlineedit.h"
44 #include "qgsmapcanvas.h"
45 #include "qgsmessagebar.h"
46 #include "qgscolorbutton.h"
49 #include "qgsfieldcombobox.h"
50 #include "qgsmapthemecollection.h"
51 #include "qgsdatetimeedit.h"
55 #include "qgsextentwidget.h"
59 #include "qgsrasterbandcombobox.h"
61 #include "qgscheckablecombobox.h"
62 #include "qgsexpressioncontext.h"
64 #include <QToolButton>
65 #include <QLabel>
66 #include <QHBoxLayout>
67 #include <QVBoxLayout>
68 #include <QCheckBox>
69 #include <QComboBox>
70 #include <QLineEdit>
71 #include <QPlainTextEdit>
72 #include <QRadioButton>
73 #include <QButtonGroup>
74 #include <QMenu>
75 #include <QFileDialog>
76 
78 
79 //
80 // QgsProcessingBooleanWidgetWrapper
81 //
82 
83 
84 QgsProcessingBooleanParameterDefinitionWidget::QgsProcessingBooleanParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
85  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
86 {
87  QVBoxLayout *vlayout = new QVBoxLayout();
88  vlayout->setContentsMargins( 0, 0, 0, 0 );
89 
90  mDefaultCheckBox = new QCheckBox( tr( "Checked" ) );
91  if ( const QgsProcessingParameterBoolean *boolParam = dynamic_cast<const QgsProcessingParameterBoolean *>( definition ) )
92  mDefaultCheckBox->setChecked( QgsProcessingParameters::parameterAsBool( boolParam, boolParam->defaultValueForGui(), context ) );
93  else
94  mDefaultCheckBox->setChecked( false );
95  vlayout->addWidget( mDefaultCheckBox );
96  setLayout( vlayout );
97 }
98 
99 QgsProcessingParameterDefinition *QgsProcessingBooleanParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
100 {
101  auto param = std::make_unique< QgsProcessingParameterBoolean >( name, description, mDefaultCheckBox->isChecked() );
102  param->setFlags( flags );
103  return param.release();
104 }
105 
106 
107 QgsProcessingBooleanWidgetWrapper::QgsProcessingBooleanWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
108  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
109 {
110 
111 }
112 
113 QWidget *QgsProcessingBooleanWidgetWrapper::createWidget()
114 {
115  switch ( type() )
116  {
118  {
119  QString description = parameterDefinition()->description();
120  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
121  description = QObject::tr( "%1 [optional]" ).arg( description );
122 
123  mCheckBox = new QCheckBox( description );
124  mCheckBox->setToolTip( parameterDefinition()->toolTip() );
125 
126  connect( mCheckBox, &QCheckBox::toggled, this, [ = ]
127  {
128  emit widgetValueHasChanged( this );
129  } );
130  return mCheckBox;
131  }
132 
135  {
136  mComboBox = new QComboBox();
137  mComboBox->addItem( tr( "Yes" ), true );
138  mComboBox->addItem( tr( "No" ), false );
139  mComboBox->setToolTip( parameterDefinition()->toolTip() );
140 
141  connect( mComboBox, qOverload< int>( &QComboBox::currentIndexChanged ), this, [ = ]
142  {
143  emit widgetValueHasChanged( this );
144  } );
145 
146  return mComboBox;
147  }
148  }
149  return nullptr;
150 }
151 
152 QLabel *QgsProcessingBooleanWidgetWrapper::createLabel()
153 {
154  // avoid creating labels in standard dialogs
155  if ( type() == QgsProcessingGui::Standard )
156  return nullptr;
157  else
159 }
160 
161 void QgsProcessingBooleanWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
162 {
163  switch ( type() )
164  {
166  {
167  const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
168  mCheckBox->setChecked( v );
169  break;
170  }
171 
174  {
175  const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
176  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
177  break;
178  }
179  }
180 }
181 
182 QVariant QgsProcessingBooleanWidgetWrapper::widgetValue() const
183 {
184  switch ( type() )
185  {
187  return mCheckBox->isChecked();
188 
191  return mComboBox->currentData();
192  }
193  return QVariant();
194 }
195 
196 QStringList QgsProcessingBooleanWidgetWrapper::compatibleParameterTypes() const
197 {
198  //pretty much everything is compatible here and can be converted to a bool!
199  return QStringList() << QgsProcessingParameterBoolean::typeName()
213 }
214 
215 QStringList QgsProcessingBooleanWidgetWrapper::compatibleOutputTypes() const
216 {
217  return QStringList() << QgsProcessingOutputNumber::typeName()
224 }
225 
226 QString QgsProcessingBooleanWidgetWrapper::parameterType() const
227 {
229 }
230 
231 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBooleanWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
232 {
233  return new QgsProcessingBooleanWidgetWrapper( parameter, type );
234 }
235 
236 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBooleanWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
237 {
238  return new QgsProcessingBooleanParameterDefinitionWidget( context, widgetContext, definition, algorithm );
239 }
240 
241 
242 //
243 // QgsProcessingCrsWidgetWrapper
244 //
245 
246 QgsProcessingCrsParameterDefinitionWidget::QgsProcessingCrsParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
247  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
248 {
249  QVBoxLayout *vlayout = new QVBoxLayout();
250  vlayout->setContentsMargins( 0, 0, 0, 0 );
251 
252  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
253 
254  mCrsSelector = new QgsProjectionSelectionWidget();
255 
256  // possibly we should expose this for parameter by parameter control
257  mCrsSelector->setShowAccuracyWarnings( true );
258 
259  if ( const QgsProcessingParameterCrs *crsParam = dynamic_cast<const QgsProcessingParameterCrs *>( definition ) )
260  mCrsSelector->setCrs( QgsProcessingParameters::parameterAsCrs( crsParam, crsParam->defaultValueForGui(), context ) );
261  else
262  mCrsSelector->setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
263 
264  vlayout->addWidget( mCrsSelector );
265  setLayout( vlayout );
266 }
267 
268 QgsProcessingParameterDefinition *QgsProcessingCrsParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
269 {
270  auto param = std::make_unique< QgsProcessingParameterCrs >( name, description, mCrsSelector->crs().authid() );
271  param->setFlags( flags );
272  return param.release();
273 }
274 
275 QgsProcessingCrsWidgetWrapper::QgsProcessingCrsWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
276  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
277 {
278 
279 }
280 
281 QWidget *QgsProcessingCrsWidgetWrapper::createWidget()
282 {
283  Q_ASSERT( mProjectionSelectionWidget == nullptr );
284  mProjectionSelectionWidget = new QgsProjectionSelectionWidget();
285  mProjectionSelectionWidget->setToolTip( parameterDefinition()->toolTip() );
286 
287  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
288  mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
289  else
290  mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, false );
291 
292  connect( mProjectionSelectionWidget, &QgsProjectionSelectionWidget::crsChanged, this, [ = ]
293  {
294  emit widgetValueHasChanged( this );
295  } );
296 
297  switch ( type() )
298  {
301  {
302  return mProjectionSelectionWidget;
303  }
304 
306  {
307  QWidget *w = new QWidget();
308  w->setToolTip( parameterDefinition()->toolTip() );
309 
310  QVBoxLayout *vl = new QVBoxLayout();
311  vl->setContentsMargins( 0, 0, 0, 0 );
312  w->setLayout( vl );
313 
314  mUseProjectCrsCheckBox = new QCheckBox( tr( "Use project CRS" ) );
315  mUseProjectCrsCheckBox->setToolTip( tr( "Always use the current project CRS when running the model" ) );
316  vl->addWidget( mUseProjectCrsCheckBox );
317  connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, mProjectionSelectionWidget, &QgsProjectionSelectionWidget::setDisabled );
318  connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, this, [ = ]
319  {
320  emit widgetValueHasChanged( this );
321  } );
322 
323  vl->addWidget( mProjectionSelectionWidget );
324 
325  return w;
326  }
327  }
328  return nullptr;
329 }
330 
331 void QgsProcessingCrsWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
332 {
333  if ( mUseProjectCrsCheckBox )
334  {
335  if ( value.toString().compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
336  {
337  mUseProjectCrsCheckBox->setChecked( true );
338  return;
339  }
340  else
341  {
342  mUseProjectCrsCheckBox->setChecked( false );
343  }
344  }
345 
346  const QgsCoordinateReferenceSystem v = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, context );
347  if ( mProjectionSelectionWidget )
348  mProjectionSelectionWidget->setCrs( v );
349 }
350 
351 QVariant QgsProcessingCrsWidgetWrapper::widgetValue() const
352 {
353  if ( mUseProjectCrsCheckBox && mUseProjectCrsCheckBox->isChecked() )
354  return QStringLiteral( "ProjectCrs" );
355  else if ( mProjectionSelectionWidget )
356  return mProjectionSelectionWidget->crs().isValid() ? mProjectionSelectionWidget->crs() : QVariant();
357  else
358  return QVariant();
359 }
360 
361 QStringList QgsProcessingCrsWidgetWrapper::compatibleParameterTypes() const
362 {
363  return QStringList()
371 }
372 
373 QStringList QgsProcessingCrsWidgetWrapper::compatibleOutputTypes() const
374 {
375  return QStringList() << QgsProcessingOutputVectorLayer::typeName()
379 }
380 
381 QString QgsProcessingCrsWidgetWrapper::modelerExpressionFormatString() const
382 {
383  return tr( "string as EPSG code, WKT or PROJ format, or a string identifying a map layer" );
384 }
385 
386 QString QgsProcessingCrsWidgetWrapper::parameterType() const
387 {
389 }
390 
391 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCrsWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
392 {
393  return new QgsProcessingCrsWidgetWrapper( parameter, type );
394 }
395 
396 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingCrsWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
397 {
398  return new QgsProcessingCrsParameterDefinitionWidget( context, widgetContext, definition, algorithm );
399 }
400 
401 
402 
403 //
404 // QgsProcessingStringWidgetWrapper
405 //
406 
407 
408 QgsProcessingStringParameterDefinitionWidget::QgsProcessingStringParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
409  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
410 {
411  QVBoxLayout *vlayout = new QVBoxLayout();
412  vlayout->setContentsMargins( 0, 0, 0, 0 );
413 
414  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
415 
416  mDefaultLineEdit = new QLineEdit();
417  if ( const QgsProcessingParameterString *stringParam = dynamic_cast<const QgsProcessingParameterString *>( definition ) )
418  mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( stringParam, stringParam->defaultValueForGui(), context ) );
419  vlayout->addWidget( mDefaultLineEdit );
420 
421  mMultiLineCheckBox = new QCheckBox( tr( "Multiline input" ) );
422  if ( const QgsProcessingParameterString *stringParam = dynamic_cast<const QgsProcessingParameterString *>( definition ) )
423  mMultiLineCheckBox->setChecked( stringParam->multiLine() );
424  vlayout->addWidget( mMultiLineCheckBox );
425 
426  setLayout( vlayout );
427 }
428 
429 QgsProcessingParameterDefinition *QgsProcessingStringParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
430 {
431  auto param = std::make_unique< QgsProcessingParameterString >( name, description, mDefaultLineEdit->text(), mMultiLineCheckBox->isChecked() );
432  param->setFlags( flags );
433  return param.release();
434 }
435 
436 
437 
438 QgsProcessingStringWidgetWrapper::QgsProcessingStringWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
439  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
440 {
441 
442 }
443 
444 QWidget *QgsProcessingStringWidgetWrapper::createWidget()
445 {
446  switch ( type() )
447  {
450  {
451  if ( static_cast< const QgsProcessingParameterString * >( parameterDefinition() )->multiLine() )
452  {
453  mPlainTextEdit = new QPlainTextEdit();
454  mPlainTextEdit->setToolTip( parameterDefinition()->toolTip() );
455 
456  connect( mPlainTextEdit, &QPlainTextEdit::textChanged, this, [ = ]
457  {
458  emit widgetValueHasChanged( this );
459  } );
460  return mPlainTextEdit;
461  }
462  else
463  {
464  mLineEdit = new QLineEdit();
465  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
466 
467  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
468  {
469  emit widgetValueHasChanged( this );
470  } );
471  return mLineEdit;
472  }
473  }
474 
476  {
477  mLineEdit = new QLineEdit();
478  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
479 
480  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
481  {
482  emit widgetValueHasChanged( this );
483  } );
484  return mLineEdit;
485  }
486  }
487  return nullptr;
488 }
489 
490 void QgsProcessingStringWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
491 {
492  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
493  if ( mLineEdit )
494  mLineEdit->setText( v );
495  if ( mPlainTextEdit )
496  mPlainTextEdit->setPlainText( v );
497 }
498 
499 QVariant QgsProcessingStringWidgetWrapper::widgetValue() const
500 {
501  if ( mLineEdit )
502  return mLineEdit->text();
503  else if ( mPlainTextEdit )
504  return mPlainTextEdit->toPlainText();
505  else
506  return QVariant();
507 }
508 
509 QStringList QgsProcessingStringWidgetWrapper::compatibleParameterTypes() const
510 {
511  return QStringList()
522 }
523 
524 QStringList QgsProcessingStringWidgetWrapper::compatibleOutputTypes() const
525 {
526  return QStringList() << QgsProcessingOutputNumber::typeName()
530 }
531 
532 QString QgsProcessingStringWidgetWrapper::parameterType() const
533 {
535 }
536 
537 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingStringWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
538 {
539  return new QgsProcessingStringWidgetWrapper( parameter, type );
540 }
541 
542 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingStringWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
543 {
544  return new QgsProcessingStringParameterDefinitionWidget( context, widgetContext, definition, algorithm );
545 }
546 
547 
548 
549 //
550 // QgsProcessingAuthConfigWidgetWrapper
551 //
552 
553 QgsProcessingAuthConfigWidgetWrapper::QgsProcessingAuthConfigWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
554  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
555 {
556 
557 }
558 
559 QWidget *QgsProcessingAuthConfigWidgetWrapper::createWidget()
560 {
561  switch ( type() )
562  {
566  {
567  mAuthConfigSelect = new QgsAuthConfigSelect();
568  mAuthConfigSelect->setToolTip( parameterDefinition()->toolTip() );
569 
570  connect( mAuthConfigSelect, &QgsAuthConfigSelect::selectedConfigIdChanged, this, [ = ]
571  {
572  emit widgetValueHasChanged( this );
573  } );
574  return mAuthConfigSelect;
575  }
576  }
577  return nullptr;
578 }
579 
580 void QgsProcessingAuthConfigWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
581 {
582  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
583  if ( mAuthConfigSelect )
584  mAuthConfigSelect->setConfigId( v );
585 }
586 
587 QVariant QgsProcessingAuthConfigWidgetWrapper::widgetValue() const
588 {
589  if ( mAuthConfigSelect )
590  return mAuthConfigSelect->configId();
591  else
592  return QVariant();
593 }
594 
595 QStringList QgsProcessingAuthConfigWidgetWrapper::compatibleParameterTypes() const
596 {
597  return QStringList()
601 }
602 
603 QStringList QgsProcessingAuthConfigWidgetWrapper::compatibleOutputTypes() const
604 {
605  return QStringList() << QgsProcessingOutputString::typeName();
606 }
607 
608 QString QgsProcessingAuthConfigWidgetWrapper::parameterType() const
609 {
611 }
612 
613 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAuthConfigWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
614 {
615  return new QgsProcessingAuthConfigWidgetWrapper( parameter, type );
616 }
617 
618 //
619 // QgsProcessingNumericWidgetWrapper
620 //
621 
622 QgsProcessingNumberParameterDefinitionWidget::QgsProcessingNumberParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
623  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
624 {
625  QVBoxLayout *vlayout = new QVBoxLayout();
626  vlayout->setContentsMargins( 0, 0, 0, 0 );
627 
628  vlayout->addWidget( new QLabel( tr( "Number type" ) ) );
629 
630  mTypeComboBox = new QComboBox();
631  mTypeComboBox->addItem( tr( "Float" ), QgsProcessingParameterNumber::Double );
632  mTypeComboBox->addItem( tr( "Integer" ), QgsProcessingParameterNumber::Integer );
633  vlayout->addWidget( mTypeComboBox );
634 
635  vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
636  mMinLineEdit = new QLineEdit();
637  vlayout->addWidget( mMinLineEdit );
638 
639  vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
640  mMaxLineEdit = new QLineEdit();
641  vlayout->addWidget( mMaxLineEdit );
642 
643  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
644  mDefaultLineEdit = new QLineEdit();
645  vlayout->addWidget( mDefaultLineEdit );
646 
647  if ( const QgsProcessingParameterNumber *numberParam = dynamic_cast<const QgsProcessingParameterNumber *>( definition ) )
648  {
649  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( numberParam->dataType() ) );
650  mMinLineEdit->setText( QString::number( numberParam->minimum() ) );
651  mMaxLineEdit->setText( QString::number( numberParam->maximum() ) );
652  mDefaultLineEdit->setText( numberParam->defaultValueForGui().toString() );
653  }
654 
655  setLayout( vlayout );
656 }
657 
658 QgsProcessingParameterDefinition *QgsProcessingNumberParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
659 {
660  bool ok;
661  double val = mDefaultLineEdit->text().toDouble( &ok );
662 
663  QgsProcessingParameterNumber::Type dataType = static_cast< QgsProcessingParameterNumber::Type >( mTypeComboBox->currentData().toInt() );
664  auto param = std::make_unique< QgsProcessingParameterNumber >( name, description, dataType, ok ? val : QVariant() );
665 
666  val = mMinLineEdit->text().toDouble( &ok );
667  if ( ok )
668  {
669  param->setMinimum( val );
670  }
671 
672  val = mMaxLineEdit->text().toDouble( &ok );
673  if ( ok )
674  {
675  param->setMaximum( val );
676  }
677 
678  param->setFlags( flags );
679  return param.release();
680 }
681 
682 QgsProcessingNumericWidgetWrapper::QgsProcessingNumericWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
683  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
684 {
685 
686 }
687 
688 QWidget *QgsProcessingNumericWidgetWrapper::createWidget()
689 {
690  const QgsProcessingParameterNumber *numberDef = static_cast< const QgsProcessingParameterNumber * >( parameterDefinition() );
691  const QVariantMap metadata = numberDef->metadata();
692  const int decimals = metadata.value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "decimals" ), 6 ).toInt();
693  switch ( type() )
694  {
698  {
699  // lots of duplicate code here -- but there's no common interface between QSpinBox/QDoubleSpinBox which would allow us to avoid this
700  QAbstractSpinBox *spinBox = nullptr;
701  switch ( numberDef->dataType() )
702  {
704  mDoubleSpinBox = new QgsDoubleSpinBox();
705  mDoubleSpinBox->setExpressionsEnabled( true );
706  mDoubleSpinBox->setDecimals( decimals );
707 
708  // guess reasonable step value for double spin boxes
709  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) &&
710  !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() + 1 ) )
711  {
712  double singleStep = calculateStep( numberDef->minimum(), numberDef->maximum() );
713  singleStep = std::max( singleStep, std::pow( 10, -decimals ) );
714  mDoubleSpinBox->setSingleStep( singleStep );
715  }
716 
717  spinBox = mDoubleSpinBox;
718  break;
719 
721  mSpinBox = new QgsSpinBox();
722  mSpinBox->setExpressionsEnabled( true );
723  spinBox = mSpinBox;
724  break;
725  }
726  spinBox->setToolTip( parameterDefinition()->toolTip() );
727 
728  double max = 999999999;
729  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) )
730  {
731  max = numberDef->maximum();
732  }
733  double min = -999999999;
734  if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
735  {
736  min = numberDef->minimum();
737  }
738  if ( mDoubleSpinBox )
739  {
740  mDoubleSpinBox->setMinimum( min );
741  mDoubleSpinBox->setMaximum( max );
742  }
743  else
744  {
745  mSpinBox->setMinimum( static_cast< int >( min ) );
746  mSpinBox->setMaximum( static_cast< int >( max ) );
747  }
748 
750  {
751  mAllowingNull = true;
752  if ( mDoubleSpinBox )
753  {
754  mDoubleSpinBox->setShowClearButton( true );
755  const double min = mDoubleSpinBox->minimum() - 1;
756  mDoubleSpinBox->setMinimum( min );
757  mDoubleSpinBox->setValue( min );
758  }
759  else
760  {
761  mSpinBox->setShowClearButton( true );
762  const int min = mSpinBox->minimum() - 1;
763  mSpinBox->setMinimum( min );
764  mSpinBox->setValue( min );
765  }
766  spinBox->setSpecialValueText( tr( "Not set" ) );
767  }
768  else
769  {
770  if ( numberDef->defaultValueForGui().isValid() )
771  {
772  // if default value for parameter, we clear to that
773  bool ok = false;
774  if ( mDoubleSpinBox )
775  {
776  double defaultVal = numberDef->defaultValueForGui().toDouble( &ok );
777  if ( ok )
778  mDoubleSpinBox->setClearValue( defaultVal );
779  }
780  else
781  {
782  int intVal = numberDef->defaultValueForGui().toInt( &ok );
783  if ( ok )
784  mSpinBox->setClearValue( intVal );
785  }
786  }
787  else if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
788  {
789  // otherwise we clear to the minimum, if it's set
790  if ( mDoubleSpinBox )
791  mDoubleSpinBox->setClearValue( numberDef->minimum() );
792  else
793  mSpinBox->setClearValue( static_cast< int >( numberDef->minimum() ) );
794  }
795  else
796  {
797  // last resort, we clear to 0
798  if ( mDoubleSpinBox )
799  {
800  mDoubleSpinBox->setValue( 0 );
801  mDoubleSpinBox->setClearValue( 0 );
802  }
803  else
804  {
805  mSpinBox->setValue( 0 );
806  mSpinBox->setClearValue( 0 );
807  }
808  }
809  }
810 
811  if ( mDoubleSpinBox )
812  connect( mDoubleSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
813  else if ( mSpinBox )
814  connect( mSpinBox, qOverload<int>( &QgsSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
815 
816  return spinBox;
817  }
818  }
819  return nullptr;
820 }
821 
822 void QgsProcessingNumericWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
823 {
824  if ( mDoubleSpinBox )
825  {
826  if ( mAllowingNull && !value.isValid() )
827  mDoubleSpinBox->clear();
828  else
829  {
830  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
831  mDoubleSpinBox->setValue( v );
832  }
833  }
834  else if ( mSpinBox )
835  {
836  if ( mAllowingNull && !value.isValid() )
837  mSpinBox->clear();
838  else
839  {
840  const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
841  mSpinBox->setValue( v );
842  }
843  }
844 }
845 
846 QVariant QgsProcessingNumericWidgetWrapper::widgetValue() const
847 {
848  if ( mDoubleSpinBox )
849  {
850  if ( mAllowingNull && qgsDoubleNear( mDoubleSpinBox->value(), mDoubleSpinBox->minimum() ) )
851  return QVariant();
852  else
853  return mDoubleSpinBox->value();
854  }
855  else if ( mSpinBox )
856  {
857  if ( mAllowingNull && mSpinBox->value() == mSpinBox->minimum() )
858  return QVariant();
859  else
860  return mSpinBox->value();
861  }
862  else
863  return QVariant();
864 }
865 
866 QStringList QgsProcessingNumericWidgetWrapper::compatibleParameterTypes() const
867 {
868  return QStringList()
873 }
874 
875 QStringList QgsProcessingNumericWidgetWrapper::compatibleOutputTypes() const
876 {
877  return QStringList() << QgsProcessingOutputNumber::typeName()
879 }
880 
881 double QgsProcessingNumericWidgetWrapper::calculateStep( const double minimum, const double maximum )
882 {
883  const double valueRange = maximum - minimum;
884  if ( valueRange <= 1.0 )
885  {
886  const double step = valueRange / 10.0;
887  // round to 1 significant figure
888  return qgsRound( step, -std::floor( std::log( step ) ) );
889  }
890  else
891  {
892  return 1.0;
893  }
894 }
895 
896 QString QgsProcessingNumericWidgetWrapper::parameterType() const
897 {
899 }
900 
901 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingNumericWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
902 {
903  return new QgsProcessingNumericWidgetWrapper( parameter, type );
904 }
905 
906 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingNumericWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
907 {
908  return new QgsProcessingNumberParameterDefinitionWidget( context, widgetContext, definition, algorithm );
909 }
910 
911 //
912 // QgsProcessingDistanceWidgetWrapper
913 //
914 
915 QgsProcessingDistanceParameterDefinitionWidget::QgsProcessingDistanceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
916  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
917 {
918  QVBoxLayout *vlayout = new QVBoxLayout();
919  vlayout->setContentsMargins( 0, 0, 0, 0 );
920 
921  vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
922 
923  mParentLayerComboBox = new QComboBox();
924 
925  QString initialParent;
926  if ( const QgsProcessingParameterDistance *distParam = dynamic_cast<const QgsProcessingParameterDistance *>( definition ) )
927  initialParent = distParam->parentParameterName();
928 
929  if ( auto *lModel = widgetContext.model() )
930  {
931  // populate combo box with other model input choices
932  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
933  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
934  {
935  if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast< const QgsProcessingParameterFeatureSource * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
936  {
937  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
938  if ( !initialParent.isEmpty() && initialParent == definition->name() )
939  {
940  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
941  }
942  }
943  else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast< const QgsProcessingParameterVectorLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
944  {
945  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
946  if ( !initialParent.isEmpty() && initialParent == definition->name() )
947  {
948  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
949  }
950  }
951  else if ( const QgsProcessingParameterMapLayer *definition = dynamic_cast< const QgsProcessingParameterMapLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
952  {
953  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
954  if ( !initialParent.isEmpty() && initialParent == definition->name() )
955  {
956  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
957  }
958  }
959  else if ( const QgsProcessingParameterCrs *definition = dynamic_cast< const QgsProcessingParameterCrs * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
960  {
961  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
962  if ( !initialParent.isEmpty() && initialParent == definition->name() )
963  {
964  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
965  }
966  }
967  }
968  }
969 
970  if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
971  {
972  // if no parent candidates found, we just add the existing one as a placeholder
973  mParentLayerComboBox->addItem( initialParent, initialParent );
974  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
975  }
976 
977  vlayout->addWidget( mParentLayerComboBox );
978 
979  vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
980  mMinLineEdit = new QLineEdit();
981  vlayout->addWidget( mMinLineEdit );
982 
983  vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
984  mMaxLineEdit = new QLineEdit();
985  vlayout->addWidget( mMaxLineEdit );
986 
987  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
988  mDefaultLineEdit = new QLineEdit();
989  vlayout->addWidget( mDefaultLineEdit );
990 
991  if ( const QgsProcessingParameterDistance *distParam = dynamic_cast<const QgsProcessingParameterDistance *>( definition ) )
992  {
993  mMinLineEdit->setText( QString::number( distParam->minimum() ) );
994  mMaxLineEdit->setText( QString::number( distParam->maximum() ) );
995  mDefaultLineEdit->setText( distParam->defaultValueForGui().toString() );
996  }
997 
998  setLayout( vlayout );
999 }
1000 
1001 QgsProcessingParameterDefinition *QgsProcessingDistanceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1002 {
1003  bool ok;
1004  double val = mDefaultLineEdit->text().toDouble( &ok );
1005 
1006  auto param = std::make_unique< QgsProcessingParameterDistance >( name, description, ok ? val : QVariant(), mParentLayerComboBox->currentData().toString() );
1007 
1008  val = mMinLineEdit->text().toDouble( &ok );
1009  if ( ok )
1010  {
1011  param->setMinimum( val );
1012  }
1013 
1014  val = mMaxLineEdit->text().toFloat( &ok );
1015  if ( ok )
1016  {
1017  param->setMaximum( val );
1018  }
1019 
1020  param->setFlags( flags );
1021  return param.release();
1022 }
1023 
1024 QgsProcessingDistanceWidgetWrapper::QgsProcessingDistanceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1025  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1026 {
1027 
1028 }
1029 
1030 QString QgsProcessingDistanceWidgetWrapper::parameterType() const
1031 {
1033 }
1034 
1035 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDistanceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1036 {
1037  return new QgsProcessingDistanceWidgetWrapper( parameter, type );
1038 }
1039 
1040 QWidget *QgsProcessingDistanceWidgetWrapper::createWidget()
1041 {
1042  const QgsProcessingParameterDistance *distanceDef = static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() );
1043 
1044  QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1045  switch ( type() )
1046  {
1048  {
1049  mLabel = new QLabel();
1050  mUnitsCombo = new QComboBox();
1051 
1057 
1058  const int labelMargin = static_cast< int >( std::round( mUnitsCombo->fontMetrics().horizontalAdvance( 'X' ) ) );
1059  QHBoxLayout *layout = new QHBoxLayout();
1060  layout->addWidget( spin, 1 );
1061  layout->insertSpacing( 1, labelMargin / 2 );
1062  layout->insertWidget( 2, mLabel );
1063  layout->insertWidget( 3, mUnitsCombo );
1064 
1065  // bit of fiddlyness here -- we want the initial spacing to only be visible
1066  // when the warning label is shown, so it's embedded inside mWarningLabel
1067  // instead of outside it
1068  mWarningLabel = new QWidget();
1069  QHBoxLayout *warningLayout = new QHBoxLayout();
1070  warningLayout->setContentsMargins( 0, 0, 0, 0 );
1071  QLabel *warning = new QLabel();
1072  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
1073  const int size = static_cast< int >( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
1074  warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
1075  warning->setToolTip( tr( "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
1076  warningLayout->insertSpacing( 0, labelMargin / 2 );
1077  warningLayout->insertWidget( 1, warning );
1078  mWarningLabel->setLayout( warningLayout );
1079  layout->insertWidget( 4, mWarningLabel );
1080 
1081  QWidget *w = new QWidget();
1082  layout->setContentsMargins( 0, 0, 0, 0 );
1083  w->setLayout( layout );
1084 
1085  setUnits( distanceDef->defaultUnit() );
1086 
1087  return w;
1088  }
1089 
1092  return spin;
1093 
1094  }
1095  return nullptr;
1096 }
1097 
1098 void QgsProcessingDistanceWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1099 {
1100  QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
1101  switch ( type() )
1102  {
1104  {
1105  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1106  {
1107  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() )->parentParameterName() )
1108  {
1109  setUnitParameterValue( wrapper->parameterValue() );
1111  {
1112  setUnitParameterValue( wrapper->parameterValue() );
1113  } );
1114  break;
1115  }
1116  }
1117  break;
1118  }
1119 
1122  break;
1123  }
1124 }
1125 
1126 void QgsProcessingDistanceWidgetWrapper::setUnitParameterValue( const QVariant &value )
1127 {
1129 
1130  // evaluate value to layer
1131  QgsProcessingContext *context = nullptr;
1132  std::unique_ptr< QgsProcessingContext > tmpContext;
1133  if ( mProcessingContextGenerator )
1134  context = mProcessingContextGenerator->processingContext();
1135 
1136  if ( !context )
1137  {
1138  tmpContext = std::make_unique< QgsProcessingContext >();
1139  context = tmpContext.get();
1140  }
1141 
1142  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, *context );
1143  if ( crs.isValid() )
1144  {
1145  units = crs.mapUnits();
1146  }
1147 
1148  setUnits( units );
1149 }
1150 
1151 void QgsProcessingDistanceWidgetWrapper::setUnits( const QgsUnitTypes::DistanceUnit units )
1152 {
1153  mLabel->setText( QgsUnitTypes::toString( units ) );
1155  {
1156  mUnitsCombo->hide();
1157  mLabel->show();
1158  }
1159  else
1160  {
1161  mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( units ) );
1162  mUnitsCombo->show();
1163  mLabel->hide();
1164  }
1165  mWarningLabel->setVisible( units == QgsUnitTypes::DistanceDegrees );
1166  mBaseUnit = units;
1167 }
1168 
1169 QVariant QgsProcessingDistanceWidgetWrapper::widgetValue() const
1170 {
1171  const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1172  if ( val.type() == QVariant::Double && mUnitsCombo && mUnitsCombo->isVisible() )
1173  {
1174  QgsUnitTypes::DistanceUnit displayUnit = static_cast<QgsUnitTypes::DistanceUnit >( mUnitsCombo->currentData().toInt() );
1175  return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1176  }
1177  else
1178  {
1179  return val;
1180  }
1181 }
1182 
1183 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDistanceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1184 {
1185  return new QgsProcessingDistanceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1186 }
1187 
1188 //
1189 // QgsProcessingScaleWidgetWrapper
1190 //
1191 
1192 QgsProcessingScaleParameterDefinitionWidget::QgsProcessingScaleParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1193  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1194 {
1195  QVBoxLayout *vlayout = new QVBoxLayout();
1196  vlayout->setContentsMargins( 0, 0, 0, 0 );
1197 
1198  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1199 
1200  mDefaultLineEdit = new QLineEdit();
1201 
1202  if ( const QgsProcessingParameterScale *scaleParam = dynamic_cast<const QgsProcessingParameterScale *>( definition ) )
1203  {
1204  mDefaultLineEdit->setText( scaleParam->defaultValueForGui().toString() );
1205  }
1206 
1207  vlayout->addWidget( mDefaultLineEdit );
1208 
1209  setLayout( vlayout );
1210 }
1211 
1212 QgsProcessingParameterDefinition *QgsProcessingScaleParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1213 {
1214  bool ok;
1215  double val = mDefaultLineEdit->text().toDouble( &ok );
1216  auto param = std::make_unique< QgsProcessingParameterScale >( name, description, ok ? val : QVariant() );
1217  param->setFlags( flags );
1218  return param.release();
1219 }
1220 
1221 QgsProcessingScaleWidgetWrapper::QgsProcessingScaleWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1222  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1223 {
1224 
1225 }
1226 
1227 QString QgsProcessingScaleWidgetWrapper::parameterType() const
1228 {
1230 }
1231 
1232 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingScaleWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1233 {
1234  return new QgsProcessingScaleWidgetWrapper( parameter, type );
1235 }
1236 
1237 QWidget *QgsProcessingScaleWidgetWrapper::createWidget()
1238 {
1239  const QgsProcessingParameterScale *scaleDef = static_cast< const QgsProcessingParameterScale * >( parameterDefinition() );
1240 
1241  switch ( type() )
1242  {
1246  {
1247  mScaleWidget = new QgsScaleWidget( nullptr );
1249  mScaleWidget->setAllowNull( true );
1250 
1251  mScaleWidget->setMapCanvas( widgetContext().mapCanvas() );
1252  mScaleWidget->setShowCurrentScaleButton( true );
1253 
1254  mScaleWidget->setToolTip( parameterDefinition()->toolTip() );
1255  connect( mScaleWidget, &QgsScaleWidget::scaleChanged, this, [ = ]( double )
1256  {
1257  emit widgetValueHasChanged( this );
1258  } );
1259  return mScaleWidget;
1260  }
1261  }
1262  return nullptr;
1263 }
1264 
1265 void QgsProcessingScaleWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
1266 {
1267  if ( mScaleWidget )
1268  mScaleWidget->setMapCanvas( context.mapCanvas() );
1270 }
1271 
1272 
1273 QVariant QgsProcessingScaleWidgetWrapper::widgetValue() const
1274 {
1275  return mScaleWidget && !mScaleWidget->isNull() ? QVariant( mScaleWidget->scale() ) : QVariant();
1276 }
1277 
1278 void QgsProcessingScaleWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1279 {
1280  if ( mScaleWidget )
1281  {
1282  if ( mScaleWidget->allowNull() && !value.isValid() )
1283  mScaleWidget->setNull();
1284  else
1285  {
1286  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
1287  mScaleWidget->setScale( v );
1288  }
1289  }
1290 }
1291 
1292 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingScaleWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1293 {
1294  return new QgsProcessingScaleParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1295 }
1296 
1297 
1298 //
1299 // QgsProcessingRangeWidgetWrapper
1300 //
1301 
1302 QgsProcessingRangeParameterDefinitionWidget::QgsProcessingRangeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1303  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1304 {
1305  QVBoxLayout *vlayout = new QVBoxLayout();
1306  vlayout->setContentsMargins( 0, 0, 0, 0 );
1307 
1308  vlayout->addWidget( new QLabel( tr( "Number type" ) ) );
1309 
1310  mTypeComboBox = new QComboBox();
1311  mTypeComboBox->addItem( tr( "Float" ), QgsProcessingParameterNumber::Double );
1312  mTypeComboBox->addItem( tr( "Integer" ), QgsProcessingParameterNumber::Integer );
1313  vlayout->addWidget( mTypeComboBox );
1314 
1315  vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1316  mMinLineEdit = new QLineEdit();
1317  vlayout->addWidget( mMinLineEdit );
1318 
1319  vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1320  mMaxLineEdit = new QLineEdit();
1321  vlayout->addWidget( mMaxLineEdit );
1322 
1323  if ( const QgsProcessingParameterRange *rangeParam = dynamic_cast<const QgsProcessingParameterRange *>( definition ) )
1324  {
1325  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( rangeParam->dataType() ) );
1326  const QList< double > range = QgsProcessingParameters::parameterAsRange( rangeParam, rangeParam->defaultValueForGui(), context );
1327  mMinLineEdit->setText( QString::number( range.at( 0 ) ) );
1328  mMaxLineEdit->setText( QString::number( range.at( 1 ) ) );
1329  }
1330 
1331  setLayout( vlayout );
1332 }
1333 
1334 QgsProcessingParameterDefinition *QgsProcessingRangeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1335 {
1336  QString defaultValue;
1337  if ( mMinLineEdit->text().isEmpty() )
1338  {
1339  defaultValue = QStringLiteral( "None" );
1340  }
1341  else
1342  {
1343  defaultValue = mMinLineEdit->text();
1344  }
1345 
1346  if ( mMaxLineEdit->text().isEmpty() )
1347  {
1348  defaultValue += QLatin1String( ",None" );
1349  }
1350  else
1351  {
1352  defaultValue += QStringLiteral( "," ) + mMaxLineEdit->text();
1353  }
1354 
1355  QgsProcessingParameterNumber::Type dataType = static_cast< QgsProcessingParameterNumber::Type >( mTypeComboBox->currentData().toInt() );
1356  auto param = std::make_unique< QgsProcessingParameterRange >( name, description, dataType, defaultValue );
1357  param->setFlags( flags );
1358  return param.release();
1359 }
1360 
1361 
1362 QgsProcessingRangeWidgetWrapper::QgsProcessingRangeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1363  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1364 {
1365 
1366 }
1367 
1368 QWidget *QgsProcessingRangeWidgetWrapper::createWidget()
1369 {
1370  const QgsProcessingParameterRange *rangeDef = static_cast< const QgsProcessingParameterRange * >( parameterDefinition() );
1371  switch ( type() )
1372  {
1376  {
1377  QHBoxLayout *layout = new QHBoxLayout();
1378 
1379  mMinSpinBox = new QgsDoubleSpinBox();
1380  mMaxSpinBox = new QgsDoubleSpinBox();
1381 
1382  mMinSpinBox->setExpressionsEnabled( true );
1383  mMinSpinBox->setShowClearButton( false );
1384  mMaxSpinBox->setExpressionsEnabled( true );
1385  mMaxSpinBox->setShowClearButton( false );
1386 
1387  QLabel *minLabel = new QLabel( tr( "Min" ) );
1388  layout->addWidget( minLabel );
1389  layout->addWidget( mMinSpinBox, 1 );
1390 
1391  QLabel *maxLabel = new QLabel( tr( "Max" ) );
1392  layout->addWidget( maxLabel );
1393  layout->addWidget( mMaxSpinBox, 1 );
1394 
1395  QWidget *w = new QWidget();
1396  layout->setContentsMargins( 0, 0, 0, 0 );
1397  w->setLayout( layout );
1398 
1399  if ( rangeDef->dataType() == QgsProcessingParameterNumber::Double )
1400  {
1401  mMinSpinBox->setDecimals( 6 );
1402  mMaxSpinBox->setDecimals( 6 );
1403  }
1404  else
1405  {
1406  mMinSpinBox->setDecimals( 0 );
1407  mMaxSpinBox->setDecimals( 0 );
1408  }
1409 
1410  mMinSpinBox->setMinimum( -99999999.999999 );
1411  mMaxSpinBox->setMinimum( -99999999.999999 );
1412  mMinSpinBox->setMaximum( 99999999.999999 );
1413  mMaxSpinBox->setMaximum( 99999999.999999 );
1414 
1416  {
1417  mAllowingNull = true;
1418 
1419  const double min = mMinSpinBox->minimum() - 1;
1420  mMinSpinBox->setMinimum( min );
1421  mMaxSpinBox->setMinimum( min );
1422  mMinSpinBox->setValue( min );
1423  mMaxSpinBox->setValue( min );
1424 
1425  mMinSpinBox->setShowClearButton( true );
1426  mMaxSpinBox->setShowClearButton( true );
1427  mMinSpinBox->setSpecialValueText( tr( "Not set" ) );
1428  mMaxSpinBox->setSpecialValueText( tr( "Not set" ) );
1429  }
1430 
1431  w->setToolTip( parameterDefinition()->toolTip() );
1432 
1433  connect( mMinSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
1434  {
1435  mBlockChangedSignal++;
1436  if ( !mAllowingNull && v > mMaxSpinBox->value() )
1437  mMaxSpinBox->setValue( v );
1438  mBlockChangedSignal--;
1439 
1440  if ( !mBlockChangedSignal )
1441  emit widgetValueHasChanged( this );
1442  } );
1443  connect( mMaxSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
1444  {
1445  mBlockChangedSignal++;
1446  if ( !mAllowingNull && v < mMinSpinBox->value() )
1447  mMinSpinBox->setValue( v );
1448  mBlockChangedSignal--;
1449 
1450  if ( !mBlockChangedSignal )
1451  emit widgetValueHasChanged( this );
1452  } );
1453 
1454  return w;
1455  }
1456  }
1457  return nullptr;
1458 }
1459 
1460 void QgsProcessingRangeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1461 {
1462  const QList< double > v = QgsProcessingParameters::parameterAsRange( parameterDefinition(), value, context );
1463  if ( mAllowingNull && v.empty() )
1464  {
1465  mMinSpinBox->clear();
1466  mMaxSpinBox->clear();
1467  }
1468  else
1469  {
1470  if ( v.empty() )
1471  return;
1472 
1473  if ( mAllowingNull )
1474  {
1475  mBlockChangedSignal++;
1476  if ( std::isnan( v.at( 0 ) ) )
1477  mMinSpinBox->clear();
1478  else
1479  mMinSpinBox->setValue( v.at( 0 ) );
1480 
1481  if ( v.count() >= 2 )
1482  {
1483  if ( std::isnan( v.at( 1 ) ) )
1484  mMaxSpinBox->clear();
1485  else
1486  mMaxSpinBox->setValue( v.at( 1 ) );
1487  }
1488  mBlockChangedSignal--;
1489  }
1490  else
1491  {
1492  mBlockChangedSignal++;
1493  mMinSpinBox->setValue( v.at( 0 ) );
1494  if ( v.count() >= 2 )
1495  mMaxSpinBox->setValue( v.at( 1 ) );
1496  mBlockChangedSignal--;
1497  }
1498  }
1499 
1500  if ( !mBlockChangedSignal )
1501  emit widgetValueHasChanged( this );
1502 }
1503 
1504 QVariant QgsProcessingRangeWidgetWrapper::widgetValue() const
1505 {
1506  if ( mAllowingNull )
1507  {
1508  QString value;
1509  if ( qgsDoubleNear( mMinSpinBox->value(), mMinSpinBox->minimum() ) )
1510  value = QStringLiteral( "None" );
1511  else
1512  value = QString::number( mMinSpinBox->value() );
1513 
1514  if ( qgsDoubleNear( mMaxSpinBox->value(), mMaxSpinBox->minimum() ) )
1515  value += QLatin1String( ",None" );
1516  else
1517  value += QStringLiteral( ",%1" ).arg( mMaxSpinBox->value() );
1518 
1519  return value;
1520  }
1521  else
1522  return QStringLiteral( "%1,%2" ).arg( mMinSpinBox->value() ).arg( mMaxSpinBox->value() );
1523 }
1524 
1525 QStringList QgsProcessingRangeWidgetWrapper::compatibleParameterTypes() const
1526 {
1527  return QStringList()
1530 }
1531 
1532 QStringList QgsProcessingRangeWidgetWrapper::compatibleOutputTypes() const
1533 {
1534  return QStringList() << QgsProcessingOutputString::typeName();
1535 }
1536 
1537 QString QgsProcessingRangeWidgetWrapper::modelerExpressionFormatString() const
1538 {
1539  return tr( "string as two comma delimited floats, e.g. '1,10'" );
1540 }
1541 
1542 QString QgsProcessingRangeWidgetWrapper::parameterType() const
1543 {
1545 }
1546 
1547 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRangeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1548 {
1549  return new QgsProcessingRangeWidgetWrapper( parameter, type );
1550 }
1551 
1552 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRangeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1553 {
1554  return new QgsProcessingRangeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1555 }
1556 
1557 
1558 //
1559 // QgsProcessingMatrixWidgetWrapper
1560 //
1561 
1562 QgsProcessingMatrixParameterDefinitionWidget::QgsProcessingMatrixParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1563  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1564 {
1565  QVBoxLayout *vlayout = new QVBoxLayout();
1566  vlayout->setContentsMargins( 0, 0, 0, 0 );
1567 
1568  mMatrixWidget = new QgsProcessingMatrixModelerWidget();
1569  if ( const QgsProcessingParameterMatrix *matrixParam = dynamic_cast<const QgsProcessingParameterMatrix *>( definition ) )
1570  {
1571  mMatrixWidget->setValue( matrixParam->headers(), matrixParam->defaultValueForGui() );
1572  mMatrixWidget->setFixedRows( matrixParam->hasFixedNumberRows() );
1573  }
1574  vlayout->addWidget( mMatrixWidget );
1575  setLayout( vlayout );
1576 }
1577 
1578 QgsProcessingParameterDefinition *QgsProcessingMatrixParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1579 {
1580  auto param = std::make_unique< QgsProcessingParameterMatrix >( name, description, 1, mMatrixWidget->fixedRows(), mMatrixWidget->headers(), mMatrixWidget->value() );
1581  param->setFlags( flags );
1582  return param.release();
1583 }
1584 
1585 
1586 QgsProcessingMatrixWidgetWrapper::QgsProcessingMatrixWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1587  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1588 {
1589 
1590 }
1591 
1592 QWidget *QgsProcessingMatrixWidgetWrapper::createWidget()
1593 {
1594  mMatrixWidget = new QgsProcessingMatrixParameterPanel( nullptr, dynamic_cast< const QgsProcessingParameterMatrix *>( parameterDefinition() ) );
1595  mMatrixWidget->setToolTip( parameterDefinition()->toolTip() );
1596 
1597  connect( mMatrixWidget, &QgsProcessingMatrixParameterPanel::changed, this, [ = ]
1598  {
1599  emit widgetValueHasChanged( this );
1600  } );
1601 
1602  switch ( type() )
1603  {
1607  {
1608  return mMatrixWidget;
1609  }
1610  }
1611  return nullptr;
1612 }
1613 
1614 void QgsProcessingMatrixWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1615 {
1616  const QVariantList v = QgsProcessingParameters::parameterAsMatrix( parameterDefinition(), value, context );
1617  if ( mMatrixWidget )
1618  mMatrixWidget->setValue( v );
1619 }
1620 
1621 QVariant QgsProcessingMatrixWidgetWrapper::widgetValue() const
1622 {
1623  if ( mMatrixWidget )
1624  return mMatrixWidget->value().isEmpty() ? QVariant() : mMatrixWidget->value();
1625  else
1626  return QVariant();
1627 }
1628 
1629 QStringList QgsProcessingMatrixWidgetWrapper::compatibleParameterTypes() const
1630 {
1631  return QStringList()
1633 }
1634 
1635 QStringList QgsProcessingMatrixWidgetWrapper::compatibleOutputTypes() const
1636 {
1637  return QStringList();
1638 }
1639 
1640 QString QgsProcessingMatrixWidgetWrapper::modelerExpressionFormatString() const
1641 {
1642  return tr( "comma delimited string of values, or an array of values" );
1643 }
1644 
1645 QString QgsProcessingMatrixWidgetWrapper::parameterType() const
1646 {
1648 }
1649 
1650 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMatrixWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1651 {
1652  return new QgsProcessingMatrixWidgetWrapper( parameter, type );
1653 }
1654 
1655 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMatrixWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1656 {
1657  return new QgsProcessingMatrixParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1658 }
1659 
1660 
1661 //
1662 // QgsProcessingFileWidgetWrapper
1663 //
1664 
1665 
1666 QgsProcessingFileParameterDefinitionWidget::QgsProcessingFileParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1667  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1668 {
1669  QVBoxLayout *vlayout = new QVBoxLayout();
1670  vlayout->setContentsMargins( 0, 0, 0, 0 );
1671 
1672  vlayout->addWidget( new QLabel( tr( "Type" ) ) );
1673 
1674  mTypeComboBox = new QComboBox();
1675  mTypeComboBox->addItem( tr( "File" ), QgsProcessingParameterFile::File );
1676  mTypeComboBox->addItem( tr( "Folder" ), QgsProcessingParameterFile::Folder );
1677  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1678  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( fileParam->behavior() ) );
1679  else
1680  mTypeComboBox->setCurrentIndex( 0 );
1681  vlayout->addWidget( mTypeComboBox );
1682 
1683  vlayout->addWidget( new QLabel( tr( "File filter" ) ) );
1684 
1685  mFilterComboBox = new QComboBox();
1686  mFilterComboBox->setEditable( true );
1687  // add some standard ones -- these also act as a demonstration of the required format
1688  mFilterComboBox->addItem( tr( "All Files (*.*)" ) );
1689  mFilterComboBox->addItem( tr( "CSV Files (*.csv)" ) );
1690  mFilterComboBox->addItem( tr( "HTML Files (*.html *.htm)" ) );
1691  mFilterComboBox->addItem( tr( "Text Files (*.txt)" ) );
1692  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1693  mFilterComboBox->setCurrentText( fileParam->fileFilter() );
1694  else
1695  mFilterComboBox->setCurrentIndex( 0 );
1696  vlayout->addWidget( mFilterComboBox );
1697 
1698  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1699 
1700  mDefaultFileWidget = new QgsFileWidget();
1701  mDefaultFileWidget->lineEdit()->setShowClearButton( true );
1702  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1703  {
1704  mDefaultFileWidget->setStorageMode( fileParam->behavior() == QgsProcessingParameterFile::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
1705  mDefaultFileWidget->setFilePath( fileParam->defaultValueForGui().toString() );
1706  }
1707  else
1708  mDefaultFileWidget->setStorageMode( QgsFileWidget::GetFile );
1709  vlayout->addWidget( mDefaultFileWidget );
1710 
1711  connect( mTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]
1712  {
1713  QgsProcessingParameterFile::Behavior behavior = static_cast< QgsProcessingParameterFile::Behavior >( mTypeComboBox->currentData().toInt() );
1714  mFilterComboBox->setEnabled( behavior == QgsProcessingParameterFile::File );
1715  mDefaultFileWidget->setStorageMode( behavior == QgsProcessingParameterFile::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
1716  } );
1717  mFilterComboBox->setEnabled( static_cast< QgsProcessingParameterFile::Behavior >( mTypeComboBox->currentData().toInt() ) == QgsProcessingParameterFile::File );
1718 
1719 
1720  setLayout( vlayout );
1721 }
1722 
1723 QgsProcessingParameterDefinition *QgsProcessingFileParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1724 {
1725  auto param = std::make_unique< QgsProcessingParameterFile >( name, description );
1726  param->setBehavior( static_cast< QgsProcessingParameterFile::Behavior>( mTypeComboBox->currentData().toInt() ) );
1727  if ( param->behavior() == QgsProcessingParameterFile::File )
1728  param->setFileFilter( mFilterComboBox->currentText() );
1729  if ( !mDefaultFileWidget->filePath().isEmpty() )
1730  param->setDefaultValue( mDefaultFileWidget->filePath() );
1731  param->setFlags( flags );
1732  return param.release();
1733 }
1734 
1735 
1736 QgsProcessingFileWidgetWrapper::QgsProcessingFileWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1737  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1738 {
1739 
1740 }
1741 
1742 QWidget *QgsProcessingFileWidgetWrapper::createWidget()
1743 {
1744  const QgsProcessingParameterFile *fileParam = dynamic_cast< const QgsProcessingParameterFile *>( parameterDefinition() );
1745  switch ( type() )
1746  {
1750  {
1751  mFileWidget = new QgsFileWidget();
1752  mFileWidget->setToolTip( parameterDefinition()->toolTip() );
1753  mFileWidget->setDialogTitle( parameterDefinition()->description() );
1754 
1755  mFileWidget->setDefaultRoot( QgsSettings().value( QStringLiteral( "/Processing/LastInputPath" ), QDir::homePath() ).toString() );
1756 
1757  switch ( fileParam->behavior() )
1758  {
1760  mFileWidget->setStorageMode( QgsFileWidget::GetFile );
1761  if ( !fileParam->fileFilter().isEmpty() )
1762  mFileWidget->setFilter( fileParam->fileFilter() );
1763  else if ( !fileParam->extension().isEmpty() )
1764  mFileWidget->setFilter( tr( "%1 files" ).arg( fileParam->extension().toUpper() ) + QStringLiteral( " (*." ) + fileParam->extension().toLower() + ')' );
1765  break;
1766 
1768  mFileWidget->setStorageMode( QgsFileWidget::GetDirectory );
1769  break;
1770  }
1771 
1772  connect( mFileWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & path )
1773  {
1774  QgsSettings().setValue( QStringLiteral( "/Processing/LastInputPath" ), QFileInfo( path ).canonicalPath() );
1775  emit widgetValueHasChanged( this );
1776  } );
1777  return mFileWidget;
1778  }
1779  }
1780  return nullptr;
1781 }
1782 
1783 void QgsProcessingFileWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1784 {
1785  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
1786  if ( mFileWidget )
1787  mFileWidget->setFilePath( v );
1788 }
1789 
1790 QVariant QgsProcessingFileWidgetWrapper::widgetValue() const
1791 {
1792  if ( mFileWidget )
1793  return mFileWidget->filePath();
1794  else
1795  return QVariant();
1796 }
1797 
1798 QStringList QgsProcessingFileWidgetWrapper::compatibleParameterTypes() const
1799 {
1800  return QStringList()
1803 }
1804 
1805 QStringList QgsProcessingFileWidgetWrapper::compatibleOutputTypes() const
1806 {
1807  return QStringList() << QgsProcessingOutputFile::typeName()
1813 }
1814 
1815 QString QgsProcessingFileWidgetWrapper::modelerExpressionFormatString() const
1816 {
1817  return tr( "string representing a path to a file or folder" );
1818 }
1819 
1820 QString QgsProcessingFileWidgetWrapper::parameterType() const
1821 {
1823 }
1824 
1825 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1826 {
1827  return new QgsProcessingFileWidgetWrapper( parameter, type );
1828 }
1829 
1830 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFileWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1831 {
1832  return new QgsProcessingFileParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1833 }
1834 
1835 
1836 
1837 //
1838 // QgsProcessingExpressionWidgetWrapper
1839 //
1840 
1841 QgsProcessingExpressionParameterDefinitionWidget::QgsProcessingExpressionParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1842  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1843 {
1844  QVBoxLayout *vlayout = new QVBoxLayout();
1845  vlayout->setContentsMargins( 0, 0, 0, 0 );
1846  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1847 
1848  mDefaultLineEdit = new QgsExpressionLineEdit();
1849  mDefaultLineEdit->registerExpressionContextGenerator( this );
1850 
1851  if ( const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( definition ) )
1852  mDefaultLineEdit->setExpression( QgsProcessingParameters::parameterAsExpression( expParam, expParam->defaultValueForGui(), context ) );
1853  vlayout->addWidget( mDefaultLineEdit );
1854 
1855  vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
1856 
1857  mParentLayerComboBox = new QComboBox();
1858  mParentLayerComboBox->addItem( tr( "None" ), QVariant() );
1859 
1860  QString initialParent;
1861  if ( const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( definition ) )
1862  initialParent = expParam->parentLayerParameterName();
1863 
1864  if ( QgsProcessingModelAlgorithm *model = widgetContext.model() )
1865  {
1866  // populate combo box with other model input choices
1867  const QMap<QString, QgsProcessingModelParameter> components = model->parameterComponents();
1868  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
1869  {
1870  if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast< const QgsProcessingParameterFeatureSource * >( model->parameterDefinition( it.value().parameterName() ) ) )
1871  {
1872  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
1873  if ( !initialParent.isEmpty() && initialParent == definition->name() )
1874  {
1875  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1876  }
1877  }
1878  else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast< const QgsProcessingParameterVectorLayer * >( model->parameterDefinition( it.value().parameterName() ) ) )
1879  {
1880  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
1881  if ( !initialParent.isEmpty() && initialParent == definition->name() )
1882  {
1883  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1884  }
1885  }
1886  }
1887  }
1888 
1889  if ( mParentLayerComboBox->count() == 1 && !initialParent.isEmpty() )
1890  {
1891  // if no parent candidates found, we just add the existing one as a placeholder
1892  mParentLayerComboBox->addItem( initialParent, initialParent );
1893  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1894  }
1895 
1896  vlayout->addWidget( mParentLayerComboBox );
1897  setLayout( vlayout );
1898 }
1899 
1900 QgsProcessingParameterDefinition *QgsProcessingExpressionParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1901 {
1902  auto param = std::make_unique< QgsProcessingParameterExpression >( name, description, mDefaultLineEdit->expression(), mParentLayerComboBox->currentData().toString() );
1903  param->setFlags( flags );
1904  return param.release();
1905 }
1906 
1907 QgsProcessingExpressionWidgetWrapper::QgsProcessingExpressionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1908  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1909 {
1910 
1911 }
1912 
1913 QWidget *QgsProcessingExpressionWidgetWrapper::createWidget()
1914 {
1915  const QgsProcessingParameterExpression *expParam = dynamic_cast< const QgsProcessingParameterExpression *>( parameterDefinition() );
1916  switch ( type() )
1917  {
1921  {
1922  if ( expParam->parentLayerParameterName().isEmpty() )
1923  {
1924  mExpLineEdit = new QgsExpressionLineEdit();
1925  mExpLineEdit->setToolTip( parameterDefinition()->toolTip() );
1926  mExpLineEdit->setExpressionDialogTitle( parameterDefinition()->description() );
1927  mExpLineEdit->registerExpressionContextGenerator( this );
1928  connect( mExpLineEdit, &QgsExpressionLineEdit::expressionChanged, this, [ = ]( const QString & )
1929  {
1930  emit widgetValueHasChanged( this );
1931  } );
1932  return mExpLineEdit;
1933  }
1934  else
1935  {
1936  if ( expParam->metadata().value( QStringLiteral( "inlineEditor" ) ).toBool() )
1937  {
1938  mExpBuilderWidget = new QgsExpressionBuilderWidget();
1939  mExpBuilderWidget->setToolTip( parameterDefinition()->toolTip() );
1940  mExpBuilderWidget->init( createExpressionContext() );
1941  connect( mExpBuilderWidget, &QgsExpressionBuilderWidget::expressionParsed, this, [ = ]( bool changed )
1942  {
1943  Q_UNUSED( changed );
1944  emit widgetValueHasChanged( this );
1945  } );
1946  return mExpBuilderWidget;
1947  }
1948  else
1949  {
1950  mFieldExpWidget = new QgsFieldExpressionWidget();
1951  mFieldExpWidget->setToolTip( parameterDefinition()->toolTip() );
1952  mFieldExpWidget->setExpressionDialogTitle( parameterDefinition()->description() );
1953  mFieldExpWidget->registerExpressionContextGenerator( this );
1955  mFieldExpWidget->setAllowEmptyFieldName( true );
1956 
1957  connect( mFieldExpWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString & ) >( &QgsFieldExpressionWidget::fieldChanged ), this, [ = ]( const QString & )
1958  {
1959  emit widgetValueHasChanged( this );
1960  } );
1961  return mFieldExpWidget;
1962  }
1963  }
1964  }
1965  }
1966  return nullptr;
1967 }
1968 
1969 void QgsProcessingExpressionWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1970 {
1972  switch ( type() )
1973  {
1976  {
1977  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1978  {
1979  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterExpression * >( parameterDefinition() )->parentLayerParameterName() )
1980  {
1981  setParentLayerWrapperValue( wrapper );
1983  {
1984  setParentLayerWrapperValue( wrapper );
1985  } );
1986  break;
1987  }
1988  }
1989  break;
1990  }
1991 
1993  break;
1994  }
1995 }
1996 
1997 void QgsProcessingExpressionWidgetWrapper::registerProcessingContextGenerator( QgsProcessingContextGenerator *generator )
1998 {
2000  if ( mExpBuilderWidget )
2001  {
2002  // we need to regenerate the expression context for use by this widget -- it doesn't fetch automatically on demand
2003  mExpBuilderWidget->setExpressionContext( createExpressionContext() );
2004  }
2005 }
2006 
2007 void QgsProcessingExpressionWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
2008 {
2009  // evaluate value to layer
2010  QgsProcessingContext *context = nullptr;
2011  std::unique_ptr< QgsProcessingContext > tmpContext;
2012  if ( mProcessingContextGenerator )
2013  context = mProcessingContextGenerator->processingContext();
2014 
2015  if ( !context )
2016  {
2017  tmpContext = std::make_unique< QgsProcessingContext >();
2018  context = tmpContext.get();
2019  }
2020 
2021  QVariant val = parentWrapper->parameterValue();
2022  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
2023  {
2024  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
2025  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
2026  val = fromVar.source;
2027  }
2028 
2029  QgsVectorLayer *layer = QgsProcessingParameters::parameterAsVectorLayer( parentWrapper->parameterDefinition(), val, *context );
2030  if ( !layer )
2031  {
2032  if ( mFieldExpWidget )
2033  mFieldExpWidget->setLayer( nullptr );
2034  else if ( mExpBuilderWidget )
2035  mExpBuilderWidget->setLayer( nullptr );
2036  else if ( mExpLineEdit )
2037  mExpLineEdit->setLayer( nullptr );
2038  return;
2039  }
2040 
2041  // need to grab ownership of layer if required - otherwise layer may be deleted when context
2042  // goes out of scope
2043  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
2044  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::VectorLayer )
2045  {
2046  mParentLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
2047  layer = mParentLayer.get();
2048  }
2049  else
2050  {
2051  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
2052  }
2053 
2054  if ( mFieldExpWidget )
2055  mFieldExpWidget->setLayer( layer );
2056  if ( mExpBuilderWidget )
2057  mExpBuilderWidget->setLayer( layer );
2058  else if ( mExpLineEdit )
2059  mExpLineEdit->setLayer( layer );
2060 }
2061 
2062 void QgsProcessingExpressionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2063 {
2064  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2065  if ( mFieldExpWidget )
2066  mFieldExpWidget->setExpression( v );
2067  else if ( mExpBuilderWidget )
2068  mExpBuilderWidget->setExpressionText( v );
2069  else if ( mExpLineEdit )
2070  mExpLineEdit->setExpression( v );
2071 }
2072 
2073 QVariant QgsProcessingExpressionWidgetWrapper::widgetValue() const
2074 {
2075  if ( mFieldExpWidget )
2076  return mFieldExpWidget->expression();
2077  if ( mExpBuilderWidget )
2078  return mExpBuilderWidget->expressionText();
2079  else if ( mExpLineEdit )
2080  return mExpLineEdit->expression();
2081  else
2082  return QVariant();
2083 }
2084 
2085 QStringList QgsProcessingExpressionWidgetWrapper::compatibleParameterTypes() const
2086 {
2087  return QStringList()
2094 }
2095 
2096 QStringList QgsProcessingExpressionWidgetWrapper::compatibleOutputTypes() const
2097 {
2098  return QStringList()
2101 }
2102 
2103 QString QgsProcessingExpressionWidgetWrapper::modelerExpressionFormatString() const
2104 {
2105  return tr( "string representation of an expression" );
2106 }
2107 
2108 const QgsVectorLayer *QgsProcessingExpressionWidgetWrapper::linkedVectorLayer() const
2109 {
2110  if ( mFieldExpWidget && mFieldExpWidget->layer() )
2111  return mFieldExpWidget->layer();
2112 
2113  if ( mExpBuilderWidget && mExpBuilderWidget->layer() )
2114  return mExpBuilderWidget->layer();
2115 
2117 }
2118 
2119 QString QgsProcessingExpressionWidgetWrapper::parameterType() const
2120 {
2122 }
2123 
2124 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExpressionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2125 {
2126  return new QgsProcessingExpressionWidgetWrapper( parameter, type );
2127 }
2128 
2129 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingExpressionWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2130 {
2131  return new QgsProcessingExpressionParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2132 }
2133 
2134 
2135 
2136 //
2137 // QgsProcessingEnumPanelWidget
2138 //
2139 
2140 QgsProcessingEnumPanelWidget::QgsProcessingEnumPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param )
2141  : QWidget( parent )
2142  , mParam( param )
2143 {
2144  QHBoxLayout *hl = new QHBoxLayout();
2145  hl->setContentsMargins( 0, 0, 0, 0 );
2146 
2147  mLineEdit = new QLineEdit();
2148  mLineEdit->setEnabled( false );
2149  hl->addWidget( mLineEdit, 1 );
2150 
2151  mToolButton = new QToolButton();
2152  mToolButton->setText( QString( QChar( 0x2026 ) ) );
2153  hl->addWidget( mToolButton );
2154 
2155  setLayout( hl );
2156 
2157  if ( mParam )
2158  {
2159  mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
2160  }
2161 
2162  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingEnumPanelWidget::showDialog );
2163 }
2164 
2165 void QgsProcessingEnumPanelWidget::setValue( const QVariant &value )
2166 {
2167  if ( value.isValid() )
2168  {
2169  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
2170 
2171  if ( mParam->usesStaticStrings() && mValue.count() == 1 && mValue.at( 0 ).toString().isEmpty() )
2172  mValue.clear();
2173  }
2174  else
2175  mValue.clear();
2176 
2177  updateSummaryText();
2178  emit changed();
2179 }
2180 
2181 void QgsProcessingEnumPanelWidget::showDialog()
2182 {
2183  QVariantList availableOptions;
2184  if ( mParam )
2185  {
2186  availableOptions.reserve( mParam->options().size() );
2187  for ( int i = 0; i < mParam->options().count(); ++i )
2188  availableOptions << i;
2189  }
2190 
2191  const QStringList options = mParam ? mParam->options() : QStringList();
2193  if ( panel && panel->dockMode() )
2194  {
2195  QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
2196  widget->setPanelTitle( mParam->description() );
2197 
2198  if ( mParam->usesStaticStrings() )
2199  {
2200  widget->setValueFormatter( [options]( const QVariant & v ) -> QString
2201  {
2202  const QString i = v.toString();
2203  return options.contains( i ) ? i : QString();
2204  } );
2205  }
2206  else
2207  {
2208  widget->setValueFormatter( [options]( const QVariant & v ) -> QString
2209  {
2210  const int i = v.toInt();
2211  return options.size() > i ? options.at( i ) : QString();
2212  } );
2213  }
2214 
2215  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
2216  {
2217  setValue( widget->selectedOptions() );
2218  } );
2219  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
2220  panel->openPanel( widget );
2221  }
2222  else
2223  {
2224  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
2225 
2226  dlg.setValueFormatter( [options]( const QVariant & v ) -> QString
2227  {
2228  const int i = v.toInt();
2229  return options.size() > i ? options.at( i ) : QString();
2230  } );
2231  if ( dlg.exec() )
2232  {
2233  setValue( dlg.selectedOptions() );
2234  }
2235  }
2236 }
2237 
2238 void QgsProcessingEnumPanelWidget::updateSummaryText()
2239 {
2240  if ( mParam )
2241  mLineEdit->setText( tr( "%1 options selected" ).arg( mValue.count() ) );
2242 }
2243 
2244 
2245 //
2246 // QgsProcessingEnumCheckboxPanelWidget
2247 //
2248 QgsProcessingEnumCheckboxPanelWidget::QgsProcessingEnumCheckboxPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param, int columns )
2249  : QWidget( parent )
2250  , mParam( param )
2251  , mButtonGroup( new QButtonGroup( this ) )
2252  , mColumns( columns )
2253 {
2254  mButtonGroup->setExclusive( !mParam->allowMultiple() );
2255 
2256  QGridLayout *l = new QGridLayout();
2257  l->setContentsMargins( 0, 0, 0, 0 );
2258 
2259  int rows = static_cast< int >( std::ceil( mParam->options().count() / static_cast< double >( mColumns ) ) );
2260  for ( int i = 0; i < mParam->options().count(); ++i )
2261  {
2262  QAbstractButton *button = nullptr;
2263  if ( mParam->allowMultiple() )
2264  button = new QCheckBox( mParam->options().at( i ) );
2265  else
2266  button = new QRadioButton( mParam->options().at( i ) );
2267 
2268  connect( button, &QAbstractButton::toggled, this, [ = ]
2269  {
2270  if ( !mBlockChangedSignal )
2271  emit changed();
2272  } );
2273 
2274  mButtons.insert( i, button );
2275 
2276  mButtonGroup->addButton( button, i );
2277  l->addWidget( button, i % rows, i / rows );
2278  }
2279  l->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ), 0, mColumns );
2280  setLayout( l );
2281 
2282  if ( mParam->allowMultiple() )
2283  {
2284  setContextMenuPolicy( Qt::CustomContextMenu );
2285  connect( this, &QWidget::customContextMenuRequested, this, &QgsProcessingEnumCheckboxPanelWidget::showPopupMenu );
2286  }
2287 }
2288 
2289 QVariant QgsProcessingEnumCheckboxPanelWidget::value() const
2290 {
2291  if ( mParam->allowMultiple() )
2292  {
2293  QVariantList value;
2294  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2295  {
2296  if ( it.value()->isChecked() )
2297  value.append( mParam->usesStaticStrings() ? mParam->options().at( it.key().toInt() ) : it.key() );
2298  }
2299  return value;
2300  }
2301  else
2302  {
2303  if ( mParam->usesStaticStrings() )
2304  return mButtonGroup->checkedId() >= 0 ? mParam->options().at( mButtonGroup->checkedId() ) : QVariant();
2305  else
2306  return mButtonGroup->checkedId() >= 0 ? mButtonGroup->checkedId() : QVariant();
2307  }
2308 }
2309 
2310 void QgsProcessingEnumCheckboxPanelWidget::setValue( const QVariant &value )
2311 {
2312  mBlockChangedSignal = true;
2313  if ( mParam->allowMultiple() )
2314  {
2315  QVariantList selected;
2316  if ( value.isValid() )
2317  selected = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
2318  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2319  {
2320  QVariant v = mParam->usesStaticStrings() ? mParam->options().at( it.key().toInt() ) : it.key();
2321  it.value()->setChecked( selected.contains( v ) );
2322  }
2323  }
2324  else
2325  {
2326  QVariant v = value;
2327  if ( v.type() == QVariant::List )
2328  v = v.toList().value( 0 );
2329 
2330  v = mParam->usesStaticStrings() ? mParam->options().indexOf( v.toString() ) : v;
2331  if ( mButtons.contains( v ) )
2332  mButtons.value( v )->setChecked( true );
2333  }
2334  mBlockChangedSignal = false;
2335  emit changed();
2336 }
2337 
2338 void QgsProcessingEnumCheckboxPanelWidget::showPopupMenu()
2339 {
2340  QMenu popupMenu;
2341  QAction *selectAllAction = new QAction( tr( "Select All" ), &popupMenu );
2342  connect( selectAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::selectAll );
2343  QAction *clearAllAction = new QAction( tr( "Clear Selection" ), &popupMenu );
2344  connect( clearAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::deselectAll );
2345  popupMenu.addAction( selectAllAction );
2346  popupMenu.addAction( clearAllAction );
2347  popupMenu.exec( QCursor::pos() );
2348 }
2349 
2350 void QgsProcessingEnumCheckboxPanelWidget::selectAll()
2351 {
2352  mBlockChangedSignal = true;
2353  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2354  it.value()->setChecked( true );
2355  mBlockChangedSignal = false;
2356  emit changed();
2357 }
2358 
2359 void QgsProcessingEnumCheckboxPanelWidget::deselectAll()
2360 {
2361  mBlockChangedSignal = true;
2362  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2363  it.value()->setChecked( false );
2364  mBlockChangedSignal = false;
2365  emit changed();
2366 }
2367 
2368 
2369 //
2370 // QgsProcessingEnumWidgetWrapper
2371 //
2372 
2373 QgsProcessingEnumParameterDefinitionWidget::QgsProcessingEnumParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2374  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2375 {
2376  QVBoxLayout *vlayout = new QVBoxLayout();
2377  vlayout->setContentsMargins( 0, 0, 0, 0 );
2378 
2379  mEnumWidget = new QgsProcessingEnumModelerWidget();
2380  if ( const QgsProcessingParameterEnum *enumParam = dynamic_cast<const QgsProcessingParameterEnum *>( definition ) )
2381  {
2382  mEnumWidget->setAllowMultiple( enumParam->allowMultiple() );
2383  mEnumWidget->setOptions( enumParam->options() );
2384  mEnumWidget->setDefaultOptions( enumParam->defaultValueForGui() );
2385  }
2386  vlayout->addWidget( mEnumWidget );
2387  setLayout( vlayout );
2388 }
2389 
2390 QgsProcessingParameterDefinition *QgsProcessingEnumParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2391 {
2392  auto param = std::make_unique< QgsProcessingParameterEnum >( name, description, mEnumWidget->options(), mEnumWidget->allowMultiple(), mEnumWidget->defaultOptions() );
2393  param->setFlags( flags );
2394  return param.release();
2395 }
2396 
2397 
2398 QgsProcessingEnumWidgetWrapper::QgsProcessingEnumWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2399  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2400 {
2401 
2402 }
2403 
2404 QWidget *QgsProcessingEnumWidgetWrapper::createWidget()
2405 {
2406  const QgsProcessingParameterEnum *expParam = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
2407  switch ( type() )
2408  {
2410  {
2411  // checkbox panel only for use outside in standard gui!
2412  if ( expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "useCheckBoxes" ), false ).toBool() )
2413  {
2414  const int columns = expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "columns" ), 2 ).toInt();
2415  mCheckboxPanel = new QgsProcessingEnumCheckboxPanelWidget( nullptr, expParam, columns );
2416  mCheckboxPanel->setToolTip( parameterDefinition()->toolTip() );
2417  connect( mCheckboxPanel, &QgsProcessingEnumCheckboxPanelWidget::changed, this, [ = ]
2418  {
2419  emit widgetValueHasChanged( this );
2420  } );
2421  return mCheckboxPanel;
2422  }
2423  }
2424  FALLTHROUGH
2427  {
2428  if ( expParam->allowMultiple() )
2429  {
2430  mPanel = new QgsProcessingEnumPanelWidget( nullptr, expParam );
2431  mPanel->setToolTip( parameterDefinition()->toolTip() );
2432  connect( mPanel, &QgsProcessingEnumPanelWidget::changed, this, [ = ]
2433  {
2434  emit widgetValueHasChanged( this );
2435  } );
2436  return mPanel;
2437  }
2438  else
2439  {
2440  mComboBox = new QComboBox();
2441 
2443  mComboBox->addItem( tr( "[Not selected]" ), QVariant() );
2444  const QStringList options = expParam->options();
2445  for ( int i = 0; i < options.count(); ++i )
2446  {
2447  if ( expParam->usesStaticStrings() )
2448  mComboBox->addItem( options.at( i ), options.at( i ) );
2449  else
2450  mComboBox->addItem( options.at( i ), i );
2451  }
2452 
2453  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2454  connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
2455  {
2456  emit widgetValueHasChanged( this );
2457  } );
2458  return mComboBox;
2459  }
2460  }
2461  }
2462  return nullptr;
2463 }
2464 
2465 void QgsProcessingEnumWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2466 {
2467  if ( mComboBox )
2468  {
2469  if ( !value.isValid() )
2470  mComboBox->setCurrentIndex( mComboBox->findData( QVariant() ) );
2471  else
2472  {
2473  const QgsProcessingParameterEnum *enumDef = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
2474  if ( enumDef->usesStaticStrings() )
2475  {
2476  const QString v = QgsProcessingParameters::parameterAsEnumString( parameterDefinition(), value, context );
2477  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
2478  }
2479  else
2480  {
2481  const int v = QgsProcessingParameters::parameterAsEnum( parameterDefinition(), value, context );
2482  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
2483  }
2484  }
2485  }
2486  else if ( mPanel || mCheckboxPanel )
2487  {
2488  QVariantList opts;
2489  if ( value.isValid() )
2490  {
2491  const QgsProcessingParameterEnum *enumDef = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
2492  if ( enumDef->usesStaticStrings() )
2493  {
2494  const QStringList v = QgsProcessingParameters::parameterAsEnumStrings( parameterDefinition(), value, context );
2495  opts.reserve( v.size() );
2496  for ( QString i : v )
2497  opts << i;
2498  }
2499  else
2500  {
2501  const QList< int > v = QgsProcessingParameters::parameterAsEnums( parameterDefinition(), value, context );
2502  opts.reserve( v.size() );
2503  for ( int i : v )
2504  opts << i;
2505  }
2506  }
2507  if ( mPanel )
2508  mPanel->setValue( opts );
2509  else if ( mCheckboxPanel )
2510  mCheckboxPanel->setValue( opts );
2511  }
2512 }
2513 
2514 QVariant QgsProcessingEnumWidgetWrapper::widgetValue() const
2515 {
2516  if ( mComboBox )
2517  return mComboBox->currentData();
2518  else if ( mPanel )
2519  return mPanel->value();
2520  else if ( mCheckboxPanel )
2521  return mCheckboxPanel->value();
2522  else
2523  return QVariant();
2524 }
2525 
2526 QStringList QgsProcessingEnumWidgetWrapper::compatibleParameterTypes() const
2527 {
2528  return QStringList()
2532 }
2533 
2534 QStringList QgsProcessingEnumWidgetWrapper::compatibleOutputTypes() const
2535 {
2536  return QStringList()
2539 }
2540 
2541 QString QgsProcessingEnumWidgetWrapper::modelerExpressionFormatString() const
2542 {
2543  return tr( "selected option index (starting from 0), array of indices, or comma separated string of options (e.g. '1,3')" );
2544 }
2545 
2546 QString QgsProcessingEnumWidgetWrapper::parameterType() const
2547 {
2549 }
2550 
2551 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingEnumWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2552 {
2553  return new QgsProcessingEnumWidgetWrapper( parameter, type );
2554 }
2555 
2556 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingEnumWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2557 {
2558  return new QgsProcessingEnumParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2559 }
2560 
2561 //
2562 // QgsProcessingLayoutWidgetWrapper
2563 //
2564 
2565 QgsProcessingLayoutWidgetWrapper::QgsProcessingLayoutWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2566  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2567 {
2568 
2569 }
2570 
2571 QWidget *QgsProcessingLayoutWidgetWrapper::createWidget()
2572 {
2573  const QgsProcessingParameterLayout *layoutParam = dynamic_cast< const QgsProcessingParameterLayout *>( parameterDefinition() );
2574  switch ( type() )
2575  {
2578  {
2579  // combobox only for use outside modeler!
2580  mComboBox = new QgsLayoutComboBox( nullptr, widgetContext().project() ? widgetContext().project()->layoutManager() : nullptr );
2582  mComboBox->setAllowEmptyLayout( true );
2583  mComboBox->setFilters( QgsLayoutManagerProxyModel::FilterPrintLayouts );
2584 
2585  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2586  connect( mComboBox, &QgsLayoutComboBox::layoutChanged, this, [ = ]( QgsMasterLayoutInterface * )
2587  {
2588  emit widgetValueHasChanged( this );
2589  } );
2590  return mComboBox;
2591  }
2592 
2594  {
2595  mPlainComboBox = new QComboBox();
2596  mPlainComboBox->setEditable( true );
2597  mPlainComboBox->setToolTip( tr( "Name of an existing print layout" ) );
2598  if ( widgetContext().project() )
2599  {
2600  const QList< QgsPrintLayout * > layouts = widgetContext().project()->layoutManager()->printLayouts();
2601  for ( const QgsPrintLayout *layout : layouts )
2602  mPlainComboBox->addItem( layout->name() );
2603  }
2604 
2605  connect( mPlainComboBox, &QComboBox::currentTextChanged, this, [ = ]( const QString & )
2606  {
2607  emit widgetValueHasChanged( this );
2608  } );
2609  return mPlainComboBox;
2610  }
2611  }
2612  return nullptr;
2613 }
2614 
2615 void QgsProcessingLayoutWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2616 {
2617  if ( mComboBox )
2618  {
2619  if ( !value.isValid() )
2620  mComboBox->setCurrentLayout( nullptr );
2621  else
2622  {
2623  if ( QgsPrintLayout *l = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, context ) )
2624  mComboBox->setCurrentLayout( l );
2625  else
2626  mComboBox->setCurrentLayout( nullptr );
2627  }
2628  }
2629  else if ( mPlainComboBox )
2630  {
2631  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2632  mPlainComboBox->setCurrentText( v );
2633  }
2634 }
2635 
2636 QVariant QgsProcessingLayoutWidgetWrapper::widgetValue() const
2637 {
2638  if ( mComboBox )
2639  {
2640  const QgsMasterLayoutInterface *l = mComboBox->currentLayout();
2641  return l ? l->name() : QVariant();
2642  }
2643  else if ( mPlainComboBox )
2644  return mPlainComboBox->currentText().isEmpty() ? QVariant() : mPlainComboBox->currentText();
2645  else
2646  return QVariant();
2647 }
2648 
2649 void QgsProcessingLayoutWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
2650 {
2652  if ( mPlainComboBox && context.project() )
2653  {
2654  const QList< QgsPrintLayout * > layouts = widgetContext().project()->layoutManager()->printLayouts();
2655  for ( const QgsPrintLayout *layout : layouts )
2656  mPlainComboBox->addItem( layout->name() );
2657  }
2658 }
2659 
2660 QStringList QgsProcessingLayoutWidgetWrapper::compatibleParameterTypes() const
2661 {
2662  return QStringList()
2665 }
2666 
2667 QStringList QgsProcessingLayoutWidgetWrapper::compatibleOutputTypes() const
2668 {
2669  return QStringList()
2671 }
2672 
2673 QString QgsProcessingLayoutWidgetWrapper::modelerExpressionFormatString() const
2674 {
2675  return tr( "string representing the name of an existing print layout" );
2676 }
2677 
2678 QString QgsProcessingLayoutWidgetWrapper::parameterType() const
2679 {
2681 }
2682 
2683 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2684 {
2685  return new QgsProcessingLayoutWidgetWrapper( parameter, type );
2686 }
2687 
2688 
2689 
2690 
2691 //
2692 // QgsProcessingLayoutItemWidgetWrapper
2693 //
2694 
2695 
2696 QgsProcessingLayoutItemParameterDefinitionWidget::QgsProcessingLayoutItemParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2697  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2698 {
2699  QVBoxLayout *vlayout = new QVBoxLayout();
2700  vlayout->setContentsMargins( 0, 0, 0, 0 );
2701 
2702  vlayout->addWidget( new QLabel( tr( "Parent layout" ) ) );
2703 
2704  mParentLayoutComboBox = new QComboBox();
2705  QString initialParent;
2706  if ( const QgsProcessingParameterLayoutItem *itemParam = dynamic_cast<const QgsProcessingParameterLayoutItem *>( definition ) )
2707  initialParent = itemParam->parentLayoutParameterName();
2708 
2709  if ( auto *lModel = widgetContext.model() )
2710  {
2711  // populate combo box with other model input choices
2712  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
2713  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
2714  {
2715  if ( const QgsProcessingParameterLayout *definition = dynamic_cast< const QgsProcessingParameterLayout * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
2716  {
2717  mParentLayoutComboBox-> addItem( definition->description(), definition->name() );
2718  if ( !initialParent.isEmpty() && initialParent == definition->name() )
2719  {
2720  mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
2721  }
2722  }
2723  }
2724  }
2725 
2726  if ( mParentLayoutComboBox->count() == 0 && !initialParent.isEmpty() )
2727  {
2728  // if no parent candidates found, we just add the existing one as a placeholder
2729  mParentLayoutComboBox->addItem( initialParent, initialParent );
2730  mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
2731  }
2732 
2733  vlayout->addWidget( mParentLayoutComboBox );
2734  setLayout( vlayout );
2735 }
2736 QgsProcessingParameterDefinition *QgsProcessingLayoutItemParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2737 {
2738  auto param = std::make_unique< QgsProcessingParameterLayoutItem >( name, description, QVariant(), mParentLayoutComboBox->currentData().toString() );
2739  param->setFlags( flags );
2740  return param.release();
2741 }
2742 
2743 
2744 QgsProcessingLayoutItemWidgetWrapper::QgsProcessingLayoutItemWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2745  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2746 {
2747 
2748 }
2749 
2750 QWidget *QgsProcessingLayoutItemWidgetWrapper::createWidget()
2751 {
2752  const QgsProcessingParameterLayoutItem *layoutParam = dynamic_cast< const QgsProcessingParameterLayoutItem *>( parameterDefinition() );
2753  switch ( type() )
2754  {
2757  {
2758  // combobox only for use outside modeler!
2759  mComboBox = new QgsLayoutItemComboBox( nullptr, nullptr );
2761  mComboBox->setAllowEmptyItem( true );
2762  if ( layoutParam->itemType() >= 0 )
2763  mComboBox->setItemType( static_cast< QgsLayoutItemRegistry::ItemType >( layoutParam->itemType() ) );
2764 
2765  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2766  connect( mComboBox, &QgsLayoutItemComboBox::itemChanged, this, [ = ]( QgsLayoutItem * )
2767  {
2768  emit widgetValueHasChanged( this );
2769  } );
2770  return mComboBox;
2771  }
2772 
2774  {
2775  mLineEdit = new QLineEdit();
2776  mLineEdit->setToolTip( tr( "UUID or ID of an existing print layout item" ) );
2777  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
2778  {
2779  emit widgetValueHasChanged( this );
2780  } );
2781  return mLineEdit;
2782  }
2783  }
2784  return nullptr;
2785 }
2786 
2787 void QgsProcessingLayoutItemWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
2788 {
2790  switch ( type() )
2791  {
2794  {
2795  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
2796  {
2797  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterLayoutItem * >( parameterDefinition() )->parentLayoutParameterName() )
2798  {
2799  setLayoutParameterValue( wrapper->parameterValue() );
2801  {
2802  setLayoutParameterValue( wrapper->parameterValue() );
2803  } );
2804  break;
2805  }
2806  }
2807  break;
2808  }
2809 
2811  break;
2812  }
2813 }
2814 
2815 void QgsProcessingLayoutItemWidgetWrapper::setLayoutParameterValue( const QVariant &value )
2816 {
2817  QgsPrintLayout *layout = nullptr;
2818 
2819  // evaluate value to layout
2820  QgsProcessingContext *context = nullptr;
2821  std::unique_ptr< QgsProcessingContext > tmpContext;
2822  if ( mProcessingContextGenerator )
2823  context = mProcessingContextGenerator->processingContext();
2824 
2825  if ( !context )
2826  {
2827  tmpContext = std::make_unique< QgsProcessingContext >();
2828  context = tmpContext.get();
2829  }
2830 
2831  layout = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, *context );
2832  setLayout( layout );
2833 }
2834 
2835 void QgsProcessingLayoutItemWidgetWrapper::setLayout( QgsPrintLayout *layout )
2836 {
2837  if ( mComboBox )
2838  mComboBox->setCurrentLayout( layout );
2839 }
2840 
2841 void QgsProcessingLayoutItemWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2842 {
2843  if ( mComboBox )
2844  {
2845  if ( !value.isValid() )
2846  mComboBox->setItem( nullptr );
2847  else
2848  {
2849  QgsLayoutItem *item = QgsProcessingParameters::parameterAsLayoutItem( parameterDefinition(), value, context, qobject_cast< QgsPrintLayout * >( mComboBox->currentLayout() ) );
2850  mComboBox->setItem( item );
2851  }
2852  }
2853  else if ( mLineEdit )
2854  {
2855  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2856  mLineEdit->setText( v );
2857  }
2858 }
2859 
2860 QVariant QgsProcessingLayoutItemWidgetWrapper::widgetValue() const
2861 {
2862  if ( mComboBox )
2863  {
2864  const QgsLayoutItem *i = mComboBox->currentItem();
2865  return i ? i->uuid() : QVariant();
2866  }
2867  else if ( mLineEdit )
2868  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
2869  else
2870  return QVariant();
2871 }
2872 
2873 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleParameterTypes() const
2874 {
2875  return QStringList()
2878 }
2879 
2880 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleOutputTypes() const
2881 {
2882  return QStringList()
2884 }
2885 
2886 QString QgsProcessingLayoutItemWidgetWrapper::modelerExpressionFormatString() const
2887 {
2888  return tr( "string representing the UUID or ID of an existing print layout item" );
2889 }
2890 
2891 QString QgsProcessingLayoutItemWidgetWrapper::parameterType() const
2892 {
2894 }
2895 
2896 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutItemWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2897 {
2898  return new QgsProcessingLayoutItemWidgetWrapper( parameter, type );
2899 }
2900 
2901 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingLayoutItemWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2902 {
2903  return new QgsProcessingLayoutItemParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2904 }
2905 
2906 //
2907 // QgsProcessingPointMapTool
2908 //
2909 
2910 QgsProcessingPointMapTool::QgsProcessingPointMapTool( QgsMapCanvas *canvas )
2911  : QgsMapTool( canvas )
2912 {
2913  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::CapturePoint ) );
2914  mSnapIndicator.reset( new QgsSnapIndicator( canvas ) );
2915 }
2916 
2917 QgsProcessingPointMapTool::~QgsProcessingPointMapTool() = default;
2918 
2919 void QgsProcessingPointMapTool::deactivate()
2920 {
2921  mSnapIndicator->setMatch( QgsPointLocator::Match() );
2923 }
2924 
2925 void QgsProcessingPointMapTool::canvasMoveEvent( QgsMapMouseEvent *e )
2926 {
2927  e->snapPoint();
2928  mSnapIndicator->setMatch( e->mapPointMatch() );
2929 }
2930 
2931 void QgsProcessingPointMapTool::canvasPressEvent( QgsMapMouseEvent *e )
2932 {
2933  if ( e->button() == Qt::LeftButton )
2934  {
2935  QgsPointXY point = e->snapPoint();
2936  emit clicked( point );
2937  emit complete();
2938  }
2939 }
2940 
2941 void QgsProcessingPointMapTool::keyPressEvent( QKeyEvent *e )
2942 {
2943  if ( e->key() == Qt::Key_Escape )
2944  {
2945 
2946  // Override default shortcut management in MapCanvas
2947  e->ignore();
2948  emit complete();
2949  }
2950 }
2951 
2952 
2953 
2954 //
2955 // QgsProcessingPointPanel
2956 //
2957 
2958 QgsProcessingPointPanel::QgsProcessingPointPanel( QWidget *parent )
2959  : QWidget( parent )
2960 {
2961  QHBoxLayout *l = new QHBoxLayout();
2962  l->setContentsMargins( 0, 0, 0, 0 );
2963  mLineEdit = new QgsFilterLineEdit( );
2964  mLineEdit->setShowClearButton( false );
2965  l->addWidget( mLineEdit, 1 );
2966  mButton = new QToolButton();
2967  mButton->setText( QString( QChar( 0x2026 ) ) );
2968  l->addWidget( mButton );
2969  setLayout( l );
2970 
2971  connect( mLineEdit, &QLineEdit::textChanged, this, &QgsProcessingPointPanel::changed );
2972  connect( mButton, &QToolButton::clicked, this, &QgsProcessingPointPanel::selectOnCanvas );
2973  mButton->setVisible( false );
2974 }
2975 
2976 void QgsProcessingPointPanel::setMapCanvas( QgsMapCanvas *canvas )
2977 {
2978  mCanvas = canvas;
2979  mButton->setVisible( true );
2980 
2981  mCrs = canvas->mapSettings().destinationCrs();
2982  mTool = std::make_unique< QgsProcessingPointMapTool >( mCanvas );
2983  connect( mTool.get(), &QgsProcessingPointMapTool::clicked, this, &QgsProcessingPointPanel::updatePoint );
2984  connect( mTool.get(), &QgsProcessingPointMapTool::complete, this, &QgsProcessingPointPanel::pointPicked );
2985 }
2986 
2987 void QgsProcessingPointPanel::setAllowNull( bool allowNull )
2988 {
2989  mLineEdit->setShowClearButton( allowNull );
2990 }
2991 
2992 QVariant QgsProcessingPointPanel::value() const
2993 {
2994  return mLineEdit->showClearButton() && mLineEdit->text().trimmed().isEmpty() ? QVariant() : QVariant( mLineEdit->text() );
2995 }
2996 
2997 void QgsProcessingPointPanel::clear()
2998 {
2999  mLineEdit->clear();
3000 }
3001 
3002 void QgsProcessingPointPanel::setValue( const QgsPointXY &point, const QgsCoordinateReferenceSystem &crs )
3003 {
3004  QString newText = QStringLiteral( "%1,%2" )
3005  .arg( QString::number( point.x(), 'f' ),
3006  QString::number( point.y(), 'f' ) );
3007 
3008  mCrs = crs;
3009  if ( mCrs.isValid() )
3010  {
3011  newText += QStringLiteral( " [%1]" ).arg( mCrs.authid() );
3012  }
3013  mLineEdit->setText( newText );
3014 }
3015 
3016 void QgsProcessingPointPanel::selectOnCanvas()
3017 {
3018  if ( !mCanvas )
3019  return;
3020 
3021  mPrevTool = mCanvas->mapTool();
3022  mCanvas->setMapTool( mTool.get() );
3023 
3024  emit toggleDialogVisibility( false );
3025 }
3026 
3027 void QgsProcessingPointPanel::updatePoint( const QgsPointXY &point )
3028 {
3029  setValue( point, mCanvas->mapSettings().destinationCrs() );
3030 }
3031 
3032 void QgsProcessingPointPanel::pointPicked()
3033 {
3034  if ( !mCanvas )
3035  return;
3036 
3037  mCanvas->setMapTool( mPrevTool );
3038 
3039  emit toggleDialogVisibility( true );
3040 }
3041 
3042 
3043 
3044 //
3045 // QgsProcessingPointWidgetWrapper
3046 //
3047 
3048 QgsProcessingPointParameterDefinitionWidget::QgsProcessingPointParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3049  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3050 {
3051  QVBoxLayout *vlayout = new QVBoxLayout();
3052  vlayout->setContentsMargins( 0, 0, 0, 0 );
3053 
3054  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3055 
3056  mDefaultLineEdit = new QLineEdit();
3057  mDefaultLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
3058  mDefaultLineEdit->setPlaceholderText( tr( "Point as 'x,y'" ) );
3059  if ( const QgsProcessingParameterPoint *pointParam = dynamic_cast<const QgsProcessingParameterPoint *>( definition ) )
3060  {
3061  QgsPointXY point = QgsProcessingParameters::parameterAsPoint( pointParam, pointParam->defaultValueForGui(), context );
3062  mDefaultLineEdit->setText( QStringLiteral( "%1,%2" ).arg( QString::number( point.x(), 'f' ), QString::number( point.y(), 'f' ) ) );
3063  }
3064 
3065  vlayout->addWidget( mDefaultLineEdit );
3066  setLayout( vlayout );
3067 }
3068 
3069 QgsProcessingParameterDefinition *QgsProcessingPointParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3070 {
3071  auto param = std::make_unique< QgsProcessingParameterPoint >( name, description, mDefaultLineEdit->text() );
3072  param->setFlags( flags );
3073  return param.release();
3074 }
3075 
3076 QgsProcessingPointWidgetWrapper::QgsProcessingPointWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3077  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3078 {
3079 
3080 }
3081 
3082 QWidget *QgsProcessingPointWidgetWrapper::createWidget()
3083 {
3084  const QgsProcessingParameterPoint *pointParam = dynamic_cast< const QgsProcessingParameterPoint *>( parameterDefinition() );
3085  switch ( type() )
3086  {
3089  {
3090  mPanel = new QgsProcessingPointPanel( nullptr );
3091  if ( widgetContext().mapCanvas() )
3092  mPanel->setMapCanvas( widgetContext().mapCanvas() );
3093 
3095  mPanel->setAllowNull( true );
3096 
3097  mPanel->setToolTip( parameterDefinition()->toolTip() );
3098 
3099  connect( mPanel, &QgsProcessingPointPanel::changed, this, [ = ]
3100  {
3101  emit widgetValueHasChanged( this );
3102  } );
3103 
3104  if ( mDialog )
3105  setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
3106  return mPanel;
3107  }
3108 
3110  {
3111  mLineEdit = new QLineEdit();
3112  mLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
3113  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
3114  {
3115  emit widgetValueHasChanged( this );
3116  } );
3117  return mLineEdit;
3118  }
3119  }
3120  return nullptr;
3121 }
3122 
3123 void QgsProcessingPointWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
3124 {
3126  if ( mPanel && context.mapCanvas() )
3127  mPanel->setMapCanvas( context.mapCanvas() );
3128 }
3129 
3130 void QgsProcessingPointWidgetWrapper::setDialog( QDialog *dialog )
3131 {
3132  mDialog = dialog;
3133  if ( mPanel )
3134  {
3135  connect( mPanel, &QgsProcessingPointPanel::toggleDialogVisibility, mDialog, [ = ]( bool visible )
3136  {
3137  if ( !visible )
3138  mDialog->showMinimized();
3139  else
3140  {
3141  mDialog->showNormal();
3142  mDialog->raise();
3143  mDialog->activateWindow();
3144  }
3145  } );
3146  }
3148 }
3149 
3150 void QgsProcessingPointWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3151 {
3152  if ( mPanel )
3153  {
3154  if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
3155  mPanel->clear();
3156  else
3157  {
3158  QgsPointXY p = QgsProcessingParameters::parameterAsPoint( parameterDefinition(), value, context );
3159  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
3160  mPanel->setValue( p, crs );
3161  }
3162  }
3163  else if ( mLineEdit )
3164  {
3165  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3166  mLineEdit->setText( v );
3167  }
3168 }
3169 
3170 QVariant QgsProcessingPointWidgetWrapper::widgetValue() const
3171 {
3172  if ( mPanel )
3173  {
3174  return mPanel->value();
3175  }
3176  else if ( mLineEdit )
3177  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3178  else
3179  return QVariant();
3180 }
3181 
3182 QStringList QgsProcessingPointWidgetWrapper::compatibleParameterTypes() const
3183 {
3184  return QStringList()
3187 }
3188 
3189 QStringList QgsProcessingPointWidgetWrapper::compatibleOutputTypes() const
3190 {
3191  return QStringList()
3193 }
3194 
3195 QString QgsProcessingPointWidgetWrapper::modelerExpressionFormatString() const
3196 {
3197  return tr( "string of the format 'x,y' or a geometry value (centroid is used)" );
3198 }
3199 
3200 QString QgsProcessingPointWidgetWrapper::parameterType() const
3201 {
3203 }
3204 
3205 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3206 {
3207  return new QgsProcessingPointWidgetWrapper( parameter, type );
3208 }
3209 
3210 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3211 {
3212  return new QgsProcessingPointParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3213 }
3214 
3215 
3216 //
3217 // QgsProcessingGeometryWidgetWrapper
3218 //
3219 
3220 
3221 QgsProcessingGeometryParameterDefinitionWidget::QgsProcessingGeometryParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3222  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3223 {
3224  QVBoxLayout *vlayout = new QVBoxLayout();
3225  vlayout->setContentsMargins( 0, 0, 0, 0 );
3226 
3227  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3228 
3229  mDefaultLineEdit = new QLineEdit();
3230  mDefaultLineEdit->setToolTip( tr( "Geometry as WKT" ) );
3231  mDefaultLineEdit->setPlaceholderText( tr( "Geometry as WKT" ) );
3232  if ( const QgsProcessingParameterGeometry *geometryParam = dynamic_cast<const QgsProcessingParameterGeometry *>( definition ) )
3233  {
3234  QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( geometryParam, geometryParam->defaultValueForGui(), context );
3235  if ( !g.isNull() )
3236  mDefaultLineEdit->setText( g.asWkt() );
3237  }
3238 
3239  vlayout->addWidget( mDefaultLineEdit );
3240  setLayout( vlayout );
3241 }
3242 
3243 QgsProcessingParameterDefinition *QgsProcessingGeometryParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3244 {
3245  auto param = std::make_unique< QgsProcessingParameterGeometry >( name, description, mDefaultLineEdit->text() );
3246  param->setFlags( flags );
3247  return param.release();
3248 }
3249 
3250 QgsProcessingGeometryWidgetWrapper::QgsProcessingGeometryWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3251  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3252 {
3253 
3254 }
3255 
3256 QWidget *QgsProcessingGeometryWidgetWrapper::createWidget()
3257 {
3258  switch ( type() )
3259  {
3263  {
3264  mLineEdit = new QLineEdit();
3265  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
3266  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
3267  {
3268  emit widgetValueHasChanged( this );
3269  } );
3270  return mLineEdit;
3271  }
3272  }
3273  return nullptr;
3274 }
3275 
3276 void QgsProcessingGeometryWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3277 {
3278  if ( mLineEdit )
3279  {
3280  QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( parameterDefinition(), value, context );
3281  if ( !g.isNull() )
3282  mLineEdit->setText( g.asWkt() );
3283  else
3284  mLineEdit->clear();
3285  }
3286 }
3287 
3288 QVariant QgsProcessingGeometryWidgetWrapper::widgetValue() const
3289 {
3290  if ( mLineEdit )
3291  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3292  else
3293  return QVariant();
3294 }
3295 
3296 QStringList QgsProcessingGeometryWidgetWrapper::compatibleParameterTypes() const
3297 {
3298  return QStringList()
3303 }
3304 
3305 QStringList QgsProcessingGeometryWidgetWrapper::compatibleOutputTypes() const
3306 {
3307  return QStringList()
3309 }
3310 
3311 QString QgsProcessingGeometryWidgetWrapper::modelerExpressionFormatString() const
3312 {
3313  return tr( "string in the Well-Known-Text format or a geometry value" );
3314 }
3315 
3316 QString QgsProcessingGeometryWidgetWrapper::parameterType() const
3317 {
3319 }
3320 
3321 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingGeometryWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3322 {
3323  return new QgsProcessingGeometryWidgetWrapper( parameter, type );
3324 }
3325 
3326 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingGeometryWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3327 {
3328  return new QgsProcessingGeometryParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3329 }
3330 
3331 
3332 //
3333 // QgsProcessingColorWidgetWrapper
3334 //
3335 
3336 
3337 QgsProcessingColorParameterDefinitionWidget::QgsProcessingColorParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3338  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3339 {
3340  QVBoxLayout *vlayout = new QVBoxLayout();
3341  vlayout->setContentsMargins( 0, 0, 0, 0 );
3342 
3343  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3344 
3345  mDefaultColorButton = new QgsColorButton();
3346  mDefaultColorButton->setShowNull( true );
3347  mAllowOpacity = new QCheckBox( tr( "Allow opacity control" ) );
3348 
3349  if ( const QgsProcessingParameterColor *colorParam = dynamic_cast<const QgsProcessingParameterColor *>( definition ) )
3350  {
3351  const QColor c = QgsProcessingParameters::parameterAsColor( colorParam, colorParam->defaultValueForGui(), context );
3352  if ( !c.isValid() )
3353  mDefaultColorButton->setToNull();
3354  else
3355  mDefaultColorButton->setColor( c );
3356  mAllowOpacity->setChecked( colorParam->opacityEnabled() );
3357  }
3358  else
3359  {
3360  mDefaultColorButton->setToNull();
3361  mAllowOpacity->setChecked( true );
3362  }
3363 
3364  vlayout->addWidget( mDefaultColorButton );
3365  vlayout->addWidget( mAllowOpacity );
3366  setLayout( vlayout );
3367 }
3368 
3369 QgsProcessingParameterDefinition *QgsProcessingColorParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3370 {
3371  auto param = std::make_unique< QgsProcessingParameterColor >( name, description, mDefaultColorButton->color(), mAllowOpacity->isChecked() );
3372  param->setFlags( flags );
3373  return param.release();
3374 }
3375 
3376 QgsProcessingColorWidgetWrapper::QgsProcessingColorWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3377  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3378 {
3379 
3380 }
3381 
3382 QWidget *QgsProcessingColorWidgetWrapper::createWidget()
3383 {
3384  const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor *>( parameterDefinition() );
3385  switch ( type() )
3386  {
3390  {
3391  mColorButton = new QgsColorButton( nullptr );
3392  mColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
3393 
3395  mColorButton->setShowNull( true );
3396 
3397  mColorButton->setAllowOpacity( colorParam->opacityEnabled() );
3398  mColorButton->setToolTip( parameterDefinition()->toolTip() );
3399  mColorButton->setColorDialogTitle( parameterDefinition()->description() );
3400  if ( colorParam->defaultValueForGui().value< QColor >().isValid() )
3401  {
3402  mColorButton->setDefaultColor( colorParam->defaultValueForGui().value< QColor >() );
3403  }
3404 
3405  connect( mColorButton, &QgsColorButton::colorChanged, this, [ = ]
3406  {
3407  emit widgetValueHasChanged( this );
3408  } );
3409 
3410  return mColorButton;
3411  }
3412  }
3413  return nullptr;
3414 }
3415 
3416 void QgsProcessingColorWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3417 {
3418  if ( mColorButton )
3419  {
3420  if ( !value.isValid() ||
3421  ( value.type() == QVariant::String && value.toString().isEmpty() )
3422  || ( value.type() == QVariant::Color && !value.value< QColor >().isValid() ) )
3423  mColorButton->setToNull();
3424  else
3425  {
3426  const QColor c = QgsProcessingParameters::parameterAsColor( parameterDefinition(), value, context );
3427  if ( !c.isValid() && mColorButton->showNull() )
3428  mColorButton->setToNull();
3429  else
3430  mColorButton->setColor( c );
3431  }
3432  }
3433 }
3434 
3435 QVariant QgsProcessingColorWidgetWrapper::widgetValue() const
3436 {
3437  if ( mColorButton )
3438  return mColorButton->isNull() ? QVariant() : mColorButton->color();
3439  else
3440  return QVariant();
3441 }
3442 
3443 QStringList QgsProcessingColorWidgetWrapper::compatibleParameterTypes() const
3444 {
3445  return QStringList()
3448 }
3449 
3450 QStringList QgsProcessingColorWidgetWrapper::compatibleOutputTypes() const
3451 {
3452  return QStringList()
3454 }
3455 
3456 QString QgsProcessingColorWidgetWrapper::modelerExpressionFormatString() const
3457 {
3458  return tr( "color style string, e.g. #ff0000 or 255,0,0" );
3459 }
3460 
3461 QString QgsProcessingColorWidgetWrapper::parameterType() const
3462 {
3464 }
3465 
3466 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingColorWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3467 {
3468  return new QgsProcessingColorWidgetWrapper( parameter, type );
3469 }
3470 
3471 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingColorWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3472 {
3473  return new QgsProcessingColorParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3474 }
3475 
3476 
3477 //
3478 // QgsProcessingCoordinateOperationWidgetWrapper
3479 //
3480 
3481 QgsProcessingCoordinateOperationParameterDefinitionWidget::QgsProcessingCoordinateOperationParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3482  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3483 {
3484  QVBoxLayout *vlayout = new QVBoxLayout();
3485  vlayout->setContentsMargins( 0, 0, 0, 0 );
3486 
3487  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3488 
3489  mDefaultLineEdit = new QLineEdit();
3490  if ( const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
3491  mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( coordParam, coordParam->defaultValueForGui(), context ) );
3492  vlayout->addWidget( mDefaultLineEdit );
3493 
3494  mSourceParamComboBox = new QComboBox();
3495  mDestParamComboBox = new QComboBox();
3496  QString initialSource;
3497  QString initialDest;
3498  QgsCoordinateReferenceSystem sourceCrs;
3500  if ( const QgsProcessingParameterCoordinateOperation *itemParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
3501  {
3502  initialSource = itemParam->sourceCrsParameterName();
3503  initialDest = itemParam->destinationCrsParameterName();
3504  sourceCrs = QgsProcessingUtils::variantToCrs( itemParam->sourceCrs(), context );
3505  destCrs = QgsProcessingUtils::variantToCrs( itemParam->destinationCrs(), context );
3506  }
3507 
3508  mSourceParamComboBox->addItem( QString(), QString() );
3509  mDestParamComboBox->addItem( QString(), QString() );
3510  if ( auto *lModel = widgetContext.model() )
3511  {
3512  // populate combo box with other model input choices
3513  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
3514  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
3515  {
3516  if ( definition && it->parameterName() == definition->name() )
3517  continue;
3518 
3519  // TODO - we should probably filter this list?
3520  mSourceParamComboBox->addItem( it->parameterName(), it->parameterName() );
3521  mDestParamComboBox->addItem( it->parameterName(), it->parameterName() );
3522  if ( !initialSource.isEmpty() && initialSource == it->parameterName() )
3523  {
3524  mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
3525  }
3526  if ( !initialDest.isEmpty() && initialDest == it->parameterName() )
3527  {
3528  mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
3529  }
3530  }
3531  }
3532 
3533  if ( mSourceParamComboBox->count() == 1 && !initialSource.isEmpty() )
3534  {
3535  // if no source candidates found, we just add the existing one as a placeholder
3536  mSourceParamComboBox->addItem( initialSource, initialSource );
3537  mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
3538  }
3539  if ( mDestParamComboBox->count() == 1 && !initialDest.isEmpty() )
3540  {
3541  // if no dest candidates found, we just add the existing one as a placeholder
3542  mDestParamComboBox->addItem( initialDest, initialDest );
3543  mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
3544  }
3545 
3546  vlayout->addWidget( new QLabel( tr( "Source CRS parameter" ) ) );
3547  vlayout->addWidget( mSourceParamComboBox );
3548  vlayout->addWidget( new QLabel( tr( "Destination CRS parameter" ) ) );
3549  vlayout->addWidget( mDestParamComboBox );
3550 
3551  mStaticSourceWidget = new QgsProjectionSelectionWidget();
3552  mStaticSourceWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
3553  mStaticSourceWidget->setCrs( sourceCrs );
3554  mStaticDestWidget = new QgsProjectionSelectionWidget();
3555  mStaticDestWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
3556  mStaticDestWidget->setCrs( destCrs );
3557 
3558  vlayout->addWidget( new QLabel( tr( "Static source CRS" ) ) );
3559  vlayout->addWidget( mStaticSourceWidget );
3560  vlayout->addWidget( new QLabel( tr( "Static destination CRS" ) ) );
3561  vlayout->addWidget( mStaticDestWidget );
3562 
3563  setLayout( vlayout );
3564 }
3565 
3566 QgsProcessingParameterDefinition *QgsProcessingCoordinateOperationParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3567 {
3568  auto param = std::make_unique< QgsProcessingParameterCoordinateOperation >( name, description, mDefaultLineEdit->text(),
3569  mSourceParamComboBox->currentText(),
3570  mDestParamComboBox->currentText(),
3571  mStaticSourceWidget->crs().isValid() ? QVariant::fromValue( mStaticSourceWidget->crs() ) : QVariant(),
3572  mStaticDestWidget->crs().isValid() ? QVariant::fromValue( mStaticDestWidget->crs() ) : QVariant() );
3573  param->setFlags( flags );
3574  return param.release();
3575 }
3576 
3577 QgsProcessingCoordinateOperationWidgetWrapper::QgsProcessingCoordinateOperationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3578  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3579 {
3580 
3581 }
3582 
3583 QWidget *QgsProcessingCoordinateOperationWidgetWrapper::createWidget()
3584 {
3585  const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast< const QgsProcessingParameterCoordinateOperation *>( parameterDefinition() );
3587  mSourceCrs = QgsProcessingUtils::variantToCrs( coordParam->sourceCrs(), c );
3588  mDestCrs = QgsProcessingUtils::variantToCrs( coordParam->destinationCrs(), c );
3589  switch ( type() )
3590  {
3592  {
3593  mOperationWidget = new QgsCoordinateOperationWidget( nullptr );
3594  mOperationWidget->setShowMakeDefault( false );
3595  mOperationWidget->setShowFallbackOption( false );
3596  mOperationWidget->setToolTip( parameterDefinition()->toolTip() );
3597  mOperationWidget->setSourceCrs( mSourceCrs );
3598  mOperationWidget->setDestinationCrs( mDestCrs );
3599  mOperationWidget->setMapCanvas( mCanvas );
3600  if ( !coordParam->defaultValueForGui().toString().isEmpty() )
3601  {
3603  deets.proj = coordParam->defaultValueForGui().toString();
3604  mOperationWidget->setSelectedOperation( deets );
3605  }
3606 
3607  connect( mOperationWidget, &QgsCoordinateOperationWidget::operationChanged, this, [ = ]
3608  {
3609  emit widgetValueHasChanged( this );
3610  } );
3611 
3612  return mOperationWidget;
3613  }
3614 
3617  {
3618  mLineEdit = new QLineEdit();
3619  QHBoxLayout *layout = new QHBoxLayout();
3620  layout->addWidget( mLineEdit, 1 );
3621  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
3622  {
3623  emit widgetValueHasChanged( this );
3624  } );
3625 
3626  QToolButton *button = new QToolButton();
3627  button->setText( QString( QChar( 0x2026 ) ) );
3628  connect( button, &QToolButton::clicked, this, [ = ]
3629  {
3630  QgsDatumTransformDialog dlg( mSourceCrs, mDestCrs, false, false, false, qMakePair( -1, -1 ), button, Qt::WindowFlags(), mLineEdit->text(), mCanvas );
3631  if ( dlg.exec() )
3632  {
3633  mLineEdit->setText( dlg.selectedDatumTransform().proj );
3634  emit widgetValueHasChanged( this );
3635  }
3636  } );
3637  layout->addWidget( button );
3638 
3639  QWidget *w = new QWidget();
3640  layout->setContentsMargins( 0, 0, 0, 0 );
3641  w->setLayout( layout );
3642  return w;
3643  }
3644 
3645  }
3646  return nullptr;
3647 }
3648 
3649 void QgsProcessingCoordinateOperationWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
3650 {
3652  switch ( type() )
3653  {
3656  {
3657  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
3658  {
3659  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterCoordinateOperation * >( parameterDefinition() )->sourceCrsParameterName() )
3660  {
3661  setSourceCrsParameterValue( wrapper->parameterValue() );
3663  {
3664  setSourceCrsParameterValue( wrapper->parameterValue() );
3665  } );
3666  }
3667  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterCoordinateOperation * >( parameterDefinition() )->destinationCrsParameterName() )
3668  {
3669  setDestinationCrsParameterValue( wrapper->parameterValue() );
3671  {
3672  setDestinationCrsParameterValue( wrapper->parameterValue() );
3673  } );
3674  }
3675  }
3676  break;
3677  }
3678 
3680  break;
3681  }
3682 }
3683 
3684 void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
3685 {
3686  mCanvas = context.mapCanvas();
3687  if ( mOperationWidget )
3688  mOperationWidget->setMapCanvas( context.mapCanvas() );
3689 }
3690 
3691 void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
3692 {
3693  if ( mOperationWidget )
3694  {
3695  if ( !value.isValid() ||
3696  ( value.type() == QVariant::String ) )
3697  {
3699  deets.proj = value.toString();
3700  mOperationWidget->setSelectedOperation( deets );
3701  }
3702  }
3703  if ( mLineEdit )
3704  {
3705  if ( !value.isValid() ||
3706  ( value.type() == QVariant::String ) )
3707  {
3708  mLineEdit->setText( value.toString() );
3709  }
3710  }
3711 }
3712 
3713 QVariant QgsProcessingCoordinateOperationWidgetWrapper::widgetValue() const
3714 {
3715  if ( mOperationWidget )
3716  return mOperationWidget->selectedOperation().proj;
3717  else if ( mLineEdit )
3718  return mLineEdit->text();
3719  else
3720  return QVariant();
3721 }
3722 
3723 QStringList QgsProcessingCoordinateOperationWidgetWrapper::compatibleParameterTypes() const
3724 {
3725  return QStringList()
3728 }
3729 
3730 QStringList QgsProcessingCoordinateOperationWidgetWrapper::compatibleOutputTypes() const
3731 {
3732  return QStringList()
3734 }
3735 
3736 QString QgsProcessingCoordinateOperationWidgetWrapper::modelerExpressionFormatString() const
3737 {
3738  return tr( "Proj coordinate operation string, e.g. '+proj=pipeline +step +inv...'" );
3739 }
3740 
3741 void QgsProcessingCoordinateOperationWidgetWrapper::setSourceCrsParameterValue( const QVariant &value )
3742 {
3743  QgsProcessingContext *context = nullptr;
3744  std::unique_ptr< QgsProcessingContext > tmpContext;
3745  if ( mProcessingContextGenerator )
3746  context = mProcessingContextGenerator->processingContext();
3747 
3748  if ( !context )
3749  {
3750  tmpContext = std::make_unique< QgsProcessingContext >();
3751  context = tmpContext.get();
3752  }
3753 
3754  mSourceCrs = QgsProcessingUtils::variantToCrs( value, *context );
3755  if ( mOperationWidget )
3756  {
3757  mOperationWidget->setSourceCrs( mSourceCrs );
3758  mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
3759  }
3760 }
3761 
3762 void QgsProcessingCoordinateOperationWidgetWrapper::setDestinationCrsParameterValue( const QVariant &value )
3763 {
3764  QgsProcessingContext *context = nullptr;
3765  std::unique_ptr< QgsProcessingContext > tmpContext;
3766  if ( mProcessingContextGenerator )
3767  context = mProcessingContextGenerator->processingContext();
3768 
3769  if ( !context )
3770  {
3771  tmpContext = std::make_unique< QgsProcessingContext >();
3772  context = tmpContext.get();
3773  }
3774 
3775  mDestCrs = QgsProcessingUtils::variantToCrs( value, *context );
3776  if ( mOperationWidget )
3777  {
3778  mOperationWidget->setDestinationCrs( mDestCrs );
3779  mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
3780  }
3781 }
3782 
3783 QString QgsProcessingCoordinateOperationWidgetWrapper::parameterType() const
3784 {
3786 }
3787 
3788 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCoordinateOperationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3789 {
3790  return new QgsProcessingCoordinateOperationWidgetWrapper( parameter, type );
3791 }
3792 
3793 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingCoordinateOperationWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3794 {
3795  return new QgsProcessingCoordinateOperationParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3796 }
3797 
3798 
3799 
3800 //
3801 // QgsProcessingFieldPanelWidget
3802 //
3803 
3804 QgsProcessingFieldPanelWidget::QgsProcessingFieldPanelWidget( QWidget *parent, const QgsProcessingParameterField *param )
3805  : QWidget( parent )
3806  , mParam( param )
3807 {
3808  QHBoxLayout *hl = new QHBoxLayout();
3809  hl->setContentsMargins( 0, 0, 0, 0 );
3810 
3811  mLineEdit = new QLineEdit();
3812  mLineEdit->setEnabled( false );
3813  hl->addWidget( mLineEdit, 1 );
3814 
3815  mToolButton = new QToolButton();
3816  mToolButton->setText( QString( QChar( 0x2026 ) ) );
3817  hl->addWidget( mToolButton );
3818 
3819  setLayout( hl );
3820 
3821  if ( mParam )
3822  {
3823  mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
3824  }
3825 
3826  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingFieldPanelWidget::showDialog );
3827 }
3828 
3829 void QgsProcessingFieldPanelWidget::setFields( const QgsFields &fields )
3830 {
3831  mFields = fields;
3832 }
3833 
3834 void QgsProcessingFieldPanelWidget::setValue( const QVariant &value )
3835 {
3836  if ( value.isValid() )
3837  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
3838  else
3839  mValue.clear();
3840 
3841  updateSummaryText();
3842  emit changed();
3843 }
3844 
3845 void QgsProcessingFieldPanelWidget::showDialog()
3846 {
3847  QVariantList availableOptions;
3848  QStringList fieldNames;
3849  availableOptions.reserve( mFields.size() );
3850  for ( const QgsField &field : std::as_const( mFields ) )
3851  {
3852  availableOptions << field.name();
3853  }
3854 
3856  if ( panel && panel->dockMode() )
3857  {
3858  QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
3859  widget->setPanelTitle( mParam->description() );
3860 
3861  widget->setValueFormatter( []( const QVariant & v ) -> QString
3862  {
3863  return v.toString();
3864  } );
3865 
3866  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
3867  {
3868  setValue( widget->selectedOptions() );
3869  } );
3870  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
3871  panel->openPanel( widget );
3872  }
3873  else
3874  {
3875  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
3876 
3877  dlg.setValueFormatter( []( const QVariant & v ) -> QString
3878  {
3879  return v.toString();
3880  } );
3881  if ( dlg.exec() )
3882  {
3883  setValue( dlg.selectedOptions() );
3884  }
3885  }
3886 }
3887 
3888 void QgsProcessingFieldPanelWidget::updateSummaryText()
3889 {
3890  if ( mParam )
3891  mLineEdit->setText( tr( "%1 options selected" ).arg( mValue.count() ) );
3892 }
3893 
3894 
3895 //
3896 // QgsProcessingFieldWidgetWrapper
3897 //
3898 
3899 QgsProcessingFieldParameterDefinitionWidget::QgsProcessingFieldParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3900  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3901 {
3902  QVBoxLayout *vlayout = new QVBoxLayout();
3903  vlayout->setContentsMargins( 0, 0, 0, 0 );
3904 
3905  vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
3906  mParentLayerComboBox = new QComboBox();
3907 
3908  QString initialParent;
3909  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
3910  initialParent = fieldParam->parentLayerParameterName();
3911 
3912  if ( auto *lModel = widgetContext.model() )
3913  {
3914  // populate combo box with other model input choices
3915  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
3916  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
3917  {
3918  if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast< const QgsProcessingParameterFeatureSource * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
3919  {
3920  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
3921  if ( !initialParent.isEmpty() && initialParent == definition->name() )
3922  {
3923  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
3924  }
3925  }
3926  else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast< const QgsProcessingParameterVectorLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
3927  {
3928  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
3929  if ( !initialParent.isEmpty() && initialParent == definition->name() )
3930  {
3931  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
3932  }
3933  }
3934  else if ( const QgsProcessingParameterMultipleLayers *definition = dynamic_cast< const QgsProcessingParameterMultipleLayers * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
3935  {
3936  if ( definition->layerType() == QgsProcessing::TypeVector )
3937  {
3938  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
3939  if ( !initialParent.isEmpty() && initialParent == definition->name() )
3940  {
3941  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
3942  }
3943  }
3944  }
3945  }
3946  }
3947 
3948  if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
3949  {
3950  // if no parent candidates found, we just add the existing one as a placeholder
3951  mParentLayerComboBox->addItem( initialParent, initialParent );
3952  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
3953  }
3954 
3955  vlayout->addWidget( mParentLayerComboBox );
3956 
3957  vlayout->addWidget( new QLabel( tr( "Allowed data type" ) ) );
3958  mDataTypeComboBox = new QComboBox();
3959  mDataTypeComboBox->addItem( tr( "Any" ), QgsProcessingParameterField::Any );
3960  mDataTypeComboBox->addItem( tr( "Number" ), QgsProcessingParameterField::Numeric );
3961  mDataTypeComboBox->addItem( tr( "String" ), QgsProcessingParameterField::String );
3962  mDataTypeComboBox->addItem( tr( "Date/time" ), QgsProcessingParameterField::DateTime );
3963  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
3964  mDataTypeComboBox->setCurrentIndex( mDataTypeComboBox->findData( fieldParam->dataType() ) );
3965 
3966  vlayout->addWidget( mDataTypeComboBox );
3967 
3968  mAllowMultipleCheckBox = new QCheckBox( tr( "Accept multiple fields" ) );
3969  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
3970  mAllowMultipleCheckBox->setChecked( fieldParam->allowMultiple() );
3971 
3972  vlayout->addWidget( mAllowMultipleCheckBox );
3973 
3974  mDefaultToAllCheckBox = new QCheckBox( tr( "Select all fields by default" ) );
3975  mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
3976  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
3977  mDefaultToAllCheckBox->setChecked( fieldParam->defaultToAllFields() );
3978 
3979  vlayout->addWidget( mDefaultToAllCheckBox );
3980 
3981  connect( mAllowMultipleCheckBox, &QCheckBox::stateChanged, this, [ = ]
3982  {
3983  mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
3984  } );
3985 
3986  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3987 
3988  mDefaultLineEdit = new QLineEdit();
3989  mDefaultLineEdit->setToolTip( tr( "Default field name, or ; separated list of field names for multiple field parameters" ) );
3990  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
3991  {
3992  const QStringList fields = QgsProcessingParameters::parameterAsFields( fieldParam, fieldParam->defaultValueForGui(), context );
3993  mDefaultLineEdit->setText( fields.join( ';' ) );
3994  }
3995  vlayout->addWidget( mDefaultLineEdit );
3996 
3997  setLayout( vlayout );
3998 }
3999 
4000 QgsProcessingParameterDefinition *QgsProcessingFieldParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4001 {
4002  QgsProcessingParameterField::DataType dataType = static_cast< QgsProcessingParameterField::DataType >( mDataTypeComboBox->currentData().toInt() );
4003  auto param = std::make_unique< QgsProcessingParameterField >( name, description, mDefaultLineEdit->text(), mParentLayerComboBox->currentData().toString(), dataType, mAllowMultipleCheckBox->isChecked(), false, mDefaultToAllCheckBox->isChecked() );
4004  param->setFlags( flags );
4005  return param.release();
4006 }
4007 
4008 QgsProcessingFieldWidgetWrapper::QgsProcessingFieldWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4009  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4010 {
4011 
4012 }
4013 
4014 QWidget *QgsProcessingFieldWidgetWrapper::createWidget()
4015 {
4016  const QgsProcessingParameterField *fieldParam = dynamic_cast< const QgsProcessingParameterField *>( parameterDefinition() );
4017  switch ( type() )
4018  {
4021  {
4022  if ( fieldParam->allowMultiple() )
4023  {
4024  mPanel = new QgsProcessingFieldPanelWidget( nullptr, fieldParam );
4025  mPanel->setToolTip( parameterDefinition()->toolTip() );
4026  connect( mPanel, &QgsProcessingFieldPanelWidget::changed, this, [ = ]
4027  {
4028  emit widgetValueHasChanged( this );
4029  } );
4030  return mPanel;
4031  }
4032  else
4033  {
4034  mComboBox = new QgsFieldComboBox();
4035  mComboBox->setAllowEmptyFieldName( fieldParam->flags() & QgsProcessingParameterDefinition::FlagOptional );
4036 
4037  if ( fieldParam->dataType() == QgsProcessingParameterField::Numeric )
4038  mComboBox->setFilters( QgsFieldProxyModel::Numeric );
4039  else if ( fieldParam->dataType() == QgsProcessingParameterField::String )
4040  mComboBox->setFilters( QgsFieldProxyModel::String );
4041  else if ( fieldParam->dataType() == QgsProcessingParameterField::DateTime )
4043 
4044  mComboBox->setToolTip( parameterDefinition()->toolTip() );
4045  connect( mComboBox, &QgsFieldComboBox::fieldChanged, this, [ = ]( const QString & )
4046  {
4047  emit widgetValueHasChanged( this );
4048  } );
4049  return mComboBox;
4050  }
4051  }
4052 
4054  {
4055  mLineEdit = new QLineEdit();
4056  mLineEdit->setToolTip( QObject::tr( "Name of field (separate field names with ; for multiple field parameters)" ) );
4057  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
4058  {
4059  emit widgetValueHasChanged( this );
4060  } );
4061  return mLineEdit;
4062  }
4063 
4064  }
4065  return nullptr;
4066 }
4067 
4068 void QgsProcessingFieldWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
4069 {
4071  switch ( type() )
4072  {
4075  {
4076  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
4077  {
4078  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterField * >( parameterDefinition() )->parentLayerParameterName() )
4079  {
4080  setParentLayerWrapperValue( wrapper );
4082  {
4083  setParentLayerWrapperValue( wrapper );
4084  } );
4085  break;
4086  }
4087  }
4088  break;
4089  }
4090 
4092  break;
4093  }
4094 }
4095 
4096 void QgsProcessingFieldWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
4097 {
4098  // evaluate value to layer
4099  QgsProcessingContext *context = nullptr;
4100  std::unique_ptr< QgsProcessingContext > tmpContext;
4101  if ( mProcessingContextGenerator )
4102  context = mProcessingContextGenerator->processingContext();
4103 
4104  if ( !context )
4105  {
4106  tmpContext = std::make_unique< QgsProcessingContext >();
4107  context = tmpContext.get();
4108  }
4109 
4110  QVariant value = parentWrapper->parameterValue();
4111 
4112  if ( value.canConvert<QgsProcessingFeatureSourceDefinition>() )
4113  {
4114  // input is a QgsProcessingFeatureSourceDefinition - source from it.
4115  // this is normally discouraged, and algorithms should NEVER do this -- but in this case we can make
4116  // certain assumptions due to the fact that we're calling this outside of algorithm/model execution and all sources
4117  // should be real map layers at this stage
4118  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
4119  value = fromVar.source;
4120  }
4121 
4122  bool valueSet = false;
4123  const QList< QgsMapLayer * > layers = QgsProcessingParameters::parameterAsLayerList( parentWrapper->parameterDefinition(), value, *context );
4124 
4125  // several layers, populate with intersection of layers fields
4126  if ( layers.count() > 1 )
4127  {
4128  QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layers.at( 0 ) );
4129  QgsFields fields = vlayer && vlayer->isValid() ? vlayer->fields() : QgsFields();
4130  const QList< QgsMapLayer * > remainingLayers = layers.mid( 1 );
4131  for ( QgsMapLayer *layer : remainingLayers )
4132  {
4133  if ( fields.isEmpty() )
4134  break;
4135 
4136  QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layer );
4137  if ( !vlayer || !vlayer->isValid() )
4138  {
4139  fields = QgsFields();
4140  break;
4141  }
4142 
4143  for ( int fieldIdx = fields.count() - 1; fieldIdx >= 0; fieldIdx-- )
4144  {
4145  if ( vlayer->fields().lookupField( fields.at( fieldIdx ).name() ) < 0 )
4146  fields.remove( fieldIdx );
4147  }
4148  }
4149 
4150  if ( mComboBox )
4151  mComboBox->setFields( fields );
4152  else if ( mPanel )
4153  mPanel->setFields( filterFields( fields ) );
4154 
4155  valueSet = true;
4156  }
4157 
4158  // only one layer
4159  if ( !valueSet && !layers.isEmpty() && layers.at( 0 )->isValid() )
4160  {
4161  QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( layers.at( 0 ) );
4162 
4163  // need to grab ownership of layer if required - otherwise layer may be deleted when context
4164  // goes out of scope
4165  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
4166  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::VectorLayer )
4167  {
4168  mParentLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
4169  layer = mParentLayer.get();
4170  }
4171  else
4172  {
4173  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
4174  }
4175 
4176  if ( mComboBox )
4177  mComboBox->setLayer( layer );
4178  else if ( mPanel )
4179  mPanel->setFields( filterFields( layer->fields() ) );
4180 
4181  valueSet = true;
4182  }
4183 
4184  if ( !valueSet )
4185  {
4186  std::unique_ptr< QgsProcessingFeatureSource > source( QgsProcessingParameters::parameterAsSource( parentWrapper->parameterDefinition(), value, *context ) );
4187  if ( source )
4188  {
4189  const QgsFields fields = source->fields();
4190  if ( mComboBox )
4191  mComboBox->setFields( fields );
4192  else if ( mPanel )
4193  mPanel->setFields( filterFields( fields ) );
4194 
4195  valueSet = true;
4196  }
4197  }
4198 
4199  if ( !valueSet )
4200  {
4201  if ( mComboBox )
4202  mComboBox->setLayer( nullptr );
4203  else if ( mPanel )
4204  mPanel->setFields( QgsFields() );
4205 
4206  if ( value.isValid() && widgetContext().messageBar() )
4207  {
4208  widgetContext().messageBar()->clearWidgets();
4209  widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent field could not be populated" ),
4210  Qgis::MessageLevel::Info );
4211  }
4212  return;
4213  }
4214 
4215  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4216  if ( mPanel && fieldParam->defaultToAllFields() )
4217  {
4218  QVariantList val;
4219  val.reserve( mPanel->fields().size() );
4220  for ( const QgsField &field : mPanel->fields() )
4221  val << field.name();
4222  setWidgetValue( val, *context );
4223  }
4224  else if ( fieldParam->defaultValueForGui().isValid() )
4225  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
4226 }
4227 
4228 void QgsProcessingFieldWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4229 {
4230  if ( mComboBox )
4231  {
4232  if ( !value.isValid() )
4233  mComboBox->setField( QString() );
4234  else
4235  {
4236  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
4237  mComboBox->setField( v );
4238  }
4239  }
4240  else if ( mPanel )
4241  {
4242  QVariantList opts;
4243  if ( value.isValid() )
4244  {
4245  const QStringList v = QgsProcessingParameters::parameterAsFields( parameterDefinition(), value, context );
4246  opts.reserve( v.size() );
4247  for ( const QString &i : v )
4248  opts << i;
4249  }
4250  if ( mPanel )
4251  mPanel->setValue( opts );
4252  }
4253  else if ( mLineEdit )
4254  {
4255  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4256  if ( fieldParam->allowMultiple() )
4257  {
4258  const QStringList v = QgsProcessingParameters::parameterAsFields( parameterDefinition(), value, context );
4259  mLineEdit->setText( v.join( ';' ) );
4260  }
4261  else
4262  {
4263  mLineEdit->setText( QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context ) );
4264  }
4265  }
4266 }
4267 
4268 QVariant QgsProcessingFieldWidgetWrapper::widgetValue() const
4269 {
4270  if ( mComboBox )
4271  return mComboBox->currentField();
4272  else if ( mPanel )
4273  return mPanel->value();
4274  else if ( mLineEdit )
4275  {
4276  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4277  if ( fieldParam->allowMultiple() )
4278  {
4279  return mLineEdit->text().split( ';' );
4280  }
4281  else
4282  return mLineEdit->text();
4283  }
4284  else
4285  return QVariant();
4286 }
4287 
4288 QStringList QgsProcessingFieldWidgetWrapper::compatibleParameterTypes() const
4289 {
4290  return QStringList()
4293 }
4294 
4295 QStringList QgsProcessingFieldWidgetWrapper::compatibleOutputTypes() const
4296 {
4297  return QStringList()
4299 }
4300 
4301 QString QgsProcessingFieldWidgetWrapper::modelerExpressionFormatString() const
4302 {
4303  return tr( "selected field names as an array of names, or semicolon separated string of options (e.g. 'fid;place_name')" );
4304 }
4305 
4306 const QgsVectorLayer *QgsProcessingFieldWidgetWrapper::linkedVectorLayer() const
4307 {
4308  if ( mComboBox && mComboBox->layer() )
4309  return mComboBox->layer();
4310 
4312 }
4313 
4314 QgsFields QgsProcessingFieldWidgetWrapper::filterFields( const QgsFields &fields ) const
4315 {
4316  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4317  QgsFields res;
4318  for ( const QgsField &f : fields )
4319  {
4320  switch ( fieldParam->dataType() )
4321  {
4323  res.append( f );
4324  break;
4325 
4327  if ( f.isNumeric() )
4328  res.append( f );
4329  break;
4330 
4332  if ( f.type() == QVariant::String )
4333  res.append( f );
4334  break;
4335 
4337  if ( f.type() == QVariant::Date || f.type() == QVariant::Time || f.type() == QVariant::DateTime )
4338  res.append( f );
4339  break;
4340  }
4341  }
4342 
4343  return res;
4344 }
4345 
4346 QString QgsProcessingFieldWidgetWrapper::parameterType() const
4347 {
4349 }
4350 
4351 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFieldWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4352 {
4353  return new QgsProcessingFieldWidgetWrapper( parameter, type );
4354 }
4355 
4356 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFieldWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4357 {
4358  return new QgsProcessingFieldParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4359 }
4360 
4361 //
4362 // QgsProcessingMapThemeWidgetWrapper
4363 //
4364 
4365 
4366 QgsProcessingMapThemeParameterDefinitionWidget::QgsProcessingMapThemeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4367  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4368 {
4369  QVBoxLayout *vlayout = new QVBoxLayout();
4370  vlayout->setContentsMargins( 0, 0, 0, 0 );
4371 
4372  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4373 
4374  mDefaultComboBox = new QComboBox();
4375  mDefaultComboBox->addItem( QString(), QVariant( -1 ) );
4376 
4377  const QStringList mapThemes = widgetContext.project() ? widgetContext.project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
4378  for ( const QString &theme : mapThemes )
4379  {
4380  mDefaultComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
4381  }
4382  mDefaultComboBox->setEditable( true );
4383 
4384  if ( const QgsProcessingParameterMapTheme *themeParam = dynamic_cast<const QgsProcessingParameterMapTheme *>( definition ) )
4385  {
4386  if ( themeParam->defaultValueForGui().isValid() )
4387  mDefaultComboBox->setCurrentText( QgsProcessingParameters::parameterAsString( themeParam, themeParam->defaultValueForGui(), context ) );
4388  else
4389  mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
4390  }
4391  else
4392  mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
4393 
4394  vlayout->addWidget( mDefaultComboBox );
4395 
4396  setLayout( vlayout );
4397 }
4398 
4399 QgsProcessingParameterDefinition *QgsProcessingMapThemeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4400 {
4401  QVariant defaultVal;
4402  if ( mDefaultComboBox->currentText().isEmpty() )
4403  defaultVal = QVariant();
4404  else
4405  defaultVal = mDefaultComboBox->currentText();
4406  auto param = std::make_unique< QgsProcessingParameterMapTheme>( name, description, defaultVal );
4407  param->setFlags( flags );
4408  return param.release();
4409 }
4410 
4411 
4412 QgsProcessingMapThemeWidgetWrapper::QgsProcessingMapThemeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4413  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4414 {
4415 
4416 }
4417 
4418 QWidget *QgsProcessingMapThemeWidgetWrapper::createWidget()
4419 {
4420  const QgsProcessingParameterMapTheme *themeParam = dynamic_cast< const QgsProcessingParameterMapTheme *>( parameterDefinition() );
4421 
4422  mComboBox = new QComboBox();
4423 
4425  mComboBox->addItem( tr( "[Not selected]" ), QVariant( -1 ) );
4426 
4427  const QStringList mapThemes = widgetContext().project() ? widgetContext().project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
4428  for ( const QString &theme : mapThemes )
4429  {
4430  mComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
4431  }
4432 
4433  switch ( type() )
4434  {
4437  break;
4438 
4440  mComboBox->setEditable( true );
4441  break;
4442  }
4443 
4444  mComboBox->setToolTip( parameterDefinition()->toolTip() );
4445  connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
4446  {
4447  emit widgetValueHasChanged( this );
4448  } );
4449 
4450  return mComboBox;
4451 }
4452 
4453 void QgsProcessingMapThemeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4454 {
4455  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
4456 
4457  if ( !value.isValid() )
4458  mComboBox->setCurrentIndex( mComboBox->findData( QVariant( -1 ) ) );
4459  else
4460  {
4461  if ( mComboBox->isEditable() && mComboBox->findData( v ) == -1 )
4462  {
4463  const QString prev = mComboBox->currentText();
4464  mComboBox->setCurrentText( v );
4465  if ( prev != v )
4466  emit widgetValueHasChanged( this );
4467  }
4468  else
4469  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
4470  }
4471 }
4472 
4473 QVariant QgsProcessingMapThemeWidgetWrapper::widgetValue() const
4474 {
4475  if ( mComboBox )
4476  return mComboBox->currentData().toInt() == -1 ? QVariant() :
4477  !mComboBox->currentData().isValid() && mComboBox->isEditable() ? mComboBox->currentText().isEmpty() ? QVariant() : QVariant( mComboBox->currentText() )
4478  : mComboBox->currentData();
4479  else
4480  return QVariant();
4481 }
4482 
4483 QStringList QgsProcessingMapThemeWidgetWrapper::compatibleParameterTypes() const
4484 {
4485  return QStringList()
4488 }
4489 
4490 QStringList QgsProcessingMapThemeWidgetWrapper::compatibleOutputTypes() const
4491 {
4492  return QStringList()
4494 }
4495 
4496 QString QgsProcessingMapThemeWidgetWrapper::modelerExpressionFormatString() const
4497 {
4498  return tr( "map theme as a string value (e.g. 'base maps')" );
4499 }
4500 
4501 QString QgsProcessingMapThemeWidgetWrapper::parameterType() const
4502 {
4504 }
4505 
4506 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapThemeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4507 {
4508  return new QgsProcessingMapThemeWidgetWrapper( parameter, type );
4509 }
4510 
4511 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapThemeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4512 {
4513  return new QgsProcessingMapThemeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4514 }
4515 
4516 
4517 
4518 //
4519 // QgsProcessingDateTimeWidgetWrapper
4520 //
4521 
4522 
4523 QgsProcessingDateTimeParameterDefinitionWidget::QgsProcessingDateTimeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4524  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4525 {
4526  QVBoxLayout *vlayout = new QVBoxLayout();
4527  vlayout->setContentsMargins( 0, 0, 0, 0 );
4528 
4529  vlayout->addWidget( new QLabel( tr( "Type" ) ) );
4530 
4531  mTypeComboBox = new QComboBox();
4532  mTypeComboBox->addItem( tr( "Date and Time" ), QgsProcessingParameterDateTime::DateTime );
4533  mTypeComboBox->addItem( tr( "Date" ), QgsProcessingParameterDateTime::Date );
4534  mTypeComboBox->addItem( tr( "Time" ), QgsProcessingParameterDateTime::Time );
4535  if ( const QgsProcessingParameterDateTime *datetimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( definition ) )
4536  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( datetimeParam->dataType() ) );
4537  else
4538  mTypeComboBox->setCurrentIndex( 0 );
4539  vlayout->addWidget( mTypeComboBox );
4540 
4541  setLayout( vlayout );
4542 }
4543 
4544 QgsProcessingParameterDefinition *QgsProcessingDateTimeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4545 {
4546  auto param = std::make_unique< QgsProcessingParameterDateTime >( name, description );
4547  param->setDataType( static_cast< QgsProcessingParameterDateTime::Type >( mTypeComboBox->currentData().toInt() ) );
4548  param->setFlags( flags );
4549  return param.release();
4550 }
4551 
4552 
4553 QgsProcessingDateTimeWidgetWrapper::QgsProcessingDateTimeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4554  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4555 {
4556 
4557 }
4558 
4559 QWidget *QgsProcessingDateTimeWidgetWrapper::createWidget()
4560 {
4561  const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast< const QgsProcessingParameterDateTime *>( parameterDefinition() );
4562 
4563  QgsDateTimeEdit *widget = nullptr;
4564  switch ( dateTimeParam->dataType() )
4565  {
4567  mDateTimeEdit = new QgsDateTimeEdit();
4568  widget = mDateTimeEdit;
4569  break;
4570 
4572  mDateEdit = new QgsDateEdit();
4573  widget = mDateEdit;
4574  break;
4575 
4577  mTimeEdit = new QgsTimeEdit();
4578  widget = mTimeEdit;
4579  break;
4580  }
4581 
4582  if ( dateTimeParam->flags() & QgsProcessingParameterDefinition::FlagOptional )
4583  {
4584  widget->setNullRepresentation( tr( "[Not selected]" ) );
4585  widget->setAllowNull( true );
4586  }
4587  else
4588  {
4589  widget->setAllowNull( false );
4590  }
4591  widget->setToolTip( parameterDefinition()->toolTip() );
4592 
4593  if ( mDateTimeEdit )
4594  {
4595  connect( mDateTimeEdit, &QgsDateTimeEdit::valueChanged, this, [ = ]( const QDateTime & )
4596  {
4597  emit widgetValueHasChanged( this );
4598  } );
4599  }
4600  else if ( mDateEdit )
4601  {
4602  connect( mDateEdit, &QgsDateEdit::dateValueChanged, this, [ = ]( const QDate & )
4603  {
4604  emit widgetValueHasChanged( this );
4605  } );
4606  }
4607  else if ( mTimeEdit )
4608  {
4609  connect( mTimeEdit, &QgsTimeEdit::timeValueChanged, this, [ = ]( const QTime & )
4610  {
4611  emit widgetValueHasChanged( this );
4612  } );
4613  }
4614 
4615  return widget;
4616 }
4617 
4618 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDateTimeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4619 {
4620  return new QgsProcessingDateTimeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4621 }
4622 
4623 void QgsProcessingDateTimeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4624 {
4625  if ( mDateTimeEdit )
4626  {
4627  mDateTimeEdit->setDateTime( QgsProcessingParameters::parameterAsDateTime( parameterDefinition(), value, context ) );
4628  }
4629  else if ( mDateEdit )
4630  {
4631  mDateEdit->setDate( QgsProcessingParameters::parameterAsDate( parameterDefinition(), value, context ) );
4632  }
4633  else if ( mTimeEdit )
4634  {
4635  mTimeEdit->setTime( QgsProcessingParameters::parameterAsTime( parameterDefinition(), value, context ) );
4636  }
4637 }
4638 
4639 QVariant QgsProcessingDateTimeWidgetWrapper::widgetValue() const
4640 {
4641  if ( mDateTimeEdit )
4642  return !mDateTimeEdit->dateTime().isNull() && mDateTimeEdit->dateTime().isValid() ? QVariant( mDateTimeEdit->dateTime() ) : QVariant();
4643  else if ( mDateEdit )
4644  return !mDateEdit->date().isNull() && mDateEdit->date().isValid() ? QVariant( mDateEdit->date() ) : QVariant();
4645  else if ( mTimeEdit )
4646  return !mTimeEdit->time().isNull() && mTimeEdit->time().isValid() ? QVariant( mTimeEdit->time() ) : QVariant();
4647  else
4648  return QVariant();
4649 }
4650 
4651 QStringList QgsProcessingDateTimeWidgetWrapper::compatibleParameterTypes() const
4652 {
4653  return QStringList()
4656 }
4657 
4658 QStringList QgsProcessingDateTimeWidgetWrapper::compatibleOutputTypes() const
4659 {
4660  return QStringList()
4662 }
4663 
4664 QString QgsProcessingDateTimeWidgetWrapper::modelerExpressionFormatString() const
4665 {
4666  const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast< const QgsProcessingParameterDateTime *>( parameterDefinition() );
4667  if ( dateTimeParam )
4668  {
4669  switch ( dateTimeParam->dataType() )
4670  {
4672  return tr( "datetime value, or a ISO string representation of a datetime" );
4673 
4675  return tr( "date value, or a ISO string representation of a date" );
4676 
4678  return tr( "time value, or a ISO string representation of a time" );
4679  }
4680  }
4681  return QString();
4682 }
4683 
4684 QString QgsProcessingDateTimeWidgetWrapper::parameterType() const
4685 {
4687 }
4688 
4689 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDateTimeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4690 {
4691  return new QgsProcessingDateTimeWidgetWrapper( parameter, type );
4692 }
4693 
4694 
4695 
4696 //
4697 // QgsProcessingProviderConnectionWidgetWrapper
4698 //
4699 
4700 QgsProcessingProviderConnectionParameterDefinitionWidget::QgsProcessingProviderConnectionParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4701  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4702 {
4703  const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast< const QgsProcessingParameterProviderConnection *>( definition );
4704 
4705  QVBoxLayout *vlayout = new QVBoxLayout();
4706  vlayout->setContentsMargins( 0, 0, 0, 0 );
4707 
4708  vlayout->addWidget( new QLabel( tr( "Provider" ) ) );
4709  mProviderComboBox = new QComboBox();
4710  mProviderComboBox->addItem( QObject::tr( "Postgres" ), QStringLiteral( "postgres" ) );
4711  mProviderComboBox->addItem( QObject::tr( "GeoPackage" ), QStringLiteral( "ogr" ) );
4712  mProviderComboBox->addItem( QObject::tr( "Spatialite" ), QStringLiteral( "spatialite" ) );
4713 
4714  vlayout->addWidget( mProviderComboBox );
4715 
4716  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4717 
4718  mDefaultEdit = new QLineEdit();
4719  vlayout->addWidget( mDefaultEdit );
4720  setLayout( vlayout );
4721 
4722  if ( connectionParam )
4723  {
4724  mProviderComboBox->setCurrentIndex( mProviderComboBox->findData( connectionParam->providerId() ) );
4725  mDefaultEdit->setText( connectionParam->defaultValueForGui().toString() );
4726  }
4727 }
4728 
4729 QgsProcessingParameterDefinition *QgsProcessingProviderConnectionParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4730 {
4731  QVariant defaultVal;
4732  if ( mDefaultEdit->text().isEmpty() )
4733  defaultVal = QVariant();
4734  else
4735  defaultVal = mDefaultEdit->text();
4736  auto param = std::make_unique< QgsProcessingParameterProviderConnection>( name, description, mProviderComboBox->currentData().toString(), defaultVal );
4737  param->setFlags( flags );
4738  return param.release();
4739 }
4740 
4741 
4742 QgsProcessingProviderConnectionWidgetWrapper::QgsProcessingProviderConnectionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4743  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4744 {
4745 
4746 }
4747 
4748 QWidget *QgsProcessingProviderConnectionWidgetWrapper::createWidget()
4749 {
4750  const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast< const QgsProcessingParameterProviderConnection *>( parameterDefinition() );
4751 
4752  mProviderComboBox = new QgsProviderConnectionComboBox( connectionParam->providerId() );
4753  if ( connectionParam->flags() & QgsProcessingParameterDefinition::FlagOptional )
4754  mProviderComboBox->setAllowEmptyConnection( true );
4755 
4756  switch ( type() )
4757  {
4760  break;
4762  mProviderComboBox->setEditable( true );
4763  break;
4764  }
4765 
4766  mProviderComboBox->setToolTip( parameterDefinition()->toolTip() );
4767  connect( mProviderComboBox, &QgsProviderConnectionComboBox::currentTextChanged, this, [ = ]( const QString & )
4768  {
4769  if ( mBlockSignals )
4770  return;
4771 
4772  emit widgetValueHasChanged( this );
4773  } );
4774 
4775  return mProviderComboBox;
4776 }
4777 
4778 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingProviderConnectionWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4779 {
4780  return new QgsProcessingProviderConnectionParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4781 }
4782 
4783 void QgsProcessingProviderConnectionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4784 {
4785  const QString v = QgsProcessingParameters::parameterAsConnectionName( parameterDefinition(), value, context );
4786 
4787  if ( !value.isValid() )
4788  mProviderComboBox->setCurrentIndex( -1 );
4789  else
4790  {
4791  if ( mProviderComboBox->isEditable() )
4792  {
4793  const QString prev = mProviderComboBox->currentText();
4794  mBlockSignals++;
4795  mProviderComboBox->setConnection( v );
4796  mProviderComboBox->setCurrentText( v );
4797 
4798  mBlockSignals--;
4799  if ( prev != v )
4800  emit widgetValueHasChanged( this );
4801  }
4802  else
4803  mProviderComboBox->setConnection( v );
4804  }
4805 }
4806 
4807 QVariant QgsProcessingProviderConnectionWidgetWrapper::widgetValue() const
4808 {
4809  if ( mProviderComboBox )
4810  if ( mProviderComboBox->isEditable() )
4811  return mProviderComboBox->currentText().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentText() );
4812  else
4813  return mProviderComboBox->currentConnection().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentConnection() );
4814  else
4815  return QVariant();
4816 }
4817 
4818 QStringList QgsProcessingProviderConnectionWidgetWrapper::compatibleParameterTypes() const
4819 {
4820  return QStringList()
4824 }
4825 
4826 QStringList QgsProcessingProviderConnectionWidgetWrapper::compatibleOutputTypes() const
4827 {
4828  return QStringList()
4830 }
4831 
4832 QString QgsProcessingProviderConnectionWidgetWrapper::modelerExpressionFormatString() const
4833 {
4834  return tr( "connection name as a string value" );
4835 }
4836 
4837 QString QgsProcessingProviderConnectionWidgetWrapper::parameterType() const
4838 {
4840 }
4841 
4842 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingProviderConnectionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4843 {
4844  return new QgsProcessingProviderConnectionWidgetWrapper( parameter, type );
4845 }
4846 
4847 
4848 
4849 
4850 //
4851 // QgsProcessingDatabaseSchemaWidgetWrapper
4852 //
4853 
4854 QgsProcessingDatabaseSchemaParameterDefinitionWidget::QgsProcessingDatabaseSchemaParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4855  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4856 {
4857  const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast< const QgsProcessingParameterDatabaseSchema *>( definition );
4858 
4859  QVBoxLayout *vlayout = new QVBoxLayout();
4860  vlayout->setContentsMargins( 0, 0, 0, 0 );
4861 
4862  mConnectionParamComboBox = new QComboBox();
4863  QString initialConnection;
4864  if ( schemaParam )
4865  {
4866  initialConnection = schemaParam->parentConnectionParameterName();
4867  }
4868 
4869  if ( auto *lModel = widgetContext.model() )
4870  {
4871  // populate combo box with other model input choices
4872  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
4873  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
4874  {
4875  if ( definition && it->parameterName() == definition->name() )
4876  continue;
4877 
4878  if ( !dynamic_cast< const QgsProcessingParameterProviderConnection * >( lModel->parameterDefinition( it->parameterName() ) ) )
4879  continue;
4880 
4881  mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
4882  if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
4883  {
4884  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
4885  }
4886  }
4887  }
4888 
4889  if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
4890  {
4891  // if no candidates found, we just add the existing one as a placeholder
4892  mConnectionParamComboBox->addItem( initialConnection, initialConnection );
4893  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
4894  }
4895 
4896  vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
4897  vlayout->addWidget( mConnectionParamComboBox );
4898 
4899  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4900 
4901  mDefaultEdit = new QLineEdit();
4902  vlayout->addWidget( mDefaultEdit );
4903  setLayout( vlayout );
4904 
4905  if ( schemaParam )
4906  {
4907  mDefaultEdit->setText( schemaParam->defaultValueForGui().toString() );
4908  }
4909 }
4910 
4911 QgsProcessingParameterDefinition *QgsProcessingDatabaseSchemaParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4912 {
4913  QVariant defaultVal;
4914  if ( mDefaultEdit->text().isEmpty() )
4915  defaultVal = QVariant();
4916  else
4917  defaultVal = mDefaultEdit->text();
4918  auto param = std::make_unique< QgsProcessingParameterDatabaseSchema>( name, description, mConnectionParamComboBox->currentData().toString(), defaultVal );
4919  param->setFlags( flags );
4920  return param.release();
4921 }
4922 
4923 
4924 QgsProcessingDatabaseSchemaWidgetWrapper::QgsProcessingDatabaseSchemaWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4925  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4926 {
4927 
4928 }
4929 
4930 QWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createWidget()
4931 {
4932  const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast< const QgsProcessingParameterDatabaseSchema *>( parameterDefinition() );
4933 
4934  mSchemaComboBox = new QgsDatabaseSchemaComboBox( QString(), QString() );
4936  mSchemaComboBox->setAllowEmptySchema( true );
4937 
4938  switch ( type() )
4939  {
4942  break;
4944  mSchemaComboBox->comboBox()->setEditable( true );
4945  break;
4946  }
4947 
4948  mSchemaComboBox->setToolTip( parameterDefinition()->toolTip() );
4949  connect( mSchemaComboBox->comboBox(), &QComboBox::currentTextChanged, this, [ = ]( const QString & )
4950  {
4951  if ( mBlockSignals )
4952  return;
4953 
4954  emit widgetValueHasChanged( this );
4955  } );
4956 
4957  return mSchemaComboBox;
4958 }
4959 
4960 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4961 {
4962  return new QgsProcessingDatabaseSchemaParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4963 }
4964 
4965 void QgsProcessingDatabaseSchemaWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
4966 {
4967  // evaluate value to connection
4968  QgsProcessingContext *context = nullptr;
4969  std::unique_ptr< QgsProcessingContext > tmpContext;
4970  if ( mProcessingContextGenerator )
4971  context = mProcessingContextGenerator->processingContext();
4972 
4973  if ( !context )
4974  {
4975  tmpContext = std::make_unique< QgsProcessingContext >();
4976  context = tmpContext.get();
4977  }
4978 
4979  const QVariant value = parentWrapper->parameterValue();
4980  const QString connection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
4981 
4982  if ( mSchemaComboBox )
4983  mSchemaComboBox->setConnectionName( connection, qgis::down_cast< const QgsProcessingParameterProviderConnection * >( parentWrapper->parameterDefinition() )->providerId() );
4984 
4985  const QgsProcessingParameterDatabaseSchema *schemaParam = qgis::down_cast< const QgsProcessingParameterDatabaseSchema * >( parameterDefinition() );
4986  if ( schemaParam->defaultValueForGui().isValid() )
4987  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
4988 }
4989 
4990 void QgsProcessingDatabaseSchemaWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4991 {
4992  const QString v = QgsProcessingParameters::parameterAsSchema( parameterDefinition(), value, context );
4993 
4994  if ( !value.isValid() )
4995  mSchemaComboBox->comboBox()->setCurrentIndex( -1 );
4996  else
4997  {
4998  if ( mSchemaComboBox->comboBox()->isEditable() )
4999  {
5000  const QString prev = mSchemaComboBox->comboBox()->currentText();
5001  mBlockSignals++;
5002  mSchemaComboBox->setSchema( v );
5003  mSchemaComboBox->comboBox()->setCurrentText( v );
5004 
5005  mBlockSignals--;
5006  if ( prev != v )
5007  emit widgetValueHasChanged( this );
5008  }
5009  else
5010  mSchemaComboBox->setSchema( v );
5011  }
5012 }
5013 
5014 QVariant QgsProcessingDatabaseSchemaWidgetWrapper::widgetValue() const
5015 {
5016  if ( mSchemaComboBox )
5017  if ( mSchemaComboBox->comboBox()->isEditable() )
5018  return mSchemaComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->comboBox()->currentText() );
5019  else
5020  return mSchemaComboBox->currentSchema().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->currentSchema() );
5021  else
5022  return QVariant();
5023 }
5024 
5025 QStringList QgsProcessingDatabaseSchemaWidgetWrapper::compatibleParameterTypes() const
5026 {
5027  return QStringList()
5031 }
5032 
5033 QStringList QgsProcessingDatabaseSchemaWidgetWrapper::compatibleOutputTypes() const
5034 {
5035  return QStringList()
5037 }
5038 
5039 QString QgsProcessingDatabaseSchemaWidgetWrapper::modelerExpressionFormatString() const
5040 {
5041  return tr( "database schema name as a string value" );
5042 }
5043 
5044 QString QgsProcessingDatabaseSchemaWidgetWrapper::parameterType() const
5045 {
5047 }
5048 
5049 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseSchemaWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5050 {
5051  return new QgsProcessingDatabaseSchemaWidgetWrapper( parameter, type );
5052 }
5053 
5054 void QgsProcessingDatabaseSchemaWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5055 {
5057  switch ( type() )
5058  {
5061  {
5062  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5063  {
5064  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseSchema * >( parameterDefinition() )->parentConnectionParameterName() )
5065  {
5066  setParentConnectionWrapperValue( wrapper );
5068  {
5069  setParentConnectionWrapperValue( wrapper );
5070  } );
5071  break;
5072  }
5073  }
5074  break;
5075  }
5076 
5078  break;
5079  }
5080 }
5081 
5082 
5083 
5084 //
5085 // QgsProcessingDatabaseTableWidgetWrapper
5086 //
5087 
5088 QgsProcessingDatabaseTableParameterDefinitionWidget::QgsProcessingDatabaseTableParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5089  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5090 {
5091  const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast< const QgsProcessingParameterDatabaseTable *>( definition );
5092 
5093  QVBoxLayout *vlayout = new QVBoxLayout();
5094  vlayout->setContentsMargins( 0, 0, 0, 0 );
5095 
5096  mConnectionParamComboBox = new QComboBox();
5097  mSchemaParamComboBox = new QComboBox();
5098  QString initialConnection;
5099  QString initialSchema;
5100  if ( tableParam )
5101  {
5102  initialConnection = tableParam->parentConnectionParameterName();
5103  initialSchema = tableParam->parentSchemaParameterName();
5104  }
5105 
5106  if ( auto *lModel = widgetContext.model() )
5107  {
5108  // populate combo box with other model input choices
5109  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5110  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5111  {
5112  if ( definition && it->parameterName() == definition->name() )
5113  continue;
5114 
5115  if ( dynamic_cast< const QgsProcessingParameterProviderConnection * >( lModel->parameterDefinition( it->parameterName() ) ) )
5116  {
5117  mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5118  if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5119  {
5120  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5121  }
5122  }
5123  else if ( dynamic_cast< const QgsProcessingParameterDatabaseSchema * >( lModel->parameterDefinition( it->parameterName() ) ) )
5124  {
5125  mSchemaParamComboBox->addItem( it->parameterName(), it->parameterName() );
5126  if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5127  {
5128  mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5129  }
5130  }
5131  }
5132  }
5133 
5134  if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5135  {
5136  // if no candidates found, we just add the existing one as a placeholder
5137  mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5138  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5139  }
5140 
5141  if ( mSchemaParamComboBox->count() == 0 && !initialSchema.isEmpty() )
5142  {
5143  // if no candidates found, we just add the existing one as a placeholder
5144  mSchemaParamComboBox->addItem( initialSchema, initialSchema );
5145  mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5146  }
5147 
5148  vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
5149  vlayout->addWidget( mConnectionParamComboBox );
5150 
5151  vlayout->addWidget( new QLabel( tr( "Database schema parameter" ) ) );
5152  vlayout->addWidget( mSchemaParamComboBox );
5153 
5154  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5155 
5156  mDefaultEdit = new QLineEdit();
5157  vlayout->addWidget( mDefaultEdit );
5158  setLayout( vlayout );
5159 
5160  if ( tableParam )
5161  {
5162  mDefaultEdit->setText( tableParam->defaultValueForGui().toString() );
5163  }
5164 }
5165 
5166 QgsProcessingParameterDefinition *QgsProcessingDatabaseTableParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5167 {
5168  QVariant defaultVal;
5169  if ( mDefaultEdit->text().isEmpty() )
5170  defaultVal = QVariant();
5171  else
5172  defaultVal = mDefaultEdit->text();
5173  auto param = std::make_unique< QgsProcessingParameterDatabaseTable>( name, description,
5174  mConnectionParamComboBox->currentData().toString(),
5175  mSchemaParamComboBox->currentData().toString(),
5176  defaultVal );
5177  param->setFlags( flags );
5178  return param.release();
5179 }
5180 
5181 
5182 QgsProcessingDatabaseTableWidgetWrapper::QgsProcessingDatabaseTableWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5183  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5184 {
5185 
5186 }
5187 
5188 QWidget *QgsProcessingDatabaseTableWidgetWrapper::createWidget()
5189 {
5190  const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast< const QgsProcessingParameterDatabaseTable *>( parameterDefinition() );
5191 
5192  mTableComboBox = new QgsDatabaseTableComboBox( QString(), QString() );
5194  mTableComboBox->setAllowEmptyTable( true );
5195 
5196  if ( type() == QgsProcessingGui::Modeler || tableParam->allowNewTableNames() )
5197  mTableComboBox->comboBox()->setEditable( true );
5198 
5199  mTableComboBox->setToolTip( parameterDefinition()->toolTip() );
5200  connect( mTableComboBox->comboBox(), &QComboBox::currentTextChanged, this, [ = ]( const QString & )
5201  {
5202  if ( mBlockSignals )
5203  return;
5204 
5205  emit widgetValueHasChanged( this );
5206  } );
5207 
5208  return mTableComboBox;
5209 }
5210 
5211 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseTableWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5212 {
5213  return new QgsProcessingDatabaseTableParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5214 }
5215 
5216 void QgsProcessingDatabaseTableWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5217 {
5218  // evaluate value to connection
5219  QgsProcessingContext *context = nullptr;
5220  std::unique_ptr< QgsProcessingContext > tmpContext;
5221  if ( mProcessingContextGenerator )
5222  context = mProcessingContextGenerator->processingContext();
5223 
5224  if ( !context )
5225  {
5226  tmpContext = std::make_unique< QgsProcessingContext >();
5227  context = tmpContext.get();
5228  }
5229 
5230  QVariant value = parentWrapper->parameterValue();
5231  mConnection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
5232  mProvider = qgis::down_cast< const QgsProcessingParameterProviderConnection * >( parentWrapper->parameterDefinition() )->providerId();
5233  if ( mTableComboBox && !mSchema.isEmpty() )
5234  {
5235  mTableComboBox->setSchema( mSchema );
5236  mTableComboBox->setConnectionName( mConnection, mProvider );
5237 
5238  const QgsProcessingParameterDatabaseTable *tableParam = qgis::down_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() );
5239  if ( tableParam->defaultValueForGui().isValid() )
5240  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5241  }
5242 }
5243 
5244 void QgsProcessingDatabaseTableWidgetWrapper::setParentSchemaWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5245 {
5246  // evaluate value to schema
5247  QgsProcessingContext *context = nullptr;
5248  std::unique_ptr< QgsProcessingContext > tmpContext;
5249  if ( mProcessingContextGenerator )
5250  context = mProcessingContextGenerator->processingContext();
5251 
5252  if ( !context )
5253  {
5254  tmpContext = std::make_unique< QgsProcessingContext >();
5255  context = tmpContext.get();
5256  }
5257 
5258  QVariant value = parentWrapper->parameterValue();
5259  mSchema = value.isValid() ? QgsProcessingParameters::parameterAsSchema( parentWrapper->parameterDefinition(), value, *context ) : QString();
5260 
5261  if ( mTableComboBox && !mSchema.isEmpty() && !mConnection.isEmpty() )
5262  {
5263  mTableComboBox->setSchema( mSchema );
5264  mTableComboBox->setConnectionName( mConnection, mProvider );
5265 
5266  const QgsProcessingParameterDatabaseTable *tableParam = static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() );
5267  if ( tableParam->defaultValueForGui().isValid() )
5268  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5269  }
5270 
5271 }
5272 
5273 void QgsProcessingDatabaseTableWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5274 {
5275  const QString v = QgsProcessingParameters::parameterAsDatabaseTableName( parameterDefinition(), value, context );
5276 
5277  if ( !value.isValid() )
5278  mTableComboBox->comboBox()->setCurrentIndex( -1 );
5279  else
5280  {
5281  if ( mTableComboBox->comboBox()->isEditable() )
5282  {
5283  const QString prev = mTableComboBox->comboBox()->currentText();
5284  mBlockSignals++;
5285  mTableComboBox->setTable( v );
5286  mTableComboBox->comboBox()->setCurrentText( v );
5287 
5288  mBlockSignals--;
5289  if ( prev != v )
5290  emit widgetValueHasChanged( this );
5291  }
5292  else
5293  mTableComboBox->setTable( v );
5294  }
5295 }
5296 
5297 QVariant QgsProcessingDatabaseTableWidgetWrapper::widgetValue() const
5298 {
5299  if ( mTableComboBox )
5300  if ( mTableComboBox->comboBox()->isEditable() )
5301  return mTableComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mTableComboBox->comboBox()->currentText() );
5302  else
5303  return mTableComboBox->currentTable().isEmpty() ? QVariant() : QVariant( mTableComboBox->currentTable() );
5304  else
5305  return QVariant();
5306 }
5307 
5308 QStringList QgsProcessingDatabaseTableWidgetWrapper::compatibleParameterTypes() const
5309 {
5310  return QStringList()
5314 }
5315 
5316 QStringList QgsProcessingDatabaseTableWidgetWrapper::compatibleOutputTypes() const
5317 {
5318  return QStringList()
5320 }
5321 
5322 QString QgsProcessingDatabaseTableWidgetWrapper::modelerExpressionFormatString() const
5323 {
5324  return tr( "database table name as a string value" );
5325 }
5326 
5327 QString QgsProcessingDatabaseTableWidgetWrapper::parameterType() const
5328 {
5330 }
5331 
5332 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseTableWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5333 {
5334  return new QgsProcessingDatabaseTableWidgetWrapper( parameter, type );
5335 }
5336 
5337 void QgsProcessingDatabaseTableWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5338 {
5340  switch ( type() )
5341  {
5344  {
5345  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5346  {
5347  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() )->parentConnectionParameterName() )
5348  {
5349  setParentConnectionWrapperValue( wrapper );
5351  {
5352  setParentConnectionWrapperValue( wrapper );
5353  } );
5354  }
5355  else if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() )->parentSchemaParameterName() )
5356  {
5357  setParentSchemaWrapperValue( wrapper );
5359  {
5360  setParentSchemaWrapperValue( wrapper );
5361  } );
5362  }
5363  }
5364  break;
5365  }
5366 
5368  break;
5369  }
5370 }
5371 
5372 
5373 //
5374 // QgsProcessingExtentWidgetWrapper
5375 //
5376 
5377 QgsProcessingExtentParameterDefinitionWidget::QgsProcessingExtentParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5378  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5379 {
5380  QVBoxLayout *vlayout = new QVBoxLayout();
5381  vlayout->setContentsMargins( 0, 0, 0, 0 );
5382 
5383  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5384 
5385  mDefaultWidget = new QgsExtentWidget();
5386  mDefaultWidget->setNullValueAllowed( true, tr( "Not set" ) );
5387  if ( const QgsProcessingParameterExtent *extentParam = dynamic_cast<const QgsProcessingParameterExtent *>( definition ) )
5388  {
5389  if ( extentParam->defaultValueForGui().isValid() )
5390  {
5391  QgsRectangle rect = QgsProcessingParameters::parameterAsExtent( extentParam, extentParam->defaultValueForGui(), context );
5392  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsExtentCrs( extentParam, extentParam->defaultValueForGui(), context );
5393  mDefaultWidget->setCurrentExtent( rect, crs );
5394  mDefaultWidget->setOutputExtentFromCurrent();
5395  }
5396  else
5397  {
5398  mDefaultWidget->clear();
5399  }
5400  }
5401 
5402  vlayout->addWidget( mDefaultWidget );
5403  setLayout( vlayout );
5404 }
5405 
5406 QgsProcessingParameterDefinition *QgsProcessingExtentParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5407 {
5408  const QString defaultVal = mDefaultWidget->isValid() ? QStringLiteral( "%1,%2,%3,%4%5" ).arg(
5409  QString::number( mDefaultWidget->outputExtent().xMinimum(), 'f', 9 ),
5410  QString::number( mDefaultWidget->outputExtent().xMaximum(), 'f', 9 ),
5411  QString::number( mDefaultWidget->outputExtent().yMinimum(), 'f', 9 ),
5412  QString::number( mDefaultWidget->outputExtent().yMaximum(), 'f', 9 ),
5413  mDefaultWidget->outputCrs().isValid() ? QStringLiteral( " [%1]" ).arg( mDefaultWidget->outputCrs().authid() ) : QString()
5414  ) : QString();
5415  auto param = std::make_unique< QgsProcessingParameterExtent >( name, description, !defaultVal.isEmpty() ? QVariant( defaultVal ) : QVariant() );
5416  param->setFlags( flags );
5417  return param.release();
5418 }
5419 
5420 
5421 
5422 QgsProcessingExtentWidgetWrapper::QgsProcessingExtentWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5423  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5424 {
5425 
5426 }
5427 
5428 QWidget *QgsProcessingExtentWidgetWrapper::createWidget()
5429 {
5430  const QgsProcessingParameterExtent *extentParam = dynamic_cast< const QgsProcessingParameterExtent *>( parameterDefinition() );
5431  switch ( type() )
5432  {
5436  {
5437  mExtentWidget = new QgsExtentWidget( nullptr );
5438  if ( widgetContext().mapCanvas() )
5439  mExtentWidget->setMapCanvas( widgetContext().mapCanvas() );
5440 
5442  mExtentWidget->setNullValueAllowed( true, tr( "Not set" ) );
5443 
5444  mExtentWidget->setToolTip( parameterDefinition()->toolTip() );
5445 
5446  connect( mExtentWidget, &QgsExtentWidget::extentChanged, this, [ = ]
5447  {
5448  emit widgetValueHasChanged( this );
5449  } );
5450 
5451  if ( mDialog && type() != QgsProcessingGui::Modeler )
5452  setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
5453 
5454  return mExtentWidget;
5455  }
5456  }
5457  return nullptr;
5458 }
5459 
5460 void QgsProcessingExtentWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
5461 {
5463  if ( mExtentWidget && context.mapCanvas() && type() != QgsProcessingGui::Modeler )
5464  mExtentWidget->setMapCanvas( context.mapCanvas() );
5465 }
5466 
5467 void QgsProcessingExtentWidgetWrapper::setDialog( QDialog *dialog )
5468 {
5469  mDialog = dialog;
5470  if ( mExtentWidget && mDialog && type() != QgsProcessingGui::Modeler )
5471  {
5472  connect( mExtentWidget, &QgsExtentWidget::toggleDialogVisibility, mDialog, [ = ]( bool visible )
5473  {
5474  if ( !visible )
5475  mDialog->showMinimized();
5476  else
5477  {
5478  mDialog->showNormal();
5479  mDialog->raise();
5480  mDialog->activateWindow();
5481  }
5482  } );
5483  }
5485 }
5486 
5487 void QgsProcessingExtentWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5488 {
5489  if ( mExtentWidget )
5490  {
5491  if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
5492  mExtentWidget->clear();
5493  else
5494  {
5495  QgsRectangle r = QgsProcessingParameters::parameterAsExtent( parameterDefinition(), value, context );
5496  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
5497  mExtentWidget->setCurrentExtent( r, crs );
5498  mExtentWidget->setOutputExtentFromUser( r, crs );
5499  }
5500  }
5501 }
5502 
5503 QVariant QgsProcessingExtentWidgetWrapper::widgetValue() const
5504 {
5505  if ( mExtentWidget )
5506  {
5507  const QString val = mExtentWidget->isValid() ? QStringLiteral( "%1,%2,%3,%4%5" ).arg(
5508  QString::number( mExtentWidget->outputExtent().xMinimum(), 'f', 9 ),
5509  QString::number( mExtentWidget->outputExtent().xMaximum(), 'f', 9 ),
5510  QString::number( mExtentWidget->outputExtent().yMinimum(), 'f', 9 ),
5511  QString::number( mExtentWidget->outputExtent().yMaximum(), 'f', 9 ),
5512  mExtentWidget->outputCrs().isValid() ? QStringLiteral( " [%1]" ).arg( mExtentWidget->outputCrs().authid() ) : QString()
5513  ) : QString();
5514 
5515  return val.isEmpty() ? QVariant() : QVariant( val );
5516  }
5517  else
5518  return QVariant();
5519 }
5520 
5521 QStringList QgsProcessingExtentWidgetWrapper::compatibleParameterTypes() const
5522 {
5523  return QStringList()
5531 
5532 }
5533 
5534 QStringList QgsProcessingExtentWidgetWrapper::compatibleOutputTypes() const
5535 {
5536  return QStringList()
5541 }
5542 
5543 QString QgsProcessingExtentWidgetWrapper::modelerExpressionFormatString() const
5544 {
5545  return tr( "string of the format 'x min,x max,y min,y max' or a geometry value (bounding box is used)" );
5546 }
5547 
5548 QString QgsProcessingExtentWidgetWrapper::parameterType() const
5549 {
5551 }
5552 
5553 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExtentWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5554 {
5555  return new QgsProcessingExtentWidgetWrapper( parameter, type );
5556 }
5557 
5558 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingExtentWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5559 {
5560  return new QgsProcessingExtentParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5561 }
5562 
5563 
5564 
5565 //
5566 // QgsProcessingMapLayerWidgetWrapper
5567 //
5568 
5569 QgsProcessingMapLayerParameterDefinitionWidget::QgsProcessingMapLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5570  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5571 {
5572  QVBoxLayout *vlayout = new QVBoxLayout();
5573  vlayout->setContentsMargins( 0, 0, 0, 0 );
5574 
5575  vlayout->addWidget( new QLabel( tr( "Layer type" ) ) );
5576  mLayerTypeComboBox = new QgsCheckableComboBox();
5577  mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), QgsProcessing::TypeMapLayer );
5578  mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), QgsProcessing::TypeVectorPoint );
5579  mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), QgsProcessing::TypeVectorLine );
5580  mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), QgsProcessing::TypeVectorPolygon );
5581  mLayerTypeComboBox->addItem( tr( "Vector (Any Geometry Type)" ), QgsProcessing::TypeVectorAnyGeometry );
5582  mLayerTypeComboBox->addItem( tr( "Raster" ), QgsProcessing::TypeRaster );
5583  mLayerTypeComboBox->addItem( tr( "Mesh" ), QgsProcessing::TypeMesh );
5584 
5585  if ( const QgsProcessingParameterMapLayer *layerParam = dynamic_cast<const QgsProcessingParameterMapLayer *>( definition ) )
5586  {
5587  for ( int i : layerParam->dataTypes() )
5588  {
5589  mLayerTypeComboBox->setItemCheckState( mLayerTypeComboBox->findData( i ), Qt::Checked );
5590  }
5591  }
5592 
5593  vlayout->addWidget( mLayerTypeComboBox );
5594 
5595  setLayout( vlayout );
5596 }
5597 
5598 QgsProcessingParameterDefinition *QgsProcessingMapLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5599 {
5600  QList< int > dataTypes;
5601  for ( const QVariant &v : mLayerTypeComboBox->checkedItemsData() )
5602  dataTypes << v.toInt();
5603 
5604  auto param = std::make_unique< QgsProcessingParameterMapLayer >( name, description );
5605  param->setDataTypes( dataTypes );
5606  param->setFlags( flags );
5607  return param.release();
5608 }
5609 
5610 QgsProcessingMapLayerWidgetWrapper::QgsProcessingMapLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5611  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5612 {
5613 
5614 }
5615 
5616 QWidget *QgsProcessingMapLayerWidgetWrapper::createWidget()
5617 {
5618  mComboBox = new QgsProcessingMapLayerComboBox( parameterDefinition(), type() );
5619 
5620  switch ( type() )
5621  {
5624  break;
5626  mComboBox->setEditable( true );
5627  break;
5628  }
5629 
5630  mComboBox->setToolTip( parameterDefinition()->toolTip() );
5631 
5632  connect( mComboBox, &QgsProcessingMapLayerComboBox::valueChanged, this, [ = ]()
5633  {
5634  if ( mBlockSignals )
5635  return;
5636 
5637  emit widgetValueHasChanged( this );
5638  } );
5639 
5640  setWidgetContext( widgetContext() );
5641  return mComboBox;
5642 }
5643 
5644 void QgsProcessingMapLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
5645 {
5647  if ( mComboBox )
5648  {
5649  mComboBox->setWidgetContext( context );
5650 
5651  if ( !( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional ) )
5652  {
5653  // non optional parameter -- if no default value set, default to active layer
5654  if ( !parameterDefinition()->defaultValueForGui().isValid() )
5655  mComboBox->setLayer( context.activeLayer() );
5656  }
5657  }
5658 }
5659 
5660 void QgsProcessingMapLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5661 {
5662  if ( mComboBox )
5663  mComboBox->setValue( value, context );
5664 }
5665 
5666 QVariant QgsProcessingMapLayerWidgetWrapper::widgetValue() const
5667 {
5668  return mComboBox ? mComboBox->value() : QVariant();
5669 }
5670 
5671 QStringList QgsProcessingMapLayerWidgetWrapper::compatibleParameterTypes() const
5672 {
5673  return QStringList()
5680 }
5681 
5682 QStringList QgsProcessingMapLayerWidgetWrapper::compatibleOutputTypes() const
5683 {
5684  return QStringList()
5690 }
5691 
5692 QString QgsProcessingMapLayerWidgetWrapper::modelerExpressionFormatString() const
5693 {
5694  return tr( "path to a map layer" );
5695 }
5696 
5697 QString QgsProcessingMapLayerWidgetWrapper::parameterType() const
5698 {
5700 }
5701 
5702 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5703 {
5704  return new QgsProcessingMapLayerWidgetWrapper( parameter, type );
5705 }
5706 
5707 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5708 {
5709  return new QgsProcessingMapLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5710 }
5711 
5712 
5713 //
5714 // QgsProcessingRasterLayerWidgetWrapper
5715 //
5716 
5717 QgsProcessingRasterLayerWidgetWrapper::QgsProcessingRasterLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5718  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
5719 {
5720 
5721 }
5722 
5723 QStringList QgsProcessingRasterLayerWidgetWrapper::compatibleParameterTypes() const
5724 {
5725  return QStringList()
5730 }
5731 
5732 QStringList QgsProcessingRasterLayerWidgetWrapper::compatibleOutputTypes() const
5733 {
5734  return QStringList()
5740 }
5741 
5742 QString QgsProcessingRasterLayerWidgetWrapper::modelerExpressionFormatString() const
5743 {
5744  return tr( "path to a raster layer" );
5745 }
5746 
5747 QString QgsProcessingRasterLayerWidgetWrapper::parameterType() const
5748 {
5750 }
5751 
5752 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5753 {
5754  return new QgsProcessingRasterLayerWidgetWrapper( parameter, type );
5755 }
5756 
5757 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRasterLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5758 {
5759  Q_UNUSED( context );
5760  Q_UNUSED( widgetContext );
5761  Q_UNUSED( definition );
5762  Q_UNUSED( algorithm );
5763 
5764  return nullptr;
5765 }
5766 
5767 
5768 //
5769 // QgsProcessingVectorLayerWidgetWrapper
5770 //
5771 
5772 QgsProcessingVectorLayerParameterDefinitionWidget::QgsProcessingVectorLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5773  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5774 {
5775  QVBoxLayout *vlayout = new QVBoxLayout();
5776  vlayout->setContentsMargins( 0, 0, 0, 0 );
5777 
5778  vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
5779  mGeometryTypeComboBox = new QgsCheckableComboBox();
5780  mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), QgsProcessing::TypeVector );
5781  mGeometryTypeComboBox->addItem( tr( "Point" ), QgsProcessing::TypeVectorPoint );
5782  mGeometryTypeComboBox->addItem( tr( "Line" ), QgsProcessing::TypeVectorLine );
5783  mGeometryTypeComboBox->addItem( tr( "Polygon" ), QgsProcessing::TypeVectorPolygon );
5784  mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
5785 
5786  if ( const QgsProcessingParameterVectorLayer *vectorParam = dynamic_cast<const QgsProcessingParameterVectorLayer *>( definition ) )
5787  {
5788  for ( int i : vectorParam->dataTypes() )
5789  {
5790  mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
5791  }
5792  }
5793 
5794  vlayout->addWidget( mGeometryTypeComboBox );
5795 
5796  setLayout( vlayout );
5797 }
5798 
5799 QgsProcessingParameterDefinition *QgsProcessingVectorLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5800 {
5801  QList< int > dataTypes;
5802  for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
5803  dataTypes << v.toInt();
5804 
5805  auto param = std::make_unique< QgsProcessingParameterVectorLayer >( name, description, dataTypes );
5806  param->setFlags( flags );
5807  return param.release();
5808 }
5809 
5810 
5811 QgsProcessingVectorLayerWidgetWrapper::QgsProcessingVectorLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5812  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
5813 {
5814 
5815 }
5816 
5817 QStringList QgsProcessingVectorLayerWidgetWrapper::compatibleParameterTypes() const
5818 {
5819  return QStringList()
5824 }
5825 
5826 QStringList QgsProcessingVectorLayerWidgetWrapper::compatibleOutputTypes() const
5827 {
5828  return QStringList()
5834 }
5835 
5836 QString QgsProcessingVectorLayerWidgetWrapper::modelerExpressionFormatString() const
5837 {
5838  return tr( "path to a vector layer" );
5839 }
5840 
5841 QList<int> QgsProcessingVectorLayerWidgetWrapper::compatibleDataTypes( const QgsProcessingParameterDefinition *parameter ) const
5842 {
5843  if ( const QgsProcessingParameterVectorLayer *param = dynamic_cast< const QgsProcessingParameterVectorLayer *>( parameter ) )
5844  return param->dataTypes();
5845  else
5846  return QList< int >();
5847 }
5848 
5849 QString QgsProcessingVectorLayerWidgetWrapper::parameterType() const
5850 {
5852 }
5853 
5854 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5855 {
5856  return new QgsProcessingVectorLayerWidgetWrapper( parameter, type );
5857 }
5858 
5859 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingVectorLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5860 {
5861  return new QgsProcessingVectorLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5862 }
5863 
5864 
5865 
5866 //
5867 // QgsProcessingFeatureSourceLayerWidgetWrapper
5868 //
5869 
5870 QgsProcessingFeatureSourceParameterDefinitionWidget::QgsProcessingFeatureSourceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5871  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5872 {
5873  QVBoxLayout *vlayout = new QVBoxLayout();
5874  vlayout->setContentsMargins( 0, 0, 0, 0 );
5875 
5876  vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
5877  mGeometryTypeComboBox = new QgsCheckableComboBox();
5878  mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), QgsProcessing::TypeVector );
5879  mGeometryTypeComboBox->addItem( tr( "Point" ), QgsProcessing::TypeVectorPoint );
5880  mGeometryTypeComboBox->addItem( tr( "Line" ), QgsProcessing::TypeVectorLine );
5881  mGeometryTypeComboBox->addItem( tr( "Polygon" ), QgsProcessing::TypeVectorPolygon );
5882  mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
5883 
5884  if ( const QgsProcessingParameterFeatureSource *sourceParam = dynamic_cast<const QgsProcessingParameterFeatureSource *>( definition ) )
5885  {
5886  for ( int i : sourceParam->dataTypes() )
5887  {
5888  mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
5889  }
5890  }
5891  else
5892  {
5893  mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( QgsProcessing::TypeVectorAnyGeometry ), Qt::Checked );
5894  }
5895 
5896  vlayout->addWidget( mGeometryTypeComboBox );
5897 
5898  setLayout( vlayout );
5899 }
5900 
5901 QgsProcessingParameterDefinition *QgsProcessingFeatureSourceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5902 {
5903  QList< int > dataTypes;
5904  for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
5905  dataTypes << v.toInt();
5906 
5907  auto param = std::make_unique< QgsProcessingParameterFeatureSource >( name, description, dataTypes );
5908  param->setFlags( flags );
5909  return param.release();
5910 }
5911 
5912 QgsProcessingFeatureSourceWidgetWrapper::QgsProcessingFeatureSourceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5913  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
5914 {
5915 
5916 }
5917 
5918 QStringList QgsProcessingFeatureSourceWidgetWrapper::compatibleParameterTypes() const
5919 {
5920  return QStringList()
5926 }
5927 
5928 QStringList QgsProcessingFeatureSourceWidgetWrapper::compatibleOutputTypes() const
5929 {
5930  return QStringList()
5936 }
5937 
5938 QString QgsProcessingFeatureSourceWidgetWrapper::modelerExpressionFormatString() const
5939 {
5940  return tr( "path to a vector layer" );
5941 }
5942 
5943 QList<int> QgsProcessingFeatureSourceWidgetWrapper::compatibleDataTypes( const QgsProcessingParameterDefinition *parameter ) const
5944 {
5945  if ( const QgsProcessingParameterFeatureSource *param = dynamic_cast< const QgsProcessingParameterFeatureSource *>( parameter ) )
5946  return param->dataTypes();
5947  else
5948  return QList< int >();
5949 }
5950 
5951 QString QgsProcessingFeatureSourceWidgetWrapper::parameterType() const
5952 {
5954 }
5955 
5956 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSourceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5957 {
5958  return new QgsProcessingFeatureSourceWidgetWrapper( parameter, type );
5959 }
5960 
5961 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFeatureSourceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5962 {
5963  return new QgsProcessingFeatureSourceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5964 }
5965 
5966 //
5967 // QgsProcessingMeshLayerWidgetWrapper
5968 //
5969 
5970 QgsProcessingMeshLayerWidgetWrapper::QgsProcessingMeshLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5971  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
5972 {
5973 
5974 }
5975 
5976 QStringList QgsProcessingMeshLayerWidgetWrapper::compatibleParameterTypes() const
5977 {
5978  return QStringList()
5983 }
5984 
5985 QStringList QgsProcessingMeshLayerWidgetWrapper::compatibleOutputTypes() const
5986 {
5987  return QStringList()
5989  // TODO << QgsProcessingOutputMeshLayer::typeName()
5993 }
5994 
5995 QString QgsProcessingMeshLayerWidgetWrapper::modelerExpressionFormatString() const
5996 {
5997  return tr( "path to a mesh layer" );
5998 }
5999 
6000 QString QgsProcessingMeshLayerWidgetWrapper::parameterType() const
6001 {
6003 }
6004 
6005 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6006 {
6007  return new QgsProcessingMeshLayerWidgetWrapper( parameter, type );
6008 }
6009 
6010 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMeshLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6011 {
6012  Q_UNUSED( context );
6013  Q_UNUSED( widgetContext );
6014  Q_UNUSED( definition );
6015  Q_UNUSED( algorithm );
6016 
6017  return nullptr;
6018 }
6019 
6020 
6021 
6022 //
6023 // QgsProcessingRasterBandPanelWidget
6024 //
6025 
6026 QgsProcessingRasterBandPanelWidget::QgsProcessingRasterBandPanelWidget( QWidget *parent, const QgsProcessingParameterBand *param )
6027  : QWidget( parent )
6028  , mParam( param )
6029 {
6030  QHBoxLayout *hl = new QHBoxLayout();
6031  hl->setContentsMargins( 0, 0, 0, 0 );
6032 
6033  mLineEdit = new QLineEdit();
6034  mLineEdit->setEnabled( false );
6035  hl->addWidget( mLineEdit, 1 );
6036 
6037  mToolButton = new QToolButton();
6038  mToolButton->setText( QString( QChar( 0x2026 ) ) );
6039  hl->addWidget( mToolButton );
6040 
6041  setLayout( hl );
6042 
6043  if ( mParam )
6044  {
6045  mLineEdit->setText( tr( "%1 bands selected" ).arg( 0 ) );
6046  }
6047 
6048  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingRasterBandPanelWidget::showDialog );
6049 }
6050 
6051 void QgsProcessingRasterBandPanelWidget::setBands( const QList< int > &bands )
6052 {
6053  mBands = bands;
6054 }
6055 
6056 void QgsProcessingRasterBandPanelWidget::setBandNames( const QHash<int, QString> &names )
6057 {
6058  mBandNames = names;
6059 }
6060 
6061 void QgsProcessingRasterBandPanelWidget::setValue( const QVariant &value )
6062 {
6063  if ( value.isValid() )
6064  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
6065  else
6066  mValue.clear();
6067 
6068  updateSummaryText();
6069  emit changed();
6070 }
6071 
6072 void QgsProcessingRasterBandPanelWidget::showDialog()
6073 {
6074  QVariantList availableOptions;
6075  QStringList fieldNames;
6076  availableOptions.reserve( mBands.size() );
6077  for ( int band : std::as_const( mBands ) )
6078  {
6079  availableOptions << band;
6080  }
6081 
6083  if ( panel && panel->dockMode() )
6084  {
6085  QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
6086  widget->setPanelTitle( mParam->description() );
6087 
6088  widget->setValueFormatter( [this]( const QVariant & v ) -> QString
6089  {
6090  int band = v.toInt();
6091  return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
6092  } );
6093 
6094  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
6095  {
6096  setValue( widget->selectedOptions() );
6097  } );
6098  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
6099  panel->openPanel( widget );
6100  }
6101  else
6102  {
6103  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
6104 
6105  dlg.setValueFormatter( [this]( const QVariant & v ) -> QString
6106  {
6107  int band = v.toInt();
6108  return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
6109  } );
6110  if ( dlg.exec() )
6111  {
6112  setValue( dlg.selectedOptions() );
6113  }
6114  }
6115 }
6116 
6117 void QgsProcessingRasterBandPanelWidget::updateSummaryText()
6118 {
6119  if ( mParam )
6120  mLineEdit->setText( tr( "%1 bands selected" ).arg( mValue.count() ) );
6121 }
6122 
6123 
6124 
6125 //
6126 // QgsProcessingBandWidgetWrapper
6127 //
6128 
6129 QgsProcessingBandParameterDefinitionWidget::QgsProcessingBandParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6130  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6131 {
6132  QVBoxLayout *vlayout = new QVBoxLayout();
6133  vlayout->setContentsMargins( 0, 0, 0, 0 );
6134 
6135  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
6136 
6137  mDefaultLineEdit = new QLineEdit();
6138  mDefaultLineEdit->setToolTip( tr( "Band number (separate bands with ; for multiple band parameters)" ) );
6139  if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6140  {
6141  const QList< int > bands = QgsProcessingParameters::parameterAsInts( bandParam, bandParam->defaultValueForGui(), context );
6142  QStringList defVal;
6143  for ( int b : bands )
6144  {
6145  defVal << QString::number( b );
6146  }
6147 
6148  mDefaultLineEdit->setText( defVal.join( ';' ) );
6149  }
6150  vlayout->addWidget( mDefaultLineEdit );
6151 
6152  vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
6153  mParentLayerComboBox = new QComboBox();
6154 
6155  QString initialParent;
6156  if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6157  initialParent = bandParam->parentLayerParameterName();
6158 
6159  if ( auto *lModel = widgetContext.model() )
6160  {
6161  // populate combo box with other model input choices
6162  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
6163  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
6164  {
6165  if ( const QgsProcessingParameterRasterLayer *definition = dynamic_cast< const QgsProcessingParameterRasterLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
6166  {
6167  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
6168  if ( !initialParent.isEmpty() && initialParent == definition->name() )
6169  {
6170  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
6171  }
6172  }
6173  }
6174  }
6175 
6176  if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
6177  {
6178  // if no parent candidates found, we just add the existing one as a placeholder
6179  mParentLayerComboBox->addItem( initialParent, initialParent );
6180  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
6181  }
6182 
6183  vlayout->addWidget( mParentLayerComboBox );
6184 
6185  mAllowMultipleCheckBox = new QCheckBox( tr( "Allow multiple" ) );
6186  if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6187  mAllowMultipleCheckBox->setChecked( bandParam->allowMultiple() );
6188 
6189  vlayout->addWidget( mAllowMultipleCheckBox );
6190  setLayout( vlayout );
6191 }
6192 
6193 QgsProcessingParameterDefinition *QgsProcessingBandParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6194 {
6195  auto param = std::make_unique< QgsProcessingParameterBand >( name, description, mDefaultLineEdit->text().split( ';' ), mParentLayerComboBox->currentData().toString(), false, mAllowMultipleCheckBox->isChecked() );
6196  param->setFlags( flags );
6197  return param.release();
6198 }
6199 
6200 QgsProcessingBandWidgetWrapper::QgsProcessingBandWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6201  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6202 {
6203 
6204 }
6205 
6206 QWidget *QgsProcessingBandWidgetWrapper::createWidget()
6207 {
6208  const QgsProcessingParameterBand *bandParam = dynamic_cast< const QgsProcessingParameterBand *>( parameterDefinition() );
6209  switch ( type() )
6210  {
6213  {
6214  if ( bandParam->allowMultiple() )
6215  {
6216  mPanel = new QgsProcessingRasterBandPanelWidget( nullptr, bandParam );
6217  mPanel->setToolTip( parameterDefinition()->toolTip() );
6218  connect( mPanel, &QgsProcessingRasterBandPanelWidget::changed, this, [ = ]
6219  {
6220  emit widgetValueHasChanged( this );
6221  } );
6222  return mPanel;
6223  }
6224  else
6225  {
6226  mComboBox = new QgsRasterBandComboBox();
6227  mComboBox->setShowNotSetOption( bandParam->flags() & QgsProcessingParameterDefinition::FlagOptional );
6228 
6229  mComboBox->setToolTip( parameterDefinition()->toolTip() );
6230  connect( mComboBox, &QgsRasterBandComboBox::bandChanged, this, [ = ]( int )
6231  {
6232  emit widgetValueHasChanged( this );
6233  } );
6234  return mComboBox;
6235  }
6236  }
6237 
6239  {
6240  mLineEdit = new QLineEdit();
6241  mLineEdit->setToolTip( QObject::tr( "Band number (separate bands with ; for multiple band parameters)" ) );
6242  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
6243  {
6244  emit widgetValueHasChanged( this );
6245  } );
6246  return mLineEdit;
6247  }
6248 
6249  }
6250  return nullptr;
6251 }
6252 
6253 void QgsProcessingBandWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
6254 {
6256  switch ( type() )
6257  {
6260  {
6261  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
6262  {
6263  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterBand * >( parameterDefinition() )->parentLayerParameterName() )
6264  {
6265  setParentLayerWrapperValue( wrapper );
6267  {
6268  setParentLayerWrapperValue( wrapper );
6269  } );
6270  break;
6271  }
6272  }
6273  break;
6274  }
6275 
6277  break;
6278  }
6279 }
6280 
6281 void QgsProcessingBandWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
6282 {
6283  // evaluate value to layer
6284  QgsProcessingContext *context = nullptr;
6285  std::unique_ptr< QgsProcessingContext > tmpContext;
6286  if ( mProcessingContextGenerator )
6287  context = mProcessingContextGenerator->processingContext();
6288 
6289  if ( !context )
6290  {
6291  tmpContext = std::make_unique< QgsProcessingContext >();
6292  context = tmpContext.get();
6293  }
6294 
6295  QVariant value = parentWrapper->parameterValue();
6296 
6297  QgsRasterLayer *layer = QgsProcessingParameters::parameterAsRasterLayer( parentWrapper->parameterDefinition(), value, *context );
6298  if ( layer && layer->isValid() )
6299  {
6300  // need to grab ownership of layer if required - otherwise layer may be deleted when context
6301  // goes out of scope
6302  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
6303  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::RasterLayer )
6304  {
6305  mParentLayer.reset( qobject_cast< QgsRasterLayer * >( ownedLayer.release() ) );
6306  layer = mParentLayer.get();
6307  }
6308  else
6309  {
6310  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
6311  }
6312 
6313  if ( mComboBox )
6314  mComboBox->setLayer( layer );
6315  else if ( mPanel )
6316  {
6317  QgsRasterDataProvider *provider = layer->dataProvider();
6318  if ( provider && layer->isValid() )
6319  {
6320  //fill available bands
6321  int nBands = provider->bandCount();
6322  QList< int > bands;
6323  QHash< int, QString > bandNames;
6324  for ( int i = 1; i <= nBands; ++i )
6325  {
6326  bandNames.insert( i, QgsRasterBandComboBox::displayBandName( provider, i ) );
6327  bands << i;
6328  }
6329  mPanel->setBands( bands );
6330  mPanel->setBandNames( bandNames );
6331  }
6332  }
6333  }
6334  else
6335  {
6336  if ( mComboBox )
6337  mComboBox->setLayer( nullptr );
6338  else if ( mPanel )
6339  mPanel->setBands( QList< int >() );
6340 
6341  if ( value.isValid() && widgetContext().messageBar() )
6342  {
6343  widgetContext().messageBar()->clearWidgets();
6344  widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent bands could not be populated" ),
6345  Qgis::MessageLevel::Info );
6346  }
6347  }
6348 
6349  if ( parameterDefinition()->defaultValueForGui().isValid() )
6350  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
6351 }
6352 
6353 void QgsProcessingBandWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6354 {
6355  if ( mComboBox )
6356  {
6357  if ( !value.isValid() )
6358  mComboBox->setBand( -1 );
6359  else
6360  {
6361  const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
6362  mComboBox->setBand( v );
6363  }
6364  }
6365  else if ( mPanel )
6366  {
6367  QVariantList opts;
6368  if ( value.isValid() )
6369  {
6370  const QList< int > v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
6371  opts.reserve( v.size() );
6372  for ( int i : v )
6373  opts << i;
6374  }
6375  if ( mPanel )
6376  mPanel->setValue( value.isValid() ? opts : QVariant() );
6377  }
6378  else if ( mLineEdit )
6379  {
6380  const QgsProcessingParameterBand *bandParam = static_cast< const QgsProcessingParameterBand * >( parameterDefinition() );
6381  if ( bandParam->allowMultiple() )
6382  {
6383  const QList< int > v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
6384  QStringList opts;
6385  opts.reserve( v.size() );
6386  for ( int i : v )
6387  opts << QString::number( i );
6388  mLineEdit->setText( value.isValid() && !opts.empty() ? opts.join( ';' ) : QString() );
6389  }
6390  else
6391  {
6392  if ( value.isValid() )
6393  mLineEdit->setText( QString::number( QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context ) ) );
6394  else
6395  mLineEdit->clear();
6396  }
6397  }
6398 }
6399 
6400 QVariant QgsProcessingBandWidgetWrapper::widgetValue() const
6401 {
6402  if ( mComboBox )
6403  return mComboBox->currentBand() == -1 ? QVariant() : mComboBox->currentBand();
6404  else if ( mPanel )
6405  return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
6406  else if ( mLineEdit )
6407  {
6408  const QgsProcessingParameterBand *bandParam = static_cast< const QgsProcessingParameterBand * >( parameterDefinition() );
6409  if ( bandParam->allowMultiple() )
6410  {
6411 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
6412  const QStringList parts = mLineEdit->text().split( ';', QString::SkipEmptyParts );
6413 #else
6414  const QStringList parts = mLineEdit->text().split( ';', Qt::SkipEmptyParts );
6415 #endif
6416  QVariantList res;
6417  res.reserve( parts.count() );
6418  for ( const QString &s : parts )
6419  {
6420  bool ok = false;
6421  int band = s.toInt( &ok );
6422  if ( ok )
6423  res << band;
6424  }
6425  return res.isEmpty() ? QVariant() : res;
6426  }
6427  else
6428  {
6429  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
6430  }
6431  }
6432  else
6433  return QVariant();
6434 }
6435 
6436 QStringList QgsProcessingBandWidgetWrapper::compatibleParameterTypes() const
6437 {
6438  return QStringList()
6441 }
6442 
6443 QStringList QgsProcessingBandWidgetWrapper::compatibleOutputTypes() const
6444 {
6445  return QStringList()
6447 }
6448 
6449 QString QgsProcessingBandWidgetWrapper::modelerExpressionFormatString() const
6450 {
6451  return tr( "selected band numbers as an array of numbers, or semicolon separated string of options (e.g. '1;3')" );
6452 }
6453 
6454 QString QgsProcessingBandWidgetWrapper::parameterType() const
6455 {
6457 }
6458 
6459 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBandWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6460 {
6461  return new QgsProcessingBandWidgetWrapper( parameter, type );
6462 }
6463 
6464 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBandWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6465 {
6466  return new QgsProcessingBandParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6467 }
6468 
6469 
6470 
6471 //
6472 // QgsProcessingMultipleLayerPanelWidget
6473 //
6474 
6475 QgsProcessingMultipleLayerPanelWidget::QgsProcessingMultipleLayerPanelWidget( QWidget *parent, const QgsProcessingParameterMultipleLayers *param )
6476  : QWidget( parent )
6477  , mParam( param )
6478 {
6479  QHBoxLayout *hl = new QHBoxLayout();
6480  hl->setContentsMargins( 0, 0, 0, 0 );
6481 
6482  mLineEdit = new QLineEdit();
6483  mLineEdit->setEnabled( false );
6484  hl->addWidget( mLineEdit, 1 );
6485 
6486  mToolButton = new QToolButton();
6487  mToolButton->setText( QString( QChar( 0x2026 ) ) );
6488  hl->addWidget( mToolButton );
6489 
6490  setLayout( hl );
6491 
6492  if ( mParam )
6493  {
6494  mLineEdit->setText( tr( "%1 inputs selected" ).arg( 0 ) );
6495  }
6496 
6497  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingMultipleLayerPanelWidget::showDialog );
6498 }
6499 
6500 void QgsProcessingMultipleLayerPanelWidget::setValue( const QVariant &value )
6501 {
6502  if ( value.isValid() )
6503  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
6504  else
6505  mValue.clear();
6506 
6507  updateSummaryText();
6508  emit changed();
6509 }
6510 
6511 void QgsProcessingMultipleLayerPanelWidget::setProject( QgsProject *project )
6512 {
6513  mProject = project;
6514  if ( mProject )
6515  {
6516  connect( mProject, &QgsProject::layerRemoved, this, [&]( const QString & layerId )
6517  {
6518  if ( mValue.removeAll( layerId ) )
6519  {
6520  updateSummaryText();
6521  emit changed();
6522  }
6523  } );
6524  }
6525 }
6526 
6527 void QgsProcessingMultipleLayerPanelWidget::setModel( QgsProcessingModelAlgorithm *model, const QString &modelChildAlgorithmID )
6528 {
6529  mModel = model;
6530  if ( !model )
6531  return;
6532 
6533  switch ( mParam->layerType() )
6534  {
6536  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFile::typeName(),
6537  QStringList() << QgsProcessingOutputFile::typeName() );
6538  break;
6539 
6541  {
6542  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterRasterLayer::typeName()
6545  QStringList() << QgsProcessingOutputFile::typeName()
6549  break;
6550  }
6551 
6553  {
6554  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterMeshLayer::typeName()
6557  QStringList() << QgsProcessingOutputFile::typeName()
6560  break;
6561  }
6562 
6564  {
6565  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6569  QStringList() << QgsProcessingOutputFile::typeName()
6573  QList< int >() << QgsProcessing::TypeVector );
6574  break;
6575  }
6576 
6578  {
6579  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6583  QStringList() << QgsProcessingOutputFile::typeName()
6587  break;
6588  }
6589 
6591  {
6592  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6596  QStringList() << QgsProcessingOutputFile::typeName()
6601  break;
6602  }
6603 
6605  {
6606  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6610  QStringList() << QgsProcessingOutputFile::typeName()
6615  break;
6616  }
6617 
6619  {
6620  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6624  QStringList() << QgsProcessingOutputFile::typeName()
6629  break;
6630  }
6631 
6633  {
6634  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6640  QStringList() << QgsProcessingOutputFile::typeName()
6644  // << QgsProcessingOutputMeshLayer::typeName()
6646  break;
6647  }
6648  }
6649 }
6650 
6651 void QgsProcessingMultipleLayerPanelWidget::showDialog()
6652 {
6654  if ( panel && panel->dockMode() )
6655  {
6656  QgsProcessingMultipleInputPanelWidget *widget = new QgsProcessingMultipleInputPanelWidget( mParam, mValue, mModelSources, mModel );
6657  widget->setPanelTitle( mParam->description() );
6658  widget->setProject( mProject );
6659  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
6660  {
6661  setValue( widget->selectedOptions() );
6662  } );
6663  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
6664  panel->openPanel( widget );
6665  }
6666  else
6667  {
6668  QgsProcessingMultipleInputDialog dlg( mParam, mValue, mModelSources, mModel, this, Qt::WindowFlags() );
6669  dlg.setProject( mProject );
6670  if ( dlg.exec() )
6671  {
6672  setValue( dlg.selectedOptions() );
6673  }
6674  }
6675 }
6676 
6677 void QgsProcessingMultipleLayerPanelWidget::updateSummaryText()
6678 {
6679  if ( mParam )
6680  mLineEdit->setText( tr( "%1 inputs selected" ).arg( mValue.count() ) );
6681 }
6682 
6683 //
6684 // QgsProcessingMultipleLayerWidgetWrapper
6685 //
6686 
6687 QgsProcessingMultipleLayerParameterDefinitionWidget::QgsProcessingMultipleLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6688  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6689 {
6690  QVBoxLayout *vlayout = new QVBoxLayout();
6691  vlayout->setContentsMargins( 0, 0, 0, 0 );
6692 
6693  vlayout->addWidget( new QLabel( tr( "Allowed layer type" ) ) );
6694  mLayerTypeComboBox = new QComboBox();
6695  mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), QgsProcessing::TypeMapLayer );
6696  mLayerTypeComboBox->addItem( tr( "Vector (No Geometry Required)" ), QgsProcessing::TypeVector );
6697  mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), QgsProcessing::TypeVectorPoint );
6698  mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), QgsProcessing::TypeVectorLine );
6699  mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), QgsProcessing::TypeVectorPolygon );
6700  mLayerTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
6701  mLayerTypeComboBox->addItem( tr( "Raster" ), QgsProcessing::TypeRaster );
6702  mLayerTypeComboBox->addItem( tr( "File" ), QgsProcessing::TypeFile );
6703  mLayerTypeComboBox->addItem( tr( "Mesh" ), QgsProcessing::TypeMesh );
6704  if ( const QgsProcessingParameterMultipleLayers *layersParam = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( definition ) )
6705  mLayerTypeComboBox->setCurrentIndex( mLayerTypeComboBox->findData( layersParam->layerType() ) );
6706 
6707  vlayout->addWidget( mLayerTypeComboBox );
6708  setLayout( vlayout );
6709 }
6710 
6711 QgsProcessingParameterDefinition *QgsProcessingMultipleLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6712 {
6713  auto param = std::make_unique< QgsProcessingParameterMultipleLayers >( name, description, static_cast< QgsProcessing::SourceType >( mLayerTypeComboBox->currentData().toInt() ) );
6714  param->setFlags( flags );
6715  return param.release();
6716 }
6717 
6718 QgsProcessingMultipleLayerWidgetWrapper::QgsProcessingMultipleLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6719  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6720 {
6721 
6722 }
6723 
6724 QWidget *QgsProcessingMultipleLayerWidgetWrapper::createWidget()
6725 {
6726  const QgsProcessingParameterMultipleLayers *layerParam = dynamic_cast< const QgsProcessingParameterMultipleLayers *>( parameterDefinition() );
6727 
6728  mPanel = new QgsProcessingMultipleLayerPanelWidget( nullptr, layerParam );
6729  mPanel->setToolTip( parameterDefinition()->toolTip() );
6730  mPanel->setProject( widgetContext().project() );
6731  if ( type() == QgsProcessingGui::Modeler )
6732  mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
6733  connect( mPanel, &QgsProcessingMultipleLayerPanelWidget::changed, this, [ = ]
6734  {
6735  emit widgetValueHasChanged( this );
6736  } );
6737  return mPanel;
6738 }
6739 
6740 void QgsProcessingMultipleLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
6741 {
6743  if ( mPanel )
6744  {
6745  mPanel->setProject( context.project() );
6746  if ( type() == QgsProcessingGui::Modeler )
6747  mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
6748  }
6749 }
6750 
6751 void QgsProcessingMultipleLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6752 {
6753  if ( mPanel )
6754  {
6755  QVariantList opts;
6756  if ( value.isValid() )
6757  {
6758  const QList< QgsMapLayer * > v = QgsProcessingParameters::parameterAsLayerList( parameterDefinition(), value, context );
6759  opts.reserve( v.size() );
6760  for ( const QgsMapLayer *l : v )
6761  opts << l->source();
6762  }
6763 
6764  for ( const QVariant &v : value.toList() )
6765  {
6766  if ( v.canConvert< QgsProcessingModelChildParameterSource >() )
6767  {
6768  const QgsProcessingModelChildParameterSource source = v.value< QgsProcessingModelChildParameterSource >();
6769  opts << QVariant::fromValue( source );
6770  }
6771  }
6772 
6773  if ( mPanel )
6774  mPanel->setValue( value.isValid() ? opts : QVariant() );
6775  }
6776 }
6777 
6778 QVariant QgsProcessingMultipleLayerWidgetWrapper::widgetValue() const
6779 {
6780  if ( mPanel )
6781  return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
6782  else
6783  return QVariant();
6784 }
6785 
6786 QStringList QgsProcessingMultipleLayerWidgetWrapper::compatibleParameterTypes() const
6787 {
6788  return QStringList()
6797 }
6798 
6799 QStringList QgsProcessingMultipleLayerWidgetWrapper::compatibleOutputTypes() const
6800 {
6801  return QStringList()
6808 }
6809 
6810 QString QgsProcessingMultipleLayerWidgetWrapper::modelerExpressionFormatString() const
6811 {
6812  return tr( "an array of layer paths, or semicolon separated string of layer paths" );
6813 }
6814 
6815 QString QgsProcessingMultipleLayerWidgetWrapper::parameterType() const
6816 {
6818 }
6819 
6820 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMultipleLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6821 {
6822  return new QgsProcessingMultipleLayerWidgetWrapper( parameter, type );
6823 }
6824 
6825 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMultipleLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6826 {
6827  return new QgsProcessingMultipleLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6828 }
6829 
6830 
6831 //
6832 // QgsProcessingOutputWidgetWrapper
6833 //
6834 
6835 QgsProcessingOutputWidgetWrapper::QgsProcessingOutputWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6836  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6837 {
6838 
6839 }
6840 
6841 QWidget *QgsProcessingOutputWidgetWrapper::createWidget()
6842 {
6843  const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( parameterDefinition() );
6844  switch ( type() )
6845  {
6848  {
6849  mOutputWidget = new QgsProcessingLayerOutputDestinationWidget( destParam, false );
6850  if ( mProcessingContextGenerator )
6851  mOutputWidget->setContext( mProcessingContextGenerator->processingContext() );
6852  if ( mParametersGenerator )
6853  mOutputWidget->registerProcessingParametersGenerator( mParametersGenerator );
6854  mOutputWidget->setToolTip( parameterDefinition()->toolTip() );
6855 
6856  connect( mOutputWidget, &QgsProcessingLayerOutputDestinationWidget::destinationChanged, this, [ = ]()
6857  {
6858  if ( mBlockSignals )
6859  return;
6860 
6861  emit widgetValueHasChanged( this );
6862  } );
6863 
6864  if ( type() == QgsProcessingGui::Standard
6868  mOutputWidget->addOpenAfterRunningOption();
6869 
6870  return mOutputWidget;
6871  }
6873  break;
6874  }
6875 
6876  return nullptr;
6877 }
6878 
6879 
6880 void QgsProcessingOutputWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
6881 {
6882  if ( mOutputWidget )
6883  mOutputWidget->setValue( value );
6884 }
6885 
6886 QVariant QgsProcessingOutputWidgetWrapper::widgetValue() const
6887 {
6888  if ( mOutputWidget )
6889  return mOutputWidget->value();
6890 
6891  return QVariant();
6892 }
6893 
6894 QVariantMap QgsProcessingOutputWidgetWrapper::customProperties() const
6895 {
6896  QVariantMap res;
6897  if ( mOutputWidget )
6898  res.insert( QStringLiteral( "OPEN_AFTER_RUNNING" ), mOutputWidget->openAfterRunning() );
6899  return res;
6900 }
6901 
6902 QStringList QgsProcessingOutputWidgetWrapper::compatibleParameterTypes() const
6903 {
6904  return QStringList()
6911 }
6912 
6913 QStringList QgsProcessingOutputWidgetWrapper::compatibleOutputTypes() const
6914 {
6915  return QStringList()
6919 }
6920 
6921 //
6922 // QgsProcessingFeatureSinkWidgetWrapper
6923 //
6924 
6925 QgsProcessingFeatureSinkWidgetWrapper::QgsProcessingFeatureSinkWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6926  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
6927 {
6928 
6929 }
6930 
6931 QString QgsProcessingFeatureSinkWidgetWrapper::parameterType() const
6932 {
6934 }
6935 
6936 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSinkWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6937 {
6938  return new QgsProcessingFeatureSinkWidgetWrapper( parameter, type );
6939 }
6940 
6941 QString QgsProcessingFeatureSinkWidgetWrapper::modelerExpressionFormatString() const
6942 {
6943  return tr( "path to layer destination" );
6944 }
6945 
6946 //
6947 // QgsProcessingFeatureSinkWidgetWrapper
6948 //
6949 
6950 QgsProcessingVectorDestinationWidgetWrapper::QgsProcessingVectorDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6951  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
6952 {
6953 
6954 }
6955 
6956 QString QgsProcessingVectorDestinationWidgetWrapper::parameterType() const
6957 {
6959 }
6960 
6961 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6962 {
6963  return new QgsProcessingVectorDestinationWidgetWrapper( parameter, type );
6964 }
6965 
6966 QString QgsProcessingVectorDestinationWidgetWrapper::modelerExpressionFormatString() const
6967 {
6968  return tr( "path to layer destination" );
6969 }
6970 
6971 //
6972 // QgsProcessingFeatureSinkWidgetWrapper
6973 //
6974 
6975 QgsProcessingRasterDestinationWidgetWrapper::QgsProcessingRasterDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6976  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
6977 {
6978 
6979 }
6980 
6981 QString QgsProcessingRasterDestinationWidgetWrapper::parameterType() const
6982 {
6984 }
6985 
6986 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6987 {
6988  return new QgsProcessingRasterDestinationWidgetWrapper( parameter, type );
6989 }
6990 
6991 QString QgsProcessingRasterDestinationWidgetWrapper::modelerExpressionFormatString() const
6992 {
6993  return tr( "path to layer destination" );
6994 }
6995 
6996 //
6997 // QgsProcessingFileDestinationWidgetWrapper
6998 //
6999 
7000 QgsProcessingFileDestinationWidgetWrapper::QgsProcessingFileDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7001  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7002 {
7003 
7004 }
7005 
7006 QString QgsProcessingFileDestinationWidgetWrapper::parameterType() const
7007 {
7009 }
7010 
7011 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7012 {
7013  return new QgsProcessingFileDestinationWidgetWrapper( parameter, type );
7014 }
7015 
7016 QString QgsProcessingFileDestinationWidgetWrapper::modelerExpressionFormatString() const
7017 {
7018  return tr( "path to file destination" );
7019 }
7020 
7021 //
7022 // QgsProcessingFolderDestinationWidgetWrapper
7023 //
7024 
7025 QgsProcessingFolderDestinationWidgetWrapper::QgsProcessingFolderDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7026  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7027 {
7028 
7029 }
7030 
7031 QString QgsProcessingFolderDestinationWidgetWrapper::parameterType() const
7032 {
7034 }
7035 
7036 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFolderDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7037 {
7038  return new QgsProcessingFolderDestinationWidgetWrapper( parameter, type );
7039 }
7040 
7041 QString QgsProcessingFolderDestinationWidgetWrapper::modelerExpressionFormatString() const
7042 {
7043  return tr( "path to folder destination" );
7044 }
7045 
A widget wrapper for Processing parameter value widgets.
QVariant parameterValue() const
Returns the current value of the parameter.
virtual QLabel * createLabel()
Creates a new label to accompany widgets created by the wrapper.
virtual void registerProcessingContextGenerator(QgsProcessingContextGenerator *generator)
Registers a Processing context generator class that will be used to retrieve a Processing context for...
void widgetValueHasChanged(QgsAbstractProcessingParameterWidgetWrapper *wrapper)
Emitted whenever the parameter value (as defined by the wrapped widget) is changed.
virtual void postInitialize(const QList< QgsAbstractProcessingParameterWidgetWrapper * > &wrappers)
Called after all wrappers have been created within a particular dialog or context,...
virtual const QgsVectorLayer * linkedVectorLayer() const
Returns the optional vector layer associated with this widget wrapper, or nullptr if no vector layer ...
const QgsProcessingParameterDefinition * parameterDefinition() const
Returns the parameter definition associated with this wrapper.
virtual void setDialog(QDialog *dialog)
Sets the parent dialog in which the wrapper is shown.
virtual void setWidgetContext(const QgsProcessingParameterWidgetContext &context)
Sets the context in which the Processing parameter widget is shown, e.g., the parent model algorithm,...
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Selector widget for authentication configs.
void selectedConfigIdChanged(const QString &authcfg)
Emitted when authentication config is changed or missing.
QComboBox subclass which allows selecting multiple items.
A cross platform button subclass for selecting colors.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
A widget for selecting the coordinate operation to use when transforming between a source and destina...
void operationChanged()
Emitted when the operation selected in the dialog is changed.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Q_GADGET QgsUnitTypes::DistanceUnit mapUnits
The QgsDatabaseSchemaComboBox class is a combo box which displays the list of schemas for a specific ...
The QgsDatabaseTableComboBox class is a combo box which displays the list of tables for a specific da...
The QgsDateEdit class is a QDateEdit widget with the capability of setting/reading null dates.
void dateValueChanged(const QDate &date)
Signal emitted whenever the date changes.
The QgsDateTimeEdit class is a QDateTimeEdit with the capability of setting/reading null date/times.
void setAllowNull(bool allowNull)
Determines if the widget allows setting null date/time.
void setNullRepresentation(const QString &null)
Sets the widget's null representation, which defaults to QgsApplication::nullRepresentation().
void valueChanged(const QDateTime &date)
Signal emitted whenever the value changes.
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
A reusable widget that can be used to build a expression string.
void expressionParsed(bool isValid)
Emitted when the user changes the expression in the widget.
The QgsExpressionLineEdit widget includes a line edit for entering expressions together with a button...
void expressionChanged(const QString &expression)
Emitted when the expression is changed.
A widget for configuration of a map extent.
void toggleDialogVisibility(bool visible)
Emitted when the parent dialog visibility must be changed (e.g.
void extentChanged(const QgsRectangle &r)
Emitted when the widget's extent is changed.
The QgsFieldComboBox is a combo box which displays the list of fields of a given layer.
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
@ DateTime
Datetime fieldss.
@ Date
Date or datetime fields.
@ String
String fields.
@ Numeric
All numeric fields.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString name
Definition: qgsfield.h:60
Container of fields for a vector layer.
Definition: qgsfields.h:45
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfields.cpp:212
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
void remove(int fieldIdx)
Removes the field with the given index.
Definition: qgsfields.cpp:101
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
bool isEmpty() const
Checks whether the container is empty.
Definition: qgsfields.cpp:128
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
The QgsFileWidget class creates a widget for selecting a file or a folder.
Definition: qgsfilewidget.h:37
@ GetFile
Select a single file.
Definition: qgsfilewidget.h:66
@ GetDirectory
Select a directory.
Definition: qgsfilewidget.h:67
void fileChanged(const QString &path)
Emitted whenever the current file or directory path is changed.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
Q_GADGET bool isNull
Definition: qgsgeometry.h:126
QString asWkt(int precision=17) const
Exports the geometry to WKT.
The QgsLayoutComboBox class is a combo box which displays available layouts from a QgsLayoutManager.
void layoutChanged(QgsMasterLayoutInterface *layout)
Emitted whenever the currently selected layout changes.
The QgsLayoutItemComboBox class is a combo box which displays items of a matching type from a layout.
void itemChanged(QgsLayoutItem *item)
Emitted whenever the currently selected item changes.
Base class for graphical items within a QgsLayout.
virtual QString uuid() const
Returns the item identification string.
@ FilterPrintLayouts
Includes print layouts.
QList< QgsPrintLayout * > printLayouts() const
Returns a list of all print layouts contained in the manager.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:86
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
Base class for all map layer types.
Definition: qgsmaplayer.h:70
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
bool isValid
Definition: qgsmaplayer.h:78
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
QgsPointLocator::Match mapPointMatch() const
Returns the matching data from the most recently snapped point.
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Abstract base class for all map tools.
Definition: qgsmaptool.h:66
virtual void deactivate()
called when map tool is being deactivated
Definition: qgsmaptool.cpp:100
Interface for master layout type objects, such as print layouts and reports.
virtual QString name() const =0
Returns the layout's name.
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
bool clearWidgets()
Removes all items from the bar.
Base class for any widget that can be shown as a inline panel.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
void acceptPanel()
Accept the panel.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
bool dockMode()
Returns the dock mode state.
A class to represent a 2D point.
Definition: qgspointxy.h:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
Print layout, a QgsLayout subclass for static or atlas-based layouts.
Abstract base class for widgets which allow users to specify the properties of a Processing parameter...
Abstract base class for processing algorithms.
An interface for objects which can create Processing contexts.
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
QgsMapLayer * takeResultLayer(const QString &id)
Takes the result map layer with matching id from the context and transfers ownership of it back to th...
Base class for all parameter definitions which represent file or layer destinations,...
Encapsulates settings relating to a feature source input to a processing algorithm.
WidgetType
Types of dialogs which Processing widgets can be created for.
@ Modeler
Modeler dialog.
@ Standard
Standard algorithm dialog.
@ Batch
Batch processing dialog.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the parameter class.
A raster band parameter for Processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
bool allowMultiple() const
Returns whether multiple band selections are permitted.
A boolean parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A color parameter for processing algorithms.
bool opacityEnabled() const
Returns true if the parameter allows opacity control.
static QString typeName()
Returns the type name for the parameter class.
A coordinate operation parameter for processing algorithms, for selection between available coordinat...
static QString typeName()
Returns the type name for the parameter class.
QVariant sourceCrs() const
Returns the static source CRS, or an invalid value if this is not set.
QVariant destinationCrs() const
Returns the static destination CRS, or an invalid value if this is not set.
A coordinate reference system parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A database schema parameter for processing algorithms, allowing users to select from existing schemas...
static QString typeName()
Returns the type name for the parameter class.
QString parentConnectionParameterName() const
Returns the name of the parent connection parameter, or an empty string if this is not set.
A database table name parameter for processing algorithms, allowing users to select from existing dat...
static QString typeName()
Returns the type name for the parameter class.
QString parentConnectionParameterName() const
Returns the name of the parent connection parameter, or an empty string if this is not set.
QString parentSchemaParameterName() const
Returns the name of the parent schema parameter, or an empty string if this is not set.
bool allowNewTableNames() const
Returns true if the parameter allows users to enter names for a new (non-existing) tables.
A datetime (or pure date or time) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
Type dataType() const
Returns the acceptable data type for the parameter.
Base class for the definition of processing parameters.
QVariantMap metadata() const
Returns the parameter's freeform metadata.
QString description() const
Returns the description for the parameter.
QVariant defaultValueForGui() const
Returns the default value to use for the parameter in a GUI.
virtual QString type() const =0
Unique parameter type name.
Flags flags() const
Returns any flags associated with the parameter.
QString name() const
Returns the name of the parameter.
void setFlags(Flags flags)
Sets the flags associated with the parameter.
A double numeric parameter for distance values.
static QString typeName()
Returns the type name for the parameter class.
QgsUnitTypes::DistanceUnit defaultUnit() const
Returns the default distance unit for the parameter.
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.
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.
void setDataType(DataType type)
Sets 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.
@ DateTime
Accepts datetime fields.
@ Numeric
Accepts numeric fields.
DataType dataType() const
Returns 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.
@ File
Parameter is a single file.
Behavior behavior() const
Returns the parameter behavior (e.g.
QString fileFilter() const
Returns the file filter string for file destinations compatible with this parameter.
static QString typeName()
Returns the type name for the parameter class.
A geometry parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A print layout item parameter, allowing users to select a particular item from a print layout.
static QString typeName()
Returns the type name for the parameter class.
int itemType() const
Returns the acceptable item type, or -1 if any item type is allowed.
A print layout parameter, allowing users to select a print layout.
static QString typeName()
Returns the type name for the parameter class.
A map layer parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A map theme parameter for processing algorithms, allowing users to select an existing map theme from ...
static QString typeName()
Returns the type name for the parameter class.
A table (matrix) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A parameter for processing algorithms which accepts multiple map layers.
static QString typeName()
Returns the type name for the parameter class.
A numeric parameter for processing algorithms.
double minimum() const
Returns the minimum value acceptable by the parameter.
double maximum() const
Returns the maximum value acceptable by the parameter.
Type dataType() const
Returns the acceptable data type for the parameter.
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.
QgsProcessingParameterNumber::Type dataType() const
Returns the acceptable data type for the range.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A raster layer parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A double numeric parameter for map scale values.
static QString typeName()
Returns the type name for the parameter class.
A string parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A vector layer (with or without geometry) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
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 QList< QgsMapLayer * > parameterAsLayerList(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a list of map layers.
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 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 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 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 QStringList parameterAsFields(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a list of fields.
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.
static QgsCoordinateReferenceSystem variantToCrs(const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue=QVariant())
Converts a variant value to a coordinate reference system.
SourceType
Data source types enum.
Definition: qgsprocessing.h:46
@ TypeVectorLine
Vector line layers.
Definition: qgsprocessing.h:50
@ TypeMapLayer
Any map layer type (raster or vector or mesh)
Definition: qgsprocessing.h:47
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:51
@ TypeFile
Files (i.e. non map layer sources, such as text files)
Definition: qgsprocessing.h:53
@ TypeMesh
Mesh layers.
Definition: qgsprocessing.h:55
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:54
@ TypeRaster
Raster layers.
Definition: qgsprocessing.h:52
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:49
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:48
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:99
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:467
QgsMapThemeCollection * mapThemeCollection
Definition: qgsproject.h:107
const QgsLayoutManager * layoutManager() const
Returns the project's layout manager, which manages print layouts, atlases and reports within the pro...
void layerRemoved(const QString &layerId)
Emitted after a layer was removed from the registry.
A widget for selecting a projection.
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
@ CrsNotSet
Not set (hidden by default)
The QgsProviderConnectionComboBox class is a combo box which displays the list of connections registe...
A combobox widget which displays the bands present in a raster layer.
void bandChanged(int band)
Emitted when the currently selected band changes.
static QString displayBandName(QgsRasterDataProvider *provider, int band)
Returns a user-friendly band name for the specified band.
Base class for raster data providers.
virtual int bandCount() const =0
Gets number of bands.
Represents a raster layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
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.
Class that shows snapping marker on map canvas for the current snapping match.
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
Definition: qgsspinbox.h:43
The QgsTimeEdit class is a QTimeEdit widget with the capability of setting/reading null date/times.
void timeValueChanged(const QTime &time)
Signal emitted whenever the time changes.
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:68
@ DistanceMeters
Meters.
Definition: qgsunittypes.h:69
@ DistanceDegrees
Degrees, for planar geographic CRS distance measurements.
Definition: qgsunittypes.h:75
@ DistanceKilometers
Kilometers.
Definition: qgsunittypes.h:70
@ DistanceMiles
Terrestrial miles.
Definition: qgsunittypes.h:74
@ DistanceUnknownUnit
Unknown distance unit.
Definition: qgsunittypes.h:78
@ DistanceYards
Imperial yards.
Definition: qgsunittypes.h:73
@ DistanceFeet
Imperial feet.
Definition: qgsunittypes.h:71
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
static Q_INVOKABLE QgsUnitTypes::DistanceUnitType unitType(QgsUnitTypes::DistanceUnit unit)
Returns the type for a distance unit.
@ Standard
Unit is a standard measurement unit.
Definition: qgsunittypes.h:87
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define FALLTHROUGH
Definition: qgis.h:1111
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places.
Definition: qgis.h:652
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:598
const QgsField & field
Definition: qgsfield.h:463
const QgsCoordinateReferenceSystem & crs
QString proj
Proj coordinate operation description, for Proj >= 6.0 builds only.