QGIS API Documentation  3.21.0-Master (5b68dc587e)
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 "qgsdoublevalidator.h"
65 #include "qgsmaplayercombobox.h"
66 #include "qgsannotationlayer.h"
67 #include <QToolButton>
68 #include <QLabel>
69 #include <QHBoxLayout>
70 #include <QVBoxLayout>
71 #include <QCheckBox>
72 #include <QComboBox>
73 #include <QLineEdit>
74 #include <QPlainTextEdit>
75 #include <QRadioButton>
76 #include <QButtonGroup>
77 #include <QMenu>
78 #include <QFileDialog>
79 
81 
82 //
83 // QgsProcessingBooleanWidgetWrapper
84 //
85 
86 
87 QgsProcessingBooleanParameterDefinitionWidget::QgsProcessingBooleanParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
88  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
89 {
90  QVBoxLayout *vlayout = new QVBoxLayout();
91  vlayout->setContentsMargins( 0, 0, 0, 0 );
92 
93  mDefaultCheckBox = new QCheckBox( tr( "Checked" ) );
94  if ( const QgsProcessingParameterBoolean *boolParam = dynamic_cast<const QgsProcessingParameterBoolean *>( definition ) )
95  mDefaultCheckBox->setChecked( QgsProcessingParameters::parameterAsBool( boolParam, boolParam->defaultValueForGui(), context ) );
96  else
97  mDefaultCheckBox->setChecked( false );
98  vlayout->addWidget( mDefaultCheckBox );
99  setLayout( vlayout );
100 }
101 
102 QgsProcessingParameterDefinition *QgsProcessingBooleanParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
103 {
104  auto param = std::make_unique< QgsProcessingParameterBoolean >( name, description, mDefaultCheckBox->isChecked() );
105  param->setFlags( flags );
106  return param.release();
107 }
108 
109 
110 QgsProcessingBooleanWidgetWrapper::QgsProcessingBooleanWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
111  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
112 {
113 
114 }
115 
116 QWidget *QgsProcessingBooleanWidgetWrapper::createWidget()
117 {
118  switch ( type() )
119  {
121  {
122  QString description = parameterDefinition()->description();
123  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
124  description = QObject::tr( "%1 [optional]" ).arg( description );
125 
126  mCheckBox = new QCheckBox( description );
127  mCheckBox->setToolTip( parameterDefinition()->toolTip() );
128 
129  connect( mCheckBox, &QCheckBox::toggled, this, [ = ]
130  {
131  emit widgetValueHasChanged( this );
132  } );
133  return mCheckBox;
134  }
135 
138  {
139  mComboBox = new QComboBox();
140  mComboBox->addItem( tr( "Yes" ), true );
141  mComboBox->addItem( tr( "No" ), false );
142  mComboBox->setToolTip( parameterDefinition()->toolTip() );
143 
144  connect( mComboBox, qOverload< int>( &QComboBox::currentIndexChanged ), this, [ = ]
145  {
146  emit widgetValueHasChanged( this );
147  } );
148 
149  return mComboBox;
150  }
151  }
152  return nullptr;
153 }
154 
155 QLabel *QgsProcessingBooleanWidgetWrapper::createLabel()
156 {
157  // avoid creating labels in standard dialogs
158  if ( type() == QgsProcessingGui::Standard )
159  return nullptr;
160  else
162 }
163 
164 void QgsProcessingBooleanWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
165 {
166  switch ( type() )
167  {
169  {
170  const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
171  mCheckBox->setChecked( v );
172  break;
173  }
174 
177  {
178  const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
179  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
180  break;
181  }
182  }
183 }
184 
185 QVariant QgsProcessingBooleanWidgetWrapper::widgetValue() const
186 {
187  switch ( type() )
188  {
190  return mCheckBox->isChecked();
191 
194  return mComboBox->currentData();
195  }
196  return QVariant();
197 }
198 
199 QStringList QgsProcessingBooleanWidgetWrapper::compatibleParameterTypes() const
200 {
201  //pretty much everything is compatible here and can be converted to a bool!
202  return QStringList() << QgsProcessingParameterBoolean::typeName()
219 }
220 
221 QStringList QgsProcessingBooleanWidgetWrapper::compatibleOutputTypes() const
222 {
223  return QStringList() << QgsProcessingOutputNumber::typeName()
230 }
231 
232 QString QgsProcessingBooleanWidgetWrapper::parameterType() const
233 {
235 }
236 
237 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBooleanWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
238 {
239  return new QgsProcessingBooleanWidgetWrapper( parameter, type );
240 }
241 
242 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBooleanWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
243 {
244  return new QgsProcessingBooleanParameterDefinitionWidget( context, widgetContext, definition, algorithm );
245 }
246 
247 
248 //
249 // QgsProcessingCrsWidgetWrapper
250 //
251 
252 QgsProcessingCrsParameterDefinitionWidget::QgsProcessingCrsParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
253  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
254 {
255  QVBoxLayout *vlayout = new QVBoxLayout();
256  vlayout->setContentsMargins( 0, 0, 0, 0 );
257 
258  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
259 
260  mCrsSelector = new QgsProjectionSelectionWidget();
261 
262  // possibly we should expose this for parameter by parameter control
263  mCrsSelector->setShowAccuracyWarnings( true );
264 
265  if ( const QgsProcessingParameterCrs *crsParam = dynamic_cast<const QgsProcessingParameterCrs *>( definition ) )
266  mCrsSelector->setCrs( QgsProcessingParameters::parameterAsCrs( crsParam, crsParam->defaultValueForGui(), context ) );
267  else
268  mCrsSelector->setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
269 
270  vlayout->addWidget( mCrsSelector );
271  setLayout( vlayout );
272 }
273 
274 QgsProcessingParameterDefinition *QgsProcessingCrsParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
275 {
276  auto param = std::make_unique< QgsProcessingParameterCrs >( name, description, mCrsSelector->crs().authid() );
277  param->setFlags( flags );
278  return param.release();
279 }
280 
281 QgsProcessingCrsWidgetWrapper::QgsProcessingCrsWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
282  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
283 {
284 
285 }
286 
287 QWidget *QgsProcessingCrsWidgetWrapper::createWidget()
288 {
289  Q_ASSERT( mProjectionSelectionWidget == nullptr );
290  mProjectionSelectionWidget = new QgsProjectionSelectionWidget();
291  mProjectionSelectionWidget->setToolTip( parameterDefinition()->toolTip() );
292 
293  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
294  mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
295  else
296  mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, false );
297 
298  connect( mProjectionSelectionWidget, &QgsProjectionSelectionWidget::crsChanged, this, [ = ]
299  {
300  emit widgetValueHasChanged( this );
301  } );
302 
303  switch ( type() )
304  {
307  {
308  return mProjectionSelectionWidget;
309  }
310 
312  {
313  QWidget *w = new QWidget();
314  w->setToolTip( parameterDefinition()->toolTip() );
315 
316  QVBoxLayout *vl = new QVBoxLayout();
317  vl->setContentsMargins( 0, 0, 0, 0 );
318  w->setLayout( vl );
319 
320  mUseProjectCrsCheckBox = new QCheckBox( tr( "Use project CRS" ) );
321  mUseProjectCrsCheckBox->setToolTip( tr( "Always use the current project CRS when running the model" ) );
322  vl->addWidget( mUseProjectCrsCheckBox );
323  connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, mProjectionSelectionWidget, &QgsProjectionSelectionWidget::setDisabled );
324  connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, this, [ = ]
325  {
326  emit widgetValueHasChanged( this );
327  } );
328 
329  vl->addWidget( mProjectionSelectionWidget );
330 
331  return w;
332  }
333  }
334  return nullptr;
335 }
336 
337 void QgsProcessingCrsWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
338 {
339  if ( mUseProjectCrsCheckBox )
340  {
341  if ( value.toString().compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
342  {
343  mUseProjectCrsCheckBox->setChecked( true );
344  return;
345  }
346  else
347  {
348  mUseProjectCrsCheckBox->setChecked( false );
349  }
350  }
351 
352  const QgsCoordinateReferenceSystem v = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, context );
353  if ( mProjectionSelectionWidget )
354  mProjectionSelectionWidget->setCrs( v );
355 }
356 
357 QVariant QgsProcessingCrsWidgetWrapper::widgetValue() const
358 {
359  if ( mUseProjectCrsCheckBox && mUseProjectCrsCheckBox->isChecked() )
360  return QStringLiteral( "ProjectCrs" );
361  else if ( mProjectionSelectionWidget )
362  return mProjectionSelectionWidget->crs().isValid() ? mProjectionSelectionWidget->crs() : QVariant();
363  else
364  return QVariant();
365 }
366 
367 QStringList QgsProcessingCrsWidgetWrapper::compatibleParameterTypes() const
368 {
369  return QStringList()
379 }
380 
381 QStringList QgsProcessingCrsWidgetWrapper::compatibleOutputTypes() const
382 {
383  return QStringList() << QgsProcessingOutputVectorLayer::typeName()
387 }
388 
389 QString QgsProcessingCrsWidgetWrapper::modelerExpressionFormatString() const
390 {
391  return tr( "string as EPSG code, WKT or PROJ format, or a string identifying a map layer" );
392 }
393 
394 QString QgsProcessingCrsWidgetWrapper::parameterType() const
395 {
397 }
398 
399 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCrsWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
400 {
401  return new QgsProcessingCrsWidgetWrapper( parameter, type );
402 }
403 
404 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingCrsWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
405 {
406  return new QgsProcessingCrsParameterDefinitionWidget( context, widgetContext, definition, algorithm );
407 }
408 
409 
410 
411 //
412 // QgsProcessingStringWidgetWrapper
413 //
414 
415 
416 QgsProcessingStringParameterDefinitionWidget::QgsProcessingStringParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
417  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
418 {
419  QVBoxLayout *vlayout = new QVBoxLayout();
420  vlayout->setContentsMargins( 0, 0, 0, 0 );
421 
422  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
423 
424  mDefaultLineEdit = new QLineEdit();
425  if ( const QgsProcessingParameterString *stringParam = dynamic_cast<const QgsProcessingParameterString *>( definition ) )
426  mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( stringParam, stringParam->defaultValueForGui(), context ) );
427  vlayout->addWidget( mDefaultLineEdit );
428 
429  mMultiLineCheckBox = new QCheckBox( tr( "Multiline input" ) );
430  if ( const QgsProcessingParameterString *stringParam = dynamic_cast<const QgsProcessingParameterString *>( definition ) )
431  mMultiLineCheckBox->setChecked( stringParam->multiLine() );
432  vlayout->addWidget( mMultiLineCheckBox );
433 
434  setLayout( vlayout );
435 }
436 
437 QgsProcessingParameterDefinition *QgsProcessingStringParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
438 {
439  auto param = std::make_unique< QgsProcessingParameterString >( name, description, mDefaultLineEdit->text(), mMultiLineCheckBox->isChecked() );
440  param->setFlags( flags );
441  return param.release();
442 }
443 
444 
445 
446 QgsProcessingStringWidgetWrapper::QgsProcessingStringWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
447  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
448 {
449 
450 }
451 
452 QWidget *QgsProcessingStringWidgetWrapper::createWidget()
453 {
454  const QVariantMap metadata = parameterDefinition()->metadata();
455  const QVariant valueHintsVariant = metadata.value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "value_hints" ) );
456 
457  if ( valueHintsVariant.isValid() )
458  {
459  const QVariantList valueList = valueHintsVariant.toList();
460  mComboBox = new QComboBox();
461  mComboBox->setToolTip( parameterDefinition()->toolTip() );
462 
463  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
464  {
465  mComboBox->addItem( QString() );
466  }
467  for ( const QVariant &entry : valueList )
468  {
469  mComboBox->addItem( entry.toString(), entry.toString() );
470  }
471  mComboBox->setCurrentIndex( 0 );
472 
473  connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
474  {
475  emit widgetValueHasChanged( this );
476  } );
477  return mComboBox;
478  }
479  else
480  {
481  switch ( type() )
482  {
485  {
486  if ( static_cast< const QgsProcessingParameterString * >( parameterDefinition() )->multiLine() )
487  {
488  mPlainTextEdit = new QPlainTextEdit();
489  mPlainTextEdit->setToolTip( parameterDefinition()->toolTip() );
490 
491  connect( mPlainTextEdit, &QPlainTextEdit::textChanged, this, [ = ]
492  {
493  emit widgetValueHasChanged( this );
494  } );
495  return mPlainTextEdit;
496  }
497  else
498  {
499  mLineEdit = new QLineEdit();
500  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
501 
502  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
503  {
504  emit widgetValueHasChanged( this );
505  } );
506  return mLineEdit;
507  }
508  }
509 
511  {
512  mLineEdit = new QLineEdit();
513  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
514 
515  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
516  {
517  emit widgetValueHasChanged( this );
518  } );
519  return mLineEdit;
520  }
521  }
522  }
523 
524  return nullptr;
525 }
526 
527 void QgsProcessingStringWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
528 {
529  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
530  if ( mLineEdit )
531  mLineEdit->setText( v );
532  if ( mPlainTextEdit )
533  mPlainTextEdit->setPlainText( v );
534  if ( mComboBox )
535  {
536  int index = -1;
537  if ( !value.isValid() )
538  index = mComboBox->findData( QVariant() );
539  else
540  index = mComboBox->findData( v );
541 
542  if ( index >= 0 )
543  mComboBox->setCurrentIndex( index );
544  else
545  mComboBox->setCurrentIndex( 0 );
546  }
547 }
548 
549 QVariant QgsProcessingStringWidgetWrapper::widgetValue() const
550 {
551  if ( mLineEdit )
552  return mLineEdit->text();
553  else if ( mPlainTextEdit )
554  return mPlainTextEdit->toPlainText();
555  else if ( mComboBox )
556  return mComboBox->currentData();
557  else
558  return QVariant();
559 }
560 
561 QStringList QgsProcessingStringWidgetWrapper::compatibleParameterTypes() const
562 {
563  return QStringList()
575 }
576 
577 QStringList QgsProcessingStringWidgetWrapper::compatibleOutputTypes() const
578 {
579  return QStringList() << QgsProcessingOutputNumber::typeName()
583 }
584 
585 QString QgsProcessingStringWidgetWrapper::parameterType() const
586 {
588 }
589 
590 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingStringWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
591 {
592  return new QgsProcessingStringWidgetWrapper( parameter, type );
593 }
594 
595 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingStringWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
596 {
597  return new QgsProcessingStringParameterDefinitionWidget( context, widgetContext, definition, algorithm );
598 }
599 
600 
601 
602 //
603 // QgsProcessingAuthConfigWidgetWrapper
604 //
605 
606 QgsProcessingAuthConfigWidgetWrapper::QgsProcessingAuthConfigWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
607  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
608 {
609 
610 }
611 
612 QWidget *QgsProcessingAuthConfigWidgetWrapper::createWidget()
613 {
614  switch ( type() )
615  {
619  {
620  mAuthConfigSelect = new QgsAuthConfigSelect();
621  mAuthConfigSelect->setToolTip( parameterDefinition()->toolTip() );
622 
623  connect( mAuthConfigSelect, &QgsAuthConfigSelect::selectedConfigIdChanged, this, [ = ]
624  {
625  emit widgetValueHasChanged( this );
626  } );
627  return mAuthConfigSelect;
628  }
629  }
630  return nullptr;
631 }
632 
633 void QgsProcessingAuthConfigWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
634 {
635  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
636  if ( mAuthConfigSelect )
637  mAuthConfigSelect->setConfigId( v );
638 }
639 
640 QVariant QgsProcessingAuthConfigWidgetWrapper::widgetValue() const
641 {
642  if ( mAuthConfigSelect )
643  return mAuthConfigSelect->configId();
644  else
645  return QVariant();
646 }
647 
648 QStringList QgsProcessingAuthConfigWidgetWrapper::compatibleParameterTypes() const
649 {
650  return QStringList()
654 }
655 
656 QStringList QgsProcessingAuthConfigWidgetWrapper::compatibleOutputTypes() const
657 {
658  return QStringList() << QgsProcessingOutputString::typeName();
659 }
660 
661 QString QgsProcessingAuthConfigWidgetWrapper::parameterType() const
662 {
664 }
665 
666 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAuthConfigWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
667 {
668  return new QgsProcessingAuthConfigWidgetWrapper( parameter, type );
669 }
670 
671 //
672 // QgsProcessingNumericWidgetWrapper
673 //
674 
675 QgsProcessingNumberParameterDefinitionWidget::QgsProcessingNumberParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
676  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
677 {
678  QVBoxLayout *vlayout = new QVBoxLayout();
679  vlayout->setContentsMargins( 0, 0, 0, 0 );
680 
681  vlayout->addWidget( new QLabel( tr( "Number type" ) ) );
682 
683  mTypeComboBox = new QComboBox();
684  mTypeComboBox->addItem( tr( "Float" ), QgsProcessingParameterNumber::Double );
685  mTypeComboBox->addItem( tr( "Integer" ), QgsProcessingParameterNumber::Integer );
686  vlayout->addWidget( mTypeComboBox );
687 
688  vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
689  mMinLineEdit = new QLineEdit();
690  vlayout->addWidget( mMinLineEdit );
691 
692  vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
693  mMaxLineEdit = new QLineEdit();
694  vlayout->addWidget( mMaxLineEdit );
695 
696  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
697  mDefaultLineEdit = new QLineEdit();
698  vlayout->addWidget( mDefaultLineEdit );
699 
700  if ( const QgsProcessingParameterNumber *numberParam = dynamic_cast<const QgsProcessingParameterNumber *>( definition ) )
701  {
702  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( numberParam->dataType() ) );
703  mMinLineEdit->setText( QLocale().toString( numberParam->minimum() ) );
704  mMaxLineEdit->setText( QLocale().toString( numberParam->maximum() ) );
705  mDefaultLineEdit->setText( numberParam->defaultValueForGui().toString() );
706  }
707 
708  setLayout( vlayout );
709 }
710 
711 QgsProcessingParameterDefinition *QgsProcessingNumberParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
712 {
713  bool ok;
714  double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
715 
716  QgsProcessingParameterNumber::Type dataType = static_cast< QgsProcessingParameterNumber::Type >( mTypeComboBox->currentData().toInt() );
717  auto param = std::make_unique< QgsProcessingParameterNumber >( name, description, dataType, ok ? val : QVariant() );
718 
719  val = QgsDoubleValidator::toDouble( mMinLineEdit->text( ), &ok );
720  if ( ok )
721  {
722  param->setMinimum( val );
723  }
724 
725  val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
726  if ( ok )
727  {
728  param->setMaximum( val );
729  }
730 
731  param->setFlags( flags );
732  return param.release();
733 }
734 
735 QgsProcessingNumericWidgetWrapper::QgsProcessingNumericWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
736  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
737 {
738 
739 }
740 
741 QWidget *QgsProcessingNumericWidgetWrapper::createWidget()
742 {
743  const QgsProcessingParameterNumber *numberDef = static_cast< const QgsProcessingParameterNumber * >( parameterDefinition() );
744  const QVariantMap metadata = numberDef->metadata();
745  const int decimals = metadata.value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "decimals" ), 6 ).toInt();
746  switch ( type() )
747  {
751  {
752  // lots of duplicate code here -- but there's no common interface between QSpinBox/QDoubleSpinBox which would allow us to avoid this
753  QAbstractSpinBox *spinBox = nullptr;
754  switch ( numberDef->dataType() )
755  {
757  mDoubleSpinBox = new QgsDoubleSpinBox();
758  mDoubleSpinBox->setExpressionsEnabled( true );
759  mDoubleSpinBox->setDecimals( decimals );
760 
761  // guess reasonable step value for double spin boxes
762  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) &&
763  !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() + 1 ) )
764  {
765  double singleStep = calculateStep( numberDef->minimum(), numberDef->maximum() );
766  singleStep = std::max( singleStep, std::pow( 10, -decimals ) );
767  mDoubleSpinBox->setSingleStep( singleStep );
768  }
769 
770  spinBox = mDoubleSpinBox;
771  break;
772 
774  mSpinBox = new QgsSpinBox();
775  mSpinBox->setExpressionsEnabled( true );
776  spinBox = mSpinBox;
777  break;
778  }
779  spinBox->setToolTip( parameterDefinition()->toolTip() );
780 
781  double max = 999999999;
782  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) )
783  {
784  max = numberDef->maximum();
785  }
786  double min = -999999999;
787  if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
788  {
789  min = numberDef->minimum();
790  }
791  if ( mDoubleSpinBox )
792  {
793  mDoubleSpinBox->setMinimum( min );
794  mDoubleSpinBox->setMaximum( max );
795  }
796  else
797  {
798  mSpinBox->setMinimum( static_cast< int >( min ) );
799  mSpinBox->setMaximum( static_cast< int >( max ) );
800  }
801 
803  {
804  mAllowingNull = true;
805  if ( mDoubleSpinBox )
806  {
807  mDoubleSpinBox->setShowClearButton( true );
808  const double min = mDoubleSpinBox->minimum() - 1;
809  mDoubleSpinBox->setMinimum( min );
810  mDoubleSpinBox->setValue( min );
811  }
812  else
813  {
814  mSpinBox->setShowClearButton( true );
815  const int min = mSpinBox->minimum() - 1;
816  mSpinBox->setMinimum( min );
817  mSpinBox->setValue( min );
818  }
819  spinBox->setSpecialValueText( tr( "Not set" ) );
820  }
821  else
822  {
823  if ( numberDef->defaultValueForGui().isValid() )
824  {
825  // if default value for parameter, we clear to that
826  bool ok = false;
827  if ( mDoubleSpinBox )
828  {
829  double defaultVal = numberDef->defaultValueForGui().toDouble( &ok );
830  if ( ok )
831  mDoubleSpinBox->setClearValue( defaultVal );
832  }
833  else
834  {
835  int intVal = numberDef->defaultValueForGui().toInt( &ok );
836  if ( ok )
837  mSpinBox->setClearValue( intVal );
838  }
839  }
840  else if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
841  {
842  // otherwise we clear to the minimum, if it's set
843  if ( mDoubleSpinBox )
844  mDoubleSpinBox->setClearValue( numberDef->minimum() );
845  else
846  mSpinBox->setClearValue( static_cast< int >( numberDef->minimum() ) );
847  }
848  else
849  {
850  // last resort, we clear to 0
851  if ( mDoubleSpinBox )
852  {
853  mDoubleSpinBox->setValue( 0 );
854  mDoubleSpinBox->setClearValue( 0 );
855  }
856  else
857  {
858  mSpinBox->setValue( 0 );
859  mSpinBox->setClearValue( 0 );
860  }
861  }
862  }
863 
864  if ( mDoubleSpinBox )
865  connect( mDoubleSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
866  else if ( mSpinBox )
867  connect( mSpinBox, qOverload<int>( &QgsSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
868 
869  return spinBox;
870  }
871  }
872  return nullptr;
873 }
874 
875 void QgsProcessingNumericWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
876 {
877  if ( mDoubleSpinBox )
878  {
879  if ( mAllowingNull && !value.isValid() )
880  mDoubleSpinBox->clear();
881  else
882  {
883  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
884  mDoubleSpinBox->setValue( v );
885  }
886  }
887  else if ( mSpinBox )
888  {
889  if ( mAllowingNull && !value.isValid() )
890  mSpinBox->clear();
891  else
892  {
893  const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
894  mSpinBox->setValue( v );
895  }
896  }
897 }
898 
899 QVariant QgsProcessingNumericWidgetWrapper::widgetValue() const
900 {
901  if ( mDoubleSpinBox )
902  {
903  if ( mAllowingNull && qgsDoubleNear( mDoubleSpinBox->value(), mDoubleSpinBox->minimum() ) )
904  return QVariant();
905  else
906  return mDoubleSpinBox->value();
907  }
908  else if ( mSpinBox )
909  {
910  if ( mAllowingNull && mSpinBox->value() == mSpinBox->minimum() )
911  return QVariant();
912  else
913  return mSpinBox->value();
914  }
915  else
916  return QVariant();
917 }
918 
919 QStringList QgsProcessingNumericWidgetWrapper::compatibleParameterTypes() const
920 {
921  return QStringList()
927 }
928 
929 QStringList QgsProcessingNumericWidgetWrapper::compatibleOutputTypes() const
930 {
931  return QStringList() << QgsProcessingOutputNumber::typeName()
933 }
934 
935 double QgsProcessingNumericWidgetWrapper::calculateStep( const double minimum, const double maximum )
936 {
937  const double valueRange = maximum - minimum;
938  if ( valueRange <= 1.0 )
939  {
940  const double step = valueRange / 10.0;
941  // round to 1 significant figure
942  return qgsRound( step, -std::floor( std::log( step ) ) );
943  }
944  else
945  {
946  return 1.0;
947  }
948 }
949 
950 QString QgsProcessingNumericWidgetWrapper::parameterType() const
951 {
953 }
954 
955 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingNumericWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
956 {
957  return new QgsProcessingNumericWidgetWrapper( parameter, type );
958 }
959 
960 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingNumericWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
961 {
962  return new QgsProcessingNumberParameterDefinitionWidget( context, widgetContext, definition, algorithm );
963 }
964 
965 //
966 // QgsProcessingDistanceWidgetWrapper
967 //
968 
969 QgsProcessingDistanceParameterDefinitionWidget::QgsProcessingDistanceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
970  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
971 {
972  QVBoxLayout *vlayout = new QVBoxLayout();
973  vlayout->setContentsMargins( 0, 0, 0, 0 );
974 
975  vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
976 
977  mParentLayerComboBox = new QComboBox();
978 
979  QString initialParent;
980  if ( const QgsProcessingParameterDistance *distParam = dynamic_cast<const QgsProcessingParameterDistance *>( definition ) )
981  initialParent = distParam->parentParameterName();
982 
983  if ( auto *lModel = widgetContext.model() )
984  {
985  // populate combo box with other model input choices
986  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
987  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
988  {
989  if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast< const QgsProcessingParameterFeatureSource * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
990  {
991  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
992  if ( !initialParent.isEmpty() && initialParent == definition->name() )
993  {
994  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
995  }
996  }
997  else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast< const QgsProcessingParameterVectorLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
998  {
999  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
1000  if ( !initialParent.isEmpty() && initialParent == definition->name() )
1001  {
1002  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1003  }
1004  }
1005  else if ( const QgsProcessingParameterMapLayer *definition = dynamic_cast< const QgsProcessingParameterMapLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
1006  {
1007  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
1008  if ( !initialParent.isEmpty() && initialParent == definition->name() )
1009  {
1010  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1011  }
1012  }
1013  else if ( const QgsProcessingParameterCrs *definition = dynamic_cast< const QgsProcessingParameterCrs * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
1014  {
1015  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
1016  if ( !initialParent.isEmpty() && initialParent == definition->name() )
1017  {
1018  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1019  }
1020  }
1021  }
1022  }
1023 
1024  if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
1025  {
1026  // if no parent candidates found, we just add the existing one as a placeholder
1027  mParentLayerComboBox->addItem( initialParent, initialParent );
1028  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1029  }
1030 
1031  vlayout->addWidget( mParentLayerComboBox );
1032 
1033  vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1034  mMinLineEdit = new QLineEdit();
1035  vlayout->addWidget( mMinLineEdit );
1036 
1037  vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1038  mMaxLineEdit = new QLineEdit();
1039  vlayout->addWidget( mMaxLineEdit );
1040 
1041  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1042  mDefaultLineEdit = new QLineEdit();
1043  vlayout->addWidget( mDefaultLineEdit );
1044 
1045  if ( const QgsProcessingParameterDistance *distParam = dynamic_cast<const QgsProcessingParameterDistance *>( definition ) )
1046  {
1047  mMinLineEdit->setText( QLocale().toString( distParam->minimum() ) );
1048  mMaxLineEdit->setText( QLocale().toString( distParam->maximum() ) );
1049  mDefaultLineEdit->setText( distParam->defaultValueForGui().toString() );
1050  }
1051 
1052  setLayout( vlayout );
1053 }
1054 
1055 QgsProcessingParameterDefinition *QgsProcessingDistanceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1056 {
1057  bool ok;
1058  double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
1059 
1060  auto param = std::make_unique< QgsProcessingParameterDistance >( name, description, ok ? val : QVariant(), mParentLayerComboBox->currentData().toString() );
1061 
1062  val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
1063  if ( ok )
1064  {
1065  param->setMinimum( val );
1066  }
1067 
1068  val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
1069  if ( ok )
1070  {
1071  param->setMaximum( val );
1072  }
1073 
1074  param->setFlags( flags );
1075  return param.release();
1076 }
1077 
1078 QgsProcessingDistanceWidgetWrapper::QgsProcessingDistanceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1079  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1080 {
1081 
1082 }
1083 
1084 QString QgsProcessingDistanceWidgetWrapper::parameterType() const
1085 {
1087 }
1088 
1089 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDistanceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1090 {
1091  return new QgsProcessingDistanceWidgetWrapper( parameter, type );
1092 }
1093 
1094 QWidget *QgsProcessingDistanceWidgetWrapper::createWidget()
1095 {
1096  const QgsProcessingParameterDistance *distanceDef = static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() );
1097 
1098  QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1099  switch ( type() )
1100  {
1102  {
1103  mLabel = new QLabel();
1104  mUnitsCombo = new QComboBox();
1105 
1111 
1112  const int labelMargin = static_cast< int >( std::round( mUnitsCombo->fontMetrics().horizontalAdvance( 'X' ) ) );
1113  QHBoxLayout *layout = new QHBoxLayout();
1114  layout->addWidget( spin, 1 );
1115  layout->insertSpacing( 1, labelMargin / 2 );
1116  layout->insertWidget( 2, mLabel );
1117  layout->insertWidget( 3, mUnitsCombo );
1118 
1119  // bit of fiddlyness here -- we want the initial spacing to only be visible
1120  // when the warning label is shown, so it's embedded inside mWarningLabel
1121  // instead of outside it
1122  mWarningLabel = new QWidget();
1123  QHBoxLayout *warningLayout = new QHBoxLayout();
1124  warningLayout->setContentsMargins( 0, 0, 0, 0 );
1125  QLabel *warning = new QLabel();
1126  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
1127  const int size = static_cast< int >( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
1128  warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
1129  warning->setToolTip( tr( "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
1130  warningLayout->insertSpacing( 0, labelMargin / 2 );
1131  warningLayout->insertWidget( 1, warning );
1132  mWarningLabel->setLayout( warningLayout );
1133  layout->insertWidget( 4, mWarningLabel );
1134 
1135  QWidget *w = new QWidget();
1136  layout->setContentsMargins( 0, 0, 0, 0 );
1137  w->setLayout( layout );
1138 
1139  setUnits( distanceDef->defaultUnit() );
1140 
1141  return w;
1142  }
1143 
1146  return spin;
1147 
1148  }
1149  return nullptr;
1150 }
1151 
1152 void QgsProcessingDistanceWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1153 {
1154  QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
1155  switch ( type() )
1156  {
1158  {
1159  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1160  {
1161  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() )->parentParameterName() )
1162  {
1163  setUnitParameterValue( wrapper->parameterValue() );
1165  {
1166  setUnitParameterValue( wrapper->parameterValue() );
1167  } );
1168  break;
1169  }
1170  }
1171  break;
1172  }
1173 
1176  break;
1177  }
1178 }
1179 
1180 void QgsProcessingDistanceWidgetWrapper::setUnitParameterValue( const QVariant &value )
1181 {
1183 
1184  // evaluate value to layer
1185  QgsProcessingContext *context = nullptr;
1186  std::unique_ptr< QgsProcessingContext > tmpContext;
1187  if ( mProcessingContextGenerator )
1188  context = mProcessingContextGenerator->processingContext();
1189 
1190  if ( !context )
1191  {
1192  tmpContext = std::make_unique< QgsProcessingContext >();
1193  context = tmpContext.get();
1194  }
1195 
1196  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, *context );
1197  if ( crs.isValid() )
1198  {
1199  units = crs.mapUnits();
1200  }
1201 
1202  setUnits( units );
1203 }
1204 
1205 void QgsProcessingDistanceWidgetWrapper::setUnits( const QgsUnitTypes::DistanceUnit units )
1206 {
1207  mLabel->setText( QgsUnitTypes::toString( units ) );
1209  {
1210  mUnitsCombo->hide();
1211  mLabel->show();
1212  }
1213  else
1214  {
1215  mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( units ) );
1216  mUnitsCombo->show();
1217  mLabel->hide();
1218  }
1219  mWarningLabel->setVisible( units == QgsUnitTypes::DistanceDegrees );
1220  mBaseUnit = units;
1221 }
1222 
1223 QVariant QgsProcessingDistanceWidgetWrapper::widgetValue() const
1224 {
1225  const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1226  if ( val.type() == QVariant::Double && mUnitsCombo && mUnitsCombo->isVisible() )
1227  {
1228  QgsUnitTypes::DistanceUnit displayUnit = static_cast<QgsUnitTypes::DistanceUnit >( mUnitsCombo->currentData().toInt() );
1229  return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1230  }
1231  else
1232  {
1233  return val;
1234  }
1235 }
1236 
1237 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDistanceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1238 {
1239  return new QgsProcessingDistanceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1240 }
1241 
1242 
1243 //
1244 // QgsProcessingDurationWidgetWrapper
1245 //
1246 
1247 QgsProcessingDurationParameterDefinitionWidget::QgsProcessingDurationParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1248  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1249 {
1250  QVBoxLayout *vlayout = new QVBoxLayout();
1251  vlayout->setContentsMargins( 0, 0, 0, 0 );
1252 
1253  vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1254  mMinLineEdit = new QLineEdit();
1255  vlayout->addWidget( mMinLineEdit );
1256 
1257  vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1258  mMaxLineEdit = new QLineEdit();
1259  vlayout->addWidget( mMaxLineEdit );
1260 
1261  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1262  mDefaultLineEdit = new QLineEdit();
1263  vlayout->addWidget( mDefaultLineEdit );
1264 
1265  vlayout->addWidget( new QLabel( tr( "Default unit type" ) ) );
1266 
1267  mUnitsCombo = new QComboBox();
1274  mUnitsCombo->addItem( tr( "years (365.25 days)" ), QgsUnitTypes::TemporalYears );
1277  vlayout->addWidget( mUnitsCombo );
1278 
1279  if ( const QgsProcessingParameterDuration *durationParam = dynamic_cast<const QgsProcessingParameterDuration *>( definition ) )
1280  {
1281  mMinLineEdit->setText( QLocale().toString( durationParam->minimum() ) );
1282  mMaxLineEdit->setText( QLocale().toString( durationParam->maximum() ) );
1283  mDefaultLineEdit->setText( durationParam->defaultValueForGui().toString() );
1284  mUnitsCombo->setCurrentIndex( durationParam->defaultUnit() );
1285  }
1286 
1287  setLayout( vlayout );
1288 }
1289 
1290 QgsProcessingParameterDefinition *QgsProcessingDurationParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1291 {
1292  bool ok;
1293  double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
1294 
1295  auto param = std::make_unique< QgsProcessingParameterDuration >( name, description, ok ? val : QVariant() );
1296 
1297  val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
1298  if ( ok )
1299  {
1300  param->setMinimum( val );
1301  }
1302 
1303  val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
1304  if ( ok )
1305  {
1306  param->setMaximum( val );
1307  }
1308 
1309  param->setDefaultUnit( static_cast<QgsUnitTypes::TemporalUnit >( mUnitsCombo->currentData().toInt() ) );
1310 
1311  param->setFlags( flags );
1312  return param.release();
1313 }
1314 
1315 QgsProcessingDurationWidgetWrapper::QgsProcessingDurationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1316  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1317 {
1318 
1319 }
1320 
1321 QString QgsProcessingDurationWidgetWrapper::parameterType() const
1322 {
1324 }
1325 
1326 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDurationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1327 {
1328  return new QgsProcessingDurationWidgetWrapper( parameter, type );
1329 }
1330 
1331 QWidget *QgsProcessingDurationWidgetWrapper::createWidget()
1332 {
1333  const QgsProcessingParameterDuration *durationDef = static_cast< const QgsProcessingParameterDuration * >( parameterDefinition() );
1334 
1335  QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1336  switch ( type() )
1337  {
1339  {
1340  mUnitsCombo = new QComboBox();
1341 
1348  mUnitsCombo->addItem( tr( "years (365.25 days)" ), QgsUnitTypes::TemporalYears );
1351 
1352  QHBoxLayout *layout = new QHBoxLayout();
1353  layout->addWidget( spin, 1 );
1354  layout->insertWidget( 1, mUnitsCombo );
1355 
1356  QWidget *w = new QWidget();
1357  layout->setContentsMargins( 0, 0, 0, 0 );
1358  w->setLayout( layout );
1359 
1360  mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( durationDef->defaultUnit() ) );
1361  mUnitsCombo->show();
1362 
1363  return w;
1364  }
1365 
1368  return spin;
1369 
1370  }
1371  return nullptr;
1372 }
1373 
1374 QLabel *QgsProcessingDurationWidgetWrapper::createLabel()
1375 {
1377 
1378  if ( type() == QgsProcessingGui::Modeler )
1379  {
1380  label->setText( QStringLiteral( "%1 [%2]" ).arg( label->text(), QgsUnitTypes::toString( mBaseUnit ) ) );
1381  }
1382 
1383  return label;
1384 }
1385 
1386 QVariant QgsProcessingDurationWidgetWrapper::widgetValue() const
1387 {
1388  const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1389  if ( val.type() == QVariant::Double && mUnitsCombo )
1390  {
1391  QgsUnitTypes::TemporalUnit displayUnit = static_cast<QgsUnitTypes::TemporalUnit >( mUnitsCombo->currentData().toInt() );
1392  return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1393  }
1394  else
1395  {
1396  return val;
1397  }
1398 }
1399 
1400 void QgsProcessingDurationWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1401 {
1402  if ( mUnitsCombo )
1403  {
1404  QgsUnitTypes::TemporalUnit displayUnit = static_cast<QgsUnitTypes::TemporalUnit >( mUnitsCombo->currentData().toInt() );
1405  const QVariant val = value.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( mBaseUnit, displayUnit );
1406  QgsProcessingNumericWidgetWrapper::setWidgetValue( val, context );
1407  }
1408  else
1409  {
1410  QgsProcessingNumericWidgetWrapper::setWidgetValue( value, context );
1411  }
1412 }
1413 
1414 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDurationWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1415 {
1416  return new QgsProcessingDurationParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1417 }
1418 
1419 //
1420 // QgsProcessingScaleWidgetWrapper
1421 //
1422 
1423 QgsProcessingScaleParameterDefinitionWidget::QgsProcessingScaleParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1424  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1425 {
1426  QVBoxLayout *vlayout = new QVBoxLayout();
1427  vlayout->setContentsMargins( 0, 0, 0, 0 );
1428 
1429  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1430 
1431  mDefaultLineEdit = new QLineEdit();
1432 
1433  if ( const QgsProcessingParameterScale *scaleParam = dynamic_cast<const QgsProcessingParameterScale *>( definition ) )
1434  {
1435  mDefaultLineEdit->setText( scaleParam->defaultValueForGui().toString() );
1436  }
1437 
1438  vlayout->addWidget( mDefaultLineEdit );
1439 
1440  setLayout( vlayout );
1441 }
1442 
1443 QgsProcessingParameterDefinition *QgsProcessingScaleParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1444 {
1445  bool ok;
1446  double val = mDefaultLineEdit->text().toDouble( &ok );
1447  auto param = std::make_unique< QgsProcessingParameterScale >( name, description, ok ? val : QVariant() );
1448  param->setFlags( flags );
1449  return param.release();
1450 }
1451 
1452 QgsProcessingScaleWidgetWrapper::QgsProcessingScaleWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1453  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1454 {
1455 
1456 }
1457 
1458 QString QgsProcessingScaleWidgetWrapper::parameterType() const
1459 {
1461 }
1462 
1463 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingScaleWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1464 {
1465  return new QgsProcessingScaleWidgetWrapper( parameter, type );
1466 }
1467 
1468 QWidget *QgsProcessingScaleWidgetWrapper::createWidget()
1469 {
1470  const QgsProcessingParameterScale *scaleDef = static_cast< const QgsProcessingParameterScale * >( parameterDefinition() );
1471 
1472  switch ( type() )
1473  {
1477  {
1478  mScaleWidget = new QgsScaleWidget( nullptr );
1480  mScaleWidget->setAllowNull( true );
1481 
1482  mScaleWidget->setMapCanvas( widgetContext().mapCanvas() );
1483  mScaleWidget->setShowCurrentScaleButton( true );
1484 
1485  mScaleWidget->setToolTip( parameterDefinition()->toolTip() );
1486  connect( mScaleWidget, &QgsScaleWidget::scaleChanged, this, [ = ]( double )
1487  {
1488  emit widgetValueHasChanged( this );
1489  } );
1490  return mScaleWidget;
1491  }
1492  }
1493  return nullptr;
1494 }
1495 
1496 void QgsProcessingScaleWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
1497 {
1498  if ( mScaleWidget )
1499  mScaleWidget->setMapCanvas( context.mapCanvas() );
1501 }
1502 
1503 
1504 QVariant QgsProcessingScaleWidgetWrapper::widgetValue() const
1505 {
1506  return mScaleWidget && !mScaleWidget->isNull() ? QVariant( mScaleWidget->scale() ) : QVariant();
1507 }
1508 
1509 void QgsProcessingScaleWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1510 {
1511  if ( mScaleWidget )
1512  {
1513  if ( mScaleWidget->allowNull() && !value.isValid() )
1514  mScaleWidget->setNull();
1515  else
1516  {
1517  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
1518  mScaleWidget->setScale( v );
1519  }
1520  }
1521 }
1522 
1523 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingScaleWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1524 {
1525  return new QgsProcessingScaleParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1526 }
1527 
1528 
1529 //
1530 // QgsProcessingRangeWidgetWrapper
1531 //
1532 
1533 QgsProcessingRangeParameterDefinitionWidget::QgsProcessingRangeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1534  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1535 {
1536  QVBoxLayout *vlayout = new QVBoxLayout();
1537  vlayout->setContentsMargins( 0, 0, 0, 0 );
1538 
1539  vlayout->addWidget( new QLabel( tr( "Number type" ) ) );
1540 
1541  mTypeComboBox = new QComboBox();
1542  mTypeComboBox->addItem( tr( "Float" ), QgsProcessingParameterNumber::Double );
1543  mTypeComboBox->addItem( tr( "Integer" ), QgsProcessingParameterNumber::Integer );
1544  vlayout->addWidget( mTypeComboBox );
1545 
1546  vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1547  mMinLineEdit = new QLineEdit();
1548  vlayout->addWidget( mMinLineEdit );
1549 
1550  vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1551  mMaxLineEdit = new QLineEdit();
1552  vlayout->addWidget( mMaxLineEdit );
1553 
1554  if ( const QgsProcessingParameterRange *rangeParam = dynamic_cast<const QgsProcessingParameterRange *>( definition ) )
1555  {
1556  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( rangeParam->dataType() ) );
1557  const QList< double > range = QgsProcessingParameters::parameterAsRange( rangeParam, rangeParam->defaultValueForGui(), context );
1558  mMinLineEdit->setText( QLocale().toString( range.at( 0 ) ) );
1559  mMaxLineEdit->setText( QLocale().toString( range.at( 1 ) ) );
1560  }
1561 
1562  setLayout( vlayout );
1563 }
1564 
1565 QgsProcessingParameterDefinition *QgsProcessingRangeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1566 {
1567  QString defaultValue;
1568  if ( mMinLineEdit->text().isEmpty() )
1569  {
1570  defaultValue = QStringLiteral( "None" );
1571  }
1572  else
1573  {
1574  bool ok;
1575  defaultValue = QString::number( QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok ) );
1576  if ( ! ok )
1577  {
1578  defaultValue = QStringLiteral( "None" );
1579  }
1580  }
1581 
1582  if ( mMaxLineEdit->text().isEmpty() )
1583  {
1584  defaultValue += QLatin1String( ",None" );
1585  }
1586  else
1587  {
1588  bool ok;
1589  const double val { QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok ) };
1590  defaultValue += QStringLiteral( ",%1" ).arg( ok ? QString::number( val ) : QLatin1String( "None" ) );
1591  }
1592 
1593  QgsProcessingParameterNumber::Type dataType = static_cast< QgsProcessingParameterNumber::Type >( mTypeComboBox->currentData().toInt() );
1594  auto param = std::make_unique< QgsProcessingParameterRange >( name, description, dataType, defaultValue );
1595  param->setFlags( flags );
1596  return param.release();
1597 }
1598 
1599 
1600 QgsProcessingRangeWidgetWrapper::QgsProcessingRangeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1601  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1602 {
1603 
1604 }
1605 
1606 QWidget *QgsProcessingRangeWidgetWrapper::createWidget()
1607 {
1608  const QgsProcessingParameterRange *rangeDef = static_cast< const QgsProcessingParameterRange * >( parameterDefinition() );
1609  switch ( type() )
1610  {
1614  {
1615  QHBoxLayout *layout = new QHBoxLayout();
1616 
1617  mMinSpinBox = new QgsDoubleSpinBox();
1618  mMaxSpinBox = new QgsDoubleSpinBox();
1619 
1620  mMinSpinBox->setExpressionsEnabled( true );
1621  mMinSpinBox->setShowClearButton( false );
1622  mMaxSpinBox->setExpressionsEnabled( true );
1623  mMaxSpinBox->setShowClearButton( false );
1624 
1625  QLabel *minLabel = new QLabel( tr( "Min" ) );
1626  layout->addWidget( minLabel );
1627  layout->addWidget( mMinSpinBox, 1 );
1628 
1629  QLabel *maxLabel = new QLabel( tr( "Max" ) );
1630  layout->addWidget( maxLabel );
1631  layout->addWidget( mMaxSpinBox, 1 );
1632 
1633  QWidget *w = new QWidget();
1634  layout->setContentsMargins( 0, 0, 0, 0 );
1635  w->setLayout( layout );
1636 
1637  if ( rangeDef->dataType() == QgsProcessingParameterNumber::Double )
1638  {
1639  mMinSpinBox->setDecimals( 6 );
1640  mMaxSpinBox->setDecimals( 6 );
1641  }
1642  else
1643  {
1644  mMinSpinBox->setDecimals( 0 );
1645  mMaxSpinBox->setDecimals( 0 );
1646  }
1647 
1648  mMinSpinBox->setMinimum( -99999999.999999 );
1649  mMaxSpinBox->setMinimum( -99999999.999999 );
1650  mMinSpinBox->setMaximum( 99999999.999999 );
1651  mMaxSpinBox->setMaximum( 99999999.999999 );
1652 
1654  {
1655  mAllowingNull = true;
1656 
1657  const double min = mMinSpinBox->minimum() - 1;
1658  mMinSpinBox->setMinimum( min );
1659  mMaxSpinBox->setMinimum( min );
1660  mMinSpinBox->setValue( min );
1661  mMaxSpinBox->setValue( min );
1662 
1663  mMinSpinBox->setShowClearButton( true );
1664  mMaxSpinBox->setShowClearButton( true );
1665  mMinSpinBox->setSpecialValueText( tr( "Not set" ) );
1666  mMaxSpinBox->setSpecialValueText( tr( "Not set" ) );
1667  }
1668 
1669  w->setToolTip( parameterDefinition()->toolTip() );
1670 
1671  connect( mMinSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
1672  {
1673  mBlockChangedSignal++;
1674  if ( !mAllowingNull && v > mMaxSpinBox->value() )
1675  mMaxSpinBox->setValue( v );
1676  mBlockChangedSignal--;
1677 
1678  if ( !mBlockChangedSignal )
1679  emit widgetValueHasChanged( this );
1680  } );
1681  connect( mMaxSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
1682  {
1683  mBlockChangedSignal++;
1684  if ( !mAllowingNull && v < mMinSpinBox->value() )
1685  mMinSpinBox->setValue( v );
1686  mBlockChangedSignal--;
1687 
1688  if ( !mBlockChangedSignal )
1689  emit widgetValueHasChanged( this );
1690  } );
1691 
1692  return w;
1693  }
1694  }
1695  return nullptr;
1696 }
1697 
1698 void QgsProcessingRangeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1699 {
1700  const QList< double > v = QgsProcessingParameters::parameterAsRange( parameterDefinition(), value, context );
1701  if ( mAllowingNull && v.empty() )
1702  {
1703  mMinSpinBox->clear();
1704  mMaxSpinBox->clear();
1705  }
1706  else
1707  {
1708  if ( v.empty() )
1709  return;
1710 
1711  if ( mAllowingNull )
1712  {
1713  mBlockChangedSignal++;
1714  if ( std::isnan( v.at( 0 ) ) )
1715  mMinSpinBox->clear();
1716  else
1717  mMinSpinBox->setValue( v.at( 0 ) );
1718 
1719  if ( v.count() >= 2 )
1720  {
1721  if ( std::isnan( v.at( 1 ) ) )
1722  mMaxSpinBox->clear();
1723  else
1724  mMaxSpinBox->setValue( v.at( 1 ) );
1725  }
1726  mBlockChangedSignal--;
1727  }
1728  else
1729  {
1730  mBlockChangedSignal++;
1731  mMinSpinBox->setValue( v.at( 0 ) );
1732  if ( v.count() >= 2 )
1733  mMaxSpinBox->setValue( v.at( 1 ) );
1734  mBlockChangedSignal--;
1735  }
1736  }
1737 
1738  if ( !mBlockChangedSignal )
1739  emit widgetValueHasChanged( this );
1740 }
1741 
1742 QVariant QgsProcessingRangeWidgetWrapper::widgetValue() const
1743 {
1744  if ( mAllowingNull )
1745  {
1746  QString value;
1747  if ( qgsDoubleNear( mMinSpinBox->value(), mMinSpinBox->minimum() ) )
1748  value = QStringLiteral( "None" );
1749  else
1750  value = QString::number( mMinSpinBox->value() );
1751 
1752  if ( qgsDoubleNear( mMaxSpinBox->value(), mMaxSpinBox->minimum() ) )
1753  value += QLatin1String( ",None" );
1754  else
1755  value += QStringLiteral( ",%1" ).arg( mMaxSpinBox->value() );
1756 
1757  return value;
1758  }
1759  else
1760  return QStringLiteral( "%1,%2" ).arg( mMinSpinBox->value() ).arg( mMaxSpinBox->value() );
1761 }
1762 
1763 QStringList QgsProcessingRangeWidgetWrapper::compatibleParameterTypes() const
1764 {
1765  return QStringList()
1768 }
1769 
1770 QStringList QgsProcessingRangeWidgetWrapper::compatibleOutputTypes() const
1771 {
1772  return QStringList() << QgsProcessingOutputString::typeName();
1773 }
1774 
1775 QString QgsProcessingRangeWidgetWrapper::modelerExpressionFormatString() const
1776 {
1777  return tr( "string as two comma delimited floats, e.g. '1,10'" );
1778 }
1779 
1780 QString QgsProcessingRangeWidgetWrapper::parameterType() const
1781 {
1783 }
1784 
1785 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRangeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1786 {
1787  return new QgsProcessingRangeWidgetWrapper( parameter, type );
1788 }
1789 
1790 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRangeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1791 {
1792  return new QgsProcessingRangeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1793 }
1794 
1795 
1796 //
1797 // QgsProcessingMatrixWidgetWrapper
1798 //
1799 
1800 QgsProcessingMatrixParameterDefinitionWidget::QgsProcessingMatrixParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1801  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1802 {
1803  QVBoxLayout *vlayout = new QVBoxLayout();
1804  vlayout->setContentsMargins( 0, 0, 0, 0 );
1805 
1806  mMatrixWidget = new QgsProcessingMatrixModelerWidget();
1807  if ( const QgsProcessingParameterMatrix *matrixParam = dynamic_cast<const QgsProcessingParameterMatrix *>( definition ) )
1808  {
1809  mMatrixWidget->setValue( matrixParam->headers(), matrixParam->defaultValueForGui() );
1810  mMatrixWidget->setFixedRows( matrixParam->hasFixedNumberRows() );
1811  }
1812  vlayout->addWidget( mMatrixWidget );
1813  setLayout( vlayout );
1814 }
1815 
1816 QgsProcessingParameterDefinition *QgsProcessingMatrixParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1817 {
1818  auto param = std::make_unique< QgsProcessingParameterMatrix >( name, description, 1, mMatrixWidget->fixedRows(), mMatrixWidget->headers(), mMatrixWidget->value() );
1819  param->setFlags( flags );
1820  return param.release();
1821 }
1822 
1823 
1824 QgsProcessingMatrixWidgetWrapper::QgsProcessingMatrixWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1825  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1826 {
1827 
1828 }
1829 
1830 QWidget *QgsProcessingMatrixWidgetWrapper::createWidget()
1831 {
1832  mMatrixWidget = new QgsProcessingMatrixParameterPanel( nullptr, dynamic_cast< const QgsProcessingParameterMatrix *>( parameterDefinition() ) );
1833  mMatrixWidget->setToolTip( parameterDefinition()->toolTip() );
1834 
1835  connect( mMatrixWidget, &QgsProcessingMatrixParameterPanel::changed, this, [ = ]
1836  {
1837  emit widgetValueHasChanged( this );
1838  } );
1839 
1840  switch ( type() )
1841  {
1845  {
1846  return mMatrixWidget;
1847  }
1848  }
1849  return nullptr;
1850 }
1851 
1852 void QgsProcessingMatrixWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1853 {
1854  const QVariantList v = QgsProcessingParameters::parameterAsMatrix( parameterDefinition(), value, context );
1855  if ( mMatrixWidget )
1856  mMatrixWidget->setValue( v );
1857 }
1858 
1859 QVariant QgsProcessingMatrixWidgetWrapper::widgetValue() const
1860 {
1861  if ( mMatrixWidget )
1862  return mMatrixWidget->value().isEmpty() ? QVariant() : mMatrixWidget->value();
1863  else
1864  return QVariant();
1865 }
1866 
1867 QStringList QgsProcessingMatrixWidgetWrapper::compatibleParameterTypes() const
1868 {
1869  return QStringList()
1871 }
1872 
1873 QStringList QgsProcessingMatrixWidgetWrapper::compatibleOutputTypes() const
1874 {
1875  return QStringList();
1876 }
1877 
1878 QString QgsProcessingMatrixWidgetWrapper::modelerExpressionFormatString() const
1879 {
1880  return tr( "comma delimited string of values, or an array of values" );
1881 }
1882 
1883 QString QgsProcessingMatrixWidgetWrapper::parameterType() const
1884 {
1886 }
1887 
1888 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMatrixWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1889 {
1890  return new QgsProcessingMatrixWidgetWrapper( parameter, type );
1891 }
1892 
1893 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMatrixWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1894 {
1895  return new QgsProcessingMatrixParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1896 }
1897 
1898 
1899 //
1900 // QgsProcessingFileWidgetWrapper
1901 //
1902 
1903 
1904 QgsProcessingFileParameterDefinitionWidget::QgsProcessingFileParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1905  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1906 {
1907  QVBoxLayout *vlayout = new QVBoxLayout();
1908  vlayout->setContentsMargins( 0, 0, 0, 0 );
1909 
1910  vlayout->addWidget( new QLabel( tr( "Type" ) ) );
1911 
1912  mTypeComboBox = new QComboBox();
1913  mTypeComboBox->addItem( tr( "File" ), QgsProcessingParameterFile::File );
1914  mTypeComboBox->addItem( tr( "Folder" ), QgsProcessingParameterFile::Folder );
1915  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1916  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( fileParam->behavior() ) );
1917  else
1918  mTypeComboBox->setCurrentIndex( 0 );
1919  vlayout->addWidget( mTypeComboBox );
1920 
1921  vlayout->addWidget( new QLabel( tr( "File filter" ) ) );
1922 
1923  mFilterComboBox = new QComboBox();
1924  mFilterComboBox->setEditable( true );
1925  // add some standard ones -- these also act as a demonstration of the required format
1926  mFilterComboBox->addItem( tr( "All Files (*.*)" ) );
1927  mFilterComboBox->addItem( tr( "CSV Files (*.csv)" ) );
1928  mFilterComboBox->addItem( tr( "HTML Files (*.html *.htm)" ) );
1929  mFilterComboBox->addItem( tr( "Text Files (*.txt)" ) );
1930  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1931  mFilterComboBox->setCurrentText( fileParam->fileFilter() );
1932  else
1933  mFilterComboBox->setCurrentIndex( 0 );
1934  vlayout->addWidget( mFilterComboBox );
1935 
1936  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1937 
1938  mDefaultFileWidget = new QgsFileWidget();
1939  mDefaultFileWidget->lineEdit()->setShowClearButton( true );
1940  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1941  {
1942  mDefaultFileWidget->setStorageMode( fileParam->behavior() == QgsProcessingParameterFile::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
1943  mDefaultFileWidget->setFilePath( fileParam->defaultValueForGui().toString() );
1944  }
1945  else
1946  mDefaultFileWidget->setStorageMode( QgsFileWidget::GetFile );
1947  vlayout->addWidget( mDefaultFileWidget );
1948 
1949  connect( mTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]
1950  {
1951  QgsProcessingParameterFile::Behavior behavior = static_cast< QgsProcessingParameterFile::Behavior >( mTypeComboBox->currentData().toInt() );
1952  mFilterComboBox->setEnabled( behavior == QgsProcessingParameterFile::File );
1953  mDefaultFileWidget->setStorageMode( behavior == QgsProcessingParameterFile::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
1954  } );
1955  mFilterComboBox->setEnabled( static_cast< QgsProcessingParameterFile::Behavior >( mTypeComboBox->currentData().toInt() ) == QgsProcessingParameterFile::File );
1956 
1957 
1958  setLayout( vlayout );
1959 }
1960 
1961 QgsProcessingParameterDefinition *QgsProcessingFileParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1962 {
1963  auto param = std::make_unique< QgsProcessingParameterFile >( name, description );
1964  param->setBehavior( static_cast< QgsProcessingParameterFile::Behavior>( mTypeComboBox->currentData().toInt() ) );
1965  if ( param->behavior() == QgsProcessingParameterFile::File )
1966  param->setFileFilter( mFilterComboBox->currentText() );
1967  if ( !mDefaultFileWidget->filePath().isEmpty() )
1968  param->setDefaultValue( mDefaultFileWidget->filePath() );
1969  param->setFlags( flags );
1970  return param.release();
1971 }
1972 
1973 
1974 QgsProcessingFileWidgetWrapper::QgsProcessingFileWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1975  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1976 {
1977 
1978 }
1979 
1980 QWidget *QgsProcessingFileWidgetWrapper::createWidget()
1981 {
1982  const QgsProcessingParameterFile *fileParam = dynamic_cast< const QgsProcessingParameterFile *>( parameterDefinition() );
1983  switch ( type() )
1984  {
1988  {
1989  mFileWidget = new QgsFileWidget();
1990  mFileWidget->setToolTip( parameterDefinition()->toolTip() );
1991  mFileWidget->setDialogTitle( parameterDefinition()->description() );
1992 
1993  mFileWidget->setDefaultRoot( QgsSettings().value( QStringLiteral( "/Processing/LastInputPath" ), QDir::homePath() ).toString() );
1994 
1995  switch ( fileParam->behavior() )
1996  {
1998  mFileWidget->setStorageMode( QgsFileWidget::GetFile );
1999  if ( !fileParam->fileFilter().isEmpty() )
2000  mFileWidget->setFilter( fileParam->fileFilter() );
2001  else if ( !fileParam->extension().isEmpty() )
2002  mFileWidget->setFilter( tr( "%1 files" ).arg( fileParam->extension().toUpper() ) + QStringLiteral( " (*." ) + fileParam->extension().toLower() + ')' );
2003  break;
2004 
2006  mFileWidget->setStorageMode( QgsFileWidget::GetDirectory );
2007  break;
2008  }
2009 
2010  connect( mFileWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & path )
2011  {
2012  QgsSettings().setValue( QStringLiteral( "/Processing/LastInputPath" ), QFileInfo( path ).canonicalPath() );
2013  emit widgetValueHasChanged( this );
2014  } );
2015  return mFileWidget;
2016  }
2017  }
2018  return nullptr;
2019 }
2020 
2021 void QgsProcessingFileWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2022 {
2023  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2024  if ( mFileWidget )
2025  mFileWidget->setFilePath( v );
2026 }
2027 
2028 QVariant QgsProcessingFileWidgetWrapper::widgetValue() const
2029 {
2030  if ( mFileWidget )
2031  return mFileWidget->filePath();
2032  else
2033  return QVariant();
2034 }
2035 
2036 QStringList QgsProcessingFileWidgetWrapper::compatibleParameterTypes() const
2037 {
2038  return QStringList()
2041 }
2042 
2043 QStringList QgsProcessingFileWidgetWrapper::compatibleOutputTypes() const
2044 {
2045  return QStringList() << QgsProcessingOutputFile::typeName()
2051 }
2052 
2053 QString QgsProcessingFileWidgetWrapper::modelerExpressionFormatString() const
2054 {
2055  return tr( "string representing a path to a file or folder" );
2056 }
2057 
2058 QString QgsProcessingFileWidgetWrapper::parameterType() const
2059 {
2061 }
2062 
2063 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2064 {
2065  return new QgsProcessingFileWidgetWrapper( parameter, type );
2066 }
2067 
2068 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFileWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2069 {
2070  return new QgsProcessingFileParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2071 }
2072 
2073 
2074 
2075 //
2076 // QgsProcessingExpressionWidgetWrapper
2077 //
2078 
2079 QgsProcessingExpressionParameterDefinitionWidget::QgsProcessingExpressionParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2080  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2081 {
2082  QVBoxLayout *vlayout = new QVBoxLayout();
2083  vlayout->setContentsMargins( 0, 0, 0, 0 );
2084  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
2085 
2086  mDefaultLineEdit = new QgsExpressionLineEdit();
2087  mDefaultLineEdit->registerExpressionContextGenerator( this );
2088 
2089  if ( const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( definition ) )
2090  mDefaultLineEdit->setExpression( QgsProcessingParameters::parameterAsExpression( expParam, expParam->defaultValueForGui(), context ) );
2091  vlayout->addWidget( mDefaultLineEdit );
2092 
2093  vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
2094 
2095  mParentLayerComboBox = new QComboBox();
2096  mParentLayerComboBox->addItem( tr( "None" ), QVariant() );
2097 
2098  QString initialParent;
2099  if ( const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( definition ) )
2100  initialParent = expParam->parentLayerParameterName();
2101 
2102  if ( QgsProcessingModelAlgorithm *model = widgetContext.model() )
2103  {
2104  // populate combo box with other model input choices
2105  const QMap<QString, QgsProcessingModelParameter> components = model->parameterComponents();
2106  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
2107  {
2108  if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast< const QgsProcessingParameterFeatureSource * >( model->parameterDefinition( it.value().parameterName() ) ) )
2109  {
2110  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
2111  if ( !initialParent.isEmpty() && initialParent == definition->name() )
2112  {
2113  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2114  }
2115  }
2116  else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast< const QgsProcessingParameterVectorLayer * >( model->parameterDefinition( it.value().parameterName() ) ) )
2117  {
2118  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
2119  if ( !initialParent.isEmpty() && initialParent == definition->name() )
2120  {
2121  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2122  }
2123  }
2124  }
2125  }
2126 
2127  if ( mParentLayerComboBox->count() == 1 && !initialParent.isEmpty() )
2128  {
2129  // if no parent candidates found, we just add the existing one as a placeholder
2130  mParentLayerComboBox->addItem( initialParent, initialParent );
2131  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2132  }
2133 
2134  vlayout->addWidget( mParentLayerComboBox );
2135  setLayout( vlayout );
2136 }
2137 
2138 QgsProcessingParameterDefinition *QgsProcessingExpressionParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2139 {
2140  auto param = std::make_unique< QgsProcessingParameterExpression >( name, description, mDefaultLineEdit->expression(), mParentLayerComboBox->currentData().toString() );
2141  param->setFlags( flags );
2142  return param.release();
2143 }
2144 
2145 QgsProcessingExpressionWidgetWrapper::QgsProcessingExpressionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2146  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2147 {
2148 
2149 }
2150 
2151 QWidget *QgsProcessingExpressionWidgetWrapper::createWidget()
2152 {
2153  const QgsProcessingParameterExpression *expParam = dynamic_cast< const QgsProcessingParameterExpression *>( parameterDefinition() );
2154  switch ( type() )
2155  {
2159  {
2160  if ( expParam->parentLayerParameterName().isEmpty() )
2161  {
2162  mExpLineEdit = new QgsExpressionLineEdit();
2163  mExpLineEdit->setToolTip( parameterDefinition()->toolTip() );
2164  mExpLineEdit->setExpressionDialogTitle( parameterDefinition()->description() );
2165  mExpLineEdit->registerExpressionContextGenerator( this );
2166  connect( mExpLineEdit, &QgsExpressionLineEdit::expressionChanged, this, [ = ]( const QString & )
2167  {
2168  emit widgetValueHasChanged( this );
2169  } );
2170  return mExpLineEdit;
2171  }
2172  else
2173  {
2174  if ( expParam->metadata().value( QStringLiteral( "inlineEditor" ) ).toBool() )
2175  {
2176  mExpBuilderWidget = new QgsExpressionBuilderWidget();
2177  mExpBuilderWidget->setToolTip( parameterDefinition()->toolTip() );
2178  mExpBuilderWidget->init( createExpressionContext() );
2179  connect( mExpBuilderWidget, &QgsExpressionBuilderWidget::expressionParsed, this, [ = ]( bool changed )
2180  {
2181  Q_UNUSED( changed );
2182  emit widgetValueHasChanged( this );
2183  } );
2184  return mExpBuilderWidget;
2185  }
2186  else
2187  {
2188  mFieldExpWidget = new QgsFieldExpressionWidget();
2189  mFieldExpWidget->setToolTip( parameterDefinition()->toolTip() );
2190  mFieldExpWidget->setExpressionDialogTitle( parameterDefinition()->description() );
2191  mFieldExpWidget->registerExpressionContextGenerator( this );
2193  mFieldExpWidget->setAllowEmptyFieldName( true );
2194 
2195  connect( mFieldExpWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString & ) >( &QgsFieldExpressionWidget::fieldChanged ), this, [ = ]( const QString & )
2196  {
2197  emit widgetValueHasChanged( this );
2198  } );
2199  return mFieldExpWidget;
2200  }
2201  }
2202  }
2203  }
2204  return nullptr;
2205 }
2206 
2207 void QgsProcessingExpressionWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
2208 {
2210  switch ( type() )
2211  {
2214  {
2215  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
2216  {
2217  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterExpression * >( parameterDefinition() )->parentLayerParameterName() )
2218  {
2219  setParentLayerWrapperValue( wrapper );
2221  {
2222  setParentLayerWrapperValue( wrapper );
2223  } );
2224  break;
2225  }
2226  }
2227  break;
2228  }
2229 
2231  break;
2232  }
2233 }
2234 
2235 void QgsProcessingExpressionWidgetWrapper::registerProcessingContextGenerator( QgsProcessingContextGenerator *generator )
2236 {
2238  if ( mExpBuilderWidget )
2239  {
2240  // we need to regenerate the expression context for use by this widget -- it doesn't fetch automatically on demand
2241  mExpBuilderWidget->setExpressionContext( createExpressionContext() );
2242  }
2243 }
2244 
2245 void QgsProcessingExpressionWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
2246 {
2247  // evaluate value to layer
2248  QgsProcessingContext *context = nullptr;
2249  std::unique_ptr< QgsProcessingContext > tmpContext;
2250  if ( mProcessingContextGenerator )
2251  context = mProcessingContextGenerator->processingContext();
2252 
2253  if ( !context )
2254  {
2255  tmpContext = std::make_unique< QgsProcessingContext >();
2256  context = tmpContext.get();
2257  }
2258 
2259  QVariant val = parentWrapper->parameterValue();
2260  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
2261  {
2262  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
2263  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
2264  val = fromVar.source;
2265  }
2266 
2267  QgsVectorLayer *layer = QgsProcessingParameters::parameterAsVectorLayer( parentWrapper->parameterDefinition(), val, *context );
2268  if ( !layer )
2269  {
2270  if ( mFieldExpWidget )
2271  mFieldExpWidget->setLayer( nullptr );
2272  else if ( mExpBuilderWidget )
2273  mExpBuilderWidget->setLayer( nullptr );
2274  else if ( mExpLineEdit )
2275  mExpLineEdit->setLayer( nullptr );
2276  return;
2277  }
2278 
2279  // need to grab ownership of layer if required - otherwise layer may be deleted when context
2280  // goes out of scope
2281  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
2282  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::VectorLayer )
2283  {
2284  mParentLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
2285  layer = mParentLayer.get();
2286  }
2287  else
2288  {
2289  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
2290  }
2291 
2292  if ( mFieldExpWidget )
2293  mFieldExpWidget->setLayer( layer );
2294  if ( mExpBuilderWidget )
2295  mExpBuilderWidget->setLayer( layer );
2296  else if ( mExpLineEdit )
2297  mExpLineEdit->setLayer( layer );
2298 }
2299 
2300 void QgsProcessingExpressionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2301 {
2302  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2303  if ( mFieldExpWidget )
2304  mFieldExpWidget->setExpression( v );
2305  else if ( mExpBuilderWidget )
2306  mExpBuilderWidget->setExpressionText( v );
2307  else if ( mExpLineEdit )
2308  mExpLineEdit->setExpression( v );
2309 }
2310 
2311 QVariant QgsProcessingExpressionWidgetWrapper::widgetValue() const
2312 {
2313  if ( mFieldExpWidget )
2314  return mFieldExpWidget->expression();
2315  if ( mExpBuilderWidget )
2316  return mExpBuilderWidget->expressionText();
2317  else if ( mExpLineEdit )
2318  return mExpLineEdit->expression();
2319  else
2320  return QVariant();
2321 }
2322 
2323 QStringList QgsProcessingExpressionWidgetWrapper::compatibleParameterTypes() const
2324 {
2325  return QStringList()
2332 }
2333 
2334 QStringList QgsProcessingExpressionWidgetWrapper::compatibleOutputTypes() const
2335 {
2336  return QStringList()
2339 }
2340 
2341 QString QgsProcessingExpressionWidgetWrapper::modelerExpressionFormatString() const
2342 {
2343  return tr( "string representation of an expression" );
2344 }
2345 
2346 const QgsVectorLayer *QgsProcessingExpressionWidgetWrapper::linkedVectorLayer() const
2347 {
2348  if ( mFieldExpWidget && mFieldExpWidget->layer() )
2349  return mFieldExpWidget->layer();
2350 
2351  if ( mExpBuilderWidget && mExpBuilderWidget->layer() )
2352  return mExpBuilderWidget->layer();
2353 
2355 }
2356 
2357 QString QgsProcessingExpressionWidgetWrapper::parameterType() const
2358 {
2360 }
2361 
2362 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExpressionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2363 {
2364  return new QgsProcessingExpressionWidgetWrapper( parameter, type );
2365 }
2366 
2367 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingExpressionWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2368 {
2369  return new QgsProcessingExpressionParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2370 }
2371 
2372 
2373 
2374 //
2375 // QgsProcessingEnumPanelWidget
2376 //
2377 
2378 QgsProcessingEnumPanelWidget::QgsProcessingEnumPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param )
2379  : QWidget( parent )
2380  , mParam( param )
2381 {
2382  QHBoxLayout *hl = new QHBoxLayout();
2383  hl->setContentsMargins( 0, 0, 0, 0 );
2384 
2385  mLineEdit = new QLineEdit();
2386  mLineEdit->setEnabled( false );
2387  hl->addWidget( mLineEdit, 1 );
2388 
2389  mToolButton = new QToolButton();
2390  mToolButton->setText( QString( QChar( 0x2026 ) ) );
2391  hl->addWidget( mToolButton );
2392 
2393  setLayout( hl );
2394 
2395  if ( mParam )
2396  {
2397  mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
2398  }
2399 
2400  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingEnumPanelWidget::showDialog );
2401 }
2402 
2403 void QgsProcessingEnumPanelWidget::setValue( const QVariant &value )
2404 {
2405  if ( value.isValid() )
2406  {
2407  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
2408 
2409  if ( mParam->usesStaticStrings() && mValue.count() == 1 && mValue.at( 0 ).toString().isEmpty() )
2410  mValue.clear();
2411  }
2412  else
2413  mValue.clear();
2414 
2415  updateSummaryText();
2416  emit changed();
2417 }
2418 
2419 void QgsProcessingEnumPanelWidget::showDialog()
2420 {
2421  QVariantList availableOptions;
2422  if ( mParam )
2423  {
2424  availableOptions.reserve( mParam->options().size() );
2425  for ( int i = 0; i < mParam->options().count(); ++i )
2426  availableOptions << i;
2427  }
2428 
2429  const QStringList options = mParam ? mParam->options() : QStringList();
2431  if ( panel && panel->dockMode() )
2432  {
2433  QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
2434  widget->setPanelTitle( mParam->description() );
2435 
2436  if ( mParam->usesStaticStrings() )
2437  {
2438  widget->setValueFormatter( [options]( const QVariant & v ) -> QString
2439  {
2440  const QString i = v.toString();
2441  return options.contains( i ) ? i : QString();
2442  } );
2443  }
2444  else
2445  {
2446  widget->setValueFormatter( [options]( const QVariant & v ) -> QString
2447  {
2448  const int i = v.toInt();
2449  return options.size() > i ? options.at( i ) : QString();
2450  } );
2451  }
2452 
2453  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
2454  {
2455  setValue( widget->selectedOptions() );
2456  } );
2457  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
2458  panel->openPanel( widget );
2459  }
2460  else
2461  {
2462  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
2463 
2464  dlg.setValueFormatter( [options]( const QVariant & v ) -> QString
2465  {
2466  const int i = v.toInt();
2467  return options.size() > i ? options.at( i ) : QString();
2468  } );
2469  if ( dlg.exec() )
2470  {
2471  setValue( dlg.selectedOptions() );
2472  }
2473  }
2474 }
2475 
2476 void QgsProcessingEnumPanelWidget::updateSummaryText()
2477 {
2478  if ( mParam )
2479  mLineEdit->setText( tr( "%1 options selected" ).arg( mValue.count() ) );
2480 }
2481 
2482 
2483 //
2484 // QgsProcessingEnumCheckboxPanelWidget
2485 //
2486 QgsProcessingEnumCheckboxPanelWidget::QgsProcessingEnumCheckboxPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param, int columns )
2487  : QWidget( parent )
2488  , mParam( param )
2489  , mButtonGroup( new QButtonGroup( this ) )
2490  , mColumns( columns )
2491 {
2492  mButtonGroup->setExclusive( !mParam->allowMultiple() );
2493 
2494  QGridLayout *l = new QGridLayout();
2495  l->setContentsMargins( 0, 0, 0, 0 );
2496 
2497  int rows = static_cast< int >( std::ceil( mParam->options().count() / static_cast< double >( mColumns ) ) );
2498  for ( int i = 0; i < mParam->options().count(); ++i )
2499  {
2500  QAbstractButton *button = nullptr;
2501  if ( mParam->allowMultiple() )
2502  button = new QCheckBox( mParam->options().at( i ) );
2503  else
2504  button = new QRadioButton( mParam->options().at( i ) );
2505 
2506  connect( button, &QAbstractButton::toggled, this, [ = ]
2507  {
2508  if ( !mBlockChangedSignal )
2509  emit changed();
2510  } );
2511 
2512  mButtons.insert( i, button );
2513 
2514  mButtonGroup->addButton( button, i );
2515  l->addWidget( button, i % rows, i / rows );
2516  }
2517  l->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ), 0, mColumns );
2518  setLayout( l );
2519 
2520  if ( mParam->allowMultiple() )
2521  {
2522  setContextMenuPolicy( Qt::CustomContextMenu );
2523  connect( this, &QWidget::customContextMenuRequested, this, &QgsProcessingEnumCheckboxPanelWidget::showPopupMenu );
2524  }
2525 }
2526 
2527 QVariant QgsProcessingEnumCheckboxPanelWidget::value() const
2528 {
2529  if ( mParam->allowMultiple() )
2530  {
2531  QVariantList value;
2532  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2533  {
2534  if ( it.value()->isChecked() )
2535  value.append( mParam->usesStaticStrings() ? mParam->options().at( it.key().toInt() ) : it.key() );
2536  }
2537  return value;
2538  }
2539  else
2540  {
2541  if ( mParam->usesStaticStrings() )
2542  return mButtonGroup->checkedId() >= 0 ? mParam->options().at( mButtonGroup->checkedId() ) : QVariant();
2543  else
2544  return mButtonGroup->checkedId() >= 0 ? mButtonGroup->checkedId() : QVariant();
2545  }
2546 }
2547 
2548 void QgsProcessingEnumCheckboxPanelWidget::setValue( const QVariant &value )
2549 {
2550  mBlockChangedSignal = true;
2551  if ( mParam->allowMultiple() )
2552  {
2553  QVariantList selected;
2554  if ( value.isValid() )
2555  selected = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
2556  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2557  {
2558  QVariant v = mParam->usesStaticStrings() ? mParam->options().at( it.key().toInt() ) : it.key();
2559  it.value()->setChecked( selected.contains( v ) );
2560  }
2561  }
2562  else
2563  {
2564  QVariant v = value;
2565  if ( v.type() == QVariant::List )
2566  v = v.toList().value( 0 );
2567 
2568  v = mParam->usesStaticStrings() ? mParam->options().indexOf( v.toString() ) : v;
2569  if ( mButtons.contains( v ) )
2570  mButtons.value( v )->setChecked( true );
2571  }
2572  mBlockChangedSignal = false;
2573  emit changed();
2574 }
2575 
2576 void QgsProcessingEnumCheckboxPanelWidget::showPopupMenu()
2577 {
2578  QMenu popupMenu;
2579  QAction *selectAllAction = new QAction( tr( "Select All" ), &popupMenu );
2580  connect( selectAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::selectAll );
2581  QAction *clearAllAction = new QAction( tr( "Clear Selection" ), &popupMenu );
2582  connect( clearAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::deselectAll );
2583  popupMenu.addAction( selectAllAction );
2584  popupMenu.addAction( clearAllAction );
2585  popupMenu.exec( QCursor::pos() );
2586 }
2587 
2588 void QgsProcessingEnumCheckboxPanelWidget::selectAll()
2589 {
2590  mBlockChangedSignal = true;
2591  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2592  it.value()->setChecked( true );
2593  mBlockChangedSignal = false;
2594  emit changed();
2595 }
2596 
2597 void QgsProcessingEnumCheckboxPanelWidget::deselectAll()
2598 {
2599  mBlockChangedSignal = true;
2600  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2601  it.value()->setChecked( false );
2602  mBlockChangedSignal = false;
2603  emit changed();
2604 }
2605 
2606 
2607 //
2608 // QgsProcessingEnumWidgetWrapper
2609 //
2610 
2611 QgsProcessingEnumParameterDefinitionWidget::QgsProcessingEnumParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2612  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2613 {
2614  QVBoxLayout *vlayout = new QVBoxLayout();
2615  vlayout->setContentsMargins( 0, 0, 0, 0 );
2616 
2617  mEnumWidget = new QgsProcessingEnumModelerWidget();
2618  if ( const QgsProcessingParameterEnum *enumParam = dynamic_cast<const QgsProcessingParameterEnum *>( definition ) )
2619  {
2620  mEnumWidget->setAllowMultiple( enumParam->allowMultiple() );
2621  mEnumWidget->setOptions( enumParam->options() );
2622  mEnumWidget->setDefaultOptions( enumParam->defaultValueForGui() );
2623  }
2624  vlayout->addWidget( mEnumWidget );
2625  setLayout( vlayout );
2626 }
2627 
2628 QgsProcessingParameterDefinition *QgsProcessingEnumParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2629 {
2630  auto param = std::make_unique< QgsProcessingParameterEnum >( name, description, mEnumWidget->options(), mEnumWidget->allowMultiple(), mEnumWidget->defaultOptions() );
2631  param->setFlags( flags );
2632  return param.release();
2633 }
2634 
2635 
2636 QgsProcessingEnumWidgetWrapper::QgsProcessingEnumWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2637  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2638 {
2639 
2640 }
2641 
2642 QWidget *QgsProcessingEnumWidgetWrapper::createWidget()
2643 {
2644  const QgsProcessingParameterEnum *expParam = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
2645  switch ( type() )
2646  {
2648  {
2649  // checkbox panel only for use outside in standard gui!
2650  if ( expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "useCheckBoxes" ), false ).toBool() )
2651  {
2652  const int columns = expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "columns" ), 2 ).toInt();
2653  mCheckboxPanel = new QgsProcessingEnumCheckboxPanelWidget( nullptr, expParam, columns );
2654  mCheckboxPanel->setToolTip( parameterDefinition()->toolTip() );
2655  connect( mCheckboxPanel, &QgsProcessingEnumCheckboxPanelWidget::changed, this, [ = ]
2656  {
2657  emit widgetValueHasChanged( this );
2658  } );
2659  return mCheckboxPanel;
2660  }
2661  }
2662  FALLTHROUGH
2665  {
2666  if ( expParam->allowMultiple() )
2667  {
2668  mPanel = new QgsProcessingEnumPanelWidget( nullptr, expParam );
2669  mPanel->setToolTip( parameterDefinition()->toolTip() );
2670  connect( mPanel, &QgsProcessingEnumPanelWidget::changed, this, [ = ]
2671  {
2672  emit widgetValueHasChanged( this );
2673  } );
2674  return mPanel;
2675  }
2676  else
2677  {
2678  mComboBox = new QComboBox();
2679 
2681  mComboBox->addItem( tr( "[Not selected]" ), QVariant() );
2682  const QStringList options = expParam->options();
2683  for ( int i = 0; i < options.count(); ++i )
2684  {
2685  if ( expParam->usesStaticStrings() )
2686  mComboBox->addItem( options.at( i ), options.at( i ) );
2687  else
2688  mComboBox->addItem( options.at( i ), i );
2689  }
2690 
2691  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2692  connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
2693  {
2694  emit widgetValueHasChanged( this );
2695  } );
2696  return mComboBox;
2697  }
2698  }
2699  }
2700  return nullptr;
2701 }
2702 
2703 void QgsProcessingEnumWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2704 {
2705  if ( mComboBox )
2706  {
2707  if ( !value.isValid() )
2708  mComboBox->setCurrentIndex( mComboBox->findData( QVariant() ) );
2709  else
2710  {
2711  const QgsProcessingParameterEnum *enumDef = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
2712  if ( enumDef->usesStaticStrings() )
2713  {
2714  const QString v = QgsProcessingParameters::parameterAsEnumString( parameterDefinition(), value, context );
2715  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
2716  }
2717  else
2718  {
2719  const int v = QgsProcessingParameters::parameterAsEnum( parameterDefinition(), value, context );
2720  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
2721  }
2722  }
2723  }
2724  else if ( mPanel || mCheckboxPanel )
2725  {
2726  QVariantList opts;
2727  if ( value.isValid() )
2728  {
2729  const QgsProcessingParameterEnum *enumDef = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
2730  if ( enumDef->usesStaticStrings() )
2731  {
2732  const QStringList v = QgsProcessingParameters::parameterAsEnumStrings( parameterDefinition(), value, context );
2733  opts.reserve( v.size() );
2734  for ( QString i : v )
2735  opts << i;
2736  }
2737  else
2738  {
2739  const QList< int > v = QgsProcessingParameters::parameterAsEnums( parameterDefinition(), value, context );
2740  opts.reserve( v.size() );
2741  for ( int i : v )
2742  opts << i;
2743  }
2744  }
2745  if ( mPanel )
2746  mPanel->setValue( opts );
2747  else if ( mCheckboxPanel )
2748  mCheckboxPanel->setValue( opts );
2749  }
2750 }
2751 
2752 QVariant QgsProcessingEnumWidgetWrapper::widgetValue() const
2753 {
2754  if ( mComboBox )
2755  return mComboBox->currentData();
2756  else if ( mPanel )
2757  return mPanel->value();
2758  else if ( mCheckboxPanel )
2759  return mCheckboxPanel->value();
2760  else
2761  return QVariant();
2762 }
2763 
2764 QStringList QgsProcessingEnumWidgetWrapper::compatibleParameterTypes() const
2765 {
2766  return QStringList()
2770 }
2771 
2772 QStringList QgsProcessingEnumWidgetWrapper::compatibleOutputTypes() const
2773 {
2774  return QStringList()
2777 }
2778 
2779 QString QgsProcessingEnumWidgetWrapper::modelerExpressionFormatString() const
2780 {
2781  return tr( "selected option index (starting from 0), array of indices, or comma separated string of options (e.g. '1,3')" );
2782 }
2783 
2784 QString QgsProcessingEnumWidgetWrapper::parameterType() const
2785 {
2787 }
2788 
2789 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingEnumWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2790 {
2791  return new QgsProcessingEnumWidgetWrapper( parameter, type );
2792 }
2793 
2794 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingEnumWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2795 {
2796  return new QgsProcessingEnumParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2797 }
2798 
2799 //
2800 // QgsProcessingLayoutWidgetWrapper
2801 //
2802 
2803 QgsProcessingLayoutWidgetWrapper::QgsProcessingLayoutWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2804  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2805 {
2806 
2807 }
2808 
2809 QWidget *QgsProcessingLayoutWidgetWrapper::createWidget()
2810 {
2811  const QgsProcessingParameterLayout *layoutParam = dynamic_cast< const QgsProcessingParameterLayout *>( parameterDefinition() );
2812  switch ( type() )
2813  {
2816  {
2817  // combobox only for use outside modeler!
2818  mComboBox = new QgsLayoutComboBox( nullptr, widgetContext().project() ? widgetContext().project()->layoutManager() : nullptr );
2820  mComboBox->setAllowEmptyLayout( true );
2821  mComboBox->setFilters( QgsLayoutManagerProxyModel::FilterPrintLayouts );
2822 
2823  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2824  connect( mComboBox, &QgsLayoutComboBox::layoutChanged, this, [ = ]( QgsMasterLayoutInterface * )
2825  {
2826  emit widgetValueHasChanged( this );
2827  } );
2828  return mComboBox;
2829  }
2830 
2832  {
2833  mPlainComboBox = new QComboBox();
2834  mPlainComboBox->setEditable( true );
2835  mPlainComboBox->setToolTip( tr( "Name of an existing print layout" ) );
2836  if ( widgetContext().project() )
2837  {
2838  const QList< QgsPrintLayout * > layouts = widgetContext().project()->layoutManager()->printLayouts();
2839  for ( const QgsPrintLayout *layout : layouts )
2840  mPlainComboBox->addItem( layout->name() );
2841  }
2842 
2843  connect( mPlainComboBox, &QComboBox::currentTextChanged, this, [ = ]( const QString & )
2844  {
2845  emit widgetValueHasChanged( this );
2846  } );
2847  return mPlainComboBox;
2848  }
2849  }
2850  return nullptr;
2851 }
2852 
2853 void QgsProcessingLayoutWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2854 {
2855  if ( mComboBox )
2856  {
2857  if ( !value.isValid() )
2858  mComboBox->setCurrentLayout( nullptr );
2859  else
2860  {
2861  if ( QgsPrintLayout *l = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, context ) )
2862  mComboBox->setCurrentLayout( l );
2863  else
2864  mComboBox->setCurrentLayout( nullptr );
2865  }
2866  }
2867  else if ( mPlainComboBox )
2868  {
2869  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2870  mPlainComboBox->setCurrentText( v );
2871  }
2872 }
2873 
2874 QVariant QgsProcessingLayoutWidgetWrapper::widgetValue() const
2875 {
2876  if ( mComboBox )
2877  {
2878  const QgsMasterLayoutInterface *l = mComboBox->currentLayout();
2879  return l ? l->name() : QVariant();
2880  }
2881  else if ( mPlainComboBox )
2882  return mPlainComboBox->currentText().isEmpty() ? QVariant() : mPlainComboBox->currentText();
2883  else
2884  return QVariant();
2885 }
2886 
2887 void QgsProcessingLayoutWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
2888 {
2890  if ( mPlainComboBox && context.project() )
2891  {
2892  const QList< QgsPrintLayout * > layouts = widgetContext().project()->layoutManager()->printLayouts();
2893  for ( const QgsPrintLayout *layout : layouts )
2894  mPlainComboBox->addItem( layout->name() );
2895  }
2896 }
2897 
2898 QStringList QgsProcessingLayoutWidgetWrapper::compatibleParameterTypes() const
2899 {
2900  return QStringList()
2903 }
2904 
2905 QStringList QgsProcessingLayoutWidgetWrapper::compatibleOutputTypes() const
2906 {
2907  return QStringList()
2909 }
2910 
2911 QString QgsProcessingLayoutWidgetWrapper::modelerExpressionFormatString() const
2912 {
2913  return tr( "string representing the name of an existing print layout" );
2914 }
2915 
2916 QString QgsProcessingLayoutWidgetWrapper::parameterType() const
2917 {
2919 }
2920 
2921 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2922 {
2923  return new QgsProcessingLayoutWidgetWrapper( parameter, type );
2924 }
2925 
2926 
2927 
2928 
2929 //
2930 // QgsProcessingLayoutItemWidgetWrapper
2931 //
2932 
2933 
2934 QgsProcessingLayoutItemParameterDefinitionWidget::QgsProcessingLayoutItemParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2935  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2936 {
2937  QVBoxLayout *vlayout = new QVBoxLayout();
2938  vlayout->setContentsMargins( 0, 0, 0, 0 );
2939 
2940  vlayout->addWidget( new QLabel( tr( "Parent layout" ) ) );
2941 
2942  mParentLayoutComboBox = new QComboBox();
2943  QString initialParent;
2944  if ( const QgsProcessingParameterLayoutItem *itemParam = dynamic_cast<const QgsProcessingParameterLayoutItem *>( definition ) )
2945  initialParent = itemParam->parentLayoutParameterName();
2946 
2947  if ( auto *lModel = widgetContext.model() )
2948  {
2949  // populate combo box with other model input choices
2950  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
2951  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
2952  {
2953  if ( const QgsProcessingParameterLayout *definition = dynamic_cast< const QgsProcessingParameterLayout * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
2954  {
2955  mParentLayoutComboBox-> addItem( definition->description(), definition->name() );
2956  if ( !initialParent.isEmpty() && initialParent == definition->name() )
2957  {
2958  mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
2959  }
2960  }
2961  }
2962  }
2963 
2964  if ( mParentLayoutComboBox->count() == 0 && !initialParent.isEmpty() )
2965  {
2966  // if no parent candidates found, we just add the existing one as a placeholder
2967  mParentLayoutComboBox->addItem( initialParent, initialParent );
2968  mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
2969  }
2970 
2971  vlayout->addWidget( mParentLayoutComboBox );
2972  setLayout( vlayout );
2973 }
2974 QgsProcessingParameterDefinition *QgsProcessingLayoutItemParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2975 {
2976  auto param = std::make_unique< QgsProcessingParameterLayoutItem >( name, description, QVariant(), mParentLayoutComboBox->currentData().toString() );
2977  param->setFlags( flags );
2978  return param.release();
2979 }
2980 
2981 
2982 QgsProcessingLayoutItemWidgetWrapper::QgsProcessingLayoutItemWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2983  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2984 {
2985 
2986 }
2987 
2988 QWidget *QgsProcessingLayoutItemWidgetWrapper::createWidget()
2989 {
2990  const QgsProcessingParameterLayoutItem *layoutParam = dynamic_cast< const QgsProcessingParameterLayoutItem *>( parameterDefinition() );
2991  switch ( type() )
2992  {
2995  {
2996  // combobox only for use outside modeler!
2997  mComboBox = new QgsLayoutItemComboBox( nullptr, nullptr );
2999  mComboBox->setAllowEmptyItem( true );
3000  if ( layoutParam->itemType() >= 0 )
3001  mComboBox->setItemType( static_cast< QgsLayoutItemRegistry::ItemType >( layoutParam->itemType() ) );
3002 
3003  mComboBox->setToolTip( parameterDefinition()->toolTip() );
3004  connect( mComboBox, &QgsLayoutItemComboBox::itemChanged, this, [ = ]( QgsLayoutItem * )
3005  {
3006  emit widgetValueHasChanged( this );
3007  } );
3008  return mComboBox;
3009  }
3010 
3012  {
3013  mLineEdit = new QLineEdit();
3014  mLineEdit->setToolTip( tr( "UUID or ID of an existing print layout item" ) );
3015  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
3016  {
3017  emit widgetValueHasChanged( this );
3018  } );
3019  return mLineEdit;
3020  }
3021  }
3022  return nullptr;
3023 }
3024 
3025 void QgsProcessingLayoutItemWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
3026 {
3028  switch ( type() )
3029  {
3032  {
3033  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
3034  {
3035  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterLayoutItem * >( parameterDefinition() )->parentLayoutParameterName() )
3036  {
3037  setLayoutParameterValue( wrapper->parameterValue() );
3039  {
3040  setLayoutParameterValue( wrapper->parameterValue() );
3041  } );
3042  break;
3043  }
3044  }
3045  break;
3046  }
3047 
3049  break;
3050  }
3051 }
3052 
3053 void QgsProcessingLayoutItemWidgetWrapper::setLayoutParameterValue( const QVariant &value )
3054 {
3055  QgsPrintLayout *layout = nullptr;
3056 
3057  // evaluate value to layout
3058  QgsProcessingContext *context = nullptr;
3059  std::unique_ptr< QgsProcessingContext > tmpContext;
3060  if ( mProcessingContextGenerator )
3061  context = mProcessingContextGenerator->processingContext();
3062 
3063  if ( !context )
3064  {
3065  tmpContext = std::make_unique< QgsProcessingContext >();
3066  context = tmpContext.get();
3067  }
3068 
3069  layout = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, *context );
3070  setLayout( layout );
3071 }
3072 
3073 void QgsProcessingLayoutItemWidgetWrapper::setLayout( QgsPrintLayout *layout )
3074 {
3075  if ( mComboBox )
3076  mComboBox->setCurrentLayout( layout );
3077 }
3078 
3079 void QgsProcessingLayoutItemWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3080 {
3081  if ( mComboBox )
3082  {
3083  if ( !value.isValid() )
3084  mComboBox->setItem( nullptr );
3085  else
3086  {
3087  QgsLayoutItem *item = QgsProcessingParameters::parameterAsLayoutItem( parameterDefinition(), value, context, qobject_cast< QgsPrintLayout * >( mComboBox->currentLayout() ) );
3088  mComboBox->setItem( item );
3089  }
3090  }
3091  else if ( mLineEdit )
3092  {
3093  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3094  mLineEdit->setText( v );
3095  }
3096 }
3097 
3098 QVariant QgsProcessingLayoutItemWidgetWrapper::widgetValue() const
3099 {
3100  if ( mComboBox )
3101  {
3102  const QgsLayoutItem *i = mComboBox->currentItem();
3103  return i ? i->uuid() : QVariant();
3104  }
3105  else if ( mLineEdit )
3106  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3107  else
3108  return QVariant();
3109 }
3110 
3111 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleParameterTypes() const
3112 {
3113  return QStringList()
3116 }
3117 
3118 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleOutputTypes() const
3119 {
3120  return QStringList()
3122 }
3123 
3124 QString QgsProcessingLayoutItemWidgetWrapper::modelerExpressionFormatString() const
3125 {
3126  return tr( "string representing the UUID or ID of an existing print layout item" );
3127 }
3128 
3129 QString QgsProcessingLayoutItemWidgetWrapper::parameterType() const
3130 {
3132 }
3133 
3134 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutItemWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3135 {
3136  return new QgsProcessingLayoutItemWidgetWrapper( parameter, type );
3137 }
3138 
3139 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingLayoutItemWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3140 {
3141  return new QgsProcessingLayoutItemParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3142 }
3143 
3144 //
3145 // QgsProcessingPointMapTool
3146 //
3147 
3148 QgsProcessingPointMapTool::QgsProcessingPointMapTool( QgsMapCanvas *canvas )
3149  : QgsMapTool( canvas )
3150 {
3151  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::CapturePoint ) );
3152  mSnapIndicator.reset( new QgsSnapIndicator( canvas ) );
3153 }
3154 
3155 QgsProcessingPointMapTool::~QgsProcessingPointMapTool() = default;
3156 
3157 void QgsProcessingPointMapTool::deactivate()
3158 {
3159  mSnapIndicator->setMatch( QgsPointLocator::Match() );
3161 }
3162 
3163 void QgsProcessingPointMapTool::canvasMoveEvent( QgsMapMouseEvent *e )
3164 {
3165  e->snapPoint();
3166  mSnapIndicator->setMatch( e->mapPointMatch() );
3167 }
3168 
3169 void QgsProcessingPointMapTool::canvasPressEvent( QgsMapMouseEvent *e )
3170 {
3171  if ( e->button() == Qt::LeftButton )
3172  {
3173  QgsPointXY point = e->snapPoint();
3174  emit clicked( point );
3175  emit complete();
3176  }
3177 }
3178 
3179 void QgsProcessingPointMapTool::keyPressEvent( QKeyEvent *e )
3180 {
3181  if ( e->key() == Qt::Key_Escape )
3182  {
3183 
3184  // Override default shortcut management in MapCanvas
3185  e->ignore();
3186  emit complete();
3187  }
3188 }
3189 
3190 
3191 
3192 //
3193 // QgsProcessingPointPanel
3194 //
3195 
3196 QgsProcessingPointPanel::QgsProcessingPointPanel( QWidget *parent )
3197  : QWidget( parent )
3198 {
3199  QHBoxLayout *l = new QHBoxLayout();
3200  l->setContentsMargins( 0, 0, 0, 0 );
3201  mLineEdit = new QgsFilterLineEdit( );
3202  mLineEdit->setShowClearButton( false );
3203  l->addWidget( mLineEdit, 1 );
3204  mButton = new QToolButton();
3205  mButton->setText( QString( QChar( 0x2026 ) ) );
3206  l->addWidget( mButton );
3207  setLayout( l );
3208 
3209  connect( mLineEdit, &QLineEdit::textChanged, this, &QgsProcessingPointPanel::changed );
3210  connect( mButton, &QToolButton::clicked, this, &QgsProcessingPointPanel::selectOnCanvas );
3211  mButton->setVisible( false );
3212 }
3213 
3214 void QgsProcessingPointPanel::setMapCanvas( QgsMapCanvas *canvas )
3215 {
3216  mCanvas = canvas;
3217  mButton->setVisible( true );
3218 
3219  mCrs = canvas->mapSettings().destinationCrs();
3220  mTool = std::make_unique< QgsProcessingPointMapTool >( mCanvas );
3221  connect( mTool.get(), &QgsProcessingPointMapTool::clicked, this, &QgsProcessingPointPanel::updatePoint );
3222  connect( mTool.get(), &QgsProcessingPointMapTool::complete, this, &QgsProcessingPointPanel::pointPicked );
3223 }
3224 
3225 void QgsProcessingPointPanel::setAllowNull( bool allowNull )
3226 {
3227  mLineEdit->setShowClearButton( allowNull );
3228 }
3229 
3230 QVariant QgsProcessingPointPanel::value() const
3231 {
3232  return mLineEdit->showClearButton() && mLineEdit->text().trimmed().isEmpty() ? QVariant() : QVariant( mLineEdit->text() );
3233 }
3234 
3235 void QgsProcessingPointPanel::clear()
3236 {
3237  mLineEdit->clear();
3238 }
3239 
3240 void QgsProcessingPointPanel::setValue( const QgsPointXY &point, const QgsCoordinateReferenceSystem &crs )
3241 {
3242  QString newText = QStringLiteral( "%1,%2" )
3243  .arg( QString::number( point.x(), 'f' ),
3244  QString::number( point.y(), 'f' ) );
3245 
3246  mCrs = crs;
3247  if ( mCrs.isValid() )
3248  {
3249  newText += QStringLiteral( " [%1]" ).arg( mCrs.authid() );
3250  }
3251  mLineEdit->setText( newText );
3252 }
3253 
3254 void QgsProcessingPointPanel::selectOnCanvas()
3255 {
3256  if ( !mCanvas )
3257  return;
3258 
3259  mPrevTool = mCanvas->mapTool();
3260  mCanvas->setMapTool( mTool.get() );
3261 
3262  emit toggleDialogVisibility( false );
3263 }
3264 
3265 void QgsProcessingPointPanel::updatePoint( const QgsPointXY &point )
3266 {
3267  setValue( point, mCanvas->mapSettings().destinationCrs() );
3268 }
3269 
3270 void QgsProcessingPointPanel::pointPicked()
3271 {
3272  if ( !mCanvas )
3273  return;
3274 
3275  mCanvas->setMapTool( mPrevTool );
3276 
3277  emit toggleDialogVisibility( true );
3278 }
3279 
3280 
3281 
3282 //
3283 // QgsProcessingPointWidgetWrapper
3284 //
3285 
3286 QgsProcessingPointParameterDefinitionWidget::QgsProcessingPointParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3287  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3288 {
3289  QVBoxLayout *vlayout = new QVBoxLayout();
3290  vlayout->setContentsMargins( 0, 0, 0, 0 );
3291 
3292  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3293 
3294  mDefaultLineEdit = new QLineEdit();
3295  mDefaultLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
3296  mDefaultLineEdit->setPlaceholderText( tr( "Point as 'x,y'" ) );
3297  if ( const QgsProcessingParameterPoint *pointParam = dynamic_cast<const QgsProcessingParameterPoint *>( definition ) )
3298  {
3299  QgsPointXY point = QgsProcessingParameters::parameterAsPoint( pointParam, pointParam->defaultValueForGui(), context );
3300  mDefaultLineEdit->setText( QStringLiteral( "%1,%2" ).arg( QString::number( point.x(), 'f' ), QString::number( point.y(), 'f' ) ) );
3301  }
3302 
3303  vlayout->addWidget( mDefaultLineEdit );
3304  setLayout( vlayout );
3305 }
3306 
3307 QgsProcessingParameterDefinition *QgsProcessingPointParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3308 {
3309  auto param = std::make_unique< QgsProcessingParameterPoint >( name, description, mDefaultLineEdit->text() );
3310  param->setFlags( flags );
3311  return param.release();
3312 }
3313 
3314 QgsProcessingPointWidgetWrapper::QgsProcessingPointWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3315  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3316 {
3317 
3318 }
3319 
3320 QWidget *QgsProcessingPointWidgetWrapper::createWidget()
3321 {
3322  const QgsProcessingParameterPoint *pointParam = dynamic_cast< const QgsProcessingParameterPoint *>( parameterDefinition() );
3323  switch ( type() )
3324  {
3327  {
3328  mPanel = new QgsProcessingPointPanel( nullptr );
3329  if ( widgetContext().mapCanvas() )
3330  mPanel->setMapCanvas( widgetContext().mapCanvas() );
3331 
3333  mPanel->setAllowNull( true );
3334 
3335  mPanel->setToolTip( parameterDefinition()->toolTip() );
3336 
3337  connect( mPanel, &QgsProcessingPointPanel::changed, this, [ = ]
3338  {
3339  emit widgetValueHasChanged( this );
3340  } );
3341 
3342  if ( mDialog )
3343  setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
3344  return mPanel;
3345  }
3346 
3348  {
3349  mLineEdit = new QLineEdit();
3350  mLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
3351  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
3352  {
3353  emit widgetValueHasChanged( this );
3354  } );
3355  return mLineEdit;
3356  }
3357  }
3358  return nullptr;
3359 }
3360 
3361 void QgsProcessingPointWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
3362 {
3364  if ( mPanel && context.mapCanvas() )
3365  mPanel->setMapCanvas( context.mapCanvas() );
3366 }
3367 
3368 void QgsProcessingPointWidgetWrapper::setDialog( QDialog *dialog )
3369 {
3370  mDialog = dialog;
3371  if ( mPanel )
3372  {
3373  connect( mPanel, &QgsProcessingPointPanel::toggleDialogVisibility, mDialog, [ = ]( bool visible )
3374  {
3375  if ( !visible )
3376  mDialog->showMinimized();
3377  else
3378  {
3379  mDialog->showNormal();
3380  mDialog->raise();
3381  mDialog->activateWindow();
3382  }
3383  } );
3384  }
3386 }
3387 
3388 void QgsProcessingPointWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3389 {
3390  if ( mPanel )
3391  {
3392  if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
3393  mPanel->clear();
3394  else
3395  {
3396  QgsPointXY p = QgsProcessingParameters::parameterAsPoint( parameterDefinition(), value, context );
3397  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
3398  mPanel->setValue( p, crs );
3399  }
3400  }
3401  else if ( mLineEdit )
3402  {
3403  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3404  mLineEdit->setText( v );
3405  }
3406 }
3407 
3408 QVariant QgsProcessingPointWidgetWrapper::widgetValue() const
3409 {
3410  if ( mPanel )
3411  {
3412  return mPanel->value();
3413  }
3414  else if ( mLineEdit )
3415  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3416  else
3417  return QVariant();
3418 }
3419 
3420 QStringList QgsProcessingPointWidgetWrapper::compatibleParameterTypes() const
3421 {
3422  return QStringList()
3425 }
3426 
3427 QStringList QgsProcessingPointWidgetWrapper::compatibleOutputTypes() const
3428 {
3429  return QStringList()
3431 }
3432 
3433 QString QgsProcessingPointWidgetWrapper::modelerExpressionFormatString() const
3434 {
3435  return tr( "string of the format 'x,y' or a geometry value (centroid is used)" );
3436 }
3437 
3438 QString QgsProcessingPointWidgetWrapper::parameterType() const
3439 {
3441 }
3442 
3443 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3444 {
3445  return new QgsProcessingPointWidgetWrapper( parameter, type );
3446 }
3447 
3448 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3449 {
3450  return new QgsProcessingPointParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3451 }
3452 
3453 
3454 //
3455 // QgsProcessingGeometryWidgetWrapper
3456 //
3457 
3458 
3459 QgsProcessingGeometryParameterDefinitionWidget::QgsProcessingGeometryParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3460  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3461 {
3462  QVBoxLayout *vlayout = new QVBoxLayout();
3463  vlayout->setContentsMargins( 0, 0, 0, 0 );
3464 
3465  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3466 
3467  mDefaultLineEdit = new QLineEdit();
3468  mDefaultLineEdit->setToolTip( tr( "Geometry as WKT" ) );
3469  mDefaultLineEdit->setPlaceholderText( tr( "Geometry as WKT" ) );
3470  if ( const QgsProcessingParameterGeometry *geometryParam = dynamic_cast<const QgsProcessingParameterGeometry *>( definition ) )
3471  {
3472  QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( geometryParam, geometryParam->defaultValueForGui(), context );
3473  if ( !g.isNull() )
3474  mDefaultLineEdit->setText( g.asWkt() );
3475  }
3476 
3477  vlayout->addWidget( mDefaultLineEdit );
3478  setLayout( vlayout );
3479 }
3480 
3481 QgsProcessingParameterDefinition *QgsProcessingGeometryParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3482 {
3483  auto param = std::make_unique< QgsProcessingParameterGeometry >( name, description, mDefaultLineEdit->text() );
3484  param->setFlags( flags );
3485  return param.release();
3486 }
3487 
3488 QgsProcessingGeometryWidgetWrapper::QgsProcessingGeometryWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3489  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3490 {
3491 
3492 }
3493 
3494 QWidget *QgsProcessingGeometryWidgetWrapper::createWidget()
3495 {
3496  switch ( type() )
3497  {
3501  {
3502  mLineEdit = new QLineEdit();
3503  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
3504  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
3505  {
3506  emit widgetValueHasChanged( this );
3507  } );
3508  return mLineEdit;
3509  }
3510  }
3511  return nullptr;
3512 }
3513 
3514 void QgsProcessingGeometryWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3515 {
3516  if ( mLineEdit )
3517  {
3518  QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( parameterDefinition(), value, context );
3519  if ( !g.isNull() )
3520  mLineEdit->setText( g.asWkt() );
3521  else
3522  mLineEdit->clear();
3523  }
3524 }
3525 
3526 QVariant QgsProcessingGeometryWidgetWrapper::widgetValue() const
3527 {
3528  if ( mLineEdit )
3529  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3530  else
3531  return QVariant();
3532 }
3533 
3534 QStringList QgsProcessingGeometryWidgetWrapper::compatibleParameterTypes() const
3535 {
3536  return QStringList()
3541 }
3542 
3543 QStringList QgsProcessingGeometryWidgetWrapper::compatibleOutputTypes() const
3544 {
3545  return QStringList()
3547 }
3548 
3549 QString QgsProcessingGeometryWidgetWrapper::modelerExpressionFormatString() const
3550 {
3551  return tr( "string in the Well-Known-Text format or a geometry value" );
3552 }
3553 
3554 QString QgsProcessingGeometryWidgetWrapper::parameterType() const
3555 {
3557 }
3558 
3559 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingGeometryWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3560 {
3561  return new QgsProcessingGeometryWidgetWrapper( parameter, type );
3562 }
3563 
3564 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingGeometryWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3565 {
3566  return new QgsProcessingGeometryParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3567 }
3568 
3569 
3570 //
3571 // QgsProcessingColorWidgetWrapper
3572 //
3573 
3574 
3575 QgsProcessingColorParameterDefinitionWidget::QgsProcessingColorParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3576  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3577 {
3578  QVBoxLayout *vlayout = new QVBoxLayout();
3579  vlayout->setContentsMargins( 0, 0, 0, 0 );
3580 
3581  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3582 
3583  mDefaultColorButton = new QgsColorButton();
3584  mDefaultColorButton->setShowNull( true );
3585  mAllowOpacity = new QCheckBox( tr( "Allow opacity control" ) );
3586 
3587  if ( const QgsProcessingParameterColor *colorParam = dynamic_cast<const QgsProcessingParameterColor *>( definition ) )
3588  {
3589  const QColor c = QgsProcessingParameters::parameterAsColor( colorParam, colorParam->defaultValueForGui(), context );
3590  if ( !c.isValid() )
3591  mDefaultColorButton->setToNull();
3592  else
3593  mDefaultColorButton->setColor( c );
3594  mAllowOpacity->setChecked( colorParam->opacityEnabled() );
3595  }
3596  else
3597  {
3598  mDefaultColorButton->setToNull();
3599  mAllowOpacity->setChecked( true );
3600  }
3601 
3602  vlayout->addWidget( mDefaultColorButton );
3603  vlayout->addWidget( mAllowOpacity );
3604  setLayout( vlayout );
3605 }
3606 
3607 QgsProcessingParameterDefinition *QgsProcessingColorParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3608 {
3609  auto param = std::make_unique< QgsProcessingParameterColor >( name, description, mDefaultColorButton->color(), mAllowOpacity->isChecked() );
3610  param->setFlags( flags );
3611  return param.release();
3612 }
3613 
3614 QgsProcessingColorWidgetWrapper::QgsProcessingColorWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3615  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3616 {
3617 
3618 }
3619 
3620 QWidget *QgsProcessingColorWidgetWrapper::createWidget()
3621 {
3622  const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor *>( parameterDefinition() );
3623  switch ( type() )
3624  {
3628  {
3629  mColorButton = new QgsColorButton( nullptr );
3630  mColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
3631 
3633  mColorButton->setShowNull( true );
3634 
3635  mColorButton->setAllowOpacity( colorParam->opacityEnabled() );
3636  mColorButton->setToolTip( parameterDefinition()->toolTip() );
3637  mColorButton->setColorDialogTitle( parameterDefinition()->description() );
3638  if ( colorParam->defaultValueForGui().value< QColor >().isValid() )
3639  {
3640  mColorButton->setDefaultColor( colorParam->defaultValueForGui().value< QColor >() );
3641  }
3642 
3643  connect( mColorButton, &QgsColorButton::colorChanged, this, [ = ]
3644  {
3645  emit widgetValueHasChanged( this );
3646  } );
3647 
3648  return mColorButton;
3649  }
3650  }
3651  return nullptr;
3652 }
3653 
3654 void QgsProcessingColorWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3655 {
3656  if ( mColorButton )
3657  {
3658  if ( !value.isValid() ||
3659  ( value.type() == QVariant::String && value.toString().isEmpty() )
3660  || ( value.type() == QVariant::Color && !value.value< QColor >().isValid() ) )
3661  mColorButton->setToNull();
3662  else
3663  {
3664  const QColor c = QgsProcessingParameters::parameterAsColor( parameterDefinition(), value, context );
3665  if ( !c.isValid() && mColorButton->showNull() )
3666  mColorButton->setToNull();
3667  else
3668  mColorButton->setColor( c );
3669  }
3670  }
3671 }
3672 
3673 QVariant QgsProcessingColorWidgetWrapper::widgetValue() const
3674 {
3675  if ( mColorButton )
3676  return mColorButton->isNull() ? QVariant() : mColorButton->color();
3677  else
3678  return QVariant();
3679 }
3680 
3681 QStringList QgsProcessingColorWidgetWrapper::compatibleParameterTypes() const
3682 {
3683  return QStringList()
3686 }
3687 
3688 QStringList QgsProcessingColorWidgetWrapper::compatibleOutputTypes() const
3689 {
3690  return QStringList()
3692 }
3693 
3694 QString QgsProcessingColorWidgetWrapper::modelerExpressionFormatString() const
3695 {
3696  return tr( "color style string, e.g. #ff0000 or 255,0,0" );
3697 }
3698 
3699 QString QgsProcessingColorWidgetWrapper::parameterType() const
3700 {
3702 }
3703 
3704 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingColorWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3705 {
3706  return new QgsProcessingColorWidgetWrapper( parameter, type );
3707 }
3708 
3709 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingColorWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3710 {
3711  return new QgsProcessingColorParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3712 }
3713 
3714 
3715 //
3716 // QgsProcessingCoordinateOperationWidgetWrapper
3717 //
3718 
3719 QgsProcessingCoordinateOperationParameterDefinitionWidget::QgsProcessingCoordinateOperationParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3720  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3721 {
3722  QVBoxLayout *vlayout = new QVBoxLayout();
3723  vlayout->setContentsMargins( 0, 0, 0, 0 );
3724 
3725  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3726 
3727  mDefaultLineEdit = new QLineEdit();
3728  if ( const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
3729  mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( coordParam, coordParam->defaultValueForGui(), context ) );
3730  vlayout->addWidget( mDefaultLineEdit );
3731 
3732  mSourceParamComboBox = new QComboBox();
3733  mDestParamComboBox = new QComboBox();
3734  QString initialSource;
3735  QString initialDest;
3736  QgsCoordinateReferenceSystem sourceCrs;
3738  if ( const QgsProcessingParameterCoordinateOperation *itemParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
3739  {
3740  initialSource = itemParam->sourceCrsParameterName();
3741  initialDest = itemParam->destinationCrsParameterName();
3742  sourceCrs = QgsProcessingUtils::variantToCrs( itemParam->sourceCrs(), context );
3743  destCrs = QgsProcessingUtils::variantToCrs( itemParam->destinationCrs(), context );
3744  }
3745 
3746  mSourceParamComboBox->addItem( QString(), QString() );
3747  mDestParamComboBox->addItem( QString(), QString() );
3748  if ( auto *lModel = widgetContext.model() )
3749  {
3750  // populate combo box with other model input choices
3751  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
3752  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
3753  {
3754  if ( definition && it->parameterName() == definition->name() )
3755  continue;
3756 
3757  // TODO - we should probably filter this list?
3758  mSourceParamComboBox->addItem( it->parameterName(), it->parameterName() );
3759  mDestParamComboBox->addItem( it->parameterName(), it->parameterName() );
3760  if ( !initialSource.isEmpty() && initialSource == it->parameterName() )
3761  {
3762  mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
3763  }
3764  if ( !initialDest.isEmpty() && initialDest == it->parameterName() )
3765  {
3766  mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
3767  }
3768  }
3769  }
3770 
3771  if ( mSourceParamComboBox->count() == 1 && !initialSource.isEmpty() )
3772  {
3773  // if no source candidates found, we just add the existing one as a placeholder
3774  mSourceParamComboBox->addItem( initialSource, initialSource );
3775  mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
3776  }
3777  if ( mDestParamComboBox->count() == 1 && !initialDest.isEmpty() )
3778  {
3779  // if no dest candidates found, we just add the existing one as a placeholder
3780  mDestParamComboBox->addItem( initialDest, initialDest );
3781  mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
3782  }
3783 
3784  vlayout->addWidget( new QLabel( tr( "Source CRS parameter" ) ) );
3785  vlayout->addWidget( mSourceParamComboBox );
3786  vlayout->addWidget( new QLabel( tr( "Destination CRS parameter" ) ) );
3787  vlayout->addWidget( mDestParamComboBox );
3788 
3789  mStaticSourceWidget = new QgsProjectionSelectionWidget();
3790  mStaticSourceWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
3791  mStaticSourceWidget->setCrs( sourceCrs );
3792  mStaticDestWidget = new QgsProjectionSelectionWidget();
3793  mStaticDestWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
3794  mStaticDestWidget->setCrs( destCrs );
3795 
3796  vlayout->addWidget( new QLabel( tr( "Static source CRS" ) ) );
3797  vlayout->addWidget( mStaticSourceWidget );
3798  vlayout->addWidget( new QLabel( tr( "Static destination CRS" ) ) );
3799  vlayout->addWidget( mStaticDestWidget );
3800 
3801  setLayout( vlayout );
3802 }
3803 
3804 QgsProcessingParameterDefinition *QgsProcessingCoordinateOperationParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3805 {
3806  auto param = std::make_unique< QgsProcessingParameterCoordinateOperation >( name, description, mDefaultLineEdit->text(),
3807  mSourceParamComboBox->currentText(),
3808  mDestParamComboBox->currentText(),
3809  mStaticSourceWidget->crs().isValid() ? QVariant::fromValue( mStaticSourceWidget->crs() ) : QVariant(),
3810  mStaticDestWidget->crs().isValid() ? QVariant::fromValue( mStaticDestWidget->crs() ) : QVariant() );
3811  param->setFlags( flags );
3812  return param.release();
3813 }
3814 
3815 QgsProcessingCoordinateOperationWidgetWrapper::QgsProcessingCoordinateOperationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3816  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3817 {
3818 
3819 }
3820 
3821 QWidget *QgsProcessingCoordinateOperationWidgetWrapper::createWidget()
3822 {
3823  const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast< const QgsProcessingParameterCoordinateOperation *>( parameterDefinition() );
3825  mSourceCrs = QgsProcessingUtils::variantToCrs( coordParam->sourceCrs(), c );
3826  mDestCrs = QgsProcessingUtils::variantToCrs( coordParam->destinationCrs(), c );
3827  switch ( type() )
3828  {
3830  {
3831  mOperationWidget = new QgsCoordinateOperationWidget( nullptr );
3832  mOperationWidget->setShowMakeDefault( false );
3833  mOperationWidget->setShowFallbackOption( false );
3834  mOperationWidget->setToolTip( parameterDefinition()->toolTip() );
3835  mOperationWidget->setSourceCrs( mSourceCrs );
3836  mOperationWidget->setDestinationCrs( mDestCrs );
3837  mOperationWidget->setMapCanvas( mCanvas );
3838  if ( !coordParam->defaultValueForGui().toString().isEmpty() )
3839  {
3841  deets.proj = coordParam->defaultValueForGui().toString();
3842  mOperationWidget->setSelectedOperation( deets );
3843  }
3844 
3845  connect( mOperationWidget, &QgsCoordinateOperationWidget::operationChanged, this, [ = ]
3846  {
3847  emit widgetValueHasChanged( this );
3848  } );
3849 
3850  return mOperationWidget;
3851  }
3852 
3855  {
3856  mLineEdit = new QLineEdit();
3857  QHBoxLayout *layout = new QHBoxLayout();
3858  layout->addWidget( mLineEdit, 1 );
3859  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
3860  {
3861  emit widgetValueHasChanged( this );
3862  } );
3863 
3864  QToolButton *button = new QToolButton();
3865  button->setText( QString( QChar( 0x2026 ) ) );
3866  connect( button, &QToolButton::clicked, this, [ = ]
3867  {
3868  QgsDatumTransformDialog dlg( mSourceCrs, mDestCrs, false, false, false, qMakePair( -1, -1 ), button, Qt::WindowFlags(), mLineEdit->text(), mCanvas );
3869  if ( dlg.exec() )
3870  {
3871  mLineEdit->setText( dlg.selectedDatumTransform().proj );
3872  emit widgetValueHasChanged( this );
3873  }
3874  } );
3875  layout->addWidget( button );
3876 
3877  QWidget *w = new QWidget();
3878  layout->setContentsMargins( 0, 0, 0, 0 );
3879  w->setLayout( layout );
3880  return w;
3881  }
3882 
3883  }
3884  return nullptr;
3885 }
3886 
3887 void QgsProcessingCoordinateOperationWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
3888 {
3890  switch ( type() )
3891  {
3894  {
3895  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
3896  {
3897  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterCoordinateOperation * >( parameterDefinition() )->sourceCrsParameterName() )
3898  {
3899  setSourceCrsParameterValue( wrapper->parameterValue() );
3901  {
3902  setSourceCrsParameterValue( wrapper->parameterValue() );
3903  } );
3904  }
3905  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterCoordinateOperation * >( parameterDefinition() )->destinationCrsParameterName() )
3906  {
3907  setDestinationCrsParameterValue( wrapper->parameterValue() );
3909  {
3910  setDestinationCrsParameterValue( wrapper->parameterValue() );
3911  } );
3912  }
3913  }
3914  break;
3915  }
3916 
3918  break;
3919  }
3920 }
3921 
3922 void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
3923 {
3924  mCanvas = context.mapCanvas();
3925  if ( mOperationWidget )
3926  mOperationWidget->setMapCanvas( context.mapCanvas() );
3927 }
3928 
3929 void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
3930 {
3931  if ( mOperationWidget )
3932  {
3933  if ( !value.isValid() ||
3934  ( value.type() == QVariant::String ) )
3935  {
3937  deets.proj = value.toString();
3938  mOperationWidget->setSelectedOperation( deets );
3939  }
3940  }
3941  if ( mLineEdit )
3942  {
3943  if ( !value.isValid() ||
3944  ( value.type() == QVariant::String ) )
3945  {
3946  mLineEdit->setText( value.toString() );
3947  }
3948  }
3949 }
3950 
3951 QVariant QgsProcessingCoordinateOperationWidgetWrapper::widgetValue() const
3952 {
3953  if ( mOperationWidget )
3954  return mOperationWidget->selectedOperation().proj;
3955  else if ( mLineEdit )
3956  return mLineEdit->text();
3957  else
3958  return QVariant();
3959 }
3960 
3961 QStringList QgsProcessingCoordinateOperationWidgetWrapper::compatibleParameterTypes() const
3962 {
3963  return QStringList()
3966 }
3967 
3968 QStringList QgsProcessingCoordinateOperationWidgetWrapper::compatibleOutputTypes() const
3969 {
3970  return QStringList()
3972 }
3973 
3974 QString QgsProcessingCoordinateOperationWidgetWrapper::modelerExpressionFormatString() const
3975 {
3976  return tr( "Proj coordinate operation string, e.g. '+proj=pipeline +step +inv...'" );
3977 }
3978 
3979 void QgsProcessingCoordinateOperationWidgetWrapper::setSourceCrsParameterValue( const QVariant &value )
3980 {
3981  QgsProcessingContext *context = nullptr;
3982  std::unique_ptr< QgsProcessingContext > tmpContext;
3983  if ( mProcessingContextGenerator )
3984  context = mProcessingContextGenerator->processingContext();
3985 
3986  if ( !context )
3987  {
3988  tmpContext = std::make_unique< QgsProcessingContext >();
3989  context = tmpContext.get();
3990  }
3991 
3992  mSourceCrs = QgsProcessingUtils::variantToCrs( value, *context );
3993  if ( mOperationWidget )
3994  {
3995  mOperationWidget->setSourceCrs( mSourceCrs );
3996  mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
3997  }
3998 }
3999 
4000 void QgsProcessingCoordinateOperationWidgetWrapper::setDestinationCrsParameterValue( const QVariant &value )
4001 {
4002  QgsProcessingContext *context = nullptr;
4003  std::unique_ptr< QgsProcessingContext > tmpContext;
4004  if ( mProcessingContextGenerator )
4005  context = mProcessingContextGenerator->processingContext();
4006 
4007  if ( !context )
4008  {
4009  tmpContext = std::make_unique< QgsProcessingContext >();
4010  context = tmpContext.get();
4011  }
4012 
4013  mDestCrs = QgsProcessingUtils::variantToCrs( value, *context );
4014  if ( mOperationWidget )
4015  {
4016  mOperationWidget->setDestinationCrs( mDestCrs );
4017  mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
4018  }
4019 }
4020 
4021 QString QgsProcessingCoordinateOperationWidgetWrapper::parameterType() const
4022 {
4024 }
4025 
4026 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCoordinateOperationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4027 {
4028  return new QgsProcessingCoordinateOperationWidgetWrapper( parameter, type );
4029 }
4030 
4031 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingCoordinateOperationWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4032 {
4033  return new QgsProcessingCoordinateOperationParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4034 }
4035 
4036 
4037 
4038 //
4039 // QgsProcessingFieldPanelWidget
4040 //
4041 
4042 QgsProcessingFieldPanelWidget::QgsProcessingFieldPanelWidget( QWidget *parent, const QgsProcessingParameterField *param )
4043  : QWidget( parent )
4044  , mParam( param )
4045 {
4046  QHBoxLayout *hl = new QHBoxLayout();
4047  hl->setContentsMargins( 0, 0, 0, 0 );
4048 
4049  mLineEdit = new QLineEdit();
4050  mLineEdit->setEnabled( false );
4051  hl->addWidget( mLineEdit, 1 );
4052 
4053  mToolButton = new QToolButton();
4054  mToolButton->setText( QString( QChar( 0x2026 ) ) );
4055  hl->addWidget( mToolButton );
4056 
4057  setLayout( hl );
4058 
4059  if ( mParam )
4060  {
4061  mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
4062  }
4063 
4064  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingFieldPanelWidget::showDialog );
4065 }
4066 
4067 void QgsProcessingFieldPanelWidget::setFields( const QgsFields &fields )
4068 {
4069  mFields = fields;
4070 }
4071 
4072 void QgsProcessingFieldPanelWidget::setValue( const QVariant &value )
4073 {
4074  if ( value.isValid() )
4075  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
4076  else
4077  mValue.clear();
4078 
4079  updateSummaryText();
4080  emit changed();
4081 }
4082 
4083 void QgsProcessingFieldPanelWidget::showDialog()
4084 {
4085  QVariantList availableOptions;
4086  QStringList fieldNames;
4087  availableOptions.reserve( mFields.size() );
4088  for ( const QgsField &field : std::as_const( mFields ) )
4089  {
4090  availableOptions << field.name();
4091  }
4092 
4094  if ( panel && panel->dockMode() )
4095  {
4096  QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
4097  widget->setPanelTitle( mParam->description() );
4098 
4099  widget->setValueFormatter( []( const QVariant & v ) -> QString
4100  {
4101  return v.toString();
4102  } );
4103 
4104  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
4105  {
4106  setValue( widget->selectedOptions() );
4107  } );
4108  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
4109  panel->openPanel( widget );
4110  }
4111  else
4112  {
4113  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
4114 
4115  dlg.setValueFormatter( []( const QVariant & v ) -> QString
4116  {
4117  return v.toString();
4118  } );
4119  if ( dlg.exec() )
4120  {
4121  setValue( dlg.selectedOptions() );
4122  }
4123  }
4124 }
4125 
4126 void QgsProcessingFieldPanelWidget::updateSummaryText()
4127 {
4128  if ( mParam )
4129  mLineEdit->setText( tr( "%1 options selected" ).arg( mValue.count() ) );
4130 }
4131 
4132 
4133 //
4134 // QgsProcessingFieldWidgetWrapper
4135 //
4136 
4137 QgsProcessingFieldParameterDefinitionWidget::QgsProcessingFieldParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4138  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4139 {
4140  QVBoxLayout *vlayout = new QVBoxLayout();
4141  vlayout->setContentsMargins( 0, 0, 0, 0 );
4142 
4143  vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
4144  mParentLayerComboBox = new QComboBox();
4145 
4146  QString initialParent;
4147  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4148  initialParent = fieldParam->parentLayerParameterName();
4149 
4150  if ( auto *lModel = widgetContext.model() )
4151  {
4152  // populate combo box with other model input choices
4153  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
4154  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
4155  {
4156  if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast< const QgsProcessingParameterFeatureSource * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
4157  {
4158  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
4159  if ( !initialParent.isEmpty() && initialParent == definition->name() )
4160  {
4161  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4162  }
4163  }
4164  else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast< const QgsProcessingParameterVectorLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
4165  {
4166  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
4167  if ( !initialParent.isEmpty() && initialParent == definition->name() )
4168  {
4169  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4170  }
4171  }
4172  else if ( const QgsProcessingParameterMultipleLayers *definition = dynamic_cast< const QgsProcessingParameterMultipleLayers * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
4173  {
4174  if ( definition->layerType() == QgsProcessing::TypeVector )
4175  {
4176  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
4177  if ( !initialParent.isEmpty() && initialParent == definition->name() )
4178  {
4179  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4180  }
4181  }
4182  }
4183  }
4184  }
4185 
4186  if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
4187  {
4188  // if no parent candidates found, we just add the existing one as a placeholder
4189  mParentLayerComboBox->addItem( initialParent, initialParent );
4190  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4191  }
4192 
4193  vlayout->addWidget( mParentLayerComboBox );
4194 
4195  vlayout->addWidget( new QLabel( tr( "Allowed data type" ) ) );
4196  mDataTypeComboBox = new QComboBox();
4197  mDataTypeComboBox->addItem( tr( "Any" ), QgsProcessingParameterField::Any );
4198  mDataTypeComboBox->addItem( tr( "Number" ), QgsProcessingParameterField::Numeric );
4199  mDataTypeComboBox->addItem( tr( "String" ), QgsProcessingParameterField::String );
4200  mDataTypeComboBox->addItem( tr( "Date/time" ), QgsProcessingParameterField::DateTime );
4201  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4202  mDataTypeComboBox->setCurrentIndex( mDataTypeComboBox->findData( fieldParam->dataType() ) );
4203 
4204  vlayout->addWidget( mDataTypeComboBox );
4205 
4206  mAllowMultipleCheckBox = new QCheckBox( tr( "Accept multiple fields" ) );
4207  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4208  mAllowMultipleCheckBox->setChecked( fieldParam->allowMultiple() );
4209 
4210  vlayout->addWidget( mAllowMultipleCheckBox );
4211 
4212  mDefaultToAllCheckBox = new QCheckBox( tr( "Select all fields by default" ) );
4213  mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
4214  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4215  mDefaultToAllCheckBox->setChecked( fieldParam->defaultToAllFields() );
4216 
4217  vlayout->addWidget( mDefaultToAllCheckBox );
4218 
4219  connect( mAllowMultipleCheckBox, &QCheckBox::stateChanged, this, [ = ]
4220  {
4221  mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
4222  } );
4223 
4224  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4225 
4226  mDefaultLineEdit = new QLineEdit();
4227  mDefaultLineEdit->setToolTip( tr( "Default field name, or ; separated list of field names for multiple field parameters" ) );
4228  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4229  {
4230  const QStringList fields = QgsProcessingParameters::parameterAsFields( fieldParam, fieldParam->defaultValueForGui(), context );
4231  mDefaultLineEdit->setText( fields.join( ';' ) );
4232  }
4233  vlayout->addWidget( mDefaultLineEdit );
4234 
4235  setLayout( vlayout );
4236 }
4237 
4238 QgsProcessingParameterDefinition *QgsProcessingFieldParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4239 {
4240  QgsProcessingParameterField::DataType dataType = static_cast< QgsProcessingParameterField::DataType >( mDataTypeComboBox->currentData().toInt() );
4241 
4242  QVariant defaultValue;
4243  if ( !mDefaultLineEdit->text().trimmed().isEmpty() )
4244  {
4245  defaultValue = mDefaultLineEdit->text();
4246  }
4247  auto param = std::make_unique< QgsProcessingParameterField >( name, description, defaultValue, mParentLayerComboBox->currentData().toString(), dataType, mAllowMultipleCheckBox->isChecked(), false, mDefaultToAllCheckBox->isChecked() );
4248  param->setFlags( flags );
4249  return param.release();
4250 }
4251 
4252 QgsProcessingFieldWidgetWrapper::QgsProcessingFieldWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4253  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4254 {
4255 
4256 }
4257 
4258 QWidget *QgsProcessingFieldWidgetWrapper::createWidget()
4259 {
4260  const QgsProcessingParameterField *fieldParam = dynamic_cast< const QgsProcessingParameterField *>( parameterDefinition() );
4261  switch ( type() )
4262  {
4265  {
4266  if ( fieldParam->allowMultiple() )
4267  {
4268  mPanel = new QgsProcessingFieldPanelWidget( nullptr, fieldParam );
4269  mPanel->setToolTip( parameterDefinition()->toolTip() );
4270  connect( mPanel, &QgsProcessingFieldPanelWidget::changed, this, [ = ]
4271  {
4272  emit widgetValueHasChanged( this );
4273  } );
4274  return mPanel;
4275  }
4276  else
4277  {
4278  mComboBox = new QgsFieldComboBox();
4279  mComboBox->setAllowEmptyFieldName( fieldParam->flags() & QgsProcessingParameterDefinition::FlagOptional );
4280 
4281  if ( fieldParam->dataType() == QgsProcessingParameterField::Numeric )
4282  mComboBox->setFilters( QgsFieldProxyModel::Numeric );
4283  else if ( fieldParam->dataType() == QgsProcessingParameterField::String )
4284  mComboBox->setFilters( QgsFieldProxyModel::String );
4285  else if ( fieldParam->dataType() == QgsProcessingParameterField::DateTime )
4287 
4288  mComboBox->setToolTip( parameterDefinition()->toolTip() );
4289  connect( mComboBox, &QgsFieldComboBox::fieldChanged, this, [ = ]( const QString & )
4290  {
4291  emit widgetValueHasChanged( this );
4292  } );
4293  return mComboBox;
4294  }
4295  }
4296 
4298  {
4299  mLineEdit = new QLineEdit();
4300  mLineEdit->setToolTip( QObject::tr( "Name of field (separate field names with ; for multiple field parameters)" ) );
4301  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
4302  {
4303  emit widgetValueHasChanged( this );
4304  } );
4305  return mLineEdit;
4306  }
4307 
4308  }
4309  return nullptr;
4310 }
4311 
4312 void QgsProcessingFieldWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
4313 {
4315  switch ( type() )
4316  {
4319  {
4320  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
4321  {
4322  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterField * >( parameterDefinition() )->parentLayerParameterName() )
4323  {
4324  setParentLayerWrapperValue( wrapper );
4326  {
4327  setParentLayerWrapperValue( wrapper );
4328  } );
4329  break;
4330  }
4331  }
4332  break;
4333  }
4334 
4336  break;
4337  }
4338 }
4339 
4340 void QgsProcessingFieldWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
4341 {
4342  // evaluate value to layer
4343  QgsProcessingContext *context = nullptr;
4344  std::unique_ptr< QgsProcessingContext > tmpContext;
4345  if ( mProcessingContextGenerator )
4346  context = mProcessingContextGenerator->processingContext();
4347 
4348  if ( !context )
4349  {
4350  tmpContext = std::make_unique< QgsProcessingContext >();
4351  context = tmpContext.get();
4352  }
4353 
4354  QVariant value = parentWrapper->parameterValue();
4355 
4356  if ( value.canConvert<QgsProcessingFeatureSourceDefinition>() )
4357  {
4358  // input is a QgsProcessingFeatureSourceDefinition - source from it.
4359  // this is normally discouraged, and algorithms should NEVER do this -- but in this case we can make
4360  // certain assumptions due to the fact that we're calling this outside of algorithm/model execution and all sources
4361  // should be real map layers at this stage
4362  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
4363  value = fromVar.source;
4364  }
4365 
4366  bool valueSet = false;
4367  const QList< QgsMapLayer * > layers = QgsProcessingParameters::parameterAsLayerList( parentWrapper->parameterDefinition(), value, *context );
4368 
4369  // several layers, populate with intersection of layers fields
4370  if ( layers.count() > 1 )
4371  {
4372  QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layers.at( 0 ) );
4373  QgsFields fields = vlayer && vlayer->isValid() ? vlayer->fields() : QgsFields();
4374  const QList< QgsMapLayer * > remainingLayers = layers.mid( 1 );
4375  for ( QgsMapLayer *layer : remainingLayers )
4376  {
4377  if ( fields.isEmpty() )
4378  break;
4379 
4380  QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layer );
4381  if ( !vlayer || !vlayer->isValid() )
4382  {
4383  fields = QgsFields();
4384  break;
4385  }
4386 
4387  for ( int fieldIdx = fields.count() - 1; fieldIdx >= 0; fieldIdx-- )
4388  {
4389  if ( vlayer->fields().lookupField( fields.at( fieldIdx ).name() ) < 0 )
4390  fields.remove( fieldIdx );
4391  }
4392  }
4393 
4394  if ( mComboBox )
4395  mComboBox->setFields( fields );
4396  else if ( mPanel )
4397  mPanel->setFields( filterFields( fields ) );
4398 
4399  valueSet = true;
4400  }
4401 
4402  // only one layer
4403  if ( !valueSet && !layers.isEmpty() && layers.at( 0 )->isValid() )
4404  {
4405  QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( layers.at( 0 ) );
4406 
4407  // need to grab ownership of layer if required - otherwise layer may be deleted when context
4408  // goes out of scope
4409  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
4410  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::VectorLayer )
4411  {
4412  mParentLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
4413  layer = mParentLayer.get();
4414  }
4415  else
4416  {
4417  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
4418  }
4419 
4420  if ( mComboBox )
4421  mComboBox->setLayer( layer );
4422  else if ( mPanel )
4423  mPanel->setFields( filterFields( layer->fields() ) );
4424 
4425  valueSet = true;
4426  }
4427 
4428  if ( !valueSet )
4429  {
4430  std::unique_ptr< QgsProcessingFeatureSource > source( QgsProcessingParameters::parameterAsSource( parentWrapper->parameterDefinition(), value, *context ) );
4431  if ( source )
4432  {
4433  const QgsFields fields = source->fields();
4434  if ( mComboBox )
4435  mComboBox->setFields( fields );
4436  else if ( mPanel )
4437  mPanel->setFields( filterFields( fields ) );
4438 
4439  valueSet = true;
4440  }
4441  }
4442 
4443  if ( !valueSet )
4444  {
4445  if ( mComboBox )
4446  mComboBox->setLayer( nullptr );
4447  else if ( mPanel )
4448  mPanel->setFields( QgsFields() );
4449 
4450  if ( value.isValid() && widgetContext().messageBar() )
4451  {
4452  widgetContext().messageBar()->clearWidgets();
4453  widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent field could not be populated" ),
4454  Qgis::MessageLevel::Info );
4455  }
4456  return;
4457  }
4458 
4459  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4460  if ( mPanel && fieldParam->defaultToAllFields() )
4461  {
4462  QVariantList val;
4463  val.reserve( mPanel->fields().size() );
4464  for ( const QgsField &field : mPanel->fields() )
4465  val << field.name();
4466  setWidgetValue( val, *context );
4467  }
4468  else if ( fieldParam->defaultValueForGui().isValid() )
4469  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
4470 }
4471 
4472 void QgsProcessingFieldWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4473 {
4474  if ( mComboBox )
4475  {
4476  if ( !value.isValid() )
4477  mComboBox->setField( QString() );
4478  else
4479  {
4480  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
4481  mComboBox->setField( v );
4482  }
4483  }
4484  else if ( mPanel )
4485  {
4486  QVariantList opts;
4487  if ( value.isValid() )
4488  {
4489  const QStringList v = QgsProcessingParameters::parameterAsFields( parameterDefinition(), value, context );
4490  opts.reserve( v.size() );
4491  for ( const QString &i : v )
4492  opts << i;
4493  }
4494  if ( mPanel )
4495  mPanel->setValue( opts );
4496  }
4497  else if ( mLineEdit )
4498  {
4499  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4500  if ( fieldParam->allowMultiple() )
4501  {
4502  const QStringList v = QgsProcessingParameters::parameterAsFields( parameterDefinition(), value, context );
4503  mLineEdit->setText( v.join( ';' ) );
4504  }
4505  else
4506  {
4507  mLineEdit->setText( QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context ) );
4508  }
4509  }
4510 }
4511 
4512 QVariant QgsProcessingFieldWidgetWrapper::widgetValue() const
4513 {
4514  if ( mComboBox )
4515  return mComboBox->currentField();
4516  else if ( mPanel )
4517  return mPanel->value();
4518  else if ( mLineEdit )
4519  {
4520  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4521  if ( fieldParam->allowMultiple() )
4522  {
4523  return mLineEdit->text().split( ';' );
4524  }
4525  else
4526  return mLineEdit->text();
4527  }
4528  else
4529  return QVariant();
4530 }
4531 
4532 QStringList QgsProcessingFieldWidgetWrapper::compatibleParameterTypes() const
4533 {
4534  return QStringList()
4537 }
4538 
4539 QStringList QgsProcessingFieldWidgetWrapper::compatibleOutputTypes() const
4540 {
4541  return QStringList()
4543 }
4544 
4545 QString QgsProcessingFieldWidgetWrapper::modelerExpressionFormatString() const
4546 {
4547  return tr( "selected field names as an array of names, or semicolon separated string of options (e.g. 'fid;place_name')" );
4548 }
4549 
4550 const QgsVectorLayer *QgsProcessingFieldWidgetWrapper::linkedVectorLayer() const
4551 {
4552  if ( mComboBox && mComboBox->layer() )
4553  return mComboBox->layer();
4554 
4556 }
4557 
4558 QgsFields QgsProcessingFieldWidgetWrapper::filterFields( const QgsFields &fields ) const
4559 {
4560  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4561  QgsFields res;
4562  for ( const QgsField &f : fields )
4563  {
4564  switch ( fieldParam->dataType() )
4565  {
4567  res.append( f );
4568  break;
4569 
4571  if ( f.isNumeric() )
4572  res.append( f );
4573  break;
4574 
4576  if ( f.type() == QVariant::String )
4577  res.append( f );
4578  break;
4579 
4581  if ( f.type() == QVariant::Date || f.type() == QVariant::Time || f.type() == QVariant::DateTime )
4582  res.append( f );
4583  break;
4584  }
4585  }
4586 
4587  return res;
4588 }
4589 
4590 QString QgsProcessingFieldWidgetWrapper::parameterType() const
4591 {
4593 }
4594 
4595 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFieldWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4596 {
4597  return new QgsProcessingFieldWidgetWrapper( parameter, type );
4598 }
4599 
4600 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFieldWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4601 {
4602  return new QgsProcessingFieldParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4603 }
4604 
4605 //
4606 // QgsProcessingMapThemeWidgetWrapper
4607 //
4608 
4609 
4610 QgsProcessingMapThemeParameterDefinitionWidget::QgsProcessingMapThemeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4611  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4612 {
4613  QVBoxLayout *vlayout = new QVBoxLayout();
4614  vlayout->setContentsMargins( 0, 0, 0, 0 );
4615 
4616  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4617 
4618  mDefaultComboBox = new QComboBox();
4619  mDefaultComboBox->addItem( QString(), QVariant( -1 ) );
4620 
4621  const QStringList mapThemes = widgetContext.project() ? widgetContext.project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
4622  for ( const QString &theme : mapThemes )
4623  {
4624  mDefaultComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
4625  }
4626  mDefaultComboBox->setEditable( true );
4627 
4628  if ( const QgsProcessingParameterMapTheme *themeParam = dynamic_cast<const QgsProcessingParameterMapTheme *>( definition ) )
4629  {
4630  if ( themeParam->defaultValueForGui().isValid() )
4631  mDefaultComboBox->setCurrentText( QgsProcessingParameters::parameterAsString( themeParam, themeParam->defaultValueForGui(), context ) );
4632  else
4633  mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
4634  }
4635  else
4636  mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
4637 
4638  vlayout->addWidget( mDefaultComboBox );
4639 
4640  setLayout( vlayout );
4641 }
4642 
4643 QgsProcessingParameterDefinition *QgsProcessingMapThemeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4644 {
4645  QVariant defaultVal;
4646  if ( mDefaultComboBox->currentText().isEmpty() )
4647  defaultVal = QVariant();
4648  else
4649  defaultVal = mDefaultComboBox->currentText();
4650  auto param = std::make_unique< QgsProcessingParameterMapTheme>( name, description, defaultVal );
4651  param->setFlags( flags );
4652  return param.release();
4653 }
4654 
4655 
4656 QgsProcessingMapThemeWidgetWrapper::QgsProcessingMapThemeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4657  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4658 {
4659 
4660 }
4661 
4662 QWidget *QgsProcessingMapThemeWidgetWrapper::createWidget()
4663 {
4664  const QgsProcessingParameterMapTheme *themeParam = dynamic_cast< const QgsProcessingParameterMapTheme *>( parameterDefinition() );
4665 
4666  mComboBox = new QComboBox();
4667 
4669  mComboBox->addItem( tr( "[Not selected]" ), QVariant( -1 ) );
4670 
4671  const QStringList mapThemes = widgetContext().project() ? widgetContext().project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
4672  for ( const QString &theme : mapThemes )
4673  {
4674  mComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
4675  }
4676 
4677  switch ( type() )
4678  {
4681  break;
4682 
4684  mComboBox->setEditable( true );
4685  break;
4686  }
4687 
4688  mComboBox->setToolTip( parameterDefinition()->toolTip() );
4689  connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
4690  {
4691  emit widgetValueHasChanged( this );
4692  } );
4693 
4694  return mComboBox;
4695 }
4696 
4697 void QgsProcessingMapThemeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4698 {
4699  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
4700 
4701  if ( !value.isValid() )
4702  mComboBox->setCurrentIndex( mComboBox->findData( QVariant( -1 ) ) );
4703  else
4704  {
4705  if ( mComboBox->isEditable() && mComboBox->findData( v ) == -1 )
4706  {
4707  const QString prev = mComboBox->currentText();
4708  mComboBox->setCurrentText( v );
4709  if ( prev != v )
4710  emit widgetValueHasChanged( this );
4711  }
4712  else
4713  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
4714  }
4715 }
4716 
4717 QVariant QgsProcessingMapThemeWidgetWrapper::widgetValue() const
4718 {
4719  if ( mComboBox )
4720  return mComboBox->currentData().toInt() == -1 ? QVariant() :
4721  !mComboBox->currentData().isValid() && mComboBox->isEditable() ? mComboBox->currentText().isEmpty() ? QVariant() : QVariant( mComboBox->currentText() )
4722  : mComboBox->currentData();
4723  else
4724  return QVariant();
4725 }
4726 
4727 QStringList QgsProcessingMapThemeWidgetWrapper::compatibleParameterTypes() const
4728 {
4729  return QStringList()
4732 }
4733 
4734 QStringList QgsProcessingMapThemeWidgetWrapper::compatibleOutputTypes() const
4735 {
4736  return QStringList()
4738 }
4739 
4740 QString QgsProcessingMapThemeWidgetWrapper::modelerExpressionFormatString() const
4741 {
4742  return tr( "map theme as a string value (e.g. 'base maps')" );
4743 }
4744 
4745 QString QgsProcessingMapThemeWidgetWrapper::parameterType() const
4746 {
4748 }
4749 
4750 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapThemeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4751 {
4752  return new QgsProcessingMapThemeWidgetWrapper( parameter, type );
4753 }
4754 
4755 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapThemeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4756 {
4757  return new QgsProcessingMapThemeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4758 }
4759 
4760 
4761 
4762 //
4763 // QgsProcessingDateTimeWidgetWrapper
4764 //
4765 
4766 
4767 QgsProcessingDateTimeParameterDefinitionWidget::QgsProcessingDateTimeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4768  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4769 {
4770  QVBoxLayout *vlayout = new QVBoxLayout();
4771  vlayout->setContentsMargins( 0, 0, 0, 0 );
4772 
4773  vlayout->addWidget( new QLabel( tr( "Type" ) ) );
4774 
4775  mTypeComboBox = new QComboBox();
4776  mTypeComboBox->addItem( tr( "Date and Time" ), QgsProcessingParameterDateTime::DateTime );
4777  mTypeComboBox->addItem( tr( "Date" ), QgsProcessingParameterDateTime::Date );
4778  mTypeComboBox->addItem( tr( "Time" ), QgsProcessingParameterDateTime::Time );
4779  if ( const QgsProcessingParameterDateTime *datetimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( definition ) )
4780  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( datetimeParam->dataType() ) );
4781  else
4782  mTypeComboBox->setCurrentIndex( 0 );
4783  vlayout->addWidget( mTypeComboBox );
4784 
4785  setLayout( vlayout );
4786 }
4787 
4788 QgsProcessingParameterDefinition *QgsProcessingDateTimeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4789 {
4790  auto param = std::make_unique< QgsProcessingParameterDateTime >( name, description );
4791  param->setDataType( static_cast< QgsProcessingParameterDateTime::Type >( mTypeComboBox->currentData().toInt() ) );
4792  param->setFlags( flags );
4793  return param.release();
4794 }
4795 
4796 
4797 QgsProcessingDateTimeWidgetWrapper::QgsProcessingDateTimeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4798  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4799 {
4800 
4801 }
4802 
4803 QWidget *QgsProcessingDateTimeWidgetWrapper::createWidget()
4804 {
4805  const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast< const QgsProcessingParameterDateTime *>( parameterDefinition() );
4806 
4807  QgsDateTimeEdit *widget = nullptr;
4808  switch ( dateTimeParam->dataType() )
4809  {
4811  mDateTimeEdit = new QgsDateTimeEdit();
4812  widget = mDateTimeEdit;
4813  break;
4814 
4816  mDateEdit = new QgsDateEdit();
4817  widget = mDateEdit;
4818  break;
4819 
4821  mTimeEdit = new QgsTimeEdit();
4822  widget = mTimeEdit;
4823  break;
4824  }
4825 
4826  if ( dateTimeParam->flags() & QgsProcessingParameterDefinition::FlagOptional )
4827  {
4828  widget->setNullRepresentation( tr( "[Not selected]" ) );
4829  widget->setAllowNull( true );
4830  }
4831  else
4832  {
4833  widget->setAllowNull( false );
4834  }
4835  widget->setToolTip( parameterDefinition()->toolTip() );
4836 
4837  if ( mDateTimeEdit )
4838  {
4839  connect( mDateTimeEdit, &QgsDateTimeEdit::valueChanged, this, [ = ]( const QDateTime & )
4840  {
4841  emit widgetValueHasChanged( this );
4842  } );
4843  }
4844  else if ( mDateEdit )
4845  {
4846  connect( mDateEdit, &QgsDateEdit::dateValueChanged, this, [ = ]( const QDate & )
4847  {
4848  emit widgetValueHasChanged( this );
4849  } );
4850  }
4851  else if ( mTimeEdit )
4852  {
4853  connect( mTimeEdit, &QgsTimeEdit::timeValueChanged, this, [ = ]( const QTime & )
4854  {
4855  emit widgetValueHasChanged( this );
4856  } );
4857  }
4858 
4859  return widget;
4860 }
4861 
4862 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDateTimeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4863 {
4864  return new QgsProcessingDateTimeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4865 }
4866 
4867 void QgsProcessingDateTimeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4868 {
4869  if ( mDateTimeEdit )
4870  {
4871  mDateTimeEdit->setDateTime( QgsProcessingParameters::parameterAsDateTime( parameterDefinition(), value, context ) );
4872  }
4873  else if ( mDateEdit )
4874  {
4875  mDateEdit->setDate( QgsProcessingParameters::parameterAsDate( parameterDefinition(), value, context ) );
4876  }
4877  else if ( mTimeEdit )
4878  {
4879  mTimeEdit->setTime( QgsProcessingParameters::parameterAsTime( parameterDefinition(), value, context ) );
4880  }
4881 }
4882 
4883 QVariant QgsProcessingDateTimeWidgetWrapper::widgetValue() const
4884 {
4885  if ( mDateTimeEdit )
4886  return !mDateTimeEdit->dateTime().isNull() && mDateTimeEdit->dateTime().isValid() ? QVariant( mDateTimeEdit->dateTime() ) : QVariant();
4887  else if ( mDateEdit )
4888  return !mDateEdit->date().isNull() && mDateEdit->date().isValid() ? QVariant( mDateEdit->date() ) : QVariant();
4889  else if ( mTimeEdit )
4890  return !mTimeEdit->time().isNull() && mTimeEdit->time().isValid() ? QVariant( mTimeEdit->time() ) : QVariant();
4891  else
4892  return QVariant();
4893 }
4894 
4895 QStringList QgsProcessingDateTimeWidgetWrapper::compatibleParameterTypes() const
4896 {
4897  return QStringList()
4900 }
4901 
4902 QStringList QgsProcessingDateTimeWidgetWrapper::compatibleOutputTypes() const
4903 {
4904  return QStringList()
4906 }
4907 
4908 QString QgsProcessingDateTimeWidgetWrapper::modelerExpressionFormatString() const
4909 {
4910  const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast< const QgsProcessingParameterDateTime *>( parameterDefinition() );
4911  if ( dateTimeParam )
4912  {
4913  switch ( dateTimeParam->dataType() )
4914  {
4916  return tr( "datetime value, or a ISO string representation of a datetime" );
4917 
4919  return tr( "date value, or a ISO string representation of a date" );
4920 
4922  return tr( "time value, or a ISO string representation of a time" );
4923  }
4924  }
4925  return QString();
4926 }
4927 
4928 QString QgsProcessingDateTimeWidgetWrapper::parameterType() const
4929 {
4931 }
4932 
4933 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDateTimeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4934 {
4935  return new QgsProcessingDateTimeWidgetWrapper( parameter, type );
4936 }
4937 
4938 
4939 
4940 //
4941 // QgsProcessingProviderConnectionWidgetWrapper
4942 //
4943 
4944 QgsProcessingProviderConnectionParameterDefinitionWidget::QgsProcessingProviderConnectionParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4945  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4946 {
4947  const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast< const QgsProcessingParameterProviderConnection *>( definition );
4948 
4949  QVBoxLayout *vlayout = new QVBoxLayout();
4950  vlayout->setContentsMargins( 0, 0, 0, 0 );
4951 
4952  vlayout->addWidget( new QLabel( tr( "Provider" ) ) );
4953  mProviderComboBox = new QComboBox();
4954  mProviderComboBox->addItem( QObject::tr( "Postgres" ), QStringLiteral( "postgres" ) );
4955  mProviderComboBox->addItem( QObject::tr( "GeoPackage" ), QStringLiteral( "ogr" ) );
4956  mProviderComboBox->addItem( QObject::tr( "Spatialite" ), QStringLiteral( "spatialite" ) );
4957 
4958  vlayout->addWidget( mProviderComboBox );
4959 
4960  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4961 
4962  mDefaultEdit = new QLineEdit();
4963  vlayout->addWidget( mDefaultEdit );
4964  setLayout( vlayout );
4965 
4966  if ( connectionParam )
4967  {
4968  mProviderComboBox->setCurrentIndex( mProviderComboBox->findData( connectionParam->providerId() ) );
4969  mDefaultEdit->setText( connectionParam->defaultValueForGui().toString() );
4970  }
4971 }
4972 
4973 QgsProcessingParameterDefinition *QgsProcessingProviderConnectionParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4974 {
4975  QVariant defaultVal;
4976  if ( mDefaultEdit->text().isEmpty() )
4977  defaultVal = QVariant();
4978  else
4979  defaultVal = mDefaultEdit->text();
4980  auto param = std::make_unique< QgsProcessingParameterProviderConnection>( name, description, mProviderComboBox->currentData().toString(), defaultVal );
4981  param->setFlags( flags );
4982  return param.release();
4983 }
4984 
4985 
4986 QgsProcessingProviderConnectionWidgetWrapper::QgsProcessingProviderConnectionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4987  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4988 {
4989 
4990 }
4991 
4992 QWidget *QgsProcessingProviderConnectionWidgetWrapper::createWidget()
4993 {
4994  const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast< const QgsProcessingParameterProviderConnection *>( parameterDefinition() );
4995 
4996  mProviderComboBox = new QgsProviderConnectionComboBox( connectionParam->providerId() );
4997  if ( connectionParam->flags() & QgsProcessingParameterDefinition::FlagOptional )
4998  mProviderComboBox->setAllowEmptyConnection( true );
4999 
5000  switch ( type() )
5001  {
5004  break;
5006  mProviderComboBox->setEditable( true );
5007  break;
5008  }
5009 
5010  mProviderComboBox->setToolTip( parameterDefinition()->toolTip() );
5011  connect( mProviderComboBox, &QgsProviderConnectionComboBox::currentTextChanged, this, [ = ]( const QString & )
5012  {
5013  if ( mBlockSignals )
5014  return;
5015 
5016  emit widgetValueHasChanged( this );
5017  } );
5018 
5019  return mProviderComboBox;
5020 }
5021 
5022 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingProviderConnectionWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5023 {
5024  return new QgsProcessingProviderConnectionParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5025 }
5026 
5027 void QgsProcessingProviderConnectionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5028 {
5029  const QString v = QgsProcessingParameters::parameterAsConnectionName( parameterDefinition(), value, context );
5030 
5031  if ( !value.isValid() )
5032  mProviderComboBox->setCurrentIndex( -1 );
5033  else
5034  {
5035  if ( mProviderComboBox->isEditable() )
5036  {
5037  const QString prev = mProviderComboBox->currentText();
5038  mBlockSignals++;
5039  mProviderComboBox->setConnection( v );
5040  mProviderComboBox->setCurrentText( v );
5041 
5042  mBlockSignals--;
5043  if ( prev != v )
5044  emit widgetValueHasChanged( this );
5045  }
5046  else
5047  mProviderComboBox->setConnection( v );
5048  }
5049 }
5050 
5051 QVariant QgsProcessingProviderConnectionWidgetWrapper::widgetValue() const
5052 {
5053  if ( mProviderComboBox )
5054  if ( mProviderComboBox->isEditable() )
5055  return mProviderComboBox->currentText().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentText() );
5056  else
5057  return mProviderComboBox->currentConnection().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentConnection() );
5058  else
5059  return QVariant();
5060 }
5061 
5062 QStringList QgsProcessingProviderConnectionWidgetWrapper::compatibleParameterTypes() const
5063 {
5064  return QStringList()
5068 }
5069 
5070 QStringList QgsProcessingProviderConnectionWidgetWrapper::compatibleOutputTypes() const
5071 {
5072  return QStringList()
5074 }
5075 
5076 QString QgsProcessingProviderConnectionWidgetWrapper::modelerExpressionFormatString() const
5077 {
5078  return tr( "connection name as a string value" );
5079 }
5080 
5081 QString QgsProcessingProviderConnectionWidgetWrapper::parameterType() const
5082 {
5084 }
5085 
5086 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingProviderConnectionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5087 {
5088  return new QgsProcessingProviderConnectionWidgetWrapper( parameter, type );
5089 }
5090 
5091 
5092 
5093 
5094 //
5095 // QgsProcessingDatabaseSchemaWidgetWrapper
5096 //
5097 
5098 QgsProcessingDatabaseSchemaParameterDefinitionWidget::QgsProcessingDatabaseSchemaParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5099  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5100 {
5101  const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast< const QgsProcessingParameterDatabaseSchema *>( definition );
5102 
5103  QVBoxLayout *vlayout = new QVBoxLayout();
5104  vlayout->setContentsMargins( 0, 0, 0, 0 );
5105 
5106  mConnectionParamComboBox = new QComboBox();
5107  QString initialConnection;
5108  if ( schemaParam )
5109  {
5110  initialConnection = schemaParam->parentConnectionParameterName();
5111  }
5112 
5113  if ( auto *lModel = widgetContext.model() )
5114  {
5115  // populate combo box with other model input choices
5116  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5117  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5118  {
5119  if ( definition && it->parameterName() == definition->name() )
5120  continue;
5121 
5122  if ( !dynamic_cast< const QgsProcessingParameterProviderConnection * >( lModel->parameterDefinition( it->parameterName() ) ) )
5123  continue;
5124 
5125  mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5126  if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5127  {
5128  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5129  }
5130  }
5131  }
5132 
5133  if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5134  {
5135  // if no candidates found, we just add the existing one as a placeholder
5136  mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5137  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5138  }
5139 
5140  vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
5141  vlayout->addWidget( mConnectionParamComboBox );
5142 
5143  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5144 
5145  mDefaultEdit = new QLineEdit();
5146  vlayout->addWidget( mDefaultEdit );
5147  setLayout( vlayout );
5148 
5149  if ( schemaParam )
5150  {
5151  mDefaultEdit->setText( schemaParam->defaultValueForGui().toString() );
5152  }
5153 }
5154 
5155 QgsProcessingParameterDefinition *QgsProcessingDatabaseSchemaParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5156 {
5157  QVariant defaultVal;
5158  if ( mDefaultEdit->text().isEmpty() )
5159  defaultVal = QVariant();
5160  else
5161  defaultVal = mDefaultEdit->text();
5162  auto param = std::make_unique< QgsProcessingParameterDatabaseSchema>( name, description, mConnectionParamComboBox->currentData().toString(), defaultVal );
5163  param->setFlags( flags );
5164  return param.release();
5165 }
5166 
5167 
5168 QgsProcessingDatabaseSchemaWidgetWrapper::QgsProcessingDatabaseSchemaWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5169  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5170 {
5171 
5172 }
5173 
5174 QWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createWidget()
5175 {
5176  const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast< const QgsProcessingParameterDatabaseSchema *>( parameterDefinition() );
5177 
5178  mSchemaComboBox = new QgsDatabaseSchemaComboBox( QString(), QString() );
5180  mSchemaComboBox->setAllowEmptySchema( true );
5181 
5182  switch ( type() )
5183  {
5186  break;
5188  mSchemaComboBox->comboBox()->setEditable( true );
5189  break;
5190  }
5191 
5192  mSchemaComboBox->setToolTip( parameterDefinition()->toolTip() );
5193  connect( mSchemaComboBox->comboBox(), &QComboBox::currentTextChanged, this, [ = ]( const QString & )
5194  {
5195  if ( mBlockSignals )
5196  return;
5197 
5198  emit widgetValueHasChanged( this );
5199  } );
5200 
5201  return mSchemaComboBox;
5202 }
5203 
5204 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5205 {
5206  return new QgsProcessingDatabaseSchemaParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5207 }
5208 
5209 void QgsProcessingDatabaseSchemaWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5210 {
5211  // evaluate value to connection
5212  QgsProcessingContext *context = nullptr;
5213  std::unique_ptr< QgsProcessingContext > tmpContext;
5214  if ( mProcessingContextGenerator )
5215  context = mProcessingContextGenerator->processingContext();
5216 
5217  if ( !context )
5218  {
5219  tmpContext = std::make_unique< QgsProcessingContext >();
5220  context = tmpContext.get();
5221  }
5222 
5223  const QVariant value = parentWrapper->parameterValue();
5224  const QString connection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
5225 
5226  if ( mSchemaComboBox )
5227  mSchemaComboBox->setConnectionName( connection, qgis::down_cast< const QgsProcessingParameterProviderConnection * >( parentWrapper->parameterDefinition() )->providerId() );
5228 
5229  const QgsProcessingParameterDatabaseSchema *schemaParam = qgis::down_cast< const QgsProcessingParameterDatabaseSchema * >( parameterDefinition() );
5230  if ( schemaParam->defaultValueForGui().isValid() )
5231  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5232 }
5233 
5234 void QgsProcessingDatabaseSchemaWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5235 {
5236  const QString v = QgsProcessingParameters::parameterAsSchema( parameterDefinition(), value, context );
5237 
5238  if ( !value.isValid() )
5239  mSchemaComboBox->comboBox()->setCurrentIndex( -1 );
5240  else
5241  {
5242  if ( mSchemaComboBox->comboBox()->isEditable() )
5243  {
5244  const QString prev = mSchemaComboBox->comboBox()->currentText();
5245  mBlockSignals++;
5246  mSchemaComboBox->setSchema( v );
5247  mSchemaComboBox->comboBox()->setCurrentText( v );
5248 
5249  mBlockSignals--;
5250  if ( prev != v )
5251  emit widgetValueHasChanged( this );
5252  }
5253  else
5254  mSchemaComboBox->setSchema( v );
5255  }
5256 }
5257 
5258 QVariant QgsProcessingDatabaseSchemaWidgetWrapper::widgetValue() const
5259 {
5260  if ( mSchemaComboBox )
5261  if ( mSchemaComboBox->comboBox()->isEditable() )
5262  return mSchemaComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->comboBox()->currentText() );
5263  else
5264  return mSchemaComboBox->currentSchema().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->currentSchema() );
5265  else
5266  return QVariant();
5267 }
5268 
5269 QStringList QgsProcessingDatabaseSchemaWidgetWrapper::compatibleParameterTypes() const
5270 {
5271  return QStringList()
5275 }
5276 
5277 QStringList QgsProcessingDatabaseSchemaWidgetWrapper::compatibleOutputTypes() const
5278 {
5279  return QStringList()
5281 }
5282 
5283 QString QgsProcessingDatabaseSchemaWidgetWrapper::modelerExpressionFormatString() const
5284 {
5285  return tr( "database schema name as a string value" );
5286 }
5287 
5288 QString QgsProcessingDatabaseSchemaWidgetWrapper::parameterType() const
5289 {
5291 }
5292 
5293 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseSchemaWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5294 {
5295  return new QgsProcessingDatabaseSchemaWidgetWrapper( parameter, type );
5296 }
5297 
5298 void QgsProcessingDatabaseSchemaWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5299 {
5301  switch ( type() )
5302  {
5305  {
5306  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5307  {
5308  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseSchema * >( parameterDefinition() )->parentConnectionParameterName() )
5309  {
5310  setParentConnectionWrapperValue( wrapper );
5312  {
5313  setParentConnectionWrapperValue( wrapper );
5314  } );
5315  break;
5316  }
5317  }
5318  break;
5319  }
5320 
5322  break;
5323  }
5324 }
5325 
5326 
5327 
5328 //
5329 // QgsProcessingDatabaseTableWidgetWrapper
5330 //
5331 
5332 QgsProcessingDatabaseTableParameterDefinitionWidget::QgsProcessingDatabaseTableParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5333  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5334 {
5335  const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast< const QgsProcessingParameterDatabaseTable *>( definition );
5336 
5337  QVBoxLayout *vlayout = new QVBoxLayout();
5338  vlayout->setContentsMargins( 0, 0, 0, 0 );
5339 
5340  mConnectionParamComboBox = new QComboBox();
5341  mSchemaParamComboBox = new QComboBox();
5342  QString initialConnection;
5343  QString initialSchema;
5344  if ( tableParam )
5345  {
5346  initialConnection = tableParam->parentConnectionParameterName();
5347  initialSchema = tableParam->parentSchemaParameterName();
5348  }
5349 
5350  if ( auto *lModel = widgetContext.model() )
5351  {
5352  // populate combo box with other model input choices
5353  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5354  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5355  {
5356  if ( definition && it->parameterName() == definition->name() )
5357  continue;
5358 
5359  if ( dynamic_cast< const QgsProcessingParameterProviderConnection * >( lModel->parameterDefinition( it->parameterName() ) ) )
5360  {
5361  mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5362  if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5363  {
5364  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5365  }
5366  }
5367  else if ( dynamic_cast< const QgsProcessingParameterDatabaseSchema * >( lModel->parameterDefinition( it->parameterName() ) ) )
5368  {
5369  mSchemaParamComboBox->addItem( it->parameterName(), it->parameterName() );
5370  if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5371  {
5372  mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5373  }
5374  }
5375  }
5376  }
5377 
5378  if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5379  {
5380  // if no candidates found, we just add the existing one as a placeholder
5381  mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5382  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5383  }
5384 
5385  if ( mSchemaParamComboBox->count() == 0 && !initialSchema.isEmpty() )
5386  {
5387  // if no candidates found, we just add the existing one as a placeholder
5388  mSchemaParamComboBox->addItem( initialSchema, initialSchema );
5389  mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5390  }
5391 
5392  vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
5393  vlayout->addWidget( mConnectionParamComboBox );
5394 
5395  vlayout->addWidget( new QLabel( tr( "Database schema parameter" ) ) );
5396  vlayout->addWidget( mSchemaParamComboBox );
5397 
5398  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5399 
5400  mDefaultEdit = new QLineEdit();
5401  vlayout->addWidget( mDefaultEdit );
5402  setLayout( vlayout );
5403 
5404  if ( tableParam )
5405  {
5406  mDefaultEdit->setText( tableParam->defaultValueForGui().toString() );
5407  }
5408 }
5409 
5410 QgsProcessingParameterDefinition *QgsProcessingDatabaseTableParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5411 {
5412  QVariant defaultVal;
5413  if ( mDefaultEdit->text().isEmpty() )
5414  defaultVal = QVariant();
5415  else
5416  defaultVal = mDefaultEdit->text();
5417  auto param = std::make_unique< QgsProcessingParameterDatabaseTable>( name, description,
5418  mConnectionParamComboBox->currentData().toString(),
5419  mSchemaParamComboBox->currentData().toString(),
5420  defaultVal );
5421  param->setFlags( flags );
5422  return param.release();
5423 }
5424 
5425 
5426 QgsProcessingDatabaseTableWidgetWrapper::QgsProcessingDatabaseTableWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5427  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5428 {
5429 
5430 }
5431 
5432 QWidget *QgsProcessingDatabaseTableWidgetWrapper::createWidget()
5433 {
5434  const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast< const QgsProcessingParameterDatabaseTable *>( parameterDefinition() );
5435 
5436  mTableComboBox = new QgsDatabaseTableComboBox( QString(), QString() );
5438  mTableComboBox->setAllowEmptyTable( true );
5439 
5440  if ( type() == QgsProcessingGui::Modeler || tableParam->allowNewTableNames() )
5441  mTableComboBox->comboBox()->setEditable( true );
5442 
5443  mTableComboBox->setToolTip( parameterDefinition()->toolTip() );
5444  connect( mTableComboBox->comboBox(), &QComboBox::currentTextChanged, this, [ = ]( const QString & )
5445  {
5446  if ( mBlockSignals )
5447  return;
5448 
5449  emit widgetValueHasChanged( this );
5450  } );
5451 
5452  return mTableComboBox;
5453 }
5454 
5455 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseTableWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5456 {
5457  return new QgsProcessingDatabaseTableParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5458 }
5459 
5460 void QgsProcessingDatabaseTableWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5461 {
5462  // evaluate value to connection
5463  QgsProcessingContext *context = nullptr;
5464  std::unique_ptr< QgsProcessingContext > tmpContext;
5465  if ( mProcessingContextGenerator )
5466  context = mProcessingContextGenerator->processingContext();
5467 
5468  if ( !context )
5469  {
5470  tmpContext = std::make_unique< QgsProcessingContext >();
5471  context = tmpContext.get();
5472  }
5473 
5474  QVariant value = parentWrapper->parameterValue();
5475  mConnection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
5476  mProvider = qgis::down_cast< const QgsProcessingParameterProviderConnection * >( parentWrapper->parameterDefinition() )->providerId();
5477  if ( mTableComboBox && !mSchema.isEmpty() )
5478  {
5479  mTableComboBox->setSchema( mSchema );
5480  mTableComboBox->setConnectionName( mConnection, mProvider );
5481 
5482  const QgsProcessingParameterDatabaseTable *tableParam = qgis::down_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() );
5483  if ( tableParam->defaultValueForGui().isValid() )
5484  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5485  }
5486 }
5487 
5488 void QgsProcessingDatabaseTableWidgetWrapper::setParentSchemaWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5489 {
5490  // evaluate value to schema
5491  QgsProcessingContext *context = nullptr;
5492  std::unique_ptr< QgsProcessingContext > tmpContext;
5493  if ( mProcessingContextGenerator )
5494  context = mProcessingContextGenerator->processingContext();
5495 
5496  if ( !context )
5497  {
5498  tmpContext = std::make_unique< QgsProcessingContext >();
5499  context = tmpContext.get();
5500  }
5501 
5502  QVariant value = parentWrapper->parameterValue();
5503  mSchema = value.isValid() ? QgsProcessingParameters::parameterAsSchema( parentWrapper->parameterDefinition(), value, *context ) : QString();
5504 
5505  if ( mTableComboBox && !mSchema.isEmpty() && !mConnection.isEmpty() )
5506  {
5507  mTableComboBox->setSchema( mSchema );
5508  mTableComboBox->setConnectionName( mConnection, mProvider );
5509 
5510  const QgsProcessingParameterDatabaseTable *tableParam = static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() );
5511  if ( tableParam->defaultValueForGui().isValid() )
5512  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5513  }
5514 
5515 }
5516 
5517 void QgsProcessingDatabaseTableWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5518 {
5519  const QString v = QgsProcessingParameters::parameterAsDatabaseTableName( parameterDefinition(), value, context );
5520 
5521  if ( !value.isValid() )
5522  mTableComboBox->comboBox()->setCurrentIndex( -1 );
5523  else
5524  {
5525  if ( mTableComboBox->comboBox()->isEditable() )
5526  {
5527  const QString prev = mTableComboBox->comboBox()->currentText();
5528  mBlockSignals++;
5529  mTableComboBox->setTable( v );
5530  mTableComboBox->comboBox()->setCurrentText( v );
5531 
5532  mBlockSignals--;
5533  if ( prev != v )
5534  emit widgetValueHasChanged( this );
5535  }
5536  else
5537  mTableComboBox->setTable( v );
5538  }
5539 }
5540 
5541 QVariant QgsProcessingDatabaseTableWidgetWrapper::widgetValue() const
5542 {
5543  if ( mTableComboBox )
5544  if ( mTableComboBox->comboBox()->isEditable() )
5545  return mTableComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mTableComboBox->comboBox()->currentText() );
5546  else
5547  return mTableComboBox->currentTable().isEmpty() ? QVariant() : QVariant( mTableComboBox->currentTable() );
5548  else
5549  return QVariant();
5550 }
5551 
5552 QStringList QgsProcessingDatabaseTableWidgetWrapper::compatibleParameterTypes() const
5553 {
5554  return QStringList()
5558 }
5559 
5560 QStringList QgsProcessingDatabaseTableWidgetWrapper::compatibleOutputTypes() const
5561 {
5562  return QStringList()
5564 }
5565 
5566 QString QgsProcessingDatabaseTableWidgetWrapper::modelerExpressionFormatString() const
5567 {
5568  return tr( "database table name as a string value" );
5569 }
5570 
5571 QString QgsProcessingDatabaseTableWidgetWrapper::parameterType() const
5572 {
5574 }
5575 
5576 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseTableWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5577 {
5578  return new QgsProcessingDatabaseTableWidgetWrapper( parameter, type );
5579 }
5580 
5581 void QgsProcessingDatabaseTableWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5582 {
5584  switch ( type() )
5585  {
5588  {
5589  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5590  {
5591  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() )->parentConnectionParameterName() )
5592  {
5593  setParentConnectionWrapperValue( wrapper );
5595  {
5596  setParentConnectionWrapperValue( wrapper );
5597  } );
5598  }
5599  else if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() )->parentSchemaParameterName() )
5600  {
5601  setParentSchemaWrapperValue( wrapper );
5603  {
5604  setParentSchemaWrapperValue( wrapper );
5605  } );
5606  }
5607  }
5608  break;
5609  }
5610 
5612  break;
5613  }
5614 }
5615 
5616 
5617 //
5618 // QgsProcessingExtentWidgetWrapper
5619 //
5620 
5621 QgsProcessingExtentParameterDefinitionWidget::QgsProcessingExtentParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5622  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5623 {
5624  QVBoxLayout *vlayout = new QVBoxLayout();
5625  vlayout->setContentsMargins( 0, 0, 0, 0 );
5626 
5627  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5628 
5629  mDefaultWidget = new QgsExtentWidget();
5630  mDefaultWidget->setNullValueAllowed( true, tr( "Not set" ) );
5631  if ( const QgsProcessingParameterExtent *extentParam = dynamic_cast<const QgsProcessingParameterExtent *>( definition ) )
5632  {
5633  if ( extentParam->defaultValueForGui().isValid() )
5634  {
5635  QgsRectangle rect = QgsProcessingParameters::parameterAsExtent( extentParam, extentParam->defaultValueForGui(), context );
5636  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsExtentCrs( extentParam, extentParam->defaultValueForGui(), context );
5637  mDefaultWidget->setCurrentExtent( rect, crs );
5638  mDefaultWidget->setOutputExtentFromCurrent();
5639  }
5640  else
5641  {
5642  mDefaultWidget->clear();
5643  }
5644  }
5645 
5646  vlayout->addWidget( mDefaultWidget );
5647  setLayout( vlayout );
5648 }
5649 
5650 QgsProcessingParameterDefinition *QgsProcessingExtentParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5651 {
5652  const QString defaultVal = mDefaultWidget->isValid() ? QStringLiteral( "%1,%2,%3,%4%5" ).arg(
5653  QString::number( mDefaultWidget->outputExtent().xMinimum(), 'f', 9 ),
5654  QString::number( mDefaultWidget->outputExtent().xMaximum(), 'f', 9 ),
5655  QString::number( mDefaultWidget->outputExtent().yMinimum(), 'f', 9 ),
5656  QString::number( mDefaultWidget->outputExtent().yMaximum(), 'f', 9 ),
5657  mDefaultWidget->outputCrs().isValid() ? QStringLiteral( " [%1]" ).arg( mDefaultWidget->outputCrs().authid() ) : QString()
5658  ) : QString();
5659  auto param = std::make_unique< QgsProcessingParameterExtent >( name, description, !defaultVal.isEmpty() ? QVariant( defaultVal ) : QVariant() );
5660  param->setFlags( flags );
5661  return param.release();
5662 }
5663 
5664 
5665 
5666 QgsProcessingExtentWidgetWrapper::QgsProcessingExtentWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5667  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5668 {
5669 
5670 }
5671 
5672 QWidget *QgsProcessingExtentWidgetWrapper::createWidget()
5673 {
5674  const QgsProcessingParameterExtent *extentParam = dynamic_cast< const QgsProcessingParameterExtent *>( parameterDefinition() );
5675  switch ( type() )
5676  {
5680  {
5681  mExtentWidget = new QgsExtentWidget( nullptr );
5682  if ( widgetContext().mapCanvas() )
5683  mExtentWidget->setMapCanvas( widgetContext().mapCanvas() );
5684 
5686  mExtentWidget->setNullValueAllowed( true, tr( "Not set" ) );
5687 
5688  mExtentWidget->setToolTip( parameterDefinition()->toolTip() );
5689 
5690  connect( mExtentWidget, &QgsExtentWidget::extentChanged, this, [ = ]
5691  {
5692  emit widgetValueHasChanged( this );
5693  } );
5694 
5695  if ( mDialog && type() != QgsProcessingGui::Modeler )
5696  setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
5697 
5698  return mExtentWidget;
5699  }
5700  }
5701  return nullptr;
5702 }
5703 
5704 void QgsProcessingExtentWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
5705 {
5707  if ( mExtentWidget && context.mapCanvas() && type() != QgsProcessingGui::Modeler )
5708  mExtentWidget->setMapCanvas( context.mapCanvas() );
5709 }
5710 
5711 void QgsProcessingExtentWidgetWrapper::setDialog( QDialog *dialog )
5712 {
5713  mDialog = dialog;
5714  if ( mExtentWidget && mDialog && type() != QgsProcessingGui::Modeler )
5715  {
5716  connect( mExtentWidget, &QgsExtentWidget::toggleDialogVisibility, mDialog, [ = ]( bool visible )
5717  {
5718  if ( !visible )
5719  mDialog->showMinimized();
5720  else
5721  {
5722  mDialog->showNormal();
5723  mDialog->raise();
5724  mDialog->activateWindow();
5725  }
5726  } );
5727  }
5729 }
5730 
5731 void QgsProcessingExtentWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5732 {
5733  if ( mExtentWidget )
5734  {
5735  if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
5736  mExtentWidget->clear();
5737  else
5738  {
5739  QgsRectangle r = QgsProcessingParameters::parameterAsExtent( parameterDefinition(), value, context );
5740  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
5741  mExtentWidget->setCurrentExtent( r, crs );
5742  mExtentWidget->setOutputExtentFromUser( r, crs );
5743  }
5744  }
5745 }
5746 
5747 QVariant QgsProcessingExtentWidgetWrapper::widgetValue() const
5748 {
5749  if ( mExtentWidget )
5750  {
5751  const QString val = mExtentWidget->isValid() ? QStringLiteral( "%1,%2,%3,%4%5" ).arg(
5752  QString::number( mExtentWidget->outputExtent().xMinimum(), 'f', 9 ),
5753  QString::number( mExtentWidget->outputExtent().xMaximum(), 'f', 9 ),
5754  QString::number( mExtentWidget->outputExtent().yMinimum(), 'f', 9 ),
5755  QString::number( mExtentWidget->outputExtent().yMaximum(), 'f', 9 ),
5756  mExtentWidget->outputCrs().isValid() ? QStringLiteral( " [%1]" ).arg( mExtentWidget->outputCrs().authid() ) : QString()
5757  ) : QString();
5758 
5759  return val.isEmpty() ? QVariant() : QVariant( val );
5760  }
5761  else
5762  return QVariant();
5763 }
5764 
5765 QStringList QgsProcessingExtentWidgetWrapper::compatibleParameterTypes() const
5766 {
5767  return QStringList()
5777 }
5778 
5779 QStringList QgsProcessingExtentWidgetWrapper::compatibleOutputTypes() const
5780 {
5781  return QStringList()
5786 }
5787 
5788 QString QgsProcessingExtentWidgetWrapper::modelerExpressionFormatString() const
5789 {
5790  return tr( "string of the format 'x min,x max,y min,y max' or a geometry value (bounding box is used)" );
5791 }
5792 
5793 QString QgsProcessingExtentWidgetWrapper::parameterType() const
5794 {
5796 }
5797 
5798 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExtentWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5799 {
5800  return new QgsProcessingExtentWidgetWrapper( parameter, type );
5801 }
5802 
5803 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingExtentWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5804 {
5805  return new QgsProcessingExtentParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5806 }
5807 
5808 
5809 
5810 //
5811 // QgsProcessingMapLayerWidgetWrapper
5812 //
5813 
5814 QgsProcessingMapLayerParameterDefinitionWidget::QgsProcessingMapLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5815  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5816 {
5817  QVBoxLayout *vlayout = new QVBoxLayout();
5818  vlayout->setContentsMargins( 0, 0, 0, 0 );
5819 
5820  vlayout->addWidget( new QLabel( tr( "Layer type" ) ) );
5821  mLayerTypeComboBox = new QgsCheckableComboBox();
5822  mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), QgsProcessing::TypeMapLayer );
5823  mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), QgsProcessing::TypeVectorPoint );
5824  mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), QgsProcessing::TypeVectorLine );
5825  mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), QgsProcessing::TypeVectorPolygon );
5826  mLayerTypeComboBox->addItem( tr( "Vector (Any Geometry Type)" ), QgsProcessing::TypeVectorAnyGeometry );
5827  mLayerTypeComboBox->addItem( tr( "Raster" ), QgsProcessing::TypeRaster );
5828  mLayerTypeComboBox->addItem( tr( "Mesh" ), QgsProcessing::TypeMesh );
5829  mLayerTypeComboBox->addItem( tr( "Plugin" ), QgsProcessing::TypePlugin );
5830  mLayerTypeComboBox->addItem( tr( "Point Cloud" ), QgsProcessing::TypePointCloud );
5831  mLayerTypeComboBox->addItem( tr( "Annotation" ), QgsProcessing::TypeAnnotation );
5832 
5833  if ( const QgsProcessingParameterMapLayer *layerParam = dynamic_cast<const QgsProcessingParameterMapLayer *>( definition ) )
5834  {
5835  for ( int i : layerParam->dataTypes() )
5836  {
5837  mLayerTypeComboBox->setItemCheckState( mLayerTypeComboBox->findData( i ), Qt::Checked );
5838  }
5839  }
5840 
5841  vlayout->addWidget( mLayerTypeComboBox );
5842 
5843  setLayout( vlayout );
5844 }
5845 
5846 QgsProcessingParameterDefinition *QgsProcessingMapLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5847 {
5848  QList< int > dataTypes;
5849  for ( const QVariant &v : mLayerTypeComboBox->checkedItemsData() )
5850  dataTypes << v.toInt();
5851 
5852  auto param = std::make_unique< QgsProcessingParameterMapLayer >( name, description );
5853  param->setDataTypes( dataTypes );
5854  param->setFlags( flags );
5855  return param.release();
5856 }
5857 
5858 QgsProcessingMapLayerWidgetWrapper::QgsProcessingMapLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5859  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5860 {
5861 
5862 }
5863 
5864 QWidget *QgsProcessingMapLayerWidgetWrapper::createWidget()
5865 {
5866  mComboBox = new QgsProcessingMapLayerComboBox( parameterDefinition(), type() );
5867 
5868  switch ( type() )
5869  {
5872  break;
5874  mComboBox->setEditable( true );
5875  break;
5876  }
5877 
5878  mComboBox->setToolTip( parameterDefinition()->toolTip() );
5879 
5880  connect( mComboBox, &QgsProcessingMapLayerComboBox::valueChanged, this, [ = ]()
5881  {
5882  if ( mBlockSignals )
5883  return;
5884 
5885  emit widgetValueHasChanged( this );
5886  } );
5887 
5888  setWidgetContext( widgetContext() );
5889  return mComboBox;
5890 }
5891 
5892 void QgsProcessingMapLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
5893 {
5895  if ( mComboBox )
5896  {
5897  mComboBox->setWidgetContext( context );
5898 
5899  if ( !( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional ) )
5900  {
5901  // non optional parameter -- if no default value set, default to active layer
5902  if ( !parameterDefinition()->defaultValueForGui().isValid() )
5903  mComboBox->setLayer( context.activeLayer() );
5904  }
5905  }
5906 }
5907 
5908 void QgsProcessingMapLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5909 {
5910  if ( mComboBox )
5911  mComboBox->setValue( value, context );
5912 }
5913 
5914 QVariant QgsProcessingMapLayerWidgetWrapper::widgetValue() const
5915 {
5916  return mComboBox ? mComboBox->value() : QVariant();
5917 }
5918 
5919 QStringList QgsProcessingMapLayerWidgetWrapper::compatibleParameterTypes() const
5920 {
5921  return QStringList()
5930 }
5931 
5932 QStringList QgsProcessingMapLayerWidgetWrapper::compatibleOutputTypes() const
5933 {
5934  return QStringList()
5940 }
5941 
5942 QString QgsProcessingMapLayerWidgetWrapper::modelerExpressionFormatString() const
5943 {
5944  return tr( "path to a map layer" );
5945 }
5946 
5947 QString QgsProcessingMapLayerWidgetWrapper::parameterType() const
5948 {
5950 }
5951 
5952 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5953 {
5954  return new QgsProcessingMapLayerWidgetWrapper( parameter, type );
5955 }
5956 
5957 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5958 {
5959  return new QgsProcessingMapLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5960 }
5961 
5962 
5963 //
5964 // QgsProcessingRasterLayerWidgetWrapper
5965 //
5966 
5967 QgsProcessingRasterLayerWidgetWrapper::QgsProcessingRasterLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5968  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
5969 {
5970 
5971 }
5972 
5973 QStringList QgsProcessingRasterLayerWidgetWrapper::compatibleParameterTypes() const
5974 {
5975  return QStringList()
5980 }
5981 
5982 QStringList QgsProcessingRasterLayerWidgetWrapper::compatibleOutputTypes() const
5983 {
5984  return QStringList()
5990 }
5991 
5992 QString QgsProcessingRasterLayerWidgetWrapper::modelerExpressionFormatString() const
5993 {
5994  return tr( "path to a raster layer" );
5995 }
5996 
5997 QString QgsProcessingRasterLayerWidgetWrapper::parameterType() const
5998 {
6000 }
6001 
6002 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6003 {
6004  return new QgsProcessingRasterLayerWidgetWrapper( parameter, type );
6005 }
6006 
6007 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRasterLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6008 {
6009  Q_UNUSED( context );
6010  Q_UNUSED( widgetContext );
6011  Q_UNUSED( definition );
6012  Q_UNUSED( algorithm );
6013 
6014  return nullptr;
6015 }
6016 
6017 
6018 //
6019 // QgsProcessingVectorLayerWidgetWrapper
6020 //
6021 
6022 QgsProcessingVectorLayerParameterDefinitionWidget::QgsProcessingVectorLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6023  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6024 {
6025  QVBoxLayout *vlayout = new QVBoxLayout();
6026  vlayout->setContentsMargins( 0, 0, 0, 0 );
6027 
6028  vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6029  mGeometryTypeComboBox = new QgsCheckableComboBox();
6030  mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), QgsProcessing::TypeVector );
6031  mGeometryTypeComboBox->addItem( tr( "Point" ), QgsProcessing::TypeVectorPoint );
6032  mGeometryTypeComboBox->addItem( tr( "Line" ), QgsProcessing::TypeVectorLine );
6033  mGeometryTypeComboBox->addItem( tr( "Polygon" ), QgsProcessing::TypeVectorPolygon );
6034  mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
6035 
6036  if ( const QgsProcessingParameterVectorLayer *vectorParam = dynamic_cast<const QgsProcessingParameterVectorLayer *>( definition ) )
6037  {
6038  for ( int i : vectorParam->dataTypes() )
6039  {
6040  mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6041  }
6042  }
6043 
6044  vlayout->addWidget( mGeometryTypeComboBox );
6045 
6046  setLayout( vlayout );
6047 }
6048 
6049 QgsProcessingParameterDefinition *QgsProcessingVectorLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6050 {
6051  QList< int > dataTypes;
6052  for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6053  dataTypes << v.toInt();
6054 
6055  auto param = std::make_unique< QgsProcessingParameterVectorLayer >( name, description, dataTypes );
6056  param->setFlags( flags );
6057  return param.release();
6058 }
6059 
6060 
6061 QgsProcessingVectorLayerWidgetWrapper::QgsProcessingVectorLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6062  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6063 {
6064 
6065 }
6066 
6067 QStringList QgsProcessingVectorLayerWidgetWrapper::compatibleParameterTypes() const
6068 {
6069  return QStringList()
6074 }
6075 
6076 QStringList QgsProcessingVectorLayerWidgetWrapper::compatibleOutputTypes() const
6077 {
6078  return QStringList()
6084 }
6085 
6086 QString QgsProcessingVectorLayerWidgetWrapper::modelerExpressionFormatString() const
6087 {
6088  return tr( "path to a vector layer" );
6089 }
6090 
6091 QList<int> QgsProcessingVectorLayerWidgetWrapper::compatibleDataTypes( const QgsProcessingParameterDefinition *parameter ) const
6092 {
6093  if ( const QgsProcessingParameterVectorLayer *param = dynamic_cast< const QgsProcessingParameterVectorLayer *>( parameter ) )
6094  return param->dataTypes();
6095  else
6096  return QList< int >();
6097 }
6098 
6099 QString QgsProcessingVectorLayerWidgetWrapper::parameterType() const
6100 {
6102 }
6103 
6104 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6105 {
6106  return new QgsProcessingVectorLayerWidgetWrapper( parameter, type );
6107 }
6108 
6109 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingVectorLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6110 {
6111  return new QgsProcessingVectorLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6112 }
6113 
6114 
6115 
6116 //
6117 // QgsProcessingFeatureSourceLayerWidgetWrapper
6118 //
6119 
6120 QgsProcessingFeatureSourceParameterDefinitionWidget::QgsProcessingFeatureSourceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6121  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6122 {
6123  QVBoxLayout *vlayout = new QVBoxLayout();
6124  vlayout->setContentsMargins( 0, 0, 0, 0 );
6125 
6126  vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6127  mGeometryTypeComboBox = new QgsCheckableComboBox();
6128  mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), QgsProcessing::TypeVector );
6129  mGeometryTypeComboBox->addItem( tr( "Point" ), QgsProcessing::TypeVectorPoint );
6130  mGeometryTypeComboBox->addItem( tr( "Line" ), QgsProcessing::TypeVectorLine );
6131  mGeometryTypeComboBox->addItem( tr( "Polygon" ), QgsProcessing::TypeVectorPolygon );
6132  mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
6133 
6134  if ( const QgsProcessingParameterFeatureSource *sourceParam = dynamic_cast<const QgsProcessingParameterFeatureSource *>( definition ) )
6135  {
6136  for ( int i : sourceParam->dataTypes() )
6137  {
6138  mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6139  }
6140  }
6141  else
6142  {
6143  mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( QgsProcessing::TypeVectorAnyGeometry ), Qt::Checked );
6144  }
6145 
6146  vlayout->addWidget( mGeometryTypeComboBox );
6147 
6148  setLayout( vlayout );
6149 }
6150 
6151 QgsProcessingParameterDefinition *QgsProcessingFeatureSourceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6152 {
6153  QList< int > dataTypes;
6154  for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6155  dataTypes << v.toInt();
6156 
6157  auto param = std::make_unique< QgsProcessingParameterFeatureSource >( name, description, dataTypes );
6158  param->setFlags( flags );
6159  return param.release();
6160 }
6161 
6162 QgsProcessingFeatureSourceWidgetWrapper::QgsProcessingFeatureSourceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6163  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6164 {
6165 
6166 }
6167 
6168 QStringList QgsProcessingFeatureSourceWidgetWrapper::compatibleParameterTypes() const
6169 {
6170  return QStringList()
6176 }
6177 
6178 QStringList QgsProcessingFeatureSourceWidgetWrapper::compatibleOutputTypes() const
6179 {
6180  return QStringList()
6186 }
6187 
6188 QString QgsProcessingFeatureSourceWidgetWrapper::modelerExpressionFormatString() const
6189 {
6190  return tr( "path to a vector layer" );
6191 }
6192 
6193 QList<int> QgsProcessingFeatureSourceWidgetWrapper::compatibleDataTypes( const QgsProcessingParameterDefinition *parameter ) const
6194 {
6195  if ( const QgsProcessingParameterFeatureSource *param = dynamic_cast< const QgsProcessingParameterFeatureSource *>( parameter ) )
6196  return param->dataTypes();
6197  else
6198  return QList< int >();
6199 }
6200 
6201 QString QgsProcessingFeatureSourceWidgetWrapper::parameterType() const
6202 {
6204 }
6205 
6206 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSourceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6207 {
6208  return new QgsProcessingFeatureSourceWidgetWrapper( parameter, type );
6209 }
6210 
6211 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFeatureSourceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6212 {
6213  return new QgsProcessingFeatureSourceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6214 }
6215 
6216 //
6217 // QgsProcessingMeshLayerWidgetWrapper
6218 //
6219 
6220 QgsProcessingMeshLayerWidgetWrapper::QgsProcessingMeshLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6221  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6222 {
6223 
6224 }
6225 
6226 QStringList QgsProcessingMeshLayerWidgetWrapper::compatibleParameterTypes() const
6227 {
6228  return QStringList()
6233 }
6234 
6235 QStringList QgsProcessingMeshLayerWidgetWrapper::compatibleOutputTypes() const
6236 {
6237