QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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 
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 
704  if ( !qgsDoubleNear( numberParam->maximum(), std::numeric_limits<double>::max() ) )
705  {
706  mMaxLineEdit->setText( QLocale().toString( numberParam->maximum() ) );
707  }
708  else
709  {
710  mMaxLineEdit->clear();
711  }
712 
713  if ( !qgsDoubleNear( numberParam->minimum(), std::numeric_limits<double>::lowest() ) )
714  {
715  mMinLineEdit->setText( QLocale().toString( numberParam->minimum() ) );
716  }
717  else
718  {
719  mMinLineEdit->clear();
720  }
721 
722  mDefaultLineEdit->setText( numberParam->defaultValueForGui().toString() );
723  }
724 
725  setLayout( vlayout );
726 }
727 
728 QgsProcessingParameterDefinition *QgsProcessingNumberParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
729 {
730  bool ok;
731  double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
732 
733  QgsProcessingParameterNumber::Type dataType = static_cast< QgsProcessingParameterNumber::Type >( mTypeComboBox->currentData().toInt() );
734  auto param = std::make_unique< QgsProcessingParameterNumber >( name, description, dataType, ok ? val : QVariant() );
735 
736  if ( !mMinLineEdit->text().trimmed().isEmpty() )
737  {
738  val = QgsDoubleValidator::toDouble( mMinLineEdit->text( ), &ok );
739  if ( ok )
740  {
741  param->setMinimum( val );
742  }
743  }
744 
745  if ( !mMaxLineEdit->text().trimmed().isEmpty() )
746  {
747  val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
748  if ( ok )
749  {
750  param->setMaximum( val );
751  }
752  }
753 
754  param->setFlags( flags );
755  return param.release();
756 }
757 
758 QgsProcessingNumericWidgetWrapper::QgsProcessingNumericWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
759  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
760 {
761 
762 }
763 
764 QWidget *QgsProcessingNumericWidgetWrapper::createWidget()
765 {
766  const QgsProcessingParameterNumber *numberDef = static_cast< const QgsProcessingParameterNumber * >( parameterDefinition() );
767  const QVariantMap metadata = numberDef->metadata();
768  const int decimals = metadata.value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "decimals" ), 6 ).toInt();
769  switch ( type() )
770  {
774  {
775  // lots of duplicate code here -- but there's no common interface between QSpinBox/QDoubleSpinBox which would allow us to avoid this
776  QAbstractSpinBox *spinBox = nullptr;
777  switch ( numberDef->dataType() )
778  {
780  mDoubleSpinBox = new QgsDoubleSpinBox();
781  mDoubleSpinBox->setExpressionsEnabled( true );
782  mDoubleSpinBox->setDecimals( decimals );
783 
784  // guess reasonable step value for double spin boxes
785  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) &&
786  !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() + 1 ) )
787  {
788  double singleStep = calculateStep( numberDef->minimum(), numberDef->maximum() );
789  singleStep = std::max( singleStep, std::pow( 10, -decimals ) );
790  mDoubleSpinBox->setSingleStep( singleStep );
791  }
792 
793  spinBox = mDoubleSpinBox;
794  break;
795 
797  mSpinBox = new QgsSpinBox();
798  mSpinBox->setExpressionsEnabled( true );
799  spinBox = mSpinBox;
800  break;
801  }
802  spinBox->setToolTip( parameterDefinition()->toolTip() );
803 
804  double max = 999999999;
805  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) )
806  {
807  max = numberDef->maximum();
808  }
809  double min = -999999999;
810  if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
811  {
812  min = numberDef->minimum();
813  }
814  if ( mDoubleSpinBox )
815  {
816  mDoubleSpinBox->setMinimum( min );
817  mDoubleSpinBox->setMaximum( max );
818  }
819  else
820  {
821  mSpinBox->setMinimum( static_cast< int >( min ) );
822  mSpinBox->setMaximum( static_cast< int >( max ) );
823  }
824 
826  {
827  mAllowingNull = true;
828  if ( mDoubleSpinBox )
829  {
830  mDoubleSpinBox->setShowClearButton( true );
831  const double min = mDoubleSpinBox->minimum() - 1;
832  mDoubleSpinBox->setMinimum( min );
833  mDoubleSpinBox->setValue( min );
834  }
835  else
836  {
837  mSpinBox->setShowClearButton( true );
838  const int min = mSpinBox->minimum() - 1;
839  mSpinBox->setMinimum( min );
840  mSpinBox->setValue( min );
841  }
842  spinBox->setSpecialValueText( tr( "Not set" ) );
843  }
844  else
845  {
846  if ( numberDef->defaultValueForGui().isValid() )
847  {
848  // if default value for parameter, we clear to that
849  bool ok = false;
850  if ( mDoubleSpinBox )
851  {
852  double defaultVal = numberDef->defaultValueForGui().toDouble( &ok );
853  if ( ok )
854  mDoubleSpinBox->setClearValue( defaultVal );
855  }
856  else
857  {
858  int intVal = numberDef->defaultValueForGui().toInt( &ok );
859  if ( ok )
860  mSpinBox->setClearValue( intVal );
861  }
862  }
863  else if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
864  {
865  // otherwise we clear to the minimum, if it's set
866  if ( mDoubleSpinBox )
867  mDoubleSpinBox->setClearValue( numberDef->minimum() );
868  else
869  mSpinBox->setClearValue( static_cast< int >( numberDef->minimum() ) );
870  }
871  else
872  {
873  // last resort, we clear to 0
874  if ( mDoubleSpinBox )
875  {
876  mDoubleSpinBox->setValue( 0 );
877  mDoubleSpinBox->setClearValue( 0 );
878  }
879  else
880  {
881  mSpinBox->setValue( 0 );
882  mSpinBox->setClearValue( 0 );
883  }
884  }
885  }
886 
887  if ( mDoubleSpinBox )
888  connect( mDoubleSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
889  else if ( mSpinBox )
890  connect( mSpinBox, qOverload<int>( &QgsSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
891 
892  return spinBox;
893  }
894  }
895  return nullptr;
896 }
897 
898 void QgsProcessingNumericWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
899 {
900  if ( mDoubleSpinBox )
901  {
902  if ( mAllowingNull && !value.isValid() )
903  mDoubleSpinBox->clear();
904  else
905  {
906  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
907  mDoubleSpinBox->setValue( v );
908  }
909  }
910  else if ( mSpinBox )
911  {
912  if ( mAllowingNull && !value.isValid() )
913  mSpinBox->clear();
914  else
915  {
916  const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
917  mSpinBox->setValue( v );
918  }
919  }
920 }
921 
922 QVariant QgsProcessingNumericWidgetWrapper::widgetValue() const
923 {
924  if ( mDoubleSpinBox )
925  {
926  if ( mAllowingNull && qgsDoubleNear( mDoubleSpinBox->value(), mDoubleSpinBox->minimum() ) )
927  return QVariant();
928  else
929  return mDoubleSpinBox->value();
930  }
931  else if ( mSpinBox )
932  {
933  if ( mAllowingNull && mSpinBox->value() == mSpinBox->minimum() )
934  return QVariant();
935  else
936  return mSpinBox->value();
937  }
938  else
939  return QVariant();
940 }
941 
942 QStringList QgsProcessingNumericWidgetWrapper::compatibleParameterTypes() const
943 {
944  return QStringList()
950 }
951 
952 QStringList QgsProcessingNumericWidgetWrapper::compatibleOutputTypes() const
953 {
954  return QStringList() << QgsProcessingOutputNumber::typeName()
956 }
957 
958 double QgsProcessingNumericWidgetWrapper::calculateStep( const double minimum, const double maximum )
959 {
960  const double valueRange = maximum - minimum;
961  if ( valueRange <= 1.0 )
962  {
963  const double step = valueRange / 10.0;
964  // round to 1 significant figure
965  return qgsRound( step, -std::floor( std::log( step ) ) );
966  }
967  else
968  {
969  return 1.0;
970  }
971 }
972 
973 QString QgsProcessingNumericWidgetWrapper::parameterType() const
974 {
976 }
977 
978 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingNumericWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
979 {
980  return new QgsProcessingNumericWidgetWrapper( parameter, type );
981 }
982 
983 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingNumericWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
984 {
985  return new QgsProcessingNumberParameterDefinitionWidget( context, widgetContext, definition, algorithm );
986 }
987 
988 //
989 // QgsProcessingDistanceWidgetWrapper
990 //
991 
992 QgsProcessingDistanceParameterDefinitionWidget::QgsProcessingDistanceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
993  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
994 {
995  QVBoxLayout *vlayout = new QVBoxLayout();
996  vlayout->setContentsMargins( 0, 0, 0, 0 );
997 
998  vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
999 
1000  mParentLayerComboBox = new QComboBox();
1001 
1002  QString initialParent;
1003  if ( const QgsProcessingParameterDistance *distParam = dynamic_cast<const QgsProcessingParameterDistance *>( definition ) )
1004  initialParent = distParam->parentParameterName();
1005 
1006  if ( auto *lModel = widgetContext.model() )
1007  {
1008  // populate combo box with other model input choices
1009  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
1010  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
1011  {
1012  if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast< const QgsProcessingParameterFeatureSource * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
1013  {
1014  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
1015  if ( !initialParent.isEmpty() && initialParent == definition->name() )
1016  {
1017  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1018  }
1019  }
1020  else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast< const QgsProcessingParameterVectorLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
1021  {
1022  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
1023  if ( !initialParent.isEmpty() && initialParent == definition->name() )
1024  {
1025  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1026  }
1027  }
1028  else if ( const QgsProcessingParameterMapLayer *definition = dynamic_cast< const QgsProcessingParameterMapLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
1029  {
1030  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
1031  if ( !initialParent.isEmpty() && initialParent == definition->name() )
1032  {
1033  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1034  }
1035  }
1036  else if ( const QgsProcessingParameterCrs *definition = dynamic_cast< const QgsProcessingParameterCrs * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
1037  {
1038  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
1039  if ( !initialParent.isEmpty() && initialParent == definition->name() )
1040  {
1041  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1042  }
1043  }
1044  }
1045  }
1046 
1047  if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
1048  {
1049  // if no parent candidates found, we just add the existing one as a placeholder
1050  mParentLayerComboBox->addItem( initialParent, initialParent );
1051  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1052  }
1053 
1054  vlayout->addWidget( mParentLayerComboBox );
1055 
1056  vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1057  mMinLineEdit = new QLineEdit();
1058  vlayout->addWidget( mMinLineEdit );
1059 
1060  vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1061  mMaxLineEdit = new QLineEdit();
1062  vlayout->addWidget( mMaxLineEdit );
1063 
1064  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1065  mDefaultLineEdit = new QLineEdit();
1066  vlayout->addWidget( mDefaultLineEdit );
1067 
1068  if ( const QgsProcessingParameterDistance *distParam = dynamic_cast<const QgsProcessingParameterDistance *>( definition ) )
1069  {
1070  mMinLineEdit->setText( QLocale().toString( distParam->minimum() ) );
1071  mMaxLineEdit->setText( QLocale().toString( distParam->maximum() ) );
1072  mDefaultLineEdit->setText( distParam->defaultValueForGui().toString() );
1073  }
1074 
1075  setLayout( vlayout );
1076 }
1077 
1078 QgsProcessingParameterDefinition *QgsProcessingDistanceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1079 {
1080  bool ok;
1081  double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
1082 
1083  auto param = std::make_unique< QgsProcessingParameterDistance >( name, description, ok ? val : QVariant(), mParentLayerComboBox->currentData().toString() );
1084 
1085  val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
1086  if ( ok )
1087  {
1088  param->setMinimum( val );
1089  }
1090 
1091  val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
1092  if ( ok )
1093  {
1094  param->setMaximum( val );
1095  }
1096 
1097  param->setFlags( flags );
1098  return param.release();
1099 }
1100 
1101 QgsProcessingDistanceWidgetWrapper::QgsProcessingDistanceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1102  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1103 {
1104 
1105 }
1106 
1107 QString QgsProcessingDistanceWidgetWrapper::parameterType() const
1108 {
1110 }
1111 
1112 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDistanceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1113 {
1114  return new QgsProcessingDistanceWidgetWrapper( parameter, type );
1115 }
1116 
1117 QWidget *QgsProcessingDistanceWidgetWrapper::createWidget()
1118 {
1119  const QgsProcessingParameterDistance *distanceDef = static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() );
1120 
1121  QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1122  switch ( type() )
1123  {
1125  {
1126  mLabel = new QLabel();
1127  mUnitsCombo = new QComboBox();
1128 
1134 
1135  const int labelMargin = static_cast< int >( std::round( mUnitsCombo->fontMetrics().horizontalAdvance( 'X' ) ) );
1136  QHBoxLayout *layout = new QHBoxLayout();
1137  layout->addWidget( spin, 1 );
1138  layout->insertSpacing( 1, labelMargin / 2 );
1139  layout->insertWidget( 2, mLabel );
1140  layout->insertWidget( 3, mUnitsCombo );
1141 
1142  // bit of fiddlyness here -- we want the initial spacing to only be visible
1143  // when the warning label is shown, so it's embedded inside mWarningLabel
1144  // instead of outside it
1145  mWarningLabel = new QWidget();
1146  QHBoxLayout *warningLayout = new QHBoxLayout();
1147  warningLayout->setContentsMargins( 0, 0, 0, 0 );
1148  QLabel *warning = new QLabel();
1149  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
1150  const int size = static_cast< int >( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
1151  warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
1152  warning->setToolTip( tr( "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
1153  warningLayout->insertSpacing( 0, labelMargin / 2 );
1154  warningLayout->insertWidget( 1, warning );
1155  mWarningLabel->setLayout( warningLayout );
1156  layout->insertWidget( 4, mWarningLabel );
1157 
1158  QWidget *w = new QWidget();
1159  layout->setContentsMargins( 0, 0, 0, 0 );
1160  w->setLayout( layout );
1161 
1162  setUnits( distanceDef->defaultUnit() );
1163 
1164  return w;
1165  }
1166 
1169  return spin;
1170 
1171  }
1172  return nullptr;
1173 }
1174 
1175 void QgsProcessingDistanceWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1176 {
1177  QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
1178  switch ( type() )
1179  {
1181  {
1182  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1183  {
1184  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() )->parentParameterName() )
1185  {
1186  setUnitParameterValue( wrapper->parameterValue() );
1188  {
1189  setUnitParameterValue( wrapper->parameterValue() );
1190  } );
1191  break;
1192  }
1193  }
1194  break;
1195  }
1196 
1199  break;
1200  }
1201 }
1202 
1203 void QgsProcessingDistanceWidgetWrapper::setUnitParameterValue( const QVariant &value )
1204 {
1206 
1207  // evaluate value to layer
1208  QgsProcessingContext *context = nullptr;
1209  std::unique_ptr< QgsProcessingContext > tmpContext;
1210  if ( mProcessingContextGenerator )
1211  context = mProcessingContextGenerator->processingContext();
1212 
1213  if ( !context )
1214  {
1215  tmpContext = std::make_unique< QgsProcessingContext >();
1216  context = tmpContext.get();
1217  }
1218 
1219  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, *context );
1220  if ( crs.isValid() )
1221  {
1222  units = crs.mapUnits();
1223  }
1224 
1225  setUnits( units );
1226 }
1227 
1228 void QgsProcessingDistanceWidgetWrapper::setUnits( const QgsUnitTypes::DistanceUnit units )
1229 {
1230  mLabel->setText( QgsUnitTypes::toString( units ) );
1232  {
1233  mUnitsCombo->hide();
1234  mLabel->show();
1235  }
1236  else
1237  {
1238  mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( units ) );
1239  mUnitsCombo->show();
1240  mLabel->hide();
1241  }
1242  mWarningLabel->setVisible( units == QgsUnitTypes::DistanceDegrees );
1243  mBaseUnit = units;
1244 }
1245 
1246 QVariant QgsProcessingDistanceWidgetWrapper::widgetValue() const
1247 {
1248  const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1249  if ( val.type() == QVariant::Double && mUnitsCombo && mUnitsCombo->isVisible() )
1250  {
1251  QgsUnitTypes::DistanceUnit displayUnit = static_cast<QgsUnitTypes::DistanceUnit >( mUnitsCombo->currentData().toInt() );
1252  return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1253  }
1254  else
1255  {
1256  return val;
1257  }
1258 }
1259 
1260 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDistanceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1261 {
1262  return new QgsProcessingDistanceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1263 }
1264 
1265 
1266 //
1267 // QgsProcessingDurationWidgetWrapper
1268 //
1269 
1270 QgsProcessingDurationParameterDefinitionWidget::QgsProcessingDurationParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1271  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1272 {
1273  QVBoxLayout *vlayout = new QVBoxLayout();
1274  vlayout->setContentsMargins( 0, 0, 0, 0 );
1275 
1276  vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1277  mMinLineEdit = new QLineEdit();
1278  vlayout->addWidget( mMinLineEdit );
1279 
1280  vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1281  mMaxLineEdit = new QLineEdit();
1282  vlayout->addWidget( mMaxLineEdit );
1283 
1284  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1285  mDefaultLineEdit = new QLineEdit();
1286  vlayout->addWidget( mDefaultLineEdit );
1287 
1288  vlayout->addWidget( new QLabel( tr( "Default unit type" ) ) );
1289 
1290  mUnitsCombo = new QComboBox();
1297  mUnitsCombo->addItem( tr( "years (365.25 days)" ), QgsUnitTypes::TemporalYears );
1300  vlayout->addWidget( mUnitsCombo );
1301 
1302  if ( const QgsProcessingParameterDuration *durationParam = dynamic_cast<const QgsProcessingParameterDuration *>( definition ) )
1303  {
1304  mMinLineEdit->setText( QLocale().toString( durationParam->minimum() ) );
1305  mMaxLineEdit->setText( QLocale().toString( durationParam->maximum() ) );
1306  mDefaultLineEdit->setText( durationParam->defaultValueForGui().toString() );
1307  mUnitsCombo->setCurrentIndex( durationParam->defaultUnit() );
1308  }
1309 
1310  setLayout( vlayout );
1311 }
1312 
1313 QgsProcessingParameterDefinition *QgsProcessingDurationParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1314 {
1315  bool ok;
1316  double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
1317 
1318  auto param = std::make_unique< QgsProcessingParameterDuration >( name, description, ok ? val : QVariant() );
1319 
1320  val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
1321  if ( ok )
1322  {
1323  param->setMinimum( val );
1324  }
1325 
1326  val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
1327  if ( ok )
1328  {
1329  param->setMaximum( val );
1330  }
1331 
1332  param->setDefaultUnit( static_cast<QgsUnitTypes::TemporalUnit >( mUnitsCombo->currentData().toInt() ) );
1333 
1334  param->setFlags( flags );
1335  return param.release();
1336 }
1337 
1338 QgsProcessingDurationWidgetWrapper::QgsProcessingDurationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1339  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1340 {
1341 
1342 }
1343 
1344 QString QgsProcessingDurationWidgetWrapper::parameterType() const
1345 {
1347 }
1348 
1349 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDurationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1350 {
1351  return new QgsProcessingDurationWidgetWrapper( parameter, type );
1352 }
1353 
1354 QWidget *QgsProcessingDurationWidgetWrapper::createWidget()
1355 {
1356  const QgsProcessingParameterDuration *durationDef = static_cast< const QgsProcessingParameterDuration * >( parameterDefinition() );
1357 
1358  QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1359  switch ( type() )
1360  {
1362  {
1363  mUnitsCombo = new QComboBox();
1364 
1371  mUnitsCombo->addItem( tr( "years (365.25 days)" ), QgsUnitTypes::TemporalYears );
1374 
1375  QHBoxLayout *layout = new QHBoxLayout();
1376  layout->addWidget( spin, 1 );
1377  layout->insertWidget( 1, mUnitsCombo );
1378 
1379  QWidget *w = new QWidget();
1380  layout->setContentsMargins( 0, 0, 0, 0 );
1381  w->setLayout( layout );
1382 
1383  mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( durationDef->defaultUnit() ) );
1384  mUnitsCombo->show();
1385 
1386  return w;
1387  }
1388 
1391  return spin;
1392 
1393  }
1394  return nullptr;
1395 }
1396 
1397 QLabel *QgsProcessingDurationWidgetWrapper::createLabel()
1398 {
1400 
1401  if ( type() == QgsProcessingGui::Modeler )
1402  {
1403  label->setText( QStringLiteral( "%1 [%2]" ).arg( label->text(), QgsUnitTypes::toString( mBaseUnit ) ) );
1404  }
1405 
1406  return label;
1407 }
1408 
1409 QVariant QgsProcessingDurationWidgetWrapper::widgetValue() const
1410 {
1411  const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1412  if ( val.type() == QVariant::Double && mUnitsCombo )
1413  {
1414  QgsUnitTypes::TemporalUnit displayUnit = static_cast<QgsUnitTypes::TemporalUnit >( mUnitsCombo->currentData().toInt() );
1415  return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1416  }
1417  else
1418  {
1419  return val;
1420  }
1421 }
1422 
1423 void QgsProcessingDurationWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1424 {
1425  if ( mUnitsCombo )
1426  {
1427  QgsUnitTypes::TemporalUnit displayUnit = static_cast<QgsUnitTypes::TemporalUnit >( mUnitsCombo->currentData().toInt() );
1428  const QVariant val = value.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( mBaseUnit, displayUnit );
1429  QgsProcessingNumericWidgetWrapper::setWidgetValue( val, context );
1430  }
1431  else
1432  {
1433  QgsProcessingNumericWidgetWrapper::setWidgetValue( value, context );
1434  }
1435 }
1436 
1437 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDurationWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1438 {
1439  return new QgsProcessingDurationParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1440 }
1441 
1442 //
1443 // QgsProcessingScaleWidgetWrapper
1444 //
1445 
1446 QgsProcessingScaleParameterDefinitionWidget::QgsProcessingScaleParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1447  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1448 {
1449  QVBoxLayout *vlayout = new QVBoxLayout();
1450  vlayout->setContentsMargins( 0, 0, 0, 0 );
1451 
1452  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1453 
1454  mDefaultLineEdit = new QLineEdit();
1455 
1456  if ( const QgsProcessingParameterScale *scaleParam = dynamic_cast<const QgsProcessingParameterScale *>( definition ) )
1457  {
1458  mDefaultLineEdit->setText( scaleParam->defaultValueForGui().toString() );
1459  }
1460 
1461  vlayout->addWidget( mDefaultLineEdit );
1462 
1463  setLayout( vlayout );
1464 }
1465 
1466 QgsProcessingParameterDefinition *QgsProcessingScaleParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1467 {
1468  bool ok;
1469  double val = mDefaultLineEdit->text().toDouble( &ok );
1470  auto param = std::make_unique< QgsProcessingParameterScale >( name, description, ok ? val : QVariant() );
1471  param->setFlags( flags );
1472  return param.release();
1473 }
1474 
1475 QgsProcessingScaleWidgetWrapper::QgsProcessingScaleWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1476  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1477 {
1478 
1479 }
1480 
1481 QString QgsProcessingScaleWidgetWrapper::parameterType() const
1482 {
1484 }
1485 
1486 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingScaleWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1487 {
1488  return new QgsProcessingScaleWidgetWrapper( parameter, type );
1489 }
1490 
1491 QWidget *QgsProcessingScaleWidgetWrapper::createWidget()
1492 {
1493  const QgsProcessingParameterScale *scaleDef = static_cast< const QgsProcessingParameterScale * >( parameterDefinition() );
1494 
1495  switch ( type() )
1496  {
1500  {
1501  mScaleWidget = new QgsScaleWidget( nullptr );
1503  mScaleWidget->setAllowNull( true );
1504 
1505  mScaleWidget->setMapCanvas( widgetContext().mapCanvas() );
1506  mScaleWidget->setShowCurrentScaleButton( true );
1507 
1508  mScaleWidget->setToolTip( parameterDefinition()->toolTip() );
1509  connect( mScaleWidget, &QgsScaleWidget::scaleChanged, this, [ = ]( double )
1510  {
1511  emit widgetValueHasChanged( this );
1512  } );
1513  return mScaleWidget;
1514  }
1515  }
1516  return nullptr;
1517 }
1518 
1519 void QgsProcessingScaleWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
1520 {
1521  if ( mScaleWidget )
1522  mScaleWidget->setMapCanvas( context.mapCanvas() );
1524 }
1525 
1526 
1527 QVariant QgsProcessingScaleWidgetWrapper::widgetValue() const
1528 {
1529  return mScaleWidget && !mScaleWidget->isNull() ? QVariant( mScaleWidget->scale() ) : QVariant();
1530 }
1531 
1532 void QgsProcessingScaleWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1533 {
1534  if ( mScaleWidget )
1535  {
1536  if ( mScaleWidget->allowNull() && !value.isValid() )
1537  mScaleWidget->setNull();
1538  else
1539  {
1540  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
1541  mScaleWidget->setScale( v );
1542  }
1543  }
1544 }
1545 
1546 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingScaleWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1547 {
1548  return new QgsProcessingScaleParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1549 }
1550 
1551 
1552 //
1553 // QgsProcessingRangeWidgetWrapper
1554 //
1555 
1556 QgsProcessingRangeParameterDefinitionWidget::QgsProcessingRangeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1557  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1558 {
1559  QVBoxLayout *vlayout = new QVBoxLayout();
1560  vlayout->setContentsMargins( 0, 0, 0, 0 );
1561 
1562  vlayout->addWidget( new QLabel( tr( "Number type" ) ) );
1563 
1564  mTypeComboBox = new QComboBox();
1565  mTypeComboBox->addItem( tr( "Float" ), QgsProcessingParameterNumber::Double );
1566  mTypeComboBox->addItem( tr( "Integer" ), QgsProcessingParameterNumber::Integer );
1567  vlayout->addWidget( mTypeComboBox );
1568 
1569  vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1570  mMinLineEdit = new QLineEdit();
1571  vlayout->addWidget( mMinLineEdit );
1572 
1573  vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1574  mMaxLineEdit = new QLineEdit();
1575  vlayout->addWidget( mMaxLineEdit );
1576 
1577  if ( const QgsProcessingParameterRange *rangeParam = dynamic_cast<const QgsProcessingParameterRange *>( definition ) )
1578  {
1579  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( rangeParam->dataType() ) );
1580  const QList< double > range = QgsProcessingParameters::parameterAsRange( rangeParam, rangeParam->defaultValueForGui(), context );
1581  mMinLineEdit->setText( QLocale().toString( range.at( 0 ) ) );
1582  mMaxLineEdit->setText( QLocale().toString( range.at( 1 ) ) );
1583  }
1584 
1585  setLayout( vlayout );
1586 }
1587 
1588 QgsProcessingParameterDefinition *QgsProcessingRangeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1589 {
1590  QString defaultValue;
1591  if ( mMinLineEdit->text().isEmpty() )
1592  {
1593  defaultValue = QStringLiteral( "None" );
1594  }
1595  else
1596  {
1597  bool ok;
1598  defaultValue = QString::number( QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok ) );
1599  if ( ! ok )
1600  {
1601  defaultValue = QStringLiteral( "None" );
1602  }
1603  }
1604 
1605  if ( mMaxLineEdit->text().isEmpty() )
1606  {
1607  defaultValue += QLatin1String( ",None" );
1608  }
1609  else
1610  {
1611  bool ok;
1612  const double val { QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok ) };
1613  defaultValue += QStringLiteral( ",%1" ).arg( ok ? QString::number( val ) : QLatin1String( "None" ) );
1614  }
1615 
1616  QgsProcessingParameterNumber::Type dataType = static_cast< QgsProcessingParameterNumber::Type >( mTypeComboBox->currentData().toInt() );
1617  auto param = std::make_unique< QgsProcessingParameterRange >( name, description, dataType, defaultValue );
1618  param->setFlags( flags );
1619  return param.release();
1620 }
1621 
1622 
1623 QgsProcessingRangeWidgetWrapper::QgsProcessingRangeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1624  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1625 {
1626 
1627 }
1628 
1629 QWidget *QgsProcessingRangeWidgetWrapper::createWidget()
1630 {
1631  const QgsProcessingParameterRange *rangeDef = static_cast< const QgsProcessingParameterRange * >( parameterDefinition() );
1632  switch ( type() )
1633  {
1637  {
1638  QHBoxLayout *layout = new QHBoxLayout();
1639 
1640  mMinSpinBox = new QgsDoubleSpinBox();
1641  mMaxSpinBox = new QgsDoubleSpinBox();
1642 
1643  mMinSpinBox->setExpressionsEnabled( true );
1644  mMinSpinBox->setShowClearButton( false );
1645  mMaxSpinBox->setExpressionsEnabled( true );
1646  mMaxSpinBox->setShowClearButton( false );
1647 
1648  QLabel *minLabel = new QLabel( tr( "Min" ) );
1649  layout->addWidget( minLabel );
1650  layout->addWidget( mMinSpinBox, 1 );
1651 
1652  QLabel *maxLabel = new QLabel( tr( "Max" ) );
1653  layout->addWidget( maxLabel );
1654  layout->addWidget( mMaxSpinBox, 1 );
1655 
1656  QWidget *w = new QWidget();
1657  layout->setContentsMargins( 0, 0, 0, 0 );
1658  w->setLayout( layout );
1659 
1660  if ( rangeDef->dataType() == QgsProcessingParameterNumber::Double )
1661  {
1662  mMinSpinBox->setDecimals( 6 );
1663  mMaxSpinBox->setDecimals( 6 );
1664  }
1665  else
1666  {
1667  mMinSpinBox->setDecimals( 0 );
1668  mMaxSpinBox->setDecimals( 0 );
1669  }
1670 
1671  mMinSpinBox->setMinimum( -99999999.999999 );
1672  mMaxSpinBox->setMinimum( -99999999.999999 );
1673  mMinSpinBox->setMaximum( 99999999.999999 );
1674  mMaxSpinBox->setMaximum( 99999999.999999 );
1675 
1677  {
1678  mAllowingNull = true;
1679 
1680  const double min = mMinSpinBox->minimum() - 1;
1681  mMinSpinBox->setMinimum( min );
1682  mMaxSpinBox->setMinimum( min );
1683  mMinSpinBox->setValue( min );
1684  mMaxSpinBox->setValue( min );
1685 
1686  mMinSpinBox->setShowClearButton( true );
1687  mMaxSpinBox->setShowClearButton( true );
1688  mMinSpinBox->setSpecialValueText( tr( "Not set" ) );
1689  mMaxSpinBox->setSpecialValueText( tr( "Not set" ) );
1690  }
1691 
1692  w->setToolTip( parameterDefinition()->toolTip() );
1693 
1694  connect( mMinSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
1695  {
1696  mBlockChangedSignal++;
1697  if ( !mAllowingNull && v > mMaxSpinBox->value() )
1698  mMaxSpinBox->setValue( v );
1699  mBlockChangedSignal--;
1700 
1701  if ( !mBlockChangedSignal )
1702  emit widgetValueHasChanged( this );
1703  } );
1704  connect( mMaxSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
1705  {
1706  mBlockChangedSignal++;
1707  if ( !mAllowingNull && v < mMinSpinBox->value() )
1708  mMinSpinBox->setValue( v );
1709  mBlockChangedSignal--;
1710 
1711  if ( !mBlockChangedSignal )
1712  emit widgetValueHasChanged( this );
1713  } );
1714 
1715  return w;
1716  }
1717  }
1718  return nullptr;
1719 }
1720 
1721 void QgsProcessingRangeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1722 {
1723  const QList< double > v = QgsProcessingParameters::parameterAsRange( parameterDefinition(), value, context );
1724  if ( mAllowingNull && v.empty() )
1725  {
1726  mMinSpinBox->clear();
1727  mMaxSpinBox->clear();
1728  }
1729  else
1730  {
1731  if ( v.empty() )
1732  return;
1733 
1734  if ( mAllowingNull )
1735  {
1736  mBlockChangedSignal++;
1737  if ( std::isnan( v.at( 0 ) ) )
1738  mMinSpinBox->clear();
1739  else
1740  mMinSpinBox->setValue( v.at( 0 ) );
1741 
1742  if ( v.count() >= 2 )
1743  {
1744  if ( std::isnan( v.at( 1 ) ) )
1745  mMaxSpinBox->clear();
1746  else
1747  mMaxSpinBox->setValue( v.at( 1 ) );
1748  }
1749  mBlockChangedSignal--;
1750  }
1751  else
1752  {
1753  mBlockChangedSignal++;
1754  mMinSpinBox->setValue( v.at( 0 ) );
1755  if ( v.count() >= 2 )
1756  mMaxSpinBox->setValue( v.at( 1 ) );
1757  mBlockChangedSignal--;
1758  }
1759  }
1760 
1761  if ( !mBlockChangedSignal )
1762  emit widgetValueHasChanged( this );
1763 }
1764 
1765 QVariant QgsProcessingRangeWidgetWrapper::widgetValue() const
1766 {
1767  if ( mAllowingNull )
1768  {
1769  QString value;
1770  if ( qgsDoubleNear( mMinSpinBox->value(), mMinSpinBox->minimum() ) )
1771  value = QStringLiteral( "None" );
1772  else
1773  value = QString::number( mMinSpinBox->value() );
1774 
1775  if ( qgsDoubleNear( mMaxSpinBox->value(), mMaxSpinBox->minimum() ) )
1776  value += QLatin1String( ",None" );
1777  else
1778  value += QStringLiteral( ",%1" ).arg( mMaxSpinBox->value() );
1779 
1780  return value;
1781  }
1782  else
1783  return QStringLiteral( "%1,%2" ).arg( mMinSpinBox->value() ).arg( mMaxSpinBox->value() );
1784 }
1785 
1786 QStringList QgsProcessingRangeWidgetWrapper::compatibleParameterTypes() const
1787 {
1788  return QStringList()
1791 }
1792 
1793 QStringList QgsProcessingRangeWidgetWrapper::compatibleOutputTypes() const
1794 {
1795  return QStringList() << QgsProcessingOutputString::typeName();
1796 }
1797 
1798 QString QgsProcessingRangeWidgetWrapper::modelerExpressionFormatString() const
1799 {
1800  return tr( "string as two comma delimited floats, e.g. '1,10'" );
1801 }
1802 
1803 QString QgsProcessingRangeWidgetWrapper::parameterType() const
1804 {
1806 }
1807 
1808 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRangeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1809 {
1810  return new QgsProcessingRangeWidgetWrapper( parameter, type );
1811 }
1812 
1813 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRangeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1814 {
1815  return new QgsProcessingRangeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1816 }
1817 
1818 
1819 //
1820 // QgsProcessingMatrixWidgetWrapper
1821 //
1822 
1823 QgsProcessingMatrixParameterDefinitionWidget::QgsProcessingMatrixParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1824  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1825 {
1826  QVBoxLayout *vlayout = new QVBoxLayout();
1827  vlayout->setContentsMargins( 0, 0, 0, 0 );
1828 
1829  mMatrixWidget = new QgsProcessingMatrixModelerWidget();
1830  if ( const QgsProcessingParameterMatrix *matrixParam = dynamic_cast<const QgsProcessingParameterMatrix *>( definition ) )
1831  {
1832  mMatrixWidget->setValue( matrixParam->headers(), matrixParam->defaultValueForGui() );
1833  mMatrixWidget->setFixedRows( matrixParam->hasFixedNumberRows() );
1834  }
1835  vlayout->addWidget( mMatrixWidget );
1836  setLayout( vlayout );
1837 }
1838 
1839 QgsProcessingParameterDefinition *QgsProcessingMatrixParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1840 {
1841  auto param = std::make_unique< QgsProcessingParameterMatrix >( name, description, 1, mMatrixWidget->fixedRows(), mMatrixWidget->headers(), mMatrixWidget->value() );
1842  param->setFlags( flags );
1843  return param.release();
1844 }
1845 
1846 
1847 QgsProcessingMatrixWidgetWrapper::QgsProcessingMatrixWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1848  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1849 {
1850 
1851 }
1852 
1853 QWidget *QgsProcessingMatrixWidgetWrapper::createWidget()
1854 {
1855  mMatrixWidget = new QgsProcessingMatrixParameterPanel( nullptr, dynamic_cast< const QgsProcessingParameterMatrix *>( parameterDefinition() ) );
1856  mMatrixWidget->setToolTip( parameterDefinition()->toolTip() );
1857 
1858  connect( mMatrixWidget, &QgsProcessingMatrixParameterPanel::changed, this, [ = ]
1859  {
1860  emit widgetValueHasChanged( this );
1861  } );
1862 
1863  switch ( type() )
1864  {
1868  {
1869  return mMatrixWidget;
1870  }
1871  }
1872  return nullptr;
1873 }
1874 
1875 void QgsProcessingMatrixWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1876 {
1877  const QVariantList v = QgsProcessingParameters::parameterAsMatrix( parameterDefinition(), value, context );
1878  if ( mMatrixWidget )
1879  mMatrixWidget->setValue( v );
1880 }
1881 
1882 QVariant QgsProcessingMatrixWidgetWrapper::widgetValue() const
1883 {
1884  if ( mMatrixWidget )
1885  return mMatrixWidget->value().isEmpty() ? QVariant() : mMatrixWidget->value();
1886  else
1887  return QVariant();
1888 }
1889 
1890 QStringList QgsProcessingMatrixWidgetWrapper::compatibleParameterTypes() const
1891 {
1892  return QStringList()
1894 }
1895 
1896 QStringList QgsProcessingMatrixWidgetWrapper::compatibleOutputTypes() const
1897 {
1898  return QStringList();
1899 }
1900 
1901 QString QgsProcessingMatrixWidgetWrapper::modelerExpressionFormatString() const
1902 {
1903  return tr( "comma delimited string of values, or an array of values" );
1904 }
1905 
1906 QString QgsProcessingMatrixWidgetWrapper::parameterType() const
1907 {
1909 }
1910 
1911 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMatrixWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1912 {
1913  return new QgsProcessingMatrixWidgetWrapper( parameter, type );
1914 }
1915 
1916 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMatrixWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1917 {
1918  return new QgsProcessingMatrixParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1919 }
1920 
1921 
1922 //
1923 // QgsProcessingFileWidgetWrapper
1924 //
1925 
1926 
1927 QgsProcessingFileParameterDefinitionWidget::QgsProcessingFileParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1928  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1929 {
1930  QVBoxLayout *vlayout = new QVBoxLayout();
1931  vlayout->setContentsMargins( 0, 0, 0, 0 );
1932 
1933  vlayout->addWidget( new QLabel( tr( "Type" ) ) );
1934 
1935  mTypeComboBox = new QComboBox();
1936  mTypeComboBox->addItem( tr( "File" ), QgsProcessingParameterFile::File );
1937  mTypeComboBox->addItem( tr( "Folder" ), QgsProcessingParameterFile::Folder );
1938  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1939  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( fileParam->behavior() ) );
1940  else
1941  mTypeComboBox->setCurrentIndex( 0 );
1942  vlayout->addWidget( mTypeComboBox );
1943 
1944  vlayout->addWidget( new QLabel( tr( "File filter" ) ) );
1945 
1946  mFilterComboBox = new QComboBox();
1947  mFilterComboBox->setEditable( true );
1948  // add some standard ones -- these also act as a demonstration of the required format
1949  mFilterComboBox->addItem( tr( "All Files (*.*)" ) );
1950  mFilterComboBox->addItem( tr( "CSV Files (*.csv)" ) );
1951  mFilterComboBox->addItem( tr( "HTML Files (*.html *.htm)" ) );
1952  mFilterComboBox->addItem( tr( "Text Files (*.txt)" ) );
1953  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1954  mFilterComboBox->setCurrentText( fileParam->fileFilter() );
1955  else
1956  mFilterComboBox->setCurrentIndex( 0 );
1957  vlayout->addWidget( mFilterComboBox );
1958 
1959  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1960 
1961  mDefaultFileWidget = new QgsFileWidget();
1962  mDefaultFileWidget->lineEdit()->setShowClearButton( true );
1963  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1964  {
1965  mDefaultFileWidget->setStorageMode( fileParam->behavior() == QgsProcessingParameterFile::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
1966  mDefaultFileWidget->setFilePath( fileParam->defaultValueForGui().toString() );
1967  }
1968  else
1969  mDefaultFileWidget->setStorageMode( QgsFileWidget::GetFile );
1970  vlayout->addWidget( mDefaultFileWidget );
1971 
1972  connect( mTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]
1973  {
1974  QgsProcessingParameterFile::Behavior behavior = static_cast< QgsProcessingParameterFile::Behavior >( mTypeComboBox->currentData().toInt() );
1975  mFilterComboBox->setEnabled( behavior == QgsProcessingParameterFile::File );
1976  mDefaultFileWidget->setStorageMode( behavior == QgsProcessingParameterFile::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
1977  } );
1978  mFilterComboBox->setEnabled( static_cast< QgsProcessingParameterFile::Behavior >( mTypeComboBox->currentData().toInt() ) == QgsProcessingParameterFile::File );
1979 
1980 
1981  setLayout( vlayout );
1982 }
1983 
1984 QgsProcessingParameterDefinition *QgsProcessingFileParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1985 {
1986  auto param = std::make_unique< QgsProcessingParameterFile >( name, description );
1987  param->setBehavior( static_cast< QgsProcessingParameterFile::Behavior>( mTypeComboBox->currentData().toInt() ) );
1988  if ( param->behavior() == QgsProcessingParameterFile::File )
1989  param->setFileFilter( mFilterComboBox->currentText() );
1990  if ( !mDefaultFileWidget->filePath().isEmpty() )
1991  param->setDefaultValue( mDefaultFileWidget->filePath() );
1992  param->setFlags( flags );
1993  return param.release();
1994 }
1995 
1996 
1997 QgsProcessingFileWidgetWrapper::QgsProcessingFileWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1998  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1999 {
2000 
2001 }
2002 
2003 QWidget *QgsProcessingFileWidgetWrapper::createWidget()
2004 {
2005  const QgsProcessingParameterFile *fileParam = dynamic_cast< const QgsProcessingParameterFile *>( parameterDefinition() );
2006  switch ( type() )
2007  {
2011  {
2012  mFileWidget = new QgsFileWidget();
2013  mFileWidget->setToolTip( parameterDefinition()->toolTip() );
2014  mFileWidget->setDialogTitle( parameterDefinition()->description() );
2015 
2016  mFileWidget->setDefaultRoot( QgsSettings().value( QStringLiteral( "/Processing/LastInputPath" ), QDir::homePath() ).toString() );
2017 
2018  switch ( fileParam->behavior() )
2019  {
2021  mFileWidget->setStorageMode( QgsFileWidget::GetFile );
2022  if ( !fileParam->fileFilter().isEmpty() )
2023  mFileWidget->setFilter( fileParam->fileFilter() );
2024  else if ( !fileParam->extension().isEmpty() )
2025  mFileWidget->setFilter( tr( "%1 files" ).arg( fileParam->extension().toUpper() ) + QStringLiteral( " (*." ) + fileParam->extension().toLower() + ')' );
2026  break;
2027 
2029  mFileWidget->setStorageMode( QgsFileWidget::GetDirectory );
2030  break;
2031  }
2032 
2033  connect( mFileWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & path )
2034  {
2035  QgsSettings().setValue( QStringLiteral( "/Processing/LastInputPath" ), QFileInfo( path ).canonicalPath() );
2036  emit widgetValueHasChanged( this );
2037  } );
2038  return mFileWidget;
2039  }
2040  }
2041  return nullptr;
2042 }
2043 
2044 void QgsProcessingFileWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2045 {
2046  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2047  if ( mFileWidget )
2048  mFileWidget->setFilePath( v );
2049 }
2050 
2051 QVariant QgsProcessingFileWidgetWrapper::widgetValue() const
2052 {
2053  if ( mFileWidget )
2054  return mFileWidget->filePath();
2055  else
2056  return QVariant();
2057 }
2058 
2059 QStringList QgsProcessingFileWidgetWrapper::compatibleParameterTypes() const
2060 {
2061  return QStringList()
2064 }
2065 
2066 QStringList QgsProcessingFileWidgetWrapper::compatibleOutputTypes() const
2067 {
2068  return QStringList() << QgsProcessingOutputFile::typeName()
2074 }
2075 
2076 QString QgsProcessingFileWidgetWrapper::modelerExpressionFormatString() const
2077 {
2078  return tr( "string representing a path to a file or folder" );
2079 }
2080 
2081 QString QgsProcessingFileWidgetWrapper::parameterType() const
2082 {
2084 }
2085 
2086 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2087 {
2088  return new QgsProcessingFileWidgetWrapper( parameter, type );
2089 }
2090 
2091 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFileWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2092 {
2093  return new QgsProcessingFileParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2094 }
2095 
2096 
2097 
2098 //
2099 // QgsProcessingExpressionWidgetWrapper
2100 //
2101 
2102 QgsProcessingExpressionParameterDefinitionWidget::QgsProcessingExpressionParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2103  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2104 {
2105  QVBoxLayout *vlayout = new QVBoxLayout();
2106  vlayout->setContentsMargins( 0, 0, 0, 0 );
2107  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
2108 
2109  mDefaultLineEdit = new QgsExpressionLineEdit();
2110  mDefaultLineEdit->registerExpressionContextGenerator( this );
2111 
2112  if ( const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( definition ) )
2113  mDefaultLineEdit->setExpression( QgsProcessingParameters::parameterAsExpression( expParam, expParam->defaultValueForGui(), context ) );
2114  vlayout->addWidget( mDefaultLineEdit );
2115 
2116  vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
2117 
2118  mParentLayerComboBox = new QComboBox();
2119  mParentLayerComboBox->addItem( tr( "None" ), QVariant() );
2120 
2121  QString initialParent;
2122  if ( const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( definition ) )
2123  initialParent = expParam->parentLayerParameterName();
2124 
2125  if ( QgsProcessingModelAlgorithm *model = widgetContext.model() )
2126  {
2127  // populate combo box with other model input choices
2128  const QMap<QString, QgsProcessingModelParameter> components = model->parameterComponents();
2129  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
2130  {
2131  if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast< const QgsProcessingParameterFeatureSource * >( model->parameterDefinition( it.value().parameterName() ) ) )
2132  {
2133  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
2134  if ( !initialParent.isEmpty() && initialParent == definition->name() )
2135  {
2136  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2137  }
2138  }
2139  else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast< const QgsProcessingParameterVectorLayer * >( model->parameterDefinition( it.value().parameterName() ) ) )
2140  {
2141  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
2142  if ( !initialParent.isEmpty() && initialParent == definition->name() )
2143  {
2144  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2145  }
2146  }
2147  }
2148  }
2149 
2150  if ( mParentLayerComboBox->count() == 1 && !initialParent.isEmpty() )
2151  {
2152  // if no parent candidates found, we just add the existing one as a placeholder
2153  mParentLayerComboBox->addItem( initialParent, initialParent );
2154  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2155  }
2156 
2157  vlayout->addWidget( mParentLayerComboBox );
2158  setLayout( vlayout );
2159 }
2160 
2161 QgsProcessingParameterDefinition *QgsProcessingExpressionParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2162 {
2163  auto param = std::make_unique< QgsProcessingParameterExpression >( name, description, mDefaultLineEdit->expression(), mParentLayerComboBox->currentData().toString() );
2164  param->setFlags( flags );
2165  return param.release();
2166 }
2167 
2168 QgsProcessingExpressionWidgetWrapper::QgsProcessingExpressionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2169  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2170 {
2171 
2172 }
2173 
2174 QWidget *QgsProcessingExpressionWidgetWrapper::createWidget()
2175 {
2176  const QgsProcessingParameterExpression *expParam = dynamic_cast< const QgsProcessingParameterExpression *>( parameterDefinition() );
2177  switch ( type() )
2178  {
2182  {
2183  if ( expParam->parentLayerParameterName().isEmpty() )
2184  {
2185  mExpLineEdit = new QgsExpressionLineEdit();
2186  mExpLineEdit->setToolTip( parameterDefinition()->toolTip() );
2187  mExpLineEdit->setExpressionDialogTitle( parameterDefinition()->description() );
2188  mExpLineEdit->registerExpressionContextGenerator( this );
2189  connect( mExpLineEdit, &QgsExpressionLineEdit::expressionChanged, this, [ = ]( const QString & )
2190  {
2191  emit widgetValueHasChanged( this );
2192  } );
2193  return mExpLineEdit;
2194  }
2195  else
2196  {
2197  if ( expParam->metadata().value( QStringLiteral( "inlineEditor" ) ).toBool() )
2198  {
2199  mExpBuilderWidget = new QgsExpressionBuilderWidget();
2200  mExpBuilderWidget->setToolTip( parameterDefinition()->toolTip() );
2201  mExpBuilderWidget->init( createExpressionContext() );
2202  connect( mExpBuilderWidget, &QgsExpressionBuilderWidget::expressionParsed, this, [ = ]( bool changed )
2203  {
2204  Q_UNUSED( changed );
2205  emit widgetValueHasChanged( this );
2206  } );
2207  return mExpBuilderWidget;
2208  }
2209  else
2210  {
2211  mFieldExpWidget = new QgsFieldExpressionWidget();
2212  mFieldExpWidget->setToolTip( parameterDefinition()->toolTip() );
2213  mFieldExpWidget->setExpressionDialogTitle( parameterDefinition()->description() );
2214  mFieldExpWidget->registerExpressionContextGenerator( this );
2216  mFieldExpWidget->setAllowEmptyFieldName( true );
2217 
2218  connect( mFieldExpWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString & ) >( &QgsFieldExpressionWidget::fieldChanged ), this, [ = ]( const QString & )
2219  {
2220  emit widgetValueHasChanged( this );
2221  } );
2222  return mFieldExpWidget;
2223  }
2224  }
2225  }
2226  }
2227  return nullptr;
2228 }
2229 
2230 void QgsProcessingExpressionWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
2231 {
2233  switch ( type() )
2234  {
2237  {
2238  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
2239  {
2240  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterExpression * >( parameterDefinition() )->parentLayerParameterName() )
2241  {
2242  setParentLayerWrapperValue( wrapper );
2244  {
2245  setParentLayerWrapperValue( wrapper );
2246  } );
2247  break;
2248  }
2249  }
2250  break;
2251  }
2252 
2254  break;
2255  }
2256 }
2257 
2258 void QgsProcessingExpressionWidgetWrapper::registerProcessingContextGenerator( QgsProcessingContextGenerator *generator )
2259 {
2261  if ( mExpBuilderWidget )
2262  {
2263  // we need to regenerate the expression context for use by this widget -- it doesn't fetch automatically on demand
2264  mExpBuilderWidget->setExpressionContext( createExpressionContext() );
2265  }
2266 }
2267 
2268 void QgsProcessingExpressionWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
2269 {
2270  // evaluate value to layer
2271  QgsProcessingContext *context = nullptr;
2272  std::unique_ptr< QgsProcessingContext > tmpContext;
2273  if ( mProcessingContextGenerator )
2274  context = mProcessingContextGenerator->processingContext();
2275 
2276  if ( !context )
2277  {
2278  tmpContext = std::make_unique< QgsProcessingContext >();
2279  context = tmpContext.get();
2280  }
2281 
2282  QVariant val = parentWrapper->parameterValue();
2283  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
2284  {
2285  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
2286  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
2287  val = fromVar.source;
2288  }
2289 
2290  QgsVectorLayer *layer = QgsProcessingParameters::parameterAsVectorLayer( parentWrapper->parameterDefinition(), val, *context );
2291  if ( !layer )
2292  {
2293  if ( mFieldExpWidget )
2294  mFieldExpWidget->setLayer( nullptr );
2295  else if ( mExpBuilderWidget )
2296  mExpBuilderWidget->setLayer( nullptr );
2297  else if ( mExpLineEdit )
2298  mExpLineEdit->setLayer( nullptr );
2299  return;
2300  }
2301 
2302  // need to grab ownership of layer if required - otherwise layer may be deleted when context
2303  // goes out of scope
2304  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
2305  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::VectorLayer )
2306  {
2307  mParentLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
2308  layer = mParentLayer.get();
2309  }
2310  else
2311  {
2312  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
2313  }
2314 
2315  if ( mFieldExpWidget )
2316  mFieldExpWidget->setLayer( layer );
2317  if ( mExpBuilderWidget )
2318  mExpBuilderWidget->setLayer( layer );
2319  else if ( mExpLineEdit )
2320  mExpLineEdit->setLayer( layer );
2321 }
2322 
2323 void QgsProcessingExpressionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2324 {
2325  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2326  if ( mFieldExpWidget )
2327  mFieldExpWidget->setExpression( v );
2328  else if ( mExpBuilderWidget )
2329  mExpBuilderWidget->setExpressionText( v );
2330  else if ( mExpLineEdit )
2331  mExpLineEdit->setExpression( v );
2332 }
2333 
2334 QVariant QgsProcessingExpressionWidgetWrapper::widgetValue() const
2335 {
2336  if ( mFieldExpWidget )
2337  return mFieldExpWidget->expression();
2338  if ( mExpBuilderWidget )
2339  return mExpBuilderWidget->expressionText();
2340  else if ( mExpLineEdit )
2341  return mExpLineEdit->expression();
2342  else
2343  return QVariant();
2344 }
2345 
2346 QStringList QgsProcessingExpressionWidgetWrapper::compatibleParameterTypes() const
2347 {
2348  return QStringList()
2355 }
2356 
2357 QStringList QgsProcessingExpressionWidgetWrapper::compatibleOutputTypes() const
2358 {
2359  return QStringList()
2362 }
2363 
2364 QString QgsProcessingExpressionWidgetWrapper::modelerExpressionFormatString() const
2365 {
2366  return tr( "string representation of an expression" );
2367 }
2368 
2369 const QgsVectorLayer *QgsProcessingExpressionWidgetWrapper::linkedVectorLayer() const
2370 {
2371  if ( mFieldExpWidget && mFieldExpWidget->layer() )
2372  return mFieldExpWidget->layer();
2373 
2374  if ( mExpBuilderWidget && mExpBuilderWidget->layer() )
2375  return mExpBuilderWidget->layer();
2376 
2378 }
2379 
2380 QString QgsProcessingExpressionWidgetWrapper::parameterType() const
2381 {
2383 }
2384 
2385 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExpressionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2386 {
2387  return new QgsProcessingExpressionWidgetWrapper( parameter, type );
2388 }
2389 
2390 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingExpressionWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2391 {
2392  return new QgsProcessingExpressionParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2393 }
2394 
2395 
2396 
2397 //
2398 // QgsProcessingEnumPanelWidget
2399 //
2400 
2401 QgsProcessingEnumPanelWidget::QgsProcessingEnumPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param )
2402  : QWidget( parent )
2403  , mParam( param )
2404 {
2405  QHBoxLayout *hl = new QHBoxLayout();
2406  hl->setContentsMargins( 0, 0, 0, 0 );
2407 
2408  mLineEdit = new QLineEdit();
2409  mLineEdit->setEnabled( false );
2410  hl->addWidget( mLineEdit, 1 );
2411 
2412  mToolButton = new QToolButton();
2413  mToolButton->setText( QString( QChar( 0x2026 ) ) );
2414  hl->addWidget( mToolButton );
2415 
2416  setLayout( hl );
2417 
2418  if ( mParam )
2419  {
2420  mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
2421  }
2422 
2423  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingEnumPanelWidget::showDialog );
2424 }
2425 
2426 void QgsProcessingEnumPanelWidget::setValue( const QVariant &value )
2427 {
2428  if ( value.isValid() )
2429  {
2430  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
2431 
2432  if ( mParam->usesStaticStrings() && mValue.count() == 1 && mValue.at( 0 ).toString().isEmpty() )
2433  mValue.clear();
2434  }
2435  else
2436  mValue.clear();
2437 
2438  updateSummaryText();
2439  emit changed();
2440 }
2441 
2442 void QgsProcessingEnumPanelWidget::showDialog()
2443 {
2444  QVariantList availableOptions;
2445  if ( mParam )
2446  {
2447  availableOptions.reserve( mParam->options().size() );
2448  for ( int i = 0; i < mParam->options().count(); ++i )
2449  availableOptions << i;
2450  }
2451 
2452  const QStringList options = mParam ? mParam->options() : QStringList();
2454  if ( panel && panel->dockMode() )
2455  {
2456  QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
2457  widget->setPanelTitle( mParam->description() );
2458 
2459  if ( mParam->usesStaticStrings() )
2460  {
2461  widget->setValueFormatter( [options]( const QVariant & v ) -> QString
2462  {
2463  const QString i = v.toString();
2464  return options.contains( i ) ? i : QString();
2465  } );
2466  }
2467  else
2468  {
2469  widget->setValueFormatter( [options]( const QVariant & v ) -> QString
2470  {
2471  const int i = v.toInt();
2472  return options.size() > i ? options.at( i ) : QString();
2473  } );
2474  }
2475 
2476  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
2477  {
2478  setValue( widget->selectedOptions() );
2479  } );
2480  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
2481  panel->openPanel( widget );
2482  }
2483  else
2484  {
2485  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
2486 
2487  dlg.setValueFormatter( [options]( const QVariant & v ) -> QString
2488  {
2489  const int i = v.toInt();
2490  return options.size() > i ? options.at( i ) : QString();
2491  } );
2492  if ( dlg.exec() )
2493  {
2494  setValue( dlg.selectedOptions() );
2495  }
2496  }
2497 }
2498 
2499 void QgsProcessingEnumPanelWidget::updateSummaryText()
2500 {
2501  if ( mParam )
2502  mLineEdit->setText( tr( "%1 options selected" ).arg( mValue.count() ) );
2503 }
2504 
2505 
2506 //
2507 // QgsProcessingEnumCheckboxPanelWidget
2508 //
2509 QgsProcessingEnumCheckboxPanelWidget::QgsProcessingEnumCheckboxPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param, int columns )
2510  : QWidget( parent )
2511  , mParam( param )
2512  , mButtonGroup( new QButtonGroup( this ) )
2513  , mColumns( columns )
2514 {
2515  mButtonGroup->setExclusive( !mParam->allowMultiple() );
2516 
2517  QGridLayout *l = new QGridLayout();
2518  l->setContentsMargins( 0, 0, 0, 0 );
2519 
2520  int rows = static_cast< int >( std::ceil( mParam->options().count() / static_cast< double >( mColumns ) ) );
2521  for ( int i = 0; i < mParam->options().count(); ++i )
2522  {
2523  QAbstractButton *button = nullptr;
2524  if ( mParam->allowMultiple() )
2525  button = new QCheckBox( mParam->options().at( i ) );
2526  else
2527  button = new QRadioButton( mParam->options().at( i ) );
2528 
2529  connect( button, &QAbstractButton::toggled, this, [ = ]
2530  {
2531  if ( !mBlockChangedSignal )
2532  emit changed();
2533  } );
2534 
2535  mButtons.insert( i, button );
2536 
2537  mButtonGroup->addButton( button, i );
2538  l->addWidget( button, i % rows, i / rows );
2539  }
2540  l->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ), 0, mColumns );
2541  setLayout( l );
2542 
2543  if ( mParam->allowMultiple() )
2544  {
2545  setContextMenuPolicy( Qt::CustomContextMenu );
2546  connect( this, &QWidget::customContextMenuRequested, this, &QgsProcessingEnumCheckboxPanelWidget::showPopupMenu );
2547  }
2548 }
2549 
2550 QVariant QgsProcessingEnumCheckboxPanelWidget::value() const
2551 {
2552  if ( mParam->allowMultiple() )
2553  {
2554  QVariantList value;
2555  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2556  {
2557  if ( it.value()->isChecked() )
2558  value.append( mParam->usesStaticStrings() ? mParam->options().at( it.key().toInt() ) : it.key() );
2559  }
2560  return value;
2561  }
2562  else
2563  {
2564  if ( mParam->usesStaticStrings() )
2565  return mButtonGroup->checkedId() >= 0 ? mParam->options().at( mButtonGroup->checkedId() ) : QVariant();
2566  else
2567  return mButtonGroup->checkedId() >= 0 ? mButtonGroup->checkedId() : QVariant();
2568  }
2569 }
2570 
2571 void QgsProcessingEnumCheckboxPanelWidget::setValue( const QVariant &value )
2572 {
2573  mBlockChangedSignal = true;
2574  if ( mParam->allowMultiple() )
2575  {
2576  QVariantList selected;
2577  if ( value.isValid() )
2578  selected = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
2579  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2580  {
2581  QVariant v = mParam->usesStaticStrings() ? mParam->options().at( it.key().toInt() ) : it.key();
2582  it.value()->setChecked( selected.contains( v ) );
2583  }
2584  }
2585  else
2586  {
2587  QVariant v = value;
2588  if ( v.type() == QVariant::List )
2589  v = v.toList().value( 0 );
2590 
2591  v = mParam->usesStaticStrings() ? mParam->options().indexOf( v.toString() ) : v;
2592  if ( mButtons.contains( v ) )
2593  mButtons.value( v )->setChecked( true );
2594  }
2595  mBlockChangedSignal = false;
2596  emit changed();
2597 }
2598 
2599 void QgsProcessingEnumCheckboxPanelWidget::showPopupMenu()
2600 {
2601  QMenu popupMenu;
2602  QAction *selectAllAction = new QAction( tr( "Select All" ), &popupMenu );
2603  connect( selectAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::selectAll );
2604  QAction *clearAllAction = new QAction( tr( "Clear Selection" ), &popupMenu );
2605  connect( clearAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::deselectAll );
2606  popupMenu.addAction( selectAllAction );
2607  popupMenu.addAction( clearAllAction );
2608  popupMenu.exec( QCursor::pos() );
2609 }
2610 
2611 void QgsProcessingEnumCheckboxPanelWidget::selectAll()
2612 {
2613  mBlockChangedSignal = true;
2614  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2615  it.value()->setChecked( true );
2616  mBlockChangedSignal = false;
2617  emit changed();
2618 }
2619 
2620 void QgsProcessingEnumCheckboxPanelWidget::deselectAll()
2621 {
2622  mBlockChangedSignal = true;
2623  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2624  it.value()->setChecked( false );
2625  mBlockChangedSignal = false;
2626  emit changed();
2627 }
2628 
2629 
2630 //
2631 // QgsProcessingEnumWidgetWrapper
2632 //
2633 
2634 QgsProcessingEnumParameterDefinitionWidget::QgsProcessingEnumParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2635  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2636 {
2637  QVBoxLayout *vlayout = new QVBoxLayout();
2638  vlayout->setContentsMargins( 0, 0, 0, 0 );
2639 
2640  mEnumWidget = new QgsProcessingEnumModelerWidget();
2641  if ( const QgsProcessingParameterEnum *enumParam = dynamic_cast<const QgsProcessingParameterEnum *>( definition ) )
2642  {
2643  mEnumWidget->setAllowMultiple( enumParam->allowMultiple() );
2644  mEnumWidget->setOptions( enumParam->options() );
2645  mEnumWidget->setDefaultOptions( enumParam->defaultValueForGui() );
2646  }
2647  vlayout->addWidget( mEnumWidget );
2648  setLayout( vlayout );
2649 }
2650 
2651 QgsProcessingParameterDefinition *QgsProcessingEnumParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2652 {
2653  auto param = std::make_unique< QgsProcessingParameterEnum >( name, description, mEnumWidget->options(), mEnumWidget->allowMultiple(), mEnumWidget->defaultOptions() );
2654  param->setFlags( flags );
2655  return param.release();
2656 }
2657 
2658 
2659 QgsProcessingEnumWidgetWrapper::QgsProcessingEnumWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2660  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2661 {
2662 
2663 }
2664 
2665 QWidget *QgsProcessingEnumWidgetWrapper::createWidget()
2666 {
2667  const QgsProcessingParameterEnum *expParam = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
2668  switch ( type() )
2669  {
2671  {
2672  // checkbox panel only for use outside in standard gui!
2673  if ( expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "useCheckBoxes" ), false ).toBool() )
2674  {
2675  const int columns = expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "columns" ), 2 ).toInt();
2676  mCheckboxPanel = new QgsProcessingEnumCheckboxPanelWidget( nullptr, expParam, columns );
2677  mCheckboxPanel->setToolTip( parameterDefinition()->toolTip() );
2678  connect( mCheckboxPanel, &QgsProcessingEnumCheckboxPanelWidget::changed, this, [ = ]
2679  {
2680  emit widgetValueHasChanged( this );
2681  } );
2682  return mCheckboxPanel;
2683  }
2684  }
2685  FALLTHROUGH
2688  {
2689  if ( expParam->allowMultiple() )
2690  {
2691  mPanel = new QgsProcessingEnumPanelWidget( nullptr, expParam );
2692  mPanel->setToolTip( parameterDefinition()->toolTip() );
2693  connect( mPanel, &QgsProcessingEnumPanelWidget::changed, this, [ = ]
2694  {
2695  emit widgetValueHasChanged( this );
2696  } );
2697  return mPanel;
2698  }
2699  else
2700  {
2701  mComboBox = new QComboBox();
2702 
2704  mComboBox->addItem( tr( "[Not selected]" ), QVariant() );
2705  const QStringList options = expParam->options();
2706  for ( int i = 0; i < options.count(); ++i )
2707  {
2708  if ( expParam->usesStaticStrings() )
2709  mComboBox->addItem( options.at( i ), options.at( i ) );
2710  else
2711  mComboBox->addItem( options.at( i ), i );
2712  }
2713 
2714  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2715  connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
2716  {
2717  emit widgetValueHasChanged( this );
2718  } );
2719  return mComboBox;
2720  }
2721  }
2722  }
2723  return nullptr;
2724 }
2725 
2726 void QgsProcessingEnumWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2727 {
2728  if ( mComboBox )
2729  {
2730  if ( !value.isValid() )
2731  mComboBox->setCurrentIndex( mComboBox->findData( QVariant() ) );
2732  else
2733  {
2734  const QgsProcessingParameterEnum *enumDef = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
2735  if ( enumDef->usesStaticStrings() )
2736  {
2737  const QString v = QgsProcessingParameters::parameterAsEnumString( parameterDefinition(), value, context );
2738  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
2739  }
2740  else
2741  {
2742  const int v = QgsProcessingParameters::parameterAsEnum( parameterDefinition(), value, context );
2743  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
2744  }
2745  }
2746  }
2747  else if ( mPanel || mCheckboxPanel )
2748  {
2749  QVariantList opts;
2750  if ( value.isValid() )
2751  {
2752  const QgsProcessingParameterEnum *enumDef = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
2753  if ( enumDef->usesStaticStrings() )
2754  {
2755  const QStringList v = QgsProcessingParameters::parameterAsEnumStrings( parameterDefinition(), value, context );
2756  opts.reserve( v.size() );
2757  for ( QString i : v )
2758  opts << i;
2759  }
2760  else
2761  {
2762  const QList< int > v = QgsProcessingParameters::parameterAsEnums( parameterDefinition(), value, context );
2763  opts.reserve( v.size() );
2764  for ( int i : v )
2765  opts << i;
2766  }
2767  }
2768  if ( mPanel )
2769  mPanel->setValue( opts );
2770  else if ( mCheckboxPanel )
2771  mCheckboxPanel->setValue( opts );
2772  }
2773 }
2774 
2775 QVariant QgsProcessingEnumWidgetWrapper::widgetValue() const
2776 {
2777  if ( mComboBox )
2778  return mComboBox->currentData();
2779  else if ( mPanel )
2780  return mPanel->value();
2781  else if ( mCheckboxPanel )
2782  return mCheckboxPanel->value();
2783  else
2784  return QVariant();
2785 }
2786 
2787 QStringList QgsProcessingEnumWidgetWrapper::compatibleParameterTypes() const
2788 {
2789  return QStringList()
2793 }
2794 
2795 QStringList QgsProcessingEnumWidgetWrapper::compatibleOutputTypes() const
2796 {
2797  return QStringList()
2800 }
2801 
2802 QString QgsProcessingEnumWidgetWrapper::modelerExpressionFormatString() const
2803 {
2804  return tr( "selected option index (starting from 0), array of indices, or comma separated string of options (e.g. '1,3')" );
2805 }
2806 
2807 QString QgsProcessingEnumWidgetWrapper::parameterType() const
2808 {
2810 }
2811 
2812 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingEnumWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2813 {
2814  return new QgsProcessingEnumWidgetWrapper( parameter, type );
2815 }
2816 
2817 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingEnumWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2818 {
2819  return new QgsProcessingEnumParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2820 }
2821 
2822 //
2823 // QgsProcessingLayoutWidgetWrapper
2824 //
2825 
2826 QgsProcessingLayoutWidgetWrapper::QgsProcessingLayoutWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2827  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2828 {
2829 
2830 }
2831 
2832 QWidget *QgsProcessingLayoutWidgetWrapper::createWidget()
2833 {
2834  const QgsProcessingParameterLayout *layoutParam = dynamic_cast< const QgsProcessingParameterLayout *>( parameterDefinition() );
2835  switch ( type() )
2836  {
2839  {
2840  // combobox only for use outside modeler!
2841  mComboBox = new QgsLayoutComboBox( nullptr, widgetContext().project() ? widgetContext().project()->layoutManager() : nullptr );
2843  mComboBox->setAllowEmptyLayout( true );
2844  mComboBox->setFilters( QgsLayoutManagerProxyModel::FilterPrintLayouts );
2845 
2846  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2847  connect( mComboBox, &QgsLayoutComboBox::layoutChanged, this, [ = ]( QgsMasterLayoutInterface * )
2848  {
2849  emit widgetValueHasChanged( this );
2850  } );
2851  return mComboBox;
2852  }
2853 
2855  {
2856  mPlainComboBox = new QComboBox();
2857  mPlainComboBox->setEditable( true );
2858  mPlainComboBox->setToolTip( tr( "Name of an existing print layout" ) );
2859  if ( widgetContext().project() )
2860  {
2861  const QList< QgsPrintLayout * > layouts = widgetContext().project()->layoutManager()->printLayouts();
2862  for ( const QgsPrintLayout *layout : layouts )
2863  mPlainComboBox->addItem( layout->name() );
2864  }
2865 
2866  connect( mPlainComboBox, &QComboBox::currentTextChanged, this, [ = ]( const QString & )
2867  {
2868  emit widgetValueHasChanged( this );
2869  } );
2870  return mPlainComboBox;
2871  }
2872  }
2873  return nullptr;
2874 }
2875 
2876 void QgsProcessingLayoutWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2877 {
2878  if ( mComboBox )
2879  {
2880  if ( !value.isValid() )
2881  mComboBox->setCurrentLayout( nullptr );
2882  else
2883  {
2884  if ( QgsPrintLayout *l = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, context ) )
2885  mComboBox->setCurrentLayout( l );
2886  else
2887  mComboBox->setCurrentLayout( nullptr );
2888  }
2889  }
2890  else if ( mPlainComboBox )
2891  {
2892  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2893  mPlainComboBox->setCurrentText( v );
2894  }
2895 }
2896 
2897 QVariant QgsProcessingLayoutWidgetWrapper::widgetValue() const
2898 {
2899  if ( mComboBox )
2900  {
2901  const QgsMasterLayoutInterface *l = mComboBox->currentLayout();
2902  return l ? l->name() : QVariant();
2903  }
2904  else if ( mPlainComboBox )
2905  return mPlainComboBox->currentText().isEmpty() ? QVariant() : mPlainComboBox->currentText();
2906  else
2907  return QVariant();
2908 }
2909 
2910 void QgsProcessingLayoutWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
2911 {
2913  if ( mPlainComboBox && context.project() )
2914  {
2915  const QList< QgsPrintLayout * > layouts = widgetContext().project()->layoutManager()->printLayouts();
2916  for ( const QgsPrintLayout *layout : layouts )
2917  mPlainComboBox->addItem( layout->name() );
2918  }
2919 }
2920 
2921 QStringList QgsProcessingLayoutWidgetWrapper::compatibleParameterTypes() const
2922 {
2923  return QStringList()
2926 }
2927 
2928 QStringList QgsProcessingLayoutWidgetWrapper::compatibleOutputTypes() const
2929 {
2930  return QStringList()
2932 }
2933 
2934 QString QgsProcessingLayoutWidgetWrapper::modelerExpressionFormatString() const
2935 {
2936  return tr( "string representing the name of an existing print layout" );
2937 }
2938 
2939 QString QgsProcessingLayoutWidgetWrapper::parameterType() const
2940 {
2942 }
2943 
2944 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2945 {
2946  return new QgsProcessingLayoutWidgetWrapper( parameter, type );
2947 }
2948 
2949 
2950 
2951 
2952 //
2953 // QgsProcessingLayoutItemWidgetWrapper
2954 //
2955 
2956 
2957 QgsProcessingLayoutItemParameterDefinitionWidget::QgsProcessingLayoutItemParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2958  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2959 {
2960  QVBoxLayout *vlayout = new QVBoxLayout();
2961  vlayout->setContentsMargins( 0, 0, 0, 0 );
2962 
2963  vlayout->addWidget( new QLabel( tr( "Parent layout" ) ) );
2964 
2965  mParentLayoutComboBox = new QComboBox();
2966  QString initialParent;
2967  if ( const QgsProcessingParameterLayoutItem *itemParam = dynamic_cast<const QgsProcessingParameterLayoutItem *>( definition ) )
2968  initialParent = itemParam->parentLayoutParameterName();
2969 
2970  if ( auto *lModel = widgetContext.model() )
2971  {
2972  // populate combo box with other model input choices
2973  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
2974  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
2975  {
2976  if ( const QgsProcessingParameterLayout *definition = dynamic_cast< const QgsProcessingParameterLayout * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
2977  {
2978  mParentLayoutComboBox-> addItem( definition->description(), definition->name() );
2979  if ( !initialParent.isEmpty() && initialParent == definition->name() )
2980  {
2981  mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
2982  }
2983  }
2984  }
2985  }
2986 
2987  if ( mParentLayoutComboBox->count() == 0 && !initialParent.isEmpty() )
2988  {
2989  // if no parent candidates found, we just add the existing one as a placeholder
2990  mParentLayoutComboBox->addItem( initialParent, initialParent );
2991  mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
2992  }
2993 
2994  vlayout->addWidget( mParentLayoutComboBox );
2995  setLayout( vlayout );
2996 }
2997 QgsProcessingParameterDefinition *QgsProcessingLayoutItemParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2998 {
2999  auto param = std::make_unique< QgsProcessingParameterLayoutItem >( name, description, QVariant(), mParentLayoutComboBox->currentData().toString() );
3000  param->setFlags( flags );
3001  return param.release();
3002 }
3003 
3004 
3005 QgsProcessingLayoutItemWidgetWrapper::QgsProcessingLayoutItemWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3006  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3007 {
3008 
3009 }
3010 
3011 QWidget *QgsProcessingLayoutItemWidgetWrapper::createWidget()
3012 {
3013  const QgsProcessingParameterLayoutItem *layoutParam = dynamic_cast< const QgsProcessingParameterLayoutItem *>( parameterDefinition() );
3014  switch ( type() )
3015  {
3018  {
3019  // combobox only for use outside modeler!
3020  mComboBox = new QgsLayoutItemComboBox( nullptr, nullptr );
3022  mComboBox->setAllowEmptyItem( true );
3023  if ( layoutParam->itemType() >= 0 )
3024  mComboBox->setItemType( static_cast< QgsLayoutItemRegistry::ItemType >( layoutParam->itemType() ) );
3025 
3026  mComboBox->setToolTip( parameterDefinition()->toolTip() );
3027  connect( mComboBox, &QgsLayoutItemComboBox::itemChanged, this, [ = ]( QgsLayoutItem * )
3028  {
3029  emit widgetValueHasChanged( this );
3030  } );
3031  return mComboBox;
3032  }
3033 
3035  {
3036  mLineEdit = new QLineEdit();
3037  mLineEdit->setToolTip( tr( "UUID or ID of an existing print layout item" ) );
3038  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
3039  {
3040  emit widgetValueHasChanged( this );
3041  } );
3042  return mLineEdit;
3043  }
3044  }
3045  return nullptr;
3046 }
3047 
3048 void QgsProcessingLayoutItemWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
3049 {
3051  switch ( type() )
3052  {
3055  {
3056  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
3057  {
3058  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterLayoutItem * >( parameterDefinition() )->parentLayoutParameterName() )
3059  {
3060  setLayoutParameterValue( wrapper->parameterValue() );
3062  {
3063  setLayoutParameterValue( wrapper->parameterValue() );
3064  } );
3065  break;
3066  }
3067  }
3068  break;
3069  }
3070 
3072  break;
3073  }
3074 }
3075 
3076 void QgsProcessingLayoutItemWidgetWrapper::setLayoutParameterValue( const QVariant &value )
3077 {
3078  QgsPrintLayout *layout = nullptr;
3079 
3080  // evaluate value to layout
3081  QgsProcessingContext *context = nullptr;
3082  std::unique_ptr< QgsProcessingContext > tmpContext;
3083  if ( mProcessingContextGenerator )
3084  context = mProcessingContextGenerator->processingContext();
3085 
3086  if ( !context )
3087  {
3088  tmpContext = std::make_unique< QgsProcessingContext >();
3089  context = tmpContext.get();
3090  }
3091 
3092  layout = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, *context );
3093  setLayout( layout );
3094 }
3095 
3096 void QgsProcessingLayoutItemWidgetWrapper::setLayout( QgsPrintLayout *layout )
3097 {
3098  if ( mComboBox )
3099  mComboBox->setCurrentLayout( layout );
3100 }
3101 
3102 void QgsProcessingLayoutItemWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3103 {
3104  if ( mComboBox )
3105  {
3106  if ( !value.isValid() )
3107  mComboBox->setItem( nullptr );
3108  else
3109  {
3110  QgsLayoutItem *item = QgsProcessingParameters::parameterAsLayoutItem( parameterDefinition(), value, context, qobject_cast< QgsPrintLayout * >( mComboBox->currentLayout() ) );
3111  mComboBox->setItem( item );
3112  }
3113  }
3114  else if ( mLineEdit )
3115  {
3116  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3117  mLineEdit->setText( v );
3118  }
3119 }
3120 
3121 QVariant QgsProcessingLayoutItemWidgetWrapper::widgetValue() const
3122 {
3123  if ( mComboBox )
3124  {
3125  const QgsLayoutItem *i = mComboBox->currentItem();
3126  return i ? i->uuid() : QVariant();
3127  }
3128  else if ( mLineEdit )
3129  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3130  else
3131  return QVariant();
3132 }
3133 
3134 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleParameterTypes() const
3135 {
3136  return QStringList()
3139 }
3140 
3141 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleOutputTypes() const
3142 {
3143  return QStringList()
3145 }
3146 
3147 QString QgsProcessingLayoutItemWidgetWrapper::modelerExpressionFormatString() const
3148 {
3149  return tr( "string representing the UUID or ID of an existing print layout item" );
3150 }
3151 
3152 QString QgsProcessingLayoutItemWidgetWrapper::parameterType() const
3153 {
3155 }
3156 
3157 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutItemWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3158 {
3159  return new QgsProcessingLayoutItemWidgetWrapper( parameter, type );
3160 }
3161 
3162 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingLayoutItemWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3163 {
3164  return new QgsProcessingLayoutItemParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3165 }
3166 
3167 //
3168 // QgsProcessingPointMapTool
3169 //
3170 
3171 QgsProcessingPointMapTool::QgsProcessingPointMapTool( QgsMapCanvas *canvas )
3172  : QgsMapTool( canvas )
3173 {
3174  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::CapturePoint ) );
3175  mSnapIndicator.reset( new QgsSnapIndicator( canvas ) );
3176 }
3177 
3178 QgsProcessingPointMapTool::~QgsProcessingPointMapTool() = default;
3179 
3180 void QgsProcessingPointMapTool::deactivate()
3181 {
3182  mSnapIndicator->setMatch( QgsPointLocator::Match() );
3184 }
3185 
3186 void QgsProcessingPointMapTool::canvasMoveEvent( QgsMapMouseEvent *e )
3187 {
3188  e->snapPoint();
3189  mSnapIndicator->setMatch( e->mapPointMatch() );
3190 }
3191 
3192 void QgsProcessingPointMapTool::canvasPressEvent( QgsMapMouseEvent *e )
3193 {
3194  if ( e->button() == Qt::LeftButton )
3195  {
3196  QgsPointXY point = e->snapPoint();
3197  emit clicked( point );
3198  emit complete();
3199  }
3200 }
3201 
3202 void QgsProcessingPointMapTool::keyPressEvent( QKeyEvent *e )
3203 {
3204  if ( e->key() == Qt::Key_Escape )
3205  {
3206 
3207  // Override default shortcut management in MapCanvas
3208  e->ignore();
3209  emit complete();
3210  }
3211 }
3212 
3213 
3214 
3215 //
3216 // QgsProcessingPointPanel
3217 //
3218 
3219 QgsProcessingPointPanel::QgsProcessingPointPanel( QWidget *parent )
3220  : QWidget( parent )
3221 {
3222  QHBoxLayout *l = new QHBoxLayout();
3223  l->setContentsMargins( 0, 0, 0, 0 );
3224  mLineEdit = new QgsFilterLineEdit( );
3225  mLineEdit->setShowClearButton( false );
3226  l->addWidget( mLineEdit, 1 );
3227  mButton = new QToolButton();
3228  mButton->setText( QString( QChar( 0x2026 ) ) );
3229  l->addWidget( mButton );
3230  setLayout( l );
3231 
3232  connect( mLineEdit, &QLineEdit::textChanged, this, &QgsProcessingPointPanel::changed );
3233  connect( mButton, &QToolButton::clicked, this, &QgsProcessingPointPanel::selectOnCanvas );
3234  mButton->setVisible( false );
3235 }
3236 
3237 void QgsProcessingPointPanel::setMapCanvas( QgsMapCanvas *canvas )
3238 {
3239  mCanvas = canvas;
3240  mButton->setVisible( true );
3241 
3242  mCrs = canvas->mapSettings().destinationCrs();
3243  mTool = std::make_unique< QgsProcessingPointMapTool >( mCanvas );
3244  connect( mTool.get(), &QgsProcessingPointMapTool::clicked, this, &QgsProcessingPointPanel::updatePoint );
3245  connect( mTool.get(), &QgsProcessingPointMapTool::complete, this, &QgsProcessingPointPanel::pointPicked );
3246 }
3247 
3248 void QgsProcessingPointPanel::setAllowNull( bool allowNull )
3249 {
3250  mLineEdit->setShowClearButton( allowNull );
3251 }
3252 
3253 QVariant QgsProcessingPointPanel::value() const
3254 {
3255  return mLineEdit->showClearButton() && mLineEdit->text().trimmed().isEmpty() ? QVariant() : QVariant( mLineEdit->text() );
3256 }
3257 
3258 void QgsProcessingPointPanel::clear()
3259 {
3260  mLineEdit->clear();
3261 }
3262 
3263 void QgsProcessingPointPanel::setValue( const QgsPointXY &point, const QgsCoordinateReferenceSystem &crs )
3264 {
3265  QString newText = QStringLiteral( "%1,%2" )
3266  .arg( QString::number( point.x(), 'f' ),
3267  QString::number( point.y(), 'f' ) );
3268 
3269  mCrs = crs;
3270  if ( mCrs.isValid() )
3271  {
3272  newText += QStringLiteral( " [%1]" ).arg( mCrs.authid() );
3273  }
3274  mLineEdit->setText( newText );
3275 }
3276 
3277 void QgsProcessingPointPanel::selectOnCanvas()
3278 {
3279  if ( !mCanvas )
3280  return;
3281 
3282  mPrevTool = mCanvas->mapTool();
3283  mCanvas->setMapTool( mTool.get() );
3284 
3285  emit toggleDialogVisibility( false );
3286 }
3287 
3288 void QgsProcessingPointPanel::updatePoint( const QgsPointXY &point )
3289 {
3290  setValue( point, mCanvas->mapSettings().destinationCrs() );
3291 }
3292 
3293 void QgsProcessingPointPanel::pointPicked()
3294 {
3295  if ( !mCanvas )
3296  return;
3297 
3298  mCanvas->setMapTool( mPrevTool );
3299 
3300  emit toggleDialogVisibility( true );
3301 }
3302 
3303 
3304 
3305 //
3306 // QgsProcessingPointWidgetWrapper
3307 //
3308 
3309 QgsProcessingPointParameterDefinitionWidget::QgsProcessingPointParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3310  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3311 {
3312  QVBoxLayout *vlayout = new QVBoxLayout();
3313  vlayout->setContentsMargins( 0, 0, 0, 0 );
3314 
3315  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3316 
3317  mDefaultLineEdit = new QLineEdit();
3318  mDefaultLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
3319  mDefaultLineEdit->setPlaceholderText( tr( "Point as 'x,y'" ) );
3320  if ( const QgsProcessingParameterPoint *pointParam = dynamic_cast<const QgsProcessingParameterPoint *>( definition ) )
3321  {
3322  QgsPointXY point = QgsProcessingParameters::parameterAsPoint( pointParam, pointParam->defaultValueForGui(), context );
3323  mDefaultLineEdit->setText( QStringLiteral( "%1,%2" ).arg( QString::number( point.x(), 'f' ), QString::number( point.y(), 'f' ) ) );
3324  }
3325 
3326  vlayout->addWidget( mDefaultLineEdit );
3327  setLayout( vlayout );
3328 }
3329 
3330 QgsProcessingParameterDefinition *QgsProcessingPointParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3331 {
3332  auto param = std::make_unique< QgsProcessingParameterPoint >( name, description, mDefaultLineEdit->text() );
3333  param->setFlags( flags );
3334  return param.release();
3335 }
3336 
3337 QgsProcessingPointWidgetWrapper::QgsProcessingPointWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3338  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3339 {
3340 
3341 }
3342 
3343 QWidget *QgsProcessingPointWidgetWrapper::createWidget()
3344 {
3345  const QgsProcessingParameterPoint *pointParam = dynamic_cast< const QgsProcessingParameterPoint *>( parameterDefinition() );
3346  switch ( type() )
3347  {
3350  {
3351  mPanel = new QgsProcessingPointPanel( nullptr );
3352  if ( widgetContext().mapCanvas() )
3353  mPanel->setMapCanvas( widgetContext().mapCanvas() );
3354 
3356  mPanel->setAllowNull( true );
3357 
3358  mPanel->setToolTip( parameterDefinition()->toolTip() );
3359 
3360  connect( mPanel, &QgsProcessingPointPanel::changed, this, [ = ]
3361  {
3362  emit widgetValueHasChanged( this );
3363  } );
3364 
3365  if ( mDialog )
3366  setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
3367  return mPanel;
3368  }
3369 
3371  {
3372  mLineEdit = new QLineEdit();
3373  mLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
3374  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
3375  {
3376  emit widgetValueHasChanged( this );
3377  } );
3378  return mLineEdit;
3379  }
3380  }
3381  return nullptr;
3382 }
3383 
3384 void QgsProcessingPointWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
3385 {
3387  if ( mPanel && context.mapCanvas() )
3388  mPanel->setMapCanvas( context.mapCanvas() );
3389 }
3390 
3391 void QgsProcessingPointWidgetWrapper::setDialog( QDialog *dialog )
3392 {
3393  mDialog = dialog;
3394  if ( mPanel )
3395  {
3396  connect( mPanel, &QgsProcessingPointPanel::toggleDialogVisibility, mDialog, [ = ]( bool visible )
3397  {
3398  if ( !visible )
3399  mDialog->showMinimized();
3400  else
3401  {
3402  mDialog->showNormal();
3403  mDialog->raise();
3404  mDialog->activateWindow();
3405  }
3406  } );
3407  }
3409 }
3410 
3411 void QgsProcessingPointWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3412 {
3413  if ( mPanel )
3414  {
3415  if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
3416  mPanel->clear();
3417  else
3418  {
3419  QgsPointXY p = QgsProcessingParameters::parameterAsPoint( parameterDefinition(), value, context );
3420  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
3421  mPanel->setValue( p, crs );
3422  }
3423  }
3424  else if ( mLineEdit )
3425  {
3426  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3427  mLineEdit->setText( v );
3428  }
3429 }
3430 
3431 QVariant QgsProcessingPointWidgetWrapper::widgetValue() const
3432 {
3433  if ( mPanel )
3434  {
3435  return mPanel->value();
3436  }
3437  else if ( mLineEdit )
3438  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3439  else
3440  return QVariant();
3441 }
3442 
3443 QStringList QgsProcessingPointWidgetWrapper::compatibleParameterTypes() const
3444 {
3445  return QStringList()
3448 }
3449 
3450 QStringList QgsProcessingPointWidgetWrapper::compatibleOutputTypes() const
3451 {
3452  return QStringList()
3454 }
3455 
3456 QString QgsProcessingPointWidgetWrapper::modelerExpressionFormatString() const
3457 {
3458  return tr( "string of the format 'x,y' or a geometry value (centroid is used)" );
3459 }
3460 
3461 QString QgsProcessingPointWidgetWrapper::parameterType() const
3462 {
3464 }
3465 
3466 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3467 {
3468  return new QgsProcessingPointWidgetWrapper( parameter, type );
3469 }
3470 
3471 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3472 {
3473  return new QgsProcessingPointParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3474 }
3475 
3476 
3477 //
3478 // QgsProcessingGeometryWidgetWrapper
3479 //
3480 
3481 
3482 QgsProcessingGeometryParameterDefinitionWidget::QgsProcessingGeometryParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3483  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3484 {
3485  QVBoxLayout *vlayout = new QVBoxLayout();
3486  vlayout->setContentsMargins( 0, 0, 0, 0 );
3487 
3488  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3489 
3490  mDefaultLineEdit = new QLineEdit();
3491  mDefaultLineEdit->setToolTip( tr( "Geometry as WKT" ) );
3492  mDefaultLineEdit->setPlaceholderText( tr( "Geometry as WKT" ) );
3493  if ( const QgsProcessingParameterGeometry *geometryParam = dynamic_cast<const QgsProcessingParameterGeometry *>( definition ) )
3494  {
3495  QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( geometryParam, geometryParam->defaultValueForGui(), context );
3496  if ( !g.isNull() )
3497  mDefaultLineEdit->setText( g.asWkt() );
3498  }
3499 
3500  vlayout->addWidget( mDefaultLineEdit );
3501  setLayout( vlayout );
3502 }
3503 
3504 QgsProcessingParameterDefinition *QgsProcessingGeometryParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3505 {
3506  auto param = std::make_unique< QgsProcessingParameterGeometry >( name, description, mDefaultLineEdit->text() );
3507  param->setFlags( flags );
3508  return param.release();
3509 }
3510 
3511 QgsProcessingGeometryWidgetWrapper::QgsProcessingGeometryWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3512  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3513 {
3514 
3515 }
3516 
3517 QWidget *QgsProcessingGeometryWidgetWrapper::createWidget()
3518 {
3519  switch ( type() )
3520  {
3524  {
3525  mLineEdit = new QLineEdit();
3526  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
3527  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
3528  {
3529  emit widgetValueHasChanged( this );
3530  } );
3531  return mLineEdit;
3532  }
3533  }
3534  return nullptr;
3535 }
3536 
3537 void QgsProcessingGeometryWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3538 {
3539  if ( mLineEdit )
3540  {
3541  QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( parameterDefinition(), value, context );
3542  if ( !g.isNull() )
3543  mLineEdit->setText( g.asWkt() );
3544  else
3545  mLineEdit->clear();
3546  }
3547 }
3548 
3549 QVariant QgsProcessingGeometryWidgetWrapper::widgetValue() const
3550 {
3551  if ( mLineEdit )
3552  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3553  else
3554  return QVariant();
3555 }
3556 
3557 QStringList QgsProcessingGeometryWidgetWrapper::compatibleParameterTypes() const
3558 {
3559  return QStringList()
3564 }
3565 
3566 QStringList QgsProcessingGeometryWidgetWrapper::compatibleOutputTypes() const
3567 {
3568  return QStringList()
3570 }
3571 
3572 QString QgsProcessingGeometryWidgetWrapper::modelerExpressionFormatString() const
3573 {
3574  return tr( "string in the Well-Known-Text format or a geometry value" );
3575 }
3576 
3577 QString QgsProcessingGeometryWidgetWrapper::parameterType() const
3578 {
3580 }
3581 
3582 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingGeometryWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3583 {
3584  return new QgsProcessingGeometryWidgetWrapper( parameter, type );
3585 }
3586 
3587 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingGeometryWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3588 {
3589  return new QgsProcessingGeometryParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3590 }
3591 
3592 
3593 //
3594 // QgsProcessingColorWidgetWrapper
3595 //
3596 
3597 
3598 QgsProcessingColorParameterDefinitionWidget::QgsProcessingColorParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3599  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3600 {
3601  QVBoxLayout *vlayout = new QVBoxLayout();
3602  vlayout->setContentsMargins( 0, 0, 0, 0 );
3603 
3604  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3605 
3606  mDefaultColorButton = new QgsColorButton();
3607  mDefaultColorButton->setShowNull( true );
3608  mAllowOpacity = new QCheckBox( tr( "Allow opacity control" ) );
3609 
3610  if ( const QgsProcessingParameterColor *colorParam = dynamic_cast<const QgsProcessingParameterColor *>( definition ) )
3611  {
3612  const QColor c = QgsProcessingParameters::parameterAsColor( colorParam, colorParam->defaultValueForGui(), context );
3613  if ( !c.isValid() )
3614  mDefaultColorButton->setToNull();
3615  else
3616  mDefaultColorButton->setColor( c );
3617  mAllowOpacity->setChecked( colorParam->opacityEnabled() );
3618  }
3619  else
3620  {
3621  mDefaultColorButton->setToNull();
3622  mAllowOpacity->setChecked( true );
3623  }
3624 
3625  vlayout->addWidget( mDefaultColorButton );
3626  vlayout->addWidget( mAllowOpacity );
3627  setLayout( vlayout );
3628 }
3629 
3630 QgsProcessingParameterDefinition *QgsProcessingColorParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3631 {
3632  auto param = std::make_unique< QgsProcessingParameterColor >( name, description, mDefaultColorButton->color(), mAllowOpacity->isChecked() );
3633  param->setFlags( flags );
3634  return param.release();
3635 }
3636 
3637 QgsProcessingColorWidgetWrapper::QgsProcessingColorWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3638  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3639 {
3640 
3641 }
3642 
3643 QWidget *QgsProcessingColorWidgetWrapper::createWidget()
3644 {
3645  const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor *>( parameterDefinition() );
3646  switch ( type() )
3647  {
3651  {
3652  mColorButton = new QgsColorButton( nullptr );
3653  mColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
3654 
3656  mColorButton->setShowNull( true );
3657 
3658  mColorButton->setAllowOpacity( colorParam->opacityEnabled() );
3659  mColorButton->setToolTip( parameterDefinition()->toolTip() );
3660  mColorButton->setColorDialogTitle( parameterDefinition()->description() );
3661  if ( colorParam->defaultValueForGui().value< QColor >().isValid() )
3662  {
3663  mColorButton->setDefaultColor( colorParam->defaultValueForGui().value< QColor >() );
3664  }
3665 
3666  connect( mColorButton, &QgsColorButton::colorChanged, this, [ = ]
3667  {
3668  emit widgetValueHasChanged( this );
3669  } );
3670 
3671  return mColorButton;
3672  }
3673  }
3674  return nullptr;
3675 }
3676 
3677 void QgsProcessingColorWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3678 {
3679  if ( mColorButton )
3680  {
3681  if ( !value.isValid() ||
3682  ( value.type() == QVariant::String && value.toString().isEmpty() )
3683  || ( value.type() == QVariant::Color && !value.value< QColor >().isValid() ) )
3684  mColorButton->setToNull();
3685  else
3686  {
3687  const QColor c = QgsProcessingParameters::parameterAsColor( parameterDefinition(), value, context );
3688  if ( !c.isValid() && mColorButton->showNull() )
3689  mColorButton->setToNull();
3690  else
3691  mColorButton->setColor( c );
3692  }
3693  }
3694 }
3695 
3696 QVariant QgsProcessingColorWidgetWrapper::widgetValue() const
3697 {
3698  if ( mColorButton )
3699  return mColorButton->isNull() ? QVariant() : mColorButton->color();
3700  else
3701  return QVariant();
3702 }
3703 
3704 QStringList QgsProcessingColorWidgetWrapper::compatibleParameterTypes() const
3705 {
3706  return QStringList()
3709 }
3710 
3711 QStringList QgsProcessingColorWidgetWrapper::compatibleOutputTypes() const
3712 {
3713  return QStringList()
3715 }
3716 
3717 QString QgsProcessingColorWidgetWrapper::modelerExpressionFormatString() const
3718 {
3719  return tr( "color style string, e.g. #ff0000 or 255,0,0" );
3720 }
3721 
3722 QString QgsProcessingColorWidgetWrapper::parameterType() const
3723 {
3725 }
3726 
3727 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingColorWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3728 {
3729  return new QgsProcessingColorWidgetWrapper( parameter, type );
3730 }
3731 
3732 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingColorWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3733 {
3734  return new QgsProcessingColorParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3735 }
3736 
3737 
3738 //
3739 // QgsProcessingCoordinateOperationWidgetWrapper
3740 //
3741 
3742 QgsProcessingCoordinateOperationParameterDefinitionWidget::QgsProcessingCoordinateOperationParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3743  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3744 {
3745  QVBoxLayout *vlayout = new QVBoxLayout();
3746  vlayout->setContentsMargins( 0, 0, 0, 0 );
3747 
3748  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3749 
3750  mDefaultLineEdit = new QLineEdit();
3751  if ( const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
3752  mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( coordParam, coordParam->defaultValueForGui(), context ) );
3753  vlayout->addWidget( mDefaultLineEdit );
3754 
3755  mSourceParamComboBox = new QComboBox();
3756  mDestParamComboBox = new QComboBox();
3757  QString initialSource;
3758  QString initialDest;
3759  QgsCoordinateReferenceSystem sourceCrs;
3761  if ( const QgsProcessingParameterCoordinateOperation *itemParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
3762  {
3763  initialSource = itemParam->sourceCrsParameterName();
3764  initialDest = itemParam->destinationCrsParameterName();
3765  sourceCrs = QgsProcessingUtils::variantToCrs( itemParam->sourceCrs(), context );
3766  destCrs = QgsProcessingUtils::variantToCrs( itemParam->destinationCrs(), context );
3767  }
3768 
3769  mSourceParamComboBox->addItem( QString(), QString() );
3770  mDestParamComboBox->addItem( QString(), QString() );
3771  if ( auto *lModel = widgetContext.model() )
3772  {
3773  // populate combo box with other model input choices
3774  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
3775  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
3776  {
3777  if ( definition && it->parameterName() == definition->name() )
3778  continue;
3779 
3780  // TODO - we should probably filter this list?
3781  mSourceParamComboBox->addItem( it->parameterName(), it->parameterName() );
3782  mDestParamComboBox->addItem( it->parameterName(), it->parameterName() );
3783  if ( !initialSource.isEmpty() && initialSource == it->parameterName() )
3784  {
3785  mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
3786  }
3787  if ( !initialDest.isEmpty() && initialDest == it->parameterName() )
3788  {
3789  mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
3790  }
3791  }
3792  }
3793 
3794  if ( mSourceParamComboBox->count() == 1 && !initialSource.isEmpty() )
3795  {
3796  // if no source candidates found, we just add the existing one as a placeholder
3797  mSourceParamComboBox->addItem( initialSource, initialSource );
3798  mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
3799  }
3800  if ( mDestParamComboBox->count() == 1 && !initialDest.isEmpty() )
3801  {
3802  // if no dest candidates found, we just add the existing one as a placeholder
3803  mDestParamComboBox->addItem( initialDest, initialDest );
3804  mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
3805  }
3806 
3807  vlayout->addWidget( new QLabel( tr( "Source CRS parameter" ) ) );
3808  vlayout->addWidget( mSourceParamComboBox );
3809  vlayout->addWidget( new QLabel( tr( "Destination CRS parameter" ) ) );
3810  vlayout->addWidget( mDestParamComboBox );
3811 
3812  mStaticSourceWidget = new QgsProjectionSelectionWidget();
3813  mStaticSourceWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
3814  mStaticSourceWidget->setCrs( sourceCrs );
3815  mStaticDestWidget = new QgsProjectionSelectionWidget();
3816  mStaticDestWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
3817  mStaticDestWidget->setCrs( destCrs );
3818 
3819  vlayout->addWidget( new QLabel( tr( "Static source CRS" ) ) );
3820  vlayout->addWidget( mStaticSourceWidget );
3821  vlayout->addWidget( new QLabel( tr( "Static destination CRS" ) ) );
3822  vlayout->addWidget( mStaticDestWidget );
3823 
3824  setLayout( vlayout );
3825 }
3826 
3827 QgsProcessingParameterDefinition *QgsProcessingCoordinateOperationParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3828 {
3829  auto param = std::make_unique< QgsProcessingParameterCoordinateOperation >( name, description, mDefaultLineEdit->text(),
3830  mSourceParamComboBox->currentText(),
3831  mDestParamComboBox->currentText(),
3832  mStaticSourceWidget->crs().isValid() ? QVariant::fromValue( mStaticSourceWidget->crs() ) : QVariant(),
3833  mStaticDestWidget->crs().isValid() ? QVariant::fromValue( mStaticDestWidget->crs() ) : QVariant() );
3834  param->setFlags( flags );
3835  return param.release();
3836 }
3837 
3838 QgsProcessingCoordinateOperationWidgetWrapper::QgsProcessingCoordinateOperationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3839  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3840 {
3841 
3842 }
3843 
3844 QWidget *QgsProcessingCoordinateOperationWidgetWrapper::createWidget()
3845 {
3846  const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast< const QgsProcessingParameterCoordinateOperation *>( parameterDefinition() );
3848  mSourceCrs = QgsProcessingUtils::variantToCrs( coordParam->sourceCrs(), c );
3849  mDestCrs = QgsProcessingUtils::variantToCrs( coordParam->destinationCrs(), c );
3850  switch ( type() )
3851  {
3853  {
3854  mOperationWidget = new QgsCoordinateOperationWidget( nullptr );
3855  mOperationWidget->setShowMakeDefault( false );
3856  mOperationWidget->setShowFallbackOption( false );
3857  mOperationWidget->setToolTip( parameterDefinition()->toolTip() );
3858  mOperationWidget->setSourceCrs( mSourceCrs );
3859  mOperationWidget->setDestinationCrs( mDestCrs );
3860  mOperationWidget->setMapCanvas( mCanvas );
3861  if ( !coordParam->defaultValueForGui().toString().isEmpty() )
3862  {
3864  deets.proj = coordParam->defaultValueForGui().toString();
3865  mOperationWidget->setSelectedOperation( deets );
3866  }
3867 
3868  connect( mOperationWidget, &QgsCoordinateOperationWidget::operationChanged, this, [ = ]
3869  {
3870  emit widgetValueHasChanged( this );
3871  } );
3872 
3873  return mOperationWidget;
3874  }
3875 
3878  {
3879  mLineEdit = new QLineEdit();
3880  QHBoxLayout *layout = new QHBoxLayout();
3881  layout->addWidget( mLineEdit, 1 );
3882  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
3883  {
3884  emit widgetValueHasChanged( this );
3885  } );
3886 
3887  QToolButton *button = new QToolButton();
3888  button->setText( QString( QChar( 0x2026 ) ) );
3889  connect( button, &QToolButton::clicked, this, [ = ]
3890  {
3891  QgsDatumTransformDialog dlg( mSourceCrs, mDestCrs, false, false, false, qMakePair( -1, -1 ), button, Qt::WindowFlags(), mLineEdit->text(), mCanvas );
3892  if ( dlg.exec() )
3893  {
3894  mLineEdit->setText( dlg.selectedDatumTransform().proj );
3895  emit widgetValueHasChanged( this );
3896  }
3897  } );
3898  layout->addWidget( button );
3899 
3900  QWidget *w = new QWidget();
3901  layout->setContentsMargins( 0, 0, 0, 0 );
3902  w->setLayout( layout );
3903  return w;
3904  }
3905 
3906  }
3907  return nullptr;
3908 }
3909 
3910 void QgsProcessingCoordinateOperationWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
3911 {
3913  switch ( type() )
3914  {
3917  {
3918  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
3919  {
3920  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterCoordinateOperation * >( parameterDefinition() )->sourceCrsParameterName() )
3921  {
3922  setSourceCrsParameterValue( wrapper->parameterValue() );
3924  {
3925  setSourceCrsParameterValue( wrapper->parameterValue() );
3926  } );
3927  }
3928  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterCoordinateOperation * >( parameterDefinition() )->destinationCrsParameterName() )
3929  {
3930  setDestinationCrsParameterValue( wrapper->parameterValue() );
3932  {
3933  setDestinationCrsParameterValue( wrapper->parameterValue() );
3934  } );
3935  }
3936  }
3937  break;
3938  }
3939 
3941  break;
3942  }
3943 }
3944 
3945 void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
3946 {
3947  mCanvas = context.mapCanvas();
3948  if ( mOperationWidget )
3949  mOperationWidget->setMapCanvas( context.mapCanvas() );
3950 }
3951 
3952 void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
3953 {
3954  if ( mOperationWidget )
3955  {
3956  if ( !value.isValid() ||
3957  ( value.type() == QVariant::String ) )
3958  {
3960  deets.proj = value.toString();
3961  mOperationWidget->setSelectedOperation( deets );
3962  }
3963  }
3964  if ( mLineEdit )
3965  {
3966  if ( !value.isValid() ||
3967  ( value.type() == QVariant::String ) )
3968  {
3969  mLineEdit->setText( value.toString() );
3970  }
3971  }
3972 }
3973 
3974 QVariant QgsProcessingCoordinateOperationWidgetWrapper::widgetValue() const
3975 {
3976  if ( mOperationWidget )
3977  return mOperationWidget->selectedOperation().proj;
3978  else if ( mLineEdit )
3979  return mLineEdit->text();
3980  else
3981  return QVariant();
3982 }
3983 
3984 QStringList QgsProcessingCoordinateOperationWidgetWrapper::compatibleParameterTypes() const
3985 {
3986  return QStringList()
3989 }
3990 
3991 QStringList QgsProcessingCoordinateOperationWidgetWrapper::compatibleOutputTypes() const
3992 {
3993  return QStringList()
3995 }
3996 
3997 QString QgsProcessingCoordinateOperationWidgetWrapper::modelerExpressionFormatString() const
3998 {
3999  return tr( "Proj coordinate operation string, e.g. '+proj=pipeline +step +inv...'" );
4000 }
4001 
4002 void QgsProcessingCoordinateOperationWidgetWrapper::setSourceCrsParameterValue( const QVariant &value )
4003 {
4004  QgsProcessingContext *context = nullptr;
4005  std::unique_ptr< QgsProcessingContext > tmpContext;
4006  if ( mProcessingContextGenerator )
4007  context = mProcessingContextGenerator->processingContext();
4008 
4009  if ( !context )
4010  {
4011  tmpContext = std::make_unique< QgsProcessingContext >();
4012  context = tmpContext.get();
4013  }
4014 
4015  mSourceCrs = QgsProcessingUtils::variantToCrs( value, *context );
4016  if ( mOperationWidget )
4017  {
4018  mOperationWidget->setSourceCrs( mSourceCrs );
4019  mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
4020  }
4021 }
4022 
4023 void QgsProcessingCoordinateOperationWidgetWrapper::setDestinationCrsParameterValue( const QVariant &value )
4024 {
4025  QgsProcessingContext *context = nullptr;
4026  std::unique_ptr< QgsProcessingContext > tmpContext;
4027  if ( mProcessingContextGenerator )
4028  context = mProcessingContextGenerator->processingContext();
4029 
4030  if ( !context )
4031  {
4032  tmpContext = std::make_unique< QgsProcessingContext >();
4033  context = tmpContext.get();
4034  }
4035 
4036  mDestCrs = QgsProcessingUtils::variantToCrs( value, *context );
4037  if ( mOperationWidget )
4038  {
4039  mOperationWidget->setDestinationCrs( mDestCrs );
4040  mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
4041  }
4042 }
4043 
4044 QString QgsProcessingCoordinateOperationWidgetWrapper::parameterType() const
4045 {
4047 }
4048 
4049 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCoordinateOperationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4050 {
4051  return new QgsProcessingCoordinateOperationWidgetWrapper( parameter, type );
4052 }
4053 
4054 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingCoordinateOperationWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4055 {
4056  return new QgsProcessingCoordinateOperationParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4057 }
4058 
4059 
4060 
4061 //
4062 // QgsProcessingFieldPanelWidget
4063 //
4064 
4065 QgsProcessingFieldPanelWidget::QgsProcessingFieldPanelWidget( QWidget *parent, const QgsProcessingParameterField *param )
4066  : QWidget( parent )
4067  , mParam( param )
4068 {
4069  QHBoxLayout *hl = new QHBoxLayout();
4070  hl->setContentsMargins( 0, 0, 0, 0 );
4071 
4072  mLineEdit = new QLineEdit();
4073  mLineEdit->setEnabled( false );
4074  hl->addWidget( mLineEdit, 1 );
4075 
4076  mToolButton = new QToolButton();
4077  mToolButton->setText( QString( QChar( 0x2026 ) ) );
4078  hl->addWidget( mToolButton );
4079 
4080  setLayout( hl );
4081 
4082  if ( mParam )
4083  {
4084  mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
4085  }
4086 
4087  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingFieldPanelWidget::showDialog );
4088 }
4089 
4090 void QgsProcessingFieldPanelWidget::setFields( const QgsFields &fields )
4091 {
4092  mFields = fields;
4093 }
4094 
4095 void QgsProcessingFieldPanelWidget::setValue( const QVariant &value )
4096 {
4097  if ( value.isValid() )
4098  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
4099  else
4100  mValue.clear();
4101 
4102  updateSummaryText();
4103  emit changed();
4104 }
4105 
4106 void QgsProcessingFieldPanelWidget::showDialog()
4107 {
4108  QVariantList availableOptions;
4109  QStringList fieldNames;
4110  availableOptions.reserve( mFields.size() );
4111  for ( const QgsField &field : std::as_const( mFields ) )
4112  {
4113  availableOptions << field.name();
4114  }
4115 
4117  if ( panel && panel->dockMode() )
4118  {
4119  QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
4120  widget->setPanelTitle( mParam->description() );
4121 
4122  widget->setValueFormatter( []( const QVariant & v ) -> QString
4123  {
4124  return v.toString();
4125  } );
4126 
4127  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
4128  {
4129  setValue( widget->selectedOptions() );
4130  } );
4131  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
4132  panel->openPanel( widget );
4133  }
4134  else
4135  {
4136  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
4137 
4138  dlg.setValueFormatter( []( const QVariant & v ) -> QString
4139  {
4140  return v.toString();
4141  } );
4142  if ( dlg.exec() )
4143  {
4144  setValue( dlg.selectedOptions() );
4145  }
4146  }
4147 }
4148 
4149 void QgsProcessingFieldPanelWidget::updateSummaryText()
4150 {
4151  if ( mParam )
4152  mLineEdit->setText( tr( "%1 options selected" ).arg( mValue.count() ) );
4153 }
4154 
4155 
4156 //
4157 // QgsProcessingFieldWidgetWrapper
4158 //
4159 
4160 QgsProcessingFieldParameterDefinitionWidget::QgsProcessingFieldParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4161  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4162 {
4163  QVBoxLayout *vlayout = new QVBoxLayout();
4164  vlayout->setContentsMargins( 0, 0, 0, 0 );
4165 
4166  vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
4167  mParentLayerComboBox = new QComboBox();
4168 
4169  QString initialParent;
4170  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4171  initialParent = fieldParam->parentLayerParameterName();
4172 
4173  if ( auto *lModel = widgetContext.model() )
4174  {
4175  // populate combo box with other model input choices
4176  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
4177  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
4178  {
4179  if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast< const QgsProcessingParameterFeatureSource * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
4180  {
4181  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
4182  if ( !initialParent.isEmpty() && initialParent == definition->name() )
4183  {
4184  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4185  }
4186  }
4187  else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast< const QgsProcessingParameterVectorLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
4188  {
4189  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
4190  if ( !initialParent.isEmpty() && initialParent == definition->name() )
4191  {
4192  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4193  }
4194  }
4195  else if ( const QgsProcessingParameterMultipleLayers *definition = dynamic_cast< const QgsProcessingParameterMultipleLayers * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
4196  {
4197  if ( definition->layerType() == QgsProcessing::TypeVector )
4198  {
4199  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
4200  if ( !initialParent.isEmpty() && initialParent == definition->name() )
4201  {
4202  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4203  }
4204  }
4205  }
4206  }
4207  }
4208 
4209  if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
4210  {
4211  // if no parent candidates found, we just add the existing one as a placeholder
4212  mParentLayerComboBox->addItem( initialParent, initialParent );
4213  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4214  }
4215 
4216  vlayout->addWidget( mParentLayerComboBox );
4217 
4218  vlayout->addWidget( new QLabel( tr( "Allowed data type" ) ) );
4219  mDataTypeComboBox = new QComboBox();
4220  mDataTypeComboBox->addItem( tr( "Any" ), QgsProcessingParameterField::Any );
4221  mDataTypeComboBox->addItem( tr( "Number" ), QgsProcessingParameterField::Numeric );
4222  mDataTypeComboBox->addItem( tr( "String" ), QgsProcessingParameterField::String );
4223  mDataTypeComboBox->addItem( tr( "Date/time" ), QgsProcessingParameterField::DateTime );
4224  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4225  mDataTypeComboBox->setCurrentIndex( mDataTypeComboBox->findData( fieldParam->dataType() ) );
4226 
4227  vlayout->addWidget( mDataTypeComboBox );
4228 
4229  mAllowMultipleCheckBox = new QCheckBox( tr( "Accept multiple fields" ) );
4230  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4231  mAllowMultipleCheckBox->setChecked( fieldParam->allowMultiple() );
4232 
4233  vlayout->addWidget( mAllowMultipleCheckBox );
4234 
4235  mDefaultToAllCheckBox = new QCheckBox( tr( "Select all fields by default" ) );
4236  mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
4237  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4238  mDefaultToAllCheckBox->setChecked( fieldParam->defaultToAllFields() );
4239 
4240  vlayout->addWidget( mDefaultToAllCheckBox );
4241 
4242  connect( mAllowMultipleCheckBox, &QCheckBox::stateChanged, this, [ = ]
4243  {
4244  mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
4245  } );
4246 
4247  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4248 
4249  mDefaultLineEdit = new QLineEdit();
4250  mDefaultLineEdit->setToolTip( tr( "Default field name, or ; separated list of field names for multiple field parameters" ) );
4251  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4252  {
4253  const QStringList fields = QgsProcessingParameters::parameterAsFields( fieldParam, fieldParam->defaultValueForGui(), context );
4254  mDefaultLineEdit->setText( fields.join( ';' ) );
4255  }
4256  vlayout->addWidget( mDefaultLineEdit );
4257 
4258  setLayout( vlayout );
4259 }
4260 
4261 QgsProcessingParameterDefinition *QgsProcessingFieldParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4262 {
4263  QgsProcessingParameterField::DataType dataType = static_cast< QgsProcessingParameterField::DataType >( mDataTypeComboBox->currentData().toInt() );
4264 
4265  QVariant defaultValue;
4266  if ( !mDefaultLineEdit->text().trimmed().isEmpty() )
4267  {
4268  defaultValue = mDefaultLineEdit->text();
4269  }
4270  auto param = std::make_unique< QgsProcessingParameterField >( name, description, defaultValue, mParentLayerComboBox->currentData().toString(), dataType, mAllowMultipleCheckBox->isChecked(), false, mDefaultToAllCheckBox->isChecked() );
4271  param->setFlags( flags );
4272  return param.release();
4273 }
4274 
4275 QgsProcessingFieldWidgetWrapper::QgsProcessingFieldWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4276  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4277 {
4278 
4279 }
4280 
4281 QWidget *QgsProcessingFieldWidgetWrapper::createWidget()
4282 {
4283  const QgsProcessingParameterField *fieldParam = dynamic_cast< const QgsProcessingParameterField *>( parameterDefinition() );
4284  switch ( type() )
4285  {
4288  {
4289  if ( fieldParam->allowMultiple() )
4290  {
4291  mPanel = new QgsProcessingFieldPanelWidget( nullptr, fieldParam );
4292  mPanel->setToolTip( parameterDefinition()->toolTip() );
4293  connect( mPanel, &QgsProcessingFieldPanelWidget::changed, this, [ = ]
4294  {
4295  emit widgetValueHasChanged( this );
4296  } );
4297  return mPanel;
4298  }
4299  else
4300  {
4301  mComboBox = new QgsFieldComboBox();
4302  mComboBox->setAllowEmptyFieldName( fieldParam->flags() & QgsProcessingParameterDefinition::FlagOptional );
4303 
4304  if ( fieldParam->dataType() == QgsProcessingParameterField::Numeric )
4305  mComboBox->setFilters( QgsFieldProxyModel::Numeric );
4306  else if ( fieldParam->dataType() == QgsProcessingParameterField::String )
4307  mComboBox->setFilters( QgsFieldProxyModel::String );
4308  else if ( fieldParam->dataType() == QgsProcessingParameterField::DateTime )
4310 
4311  mComboBox->setToolTip( parameterDefinition()->toolTip() );
4312  connect( mComboBox, &QgsFieldComboBox::fieldChanged, this, [ = ]( const QString & )
4313  {
4314  emit widgetValueHasChanged( this );
4315  } );
4316  return mComboBox;
4317  }
4318  }
4319 
4321  {
4322  mLineEdit = new QLineEdit();
4323  mLineEdit->setToolTip( QObject::tr( "Name of field (separate field names with ; for multiple field parameters)" ) );
4324  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
4325  {
4326  emit widgetValueHasChanged( this );
4327  } );
4328  return mLineEdit;
4329  }
4330 
4331  }
4332  return nullptr;
4333 }
4334 
4335 void QgsProcessingFieldWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
4336 {
4338  switch ( type() )
4339  {
4342  {
4343  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
4344  {
4345  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterField * >( parameterDefinition() )->parentLayerParameterName() )
4346  {
4347  setParentLayerWrapperValue( wrapper );
4349  {
4350  setParentLayerWrapperValue( wrapper );
4351  } );
4352  break;
4353  }
4354  }
4355  break;
4356  }
4357 
4359  break;
4360  }
4361 }
4362 
4363 void QgsProcessingFieldWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
4364 {
4365  // evaluate value to layer
4366  QgsProcessingContext *context = nullptr;
4367  std::unique_ptr< QgsProcessingContext > tmpContext;
4368  if ( mProcessingContextGenerator )
4369  context = mProcessingContextGenerator->processingContext();
4370 
4371  if ( !context )
4372  {
4373  tmpContext = std::make_unique< QgsProcessingContext >();
4374  context = tmpContext.get();
4375  }
4376 
4377  QVariant value = parentWrapper->parameterValue();
4378 
4379  if ( value.canConvert<QgsProcessingFeatureSourceDefinition>() )
4380  {
4381  // input is a QgsProcessingFeatureSourceDefinition - source from it.
4382  // this is normally discouraged, and algorithms should NEVER do this -- but in this case we can make
4383  // certain assumptions due to the fact that we're calling this outside of algorithm/model execution and all sources
4384  // should be real map layers at this stage
4385  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
4386  value = fromVar.source;
4387  }
4388 
4389  bool valueSet = false;
4390  const QList< QgsMapLayer * > layers = QgsProcessingParameters::parameterAsLayerList( parentWrapper->parameterDefinition(), value, *context );
4391 
4392  // several layers, populate with intersection of layers fields
4393  if ( layers.count() > 1 )
4394  {
4395  QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layers.at( 0 ) );
4396  QgsFields fields = vlayer && vlayer->isValid() ? vlayer->fields() : QgsFields();
4397  const QList< QgsMapLayer * > remainingLayers = layers.mid( 1 );
4398  for ( QgsMapLayer *layer : remainingLayers )
4399  {
4400  if ( fields.isEmpty() )
4401  break;
4402 
4403  QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layer );
4404  if ( !vlayer || !vlayer->isValid() )
4405  {
4406  fields = QgsFields();
4407  break;
4408  }
4409 
4410  for ( int fieldIdx = fields.count() - 1; fieldIdx >= 0; fieldIdx-- )
4411  {
4412  if ( vlayer->fields().lookupField( fields.at( fieldIdx ).name() ) < 0 )
4413  fields.remove( fieldIdx );
4414  }
4415  }
4416 
4417  if ( mComboBox )
4418  mComboBox->setFields( fields );
4419  else if ( mPanel )
4420  mPanel->setFields( filterFields( fields ) );
4421 
4422  valueSet = true;
4423  }
4424 
4425  // only one layer
4426  if ( !valueSet && !layers.isEmpty() && layers.at( 0 )->isValid() )
4427  {
4428  QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( layers.at( 0 ) );
4429 
4430  // need to grab ownership of layer if required - otherwise layer may be deleted when context
4431  // goes out of scope
4432  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
4433  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::VectorLayer )
4434  {
4435  mParentLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
4436  layer = mParentLayer.get();
4437  }
4438  else
4439  {
4440  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
4441  }
4442 
4443  if ( mComboBox )
4444  mComboBox->setLayer( layer );
4445  else if ( mPanel )
4446  mPanel->setFields( filterFields( layer->fields() ) );
4447 
4448  valueSet = true;
4449  }
4450 
4451  if ( !valueSet )
4452  {
4453  std::unique_ptr< QgsProcessingFeatureSource > source( QgsProcessingParameters::parameterAsSource( parentWrapper->parameterDefinition(), value, *context ) );
4454  if ( source )
4455  {
4456  const QgsFields fields = source->fields();
4457  if ( mComboBox )
4458  mComboBox->setFields( fields );
4459  else if ( mPanel )
4460  mPanel->setFields( filterFields( fields ) );
4461 
4462  valueSet = true;
4463  }
4464  }
4465 
4466  if ( !valueSet )
4467  {
4468  if ( mComboBox )
4469  mComboBox->setLayer( nullptr );
4470  else if ( mPanel )
4471  mPanel->setFields( QgsFields() );
4472 
4473  if ( value.isValid() && widgetContext().messageBar() )
4474  {
4475  widgetContext().messageBar()->clearWidgets();
4476  widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent field could not be populated" ),
4477  Qgis::MessageLevel::Info );
4478  }
4479  return;
4480  }
4481 
4482  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4483  if ( mPanel && fieldParam->defaultToAllFields() )
4484  {
4485  QVariantList val;
4486  val.reserve( mPanel->fields().size() );
4487  for ( const QgsField &field : mPanel->fields() )
4488  val << field.name();
4489  setWidgetValue( val, *context );
4490  }
4491  else if ( fieldParam->defaultValueForGui().isValid() )
4492  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
4493 }
4494 
4495 void QgsProcessingFieldWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4496 {
4497  if ( mComboBox )
4498  {
4499  if ( !value.isValid() )
4500  mComboBox->setField( QString() );
4501  else
4502  {
4503  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
4504  mComboBox->setField( v );
4505  }
4506  }
4507  else if ( mPanel )
4508  {
4509  QVariantList opts;
4510  if ( value.isValid() )
4511  {
4512  const QStringList v = QgsProcessingParameters::parameterAsFields( parameterDefinition(), value, context );
4513  opts.reserve( v.size() );
4514  for ( const QString &i : v )
4515  opts << i;
4516  }
4517  if ( mPanel )
4518  mPanel->setValue( opts );
4519  }
4520  else if ( mLineEdit )
4521  {
4522  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4523  if ( fieldParam->allowMultiple() )
4524  {
4525  const QStringList v = QgsProcessingParameters::parameterAsFields( parameterDefinition(), value, context );
4526  mLineEdit->setText( v.join( ';' ) );
4527  }
4528  else
4529  {
4530  mLineEdit->setText( QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context ) );
4531  }
4532  }
4533 }
4534 
4535 QVariant QgsProcessingFieldWidgetWrapper::widgetValue() const
4536 {
4537  if ( mComboBox )
4538  return mComboBox->currentField();
4539  else if ( mPanel )
4540  return mPanel->value();
4541  else if ( mLineEdit )
4542  {
4543  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4544  if ( fieldParam->allowMultiple() )
4545  {
4546  return mLineEdit->text().split( ';' );
4547  }
4548  else
4549  return mLineEdit->text();
4550  }
4551  else
4552  return QVariant();
4553 }
4554 
4555 QStringList QgsProcessingFieldWidgetWrapper::compatibleParameterTypes() const
4556 {
4557  return QStringList()
4560 }
4561 
4562 QStringList QgsProcessingFieldWidgetWrapper::compatibleOutputTypes() const
4563 {
4564  return QStringList()
4566 }
4567 
4568 QString QgsProcessingFieldWidgetWrapper::modelerExpressionFormatString() const
4569 {
4570  return tr( "selected field names as an array of names, or semicolon separated string of options (e.g. 'fid;place_name')" );
4571 }
4572 
4573 const QgsVectorLayer *QgsProcessingFieldWidgetWrapper::linkedVectorLayer() const
4574 {
4575  if ( mComboBox && mComboBox->layer() )
4576  return mComboBox->layer();
4577 
4579 }
4580 
4581 QgsFields QgsProcessingFieldWidgetWrapper::filterFields( const QgsFields &fields ) const
4582 {
4583  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4584  QgsFields res;
4585  for ( const QgsField &f : fields )
4586  {
4587  switch ( fieldParam->dataType() )
4588  {
4590  res.append( f );
4591  break;
4592 
4594  if ( f.isNumeric() )
4595  res.append( f );
4596  break;
4597 
4599  if ( f.type() == QVariant::String )
4600  res.append( f );
4601  break;
4602 
4604  if ( f.type() == QVariant::Date || f.type() == QVariant::Time || f.type() == QVariant::DateTime )
4605  res.append( f );
4606  break;
4607  }
4608  }
4609 
4610  return res;
4611 }
4612 
4613 QString QgsProcessingFieldWidgetWrapper::parameterType() const
4614 {
4616 }
4617 
4618 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFieldWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4619 {
4620  return new QgsProcessingFieldWidgetWrapper( parameter, type );
4621 }
4622 
4623 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFieldWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4624 {
4625  return new QgsProcessingFieldParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4626 }
4627 
4628 //
4629 // QgsProcessingMapThemeWidgetWrapper
4630 //
4631 
4632 
4633 QgsProcessingMapThemeParameterDefinitionWidget::QgsProcessingMapThemeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4634  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4635 {
4636  QVBoxLayout *vlayout = new QVBoxLayout();
4637  vlayout->setContentsMargins( 0, 0, 0, 0 );
4638 
4639  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4640 
4641  mDefaultComboBox = new QComboBox();
4642  mDefaultComboBox->addItem( QString(), QVariant( -1 ) );
4643 
4644  const QStringList mapThemes = widgetContext.project() ? widgetContext.project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
4645  for ( const QString &theme : mapThemes )
4646  {
4647  mDefaultComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
4648  }
4649  mDefaultComboBox->setEditable( true );
4650 
4651  if ( const QgsProcessingParameterMapTheme *themeParam = dynamic_cast<const QgsProcessingParameterMapTheme *>( definition ) )
4652  {
4653  if ( themeParam->defaultValueForGui().isValid() )
4654  mDefaultComboBox->setCurrentText( QgsProcessingParameters::parameterAsString( themeParam, themeParam->defaultValueForGui(), context ) );
4655  else
4656  mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
4657  }
4658  else
4659  mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
4660 
4661  vlayout->addWidget( mDefaultComboBox );
4662 
4663  setLayout( vlayout );
4664 }
4665 
4666 QgsProcessingParameterDefinition *QgsProcessingMapThemeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4667 {
4668  QVariant defaultVal;
4669  if ( mDefaultComboBox->currentText().isEmpty() )
4670  defaultVal = QVariant();
4671  else
4672  defaultVal = mDefaultComboBox->currentText();
4673  auto param = std::make_unique< QgsProcessingParameterMapTheme>( name, description, defaultVal );
4674  param->setFlags( flags );
4675  return param.release();
4676 }
4677 
4678 
4679 QgsProcessingMapThemeWidgetWrapper::QgsProcessingMapThemeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4680  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4681 {
4682 
4683 }
4684 
4685 QWidget *QgsProcessingMapThemeWidgetWrapper::createWidget()
4686 {
4687  const QgsProcessingParameterMapTheme *themeParam = dynamic_cast< const QgsProcessingParameterMapTheme *>( parameterDefinition() );
4688 
4689  mComboBox = new QComboBox();
4690 
4692  mComboBox->addItem( tr( "[Not selected]" ), QVariant( -1 ) );
4693 
4694  const QStringList mapThemes = widgetContext().project() ? widgetContext().project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
4695  for ( const QString &theme : mapThemes )
4696  {
4697  mComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
4698  }
4699 
4700  switch ( type() )
4701  {
4704  break;
4705 
4707  mComboBox->setEditable( true );
4708  break;
4709  }
4710 
4711  mComboBox->setToolTip( parameterDefinition()->toolTip() );
4712  connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
4713  {
4714  emit widgetValueHasChanged( this );
4715  } );
4716 
4717  return mComboBox;
4718 }
4719 
4720 void QgsProcessingMapThemeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4721 {
4722  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
4723 
4724  if ( !value.isValid() )
4725  mComboBox->setCurrentIndex( mComboBox->findData( QVariant( -1 ) ) );
4726  else
4727  {
4728  if ( mComboBox->isEditable() && mComboBox->findData( v ) == -1 )
4729  {
4730  const QString prev = mComboBox->currentText();
4731  mComboBox->setCurrentText( v );
4732  if ( prev != v )
4733  emit widgetValueHasChanged( this );
4734  }
4735  else
4736  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
4737  }
4738 }
4739 
4740 QVariant QgsProcessingMapThemeWidgetWrapper::widgetValue() const
4741 {
4742  if ( mComboBox )
4743  return mComboBox->currentData().toInt() == -1 ? QVariant() :
4744  !mComboBox->currentData().isValid() && mComboBox->isEditable() ? mComboBox->currentText().isEmpty() ? QVariant() : QVariant( mComboBox->currentText() )
4745  : mComboBox->currentData();
4746  else
4747  return QVariant();
4748 }
4749 
4750 QStringList QgsProcessingMapThemeWidgetWrapper::compatibleParameterTypes() const
4751 {
4752  return QStringList()
4755 }
4756 
4757 QStringList QgsProcessingMapThemeWidgetWrapper::compatibleOutputTypes() const
4758 {
4759  return QStringList()
4761 }
4762 
4763 QString QgsProcessingMapThemeWidgetWrapper::modelerExpressionFormatString() const
4764 {
4765  return tr( "map theme as a string value (e.g. 'base maps')" );
4766 }
4767 
4768 QString QgsProcessingMapThemeWidgetWrapper::parameterType() const
4769 {
4771 }
4772 
4773 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapThemeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4774 {
4775  return new QgsProcessingMapThemeWidgetWrapper( parameter, type );
4776 }
4777 
4778 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapThemeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4779 {
4780  return new QgsProcessingMapThemeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4781 }
4782 
4783 
4784 
4785 //
4786 // QgsProcessingDateTimeWidgetWrapper
4787 //
4788 
4789 
4790 QgsProcessingDateTimeParameterDefinitionWidget::QgsProcessingDateTimeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4791  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4792 {
4793  QVBoxLayout *vlayout = new QVBoxLayout();
4794  vlayout->setContentsMargins( 0, 0, 0, 0 );
4795 
4796  vlayout->addWidget( new QLabel( tr( "Type" ) ) );
4797 
4798  mTypeComboBox = new QComboBox();
4799  mTypeComboBox->addItem( tr( "Date and Time" ), QgsProcessingParameterDateTime::DateTime );
4800  mTypeComboBox->addItem( tr( "Date" ), QgsProcessingParameterDateTime::Date );
4801  mTypeComboBox->addItem( tr( "Time" ), QgsProcessingParameterDateTime::Time );
4802  if ( const QgsProcessingParameterDateTime *datetimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( definition ) )
4803  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( datetimeParam->dataType() ) );
4804  else
4805  mTypeComboBox->setCurrentIndex( 0 );
4806  vlayout->addWidget( mTypeComboBox );
4807 
4808  setLayout( vlayout );
4809 }
4810 
4811 QgsProcessingParameterDefinition *QgsProcessingDateTimeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4812 {
4813  auto param = std::make_unique< QgsProcessingParameterDateTime >( name, description );
4814  param->setDataType( static_cast< QgsProcessingParameterDateTime::Type >( mTypeComboBox->currentData().toInt() ) );
4815  param->setFlags( flags );
4816  return param.release();
4817 }
4818 
4819 
4820 QgsProcessingDateTimeWidgetWrapper::QgsProcessingDateTimeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4821  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4822 {
4823 
4824 }
4825 
4826 QWidget *QgsProcessingDateTimeWidgetWrapper::createWidget()
4827 {
4828  const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast< const QgsProcessingParameterDateTime *>( parameterDefinition() );
4829 
4830  QgsDateTimeEdit *widget = nullptr;
4831  switch ( dateTimeParam->dataType() )
4832  {
4834  mDateTimeEdit = new QgsDateTimeEdit();
4835  widget = mDateTimeEdit;
4836  break;
4837 
4839  mDateEdit = new QgsDateEdit();
4840  widget = mDateEdit;
4841  break;
4842 
4844  mTimeEdit = new QgsTimeEdit();
4845  widget = mTimeEdit;
4846  break;
4847  }
4848 
4849  if ( dateTimeParam->flags() & QgsProcessingParameterDefinition::FlagOptional )
4850  {
4851  widget->setNullRepresentation( tr( "[Not selected]" ) );
4852  widget->setAllowNull( true );
4853  }
4854  else
4855  {
4856  widget->setAllowNull( false );
4857  }
4858  widget->setToolTip( parameterDefinition()->toolTip() );
4859 
4860  if ( mDateTimeEdit )
4861  {
4862  connect( mDateTimeEdit, &QgsDateTimeEdit::valueChanged, this, [ = ]( const QDateTime & )
4863  {
4864  emit widgetValueHasChanged( this );
4865  } );
4866  }
4867  else if ( mDateEdit )
4868  {
4869  connect( mDateEdit, &QgsDateEdit::dateValueChanged, this, [ = ]( const QDate & )
4870  {
4871  emit widgetValueHasChanged( this );
4872  } );
4873  }
4874  else if ( mTimeEdit )
4875  {
4876  connect( mTimeEdit, &QgsTimeEdit::timeValueChanged, this, [ = ]( const QTime & )
4877  {
4878  emit widgetValueHasChanged( this );
4879  } );
4880  }
4881 
4882  return widget;
4883 }
4884 
4885 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDateTimeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4886 {
4887  return new QgsProcessingDateTimeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4888 }
4889 
4890 void QgsProcessingDateTimeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4891 {
4892  if ( mDateTimeEdit )
4893  {
4894  mDateTimeEdit->setDateTime( QgsProcessingParameters::parameterAsDateTime( parameterDefinition(), value, context ) );
4895  }
4896  else if ( mDateEdit )
4897  {
4898  mDateEdit->setDate( QgsProcessingParameters::parameterAsDate( parameterDefinition(), value, context ) );
4899  }
4900  else if ( mTimeEdit )
4901  {
4902  mTimeEdit->setTime( QgsProcessingParameters::parameterAsTime( parameterDefinition(), value, context ) );
4903  }
4904 }
4905 
4906 QVariant QgsProcessingDateTimeWidgetWrapper::widgetValue() const
4907 {
4908  if ( mDateTimeEdit )
4909  return !mDateTimeEdit->dateTime().isNull() && mDateTimeEdit->dateTime().isValid() ? QVariant( mDateTimeEdit->dateTime() ) : QVariant();
4910  else if ( mDateEdit )
4911  return !mDateEdit->date().isNull() && mDateEdit->date().isValid() ? QVariant( mDateEdit->date() ) : QVariant();
4912  else if ( mTimeEdit )
4913  return !mTimeEdit->time().isNull() && mTimeEdit->time().isValid() ? QVariant( mTimeEdit->time() ) : QVariant();
4914  else
4915  return QVariant();
4916 }
4917 
4918 QStringList QgsProcessingDateTimeWidgetWrapper::compatibleParameterTypes() const
4919 {
4920  return QStringList()
4923 }
4924 
4925 QStringList QgsProcessingDateTimeWidgetWrapper::compatibleOutputTypes() const
4926 {
4927  return QStringList()
4929 }
4930 
4931 QString QgsProcessingDateTimeWidgetWrapper::modelerExpressionFormatString() const
4932 {
4933  const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast< const QgsProcessingParameterDateTime *>( parameterDefinition() );
4934  if ( dateTimeParam )
4935  {
4936  switch ( dateTimeParam->dataType() )
4937  {
4939  return tr( "datetime value, or a ISO string representation of a datetime" );
4940 
4942  return tr( "date value, or a ISO string representation of a date" );
4943 
4945  return tr( "time value, or a ISO string representation of a time" );
4946  }
4947  }
4948  return QString();
4949 }
4950 
4951 QString QgsProcessingDateTimeWidgetWrapper::parameterType() const
4952 {
4954 }
4955 
4956 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDateTimeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4957 {
4958  return new QgsProcessingDateTimeWidgetWrapper( parameter, type );
4959 }
4960 
4961 
4962 
4963 //
4964 // QgsProcessingProviderConnectionWidgetWrapper
4965 //
4966 
4967 QgsProcessingProviderConnectionParameterDefinitionWidget::QgsProcessingProviderConnectionParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4968  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4969 {
4970  const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast< const QgsProcessingParameterProviderConnection *>( definition );
4971 
4972  QVBoxLayout *vlayout = new QVBoxLayout();
4973  vlayout->setContentsMargins( 0, 0, 0, 0 );
4974 
4975  vlayout->addWidget( new QLabel( tr( "Provider" ) ) );
4976  mProviderComboBox = new QComboBox();
4977  mProviderComboBox->addItem( QObject::tr( "Postgres" ), QStringLiteral( "postgres" ) );
4978  mProviderComboBox->addItem( QObject::tr( "GeoPackage" ), QStringLiteral( "ogr" ) );
4979  mProviderComboBox->addItem( QObject::tr( "Spatialite" ), QStringLiteral( "spatialite" ) );
4980 
4981  vlayout->addWidget( mProviderComboBox );
4982 
4983  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4984 
4985  mDefaultEdit = new QLineEdit();
4986  vlayout->addWidget( mDefaultEdit );
4987  setLayout( vlayout );
4988 
4989  if ( connectionParam )
4990  {
4991  mProviderComboBox->setCurrentIndex( mProviderComboBox->findData( connectionParam->providerId() ) );
4992  mDefaultEdit->setText( connectionParam->defaultValueForGui().toString() );
4993  }
4994 }
4995 
4996 QgsProcessingParameterDefinition *QgsProcessingProviderConnectionParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4997 {
4998  QVariant defaultVal;
4999  if ( mDefaultEdit->text().isEmpty() )
5000  defaultVal = QVariant();
5001  else
5002  defaultVal = mDefaultEdit->text();
5003  auto param = std::make_unique< QgsProcessingParameterProviderConnection>( name, description, mProviderComboBox->currentData().toString(), defaultVal );
5004  param->setFlags( flags );
5005  return param.release();
5006 }
5007 
5008 
5009 QgsProcessingProviderConnectionWidgetWrapper::QgsProcessingProviderConnectionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5010  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5011 {
5012 
5013 }
5014 
5015 QWidget *QgsProcessingProviderConnectionWidgetWrapper::createWidget()
5016 {
5017  const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast< const QgsProcessingParameterProviderConnection *>( parameterDefinition() );
5018 
5019  mProviderComboBox = new QgsProviderConnectionComboBox( connectionParam->providerId() );
5020  if ( connectionParam->flags() & QgsProcessingParameterDefinition::FlagOptional )
5021  mProviderComboBox->setAllowEmptyConnection( true );
5022 
5023  switch ( type() )
5024  {
5027  break;
5029  mProviderComboBox->setEditable( true );
5030  break;
5031  }
5032 
5033  mProviderComboBox->setToolTip( parameterDefinition()->toolTip() );
5034  connect( mProviderComboBox, &QgsProviderConnectionComboBox::currentTextChanged, this, [ = ]( const QString & )
5035  {
5036  if ( mBlockSignals )
5037  return;
5038 
5039  emit widgetValueHasChanged( this );
5040  } );
5041 
5042  return mProviderComboBox;
5043 }
5044 
5045 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingProviderConnectionWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5046 {
5047  return new QgsProcessingProviderConnectionParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5048 }
5049 
5050 void QgsProcessingProviderConnectionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5051 {
5052  const QString v = QgsProcessingParameters::parameterAsConnectionName( parameterDefinition(), value, context );
5053 
5054  if ( !value.isValid() )
5055  mProviderComboBox->setCurrentIndex( -1 );
5056  else
5057  {
5058  if ( mProviderComboBox->isEditable() )
5059  {
5060  const QString prev = mProviderComboBox->currentText();
5061  mBlockSignals++;
5062  mProviderComboBox->setConnection( v );
5063  mProviderComboBox->setCurrentText( v );
5064 
5065  mBlockSignals--;
5066  if ( prev != v )
5067  emit widgetValueHasChanged( this );
5068  }
5069  else
5070  mProviderComboBox->setConnection( v );
5071  }
5072 }
5073 
5074 QVariant QgsProcessingProviderConnectionWidgetWrapper::widgetValue() const
5075 {
5076  if ( mProviderComboBox )
5077  if ( mProviderComboBox->isEditable() )
5078  return mProviderComboBox->currentText().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentText() );
5079  else
5080  return mProviderComboBox->currentConnection().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentConnection() );
5081  else
5082  return QVariant();
5083 }
5084 
5085 QStringList QgsProcessingProviderConnectionWidgetWrapper::compatibleParameterTypes() const
5086 {
5087  return QStringList()
5091 }
5092 
5093 QStringList QgsProcessingProviderConnectionWidgetWrapper::compatibleOutputTypes() const
5094 {
5095  return QStringList()
5097 }
5098 
5099 QString QgsProcessingProviderConnectionWidgetWrapper::modelerExpressionFormatString() const
5100 {
5101  return tr( "connection name as a string value" );
5102 }
5103 
5104 QString QgsProcessingProviderConnectionWidgetWrapper::parameterType() const
5105 {
5107 }
5108 
5109 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingProviderConnectionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5110 {
5111  return new QgsProcessingProviderConnectionWidgetWrapper( parameter, type );
5112 }
5113 
5114 
5115 
5116 
5117 //
5118 // QgsProcessingDatabaseSchemaWidgetWrapper
5119 //
5120 
5121 QgsProcessingDatabaseSchemaParameterDefinitionWidget::QgsProcessingDatabaseSchemaParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5122  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5123 {
5124  const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast< const QgsProcessingParameterDatabaseSchema *>( definition );
5125 
5126  QVBoxLayout *vlayout = new QVBoxLayout();
5127  vlayout->setContentsMargins( 0, 0, 0, 0 );
5128 
5129  mConnectionParamComboBox = new QComboBox();
5130  QString initialConnection;
5131  if ( schemaParam )
5132  {
5133  initialConnection = schemaParam->parentConnectionParameterName();
5134  }
5135 
5136  if ( auto *lModel = widgetContext.model() )
5137  {
5138  // populate combo box with other model input choices
5139  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5140  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5141  {
5142  if ( definition && it->parameterName() == definition->name() )
5143  continue;
5144 
5145  if ( !dynamic_cast< const QgsProcessingParameterProviderConnection * >( lModel->parameterDefinition( it->parameterName() ) ) )
5146  continue;
5147 
5148  mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5149  if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5150  {
5151  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5152  }
5153  }
5154  }
5155 
5156  if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5157  {
5158  // if no candidates found, we just add the existing one as a placeholder
5159  mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5160  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5161  }
5162 
5163  vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
5164  vlayout->addWidget( mConnectionParamComboBox );
5165 
5166  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5167 
5168  mDefaultEdit = new QLineEdit();
5169  vlayout->addWidget( mDefaultEdit );
5170  setLayout( vlayout );
5171 
5172  if ( schemaParam )
5173  {
5174  mDefaultEdit->setText( schemaParam->defaultValueForGui().toString() );
5175  }
5176 }
5177 
5178 QgsProcessingParameterDefinition *QgsProcessingDatabaseSchemaParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5179 {
5180  QVariant defaultVal;
5181  if ( mDefaultEdit->text().isEmpty() )
5182  defaultVal = QVariant();
5183  else
5184  defaultVal = mDefaultEdit->text();
5185  auto param = std::make_unique< QgsProcessingParameterDatabaseSchema>( name, description, mConnectionParamComboBox->currentData().toString(), defaultVal );
5186  param->setFlags( flags );
5187  return param.release();
5188 }
5189 
5190 
5191 QgsProcessingDatabaseSchemaWidgetWrapper::QgsProcessingDatabaseSchemaWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5192  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5193 {
5194 
5195 }
5196 
5197 QWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createWidget()
5198 {
5199  const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast< const QgsProcessingParameterDatabaseSchema *>( parameterDefinition() );
5200 
5201  mSchemaComboBox = new QgsDatabaseSchemaComboBox( QString(), QString() );
5203  mSchemaComboBox->setAllowEmptySchema( true );
5204 
5205  switch ( type() )
5206  {
5209  break;
5211  mSchemaComboBox->comboBox()->setEditable( true );
5212  break;
5213  }
5214 
5215  mSchemaComboBox->setToolTip( parameterDefinition()->toolTip() );
5216  connect( mSchemaComboBox->comboBox(), &QComboBox::currentTextChanged, this, [ = ]( const QString & )
5217  {
5218  if ( mBlockSignals )
5219  return;
5220 
5221  emit widgetValueHasChanged( this );
5222  } );
5223 
5224  return mSchemaComboBox;
5225 }
5226 
5227 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5228 {
5229  return new QgsProcessingDatabaseSchemaParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5230 }
5231 
5232 void QgsProcessingDatabaseSchemaWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5233 {
5234  // evaluate value to connection
5235  QgsProcessingContext *context = nullptr;
5236  std::unique_ptr< QgsProcessingContext > tmpContext;
5237  if ( mProcessingContextGenerator )
5238  context = mProcessingContextGenerator->processingContext();
5239 
5240  if ( !context )
5241  {
5242  tmpContext = std::make_unique< QgsProcessingContext >();
5243  context = tmpContext.get();
5244  }
5245 
5246  const QVariant value = parentWrapper->parameterValue();
5247  const QString connection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
5248 
5249  if ( mSchemaComboBox )
5250  mSchemaComboBox->setConnectionName( connection, qgis::down_cast< const QgsProcessingParameterProviderConnection * >( parentWrapper->parameterDefinition() )->providerId() );
5251 
5252  const QgsProcessingParameterDatabaseSchema *schemaParam = qgis::down_cast< const QgsProcessingParameterDatabaseSchema * >( parameterDefinition() );
5253  if ( schemaParam->defaultValueForGui().isValid() )
5254  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5255 }
5256 
5257 void QgsProcessingDatabaseSchemaWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5258 {
5259  const QString v = QgsProcessingParameters::parameterAsSchema( parameterDefinition(), value, context );
5260 
5261  if ( !value.isValid() )
5262  mSchemaComboBox->comboBox()->setCurrentIndex( -1 );
5263  else
5264  {
5265  if ( mSchemaComboBox->comboBox()->isEditable() )
5266  {
5267  const QString prev = mSchemaComboBox->comboBox()->currentText();
5268  mBlockSignals++;
5269  mSchemaComboBox->setSchema( v );
5270  mSchemaComboBox->comboBox()->setCurrentText( v );
5271 
5272  mBlockSignals--;
5273  if ( prev != v )
5274  emit widgetValueHasChanged( this );
5275  }
5276  else
5277  mSchemaComboBox->setSchema( v );
5278  }
5279 }
5280 
5281 QVariant QgsProcessingDatabaseSchemaWidgetWrapper::widgetValue() const
5282 {
5283  if ( mSchemaComboBox )
5284  if ( mSchemaComboBox->comboBox()->isEditable() )
5285  return mSchemaComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->comboBox()->currentText() );
5286  else
5287  return mSchemaComboBox->currentSchema().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->currentSchema() );
5288  else
5289  return QVariant();
5290 }
5291 
5292 QStringList QgsProcessingDatabaseSchemaWidgetWrapper::compatibleParameterTypes() const
5293 {
5294  return QStringList()
5298 }
5299 
5300 QStringList QgsProcessingDatabaseSchemaWidgetWrapper::compatibleOutputTypes() const
5301 {
5302  return QStringList()
5304 }
5305 
5306 QString QgsProcessingDatabaseSchemaWidgetWrapper::modelerExpressionFormatString() const
5307 {
5308  return tr( "database schema name as a string value" );
5309 }
5310 
5311 QString QgsProcessingDatabaseSchemaWidgetWrapper::parameterType() const
5312 {
5314 }
5315 
5316 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseSchemaWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5317 {
5318  return new QgsProcessingDatabaseSchemaWidgetWrapper( parameter, type );
5319 }
5320 
5321 void QgsProcessingDatabaseSchemaWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5322 {
5324  switch ( type() )
5325  {
5328  {
5329  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5330  {
5331  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseSchema * >( parameterDefinition() )->parentConnectionParameterName() )
5332  {
5333  setParentConnectionWrapperValue( wrapper );
5335  {
5336  setParentConnectionWrapperValue( wrapper );
5337  } );
5338  break;
5339  }
5340  }
5341  break;
5342  }
5343 
5345  break;
5346  }
5347 }
5348 
5349 
5350 
5351 //
5352 // QgsProcessingDatabaseTableWidgetWrapper
5353 //
5354 
5355 QgsProcessingDatabaseTableParameterDefinitionWidget::QgsProcessingDatabaseTableParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5356  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5357 {
5358  const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast< const QgsProcessingParameterDatabaseTable *>( definition );
5359 
5360  QVBoxLayout *vlayout = new QVBoxLayout();
5361  vlayout->setContentsMargins( 0, 0, 0, 0 );
5362 
5363  mConnectionParamComboBox = new QComboBox();
5364  mSchemaParamComboBox = new QComboBox();
5365  QString initialConnection;
5366  QString initialSchema;
5367  if ( tableParam )
5368  {
5369  initialConnection = tableParam->parentConnectionParameterName();
5370  initialSchema = tableParam->parentSchemaParameterName();
5371  }
5372 
5373  if ( auto *lModel = widgetContext.model() )
5374  {
5375  // populate combo box with other model input choices
5376  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5377  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5378  {
5379  if ( definition && it->parameterName() == definition->name() )
5380  continue;
5381 
5382  if ( dynamic_cast< const QgsProcessingParameterProviderConnection * >( lModel->parameterDefinition( it->parameterName() ) ) )
5383  {
5384  mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5385  if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5386  {
5387  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5388  }
5389  }
5390  else if ( dynamic_cast< const QgsProcessingParameterDatabaseSchema * >( lModel->parameterDefinition( it->parameterName() ) ) )
5391  {
5392  mSchemaParamComboBox->addItem( it->parameterName(), it->parameterName() );
5393  if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5394  {
5395  mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5396  }
5397  }
5398  }
5399  }
5400 
5401  if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5402  {
5403  // if no candidates found, we just add the existing one as a placeholder
5404  mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5405  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5406  }
5407 
5408  if ( mSchemaParamComboBox->count() == 0 && !initialSchema.isEmpty() )
5409  {
5410  // if no candidates found, we just add the existing one as a placeholder
5411  mSchemaParamComboBox->addItem( initialSchema, initialSchema );
5412  mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5413  }
5414 
5415  vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
5416  vlayout->addWidget( mConnectionParamComboBox );
5417 
5418  vlayout->addWidget( new QLabel( tr( "Database schema parameter" ) ) );
5419  vlayout->addWidget( mSchemaParamComboBox );
5420 
5421  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5422 
5423  mDefaultEdit = new QLineEdit();
5424  vlayout->addWidget( mDefaultEdit );
5425  setLayout( vlayout );
5426 
5427  if ( tableParam )
5428  {
5429  mDefaultEdit->setText( tableParam->defaultValueForGui().toString() );
5430  }
5431 }
5432 
5433 QgsProcessingParameterDefinition *QgsProcessingDatabaseTableParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5434 {
5435  QVariant defaultVal;
5436  if ( mDefaultEdit->text().isEmpty() )
5437  defaultVal = QVariant();
5438  else
5439  defaultVal = mDefaultEdit->text();
5440  auto param = std::make_unique< QgsProcessingParameterDatabaseTable>( name, description,
5441  mConnectionParamComboBox->currentData().toString(),
5442  mSchemaParamComboBox->currentData().toString(),
5443  defaultVal );
5444  param->setFlags( flags );
5445  return param.release();
5446 }
5447 
5448 
5449 QgsProcessingDatabaseTableWidgetWrapper::QgsProcessingDatabaseTableWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5450  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5451 {
5452 
5453 }
5454 
5455 QWidget *QgsProcessingDatabaseTableWidgetWrapper::createWidget()
5456 {
5457  const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast< const QgsProcessingParameterDatabaseTable *>( parameterDefinition() );
5458 
5459  mTableComboBox = new QgsDatabaseTableComboBox( QString(), QString() );
5461  mTableComboBox->setAllowEmptyTable( true );
5462 
5463  if ( type() == QgsProcessingGui::Modeler || tableParam->allowNewTableNames() )
5464  mTableComboBox->comboBox()->setEditable( true );
5465 
5466  mTableComboBox->setToolTip( parameterDefinition()->toolTip() );
5467  connect( mTableComboBox->comboBox(), &QComboBox::currentTextChanged, this, [ = ]( const QString & )
5468  {
5469  if ( mBlockSignals )
5470  return;
5471 
5472  emit widgetValueHasChanged( this );
5473  } );
5474 
5475  return mTableComboBox;
5476 }
5477 
5478 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseTableWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5479 {
5480  return new QgsProcessingDatabaseTableParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5481 }
5482 
5483 void QgsProcessingDatabaseTableWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5484 {
5485  // evaluate value to connection
5486  QgsProcessingContext *context = nullptr;
5487  std::unique_ptr< QgsProcessingContext > tmpContext;
5488  if ( mProcessingContextGenerator )
5489  context = mProcessingContextGenerator->processingContext();
5490 
5491  if ( !context )
5492  {
5493  tmpContext = std::make_unique< QgsProcessingContext >();
5494  context = tmpContext.get();
5495  }
5496 
5497  QVariant value = parentWrapper->parameterValue();
5498  mConnection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
5499  mProvider = qgis::down_cast< const QgsProcessingParameterProviderConnection * >( parentWrapper->parameterDefinition() )->providerId();
5500  if ( mTableComboBox && !mSchema.isEmpty() )
5501  {
5502  mTableComboBox->setSchema( mSchema );
5503  mTableComboBox->setConnectionName( mConnection, mProvider );
5504 
5505  const QgsProcessingParameterDatabaseTable *tableParam = qgis::down_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() );
5506  if ( tableParam->defaultValueForGui().isValid() )
5507  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5508  }
5509 }
5510 
5511 void QgsProcessingDatabaseTableWidgetWrapper::setParentSchemaWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5512 {
5513  // evaluate value to schema
5514  QgsProcessingContext *context = nullptr;
5515  std::unique_ptr< QgsProcessingContext > tmpContext;
5516  if ( mProcessingContextGenerator )
5517  context = mProcessingContextGenerator->processingContext();
5518 
5519  if ( !context )
5520  {
5521  tmpContext = std::make_unique< QgsProcessingContext >();
5522  context = tmpContext.get();
5523  }
5524 
5525  QVariant value = parentWrapper->parameterValue();
5526  mSchema = value.isValid() ? QgsProcessingParameters::parameterAsSchema( parentWrapper->parameterDefinition(), value, *context ) : QString();
5527 
5528  if ( mTableComboBox && !mSchema.isEmpty() && !mConnection.isEmpty() )
5529  {
5530  mTableComboBox->setSchema( mSchema );
5531  mTableComboBox->setConnectionName( mConnection, mProvider );
5532 
5533  const QgsProcessingParameterDatabaseTable *tableParam = static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() );
5534  if ( tableParam->defaultValueForGui().isValid() )
5535  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5536  }
5537 
5538 }
5539 
5540 void QgsProcessingDatabaseTableWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5541 {
5542  const QString v = QgsProcessingParameters::parameterAsDatabaseTableName( parameterDefinition(), value, context );
5543 
5544  if ( !value.isValid() )
5545  mTableComboBox->comboBox()->setCurrentIndex( -1 );
5546  else
5547  {
5548  if ( mTableComboBox->comboBox()->isEditable() )
5549  {
5550  const QString prev = mTableComboBox->comboBox()->currentText();
5551  mBlockSignals++;
5552  mTableComboBox->setTable( v );
5553  mTableComboBox->comboBox()->setCurrentText( v );
5554 
5555  mBlockSignals--;
5556  if ( prev != v )
5557  emit widgetValueHasChanged( this );
5558  }
5559  else
5560  mTableComboBox->setTable( v );
5561  }
5562 }
5563 
5564 QVariant QgsProcessingDatabaseTableWidgetWrapper::widgetValue() const
5565 {
5566  if ( mTableComboBox )
5567  if ( mTableComboBox->comboBox()->isEditable() )
5568  return mTableComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mTableComboBox->comboBox()->currentText() );
5569  else
5570  return mTableComboBox->currentTable().isEmpty() ? QVariant() : QVariant( mTableComboBox->currentTable() );
5571  else
5572  return QVariant();
5573 }
5574 
5575 QStringList QgsProcessingDatabaseTableWidgetWrapper::compatibleParameterTypes() const
5576 {
5577  return QStringList()
5581 }
5582 
5583 QStringList QgsProcessingDatabaseTableWidgetWrapper::compatibleOutputTypes() const
5584 {
5585  return QStringList()
5587 }
5588 
5589 QString QgsProcessingDatabaseTableWidgetWrapper::modelerExpressionFormatString() const
5590 {
5591  return tr( "database table name as a string value" );
5592 }
5593 
5594 QString QgsProcessingDatabaseTableWidgetWrapper::parameterType() const
5595 {
5597 }
5598 
5599 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseTableWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5600 {
5601  return new QgsProcessingDatabaseTableWidgetWrapper( parameter, type );
5602 }
5603 
5604 void QgsProcessingDatabaseTableWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5605 {
5607  switch ( type() )
5608  {
5611  {
5612  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5613  {
5614  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() )->parentConnectionParameterName() )
5615  {
5616  setParentConnectionWrapperValue( wrapper );
5618  {
5619  setParentConnectionWrapperValue( wrapper );
5620  } );
5621  }
5622  else if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() )->parentSchemaParameterName() )
5623  {
5624  setParentSchemaWrapperValue( wrapper );
5626  {
5627  setParentSchemaWrapperValue( wrapper );
5628  } );
5629  }
5630  }
5631  break;
5632  }
5633 
5635  break;
5636  }
5637 }
5638 
5639 
5640 //
5641 // QgsProcessingExtentWidgetWrapper
5642 //
5643 
5644 QgsProcessingExtentParameterDefinitionWidget::QgsProcessingExtentParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5645  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5646 {
5647  QVBoxLayout *vlayout = new QVBoxLayout();
5648  vlayout->setContentsMargins( 0, 0, 0, 0 );
5649 
5650  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5651 
5652  mDefaultWidget = new QgsExtentWidget();
5653  mDefaultWidget->setNullValueAllowed( true, tr( "Not set" ) );
5654  if ( const QgsProcessingParameterExtent *extentParam = dynamic_cast<const QgsProcessingParameterExtent *>( definition ) )
5655  {
5656  if ( extentParam->defaultValueForGui().isValid() )
5657  {
5658  QgsRectangle rect = QgsProcessingParameters::parameterAsExtent( extentParam, extentParam->defaultValueForGui(), context );
5659  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsExtentCrs( extentParam, extentParam->defaultValueForGui(), context );
5660  mDefaultWidget->setCurrentExtent( rect, crs );
5661  mDefaultWidget->setOutputExtentFromCurrent();
5662  }
5663  else
5664  {
5665  mDefaultWidget->clear();
5666  }
5667  }
5668 
5669  vlayout->addWidget( mDefaultWidget );
5670  setLayout( vlayout );
5671 }
5672 
5673 QgsProcessingParameterDefinition *QgsProcessingExtentParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5674 {
5675  const QString defaultVal = mDefaultWidget->isValid() ? QStringLiteral( "%1,%2,%3,%4%5" ).arg(
5676  QString::number( mDefaultWidget->outputExtent().xMinimum(), 'f', 9 ),
5677  QString::number( mDefaultWidget->outputExtent().xMaximum(), 'f', 9 ),
5678  QString::number( mDefaultWidget->outputExtent().yMinimum(), 'f', 9 ),
5679  QString::number( mDefaultWidget->outputExtent().yMaximum(), 'f', 9 ),
5680  mDefaultWidget->outputCrs().isValid() ? QStringLiteral( " [%1]" ).arg( mDefaultWidget->outputCrs().authid() ) : QString()
5681  ) : QString();
5682  auto param = std::make_unique< QgsProcessingParameterExtent >( name, description, !defaultVal.isEmpty() ? QVariant( defaultVal ) : QVariant() );
5683  param->setFlags( flags );
5684  return param.release();
5685 }
5686 
5687 
5688 
5689 QgsProcessingExtentWidgetWrapper::QgsProcessingExtentWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5690  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5691 {
5692 
5693 }
5694 
5695 QWidget *QgsProcessingExtentWidgetWrapper::createWidget()
5696 {
5697  const QgsProcessingParameterExtent *extentParam = dynamic_cast< const QgsProcessingParameterExtent *>( parameterDefinition() );
5698  switch ( type() )
5699  {
5703  {
5704  mExtentWidget = new QgsExtentWidget( nullptr );
5705  if ( widgetContext().mapCanvas() )
5706  mExtentWidget->setMapCanvas( widgetContext().mapCanvas() );
5707 
5709  mExtentWidget->setNullValueAllowed( true, tr( "Not set" ) );
5710 
5711  mExtentWidget->setToolTip( parameterDefinition()->toolTip() );
5712 
5713  connect( mExtentWidget, &QgsExtentWidget::extentChanged, this, [ = ]
5714  {
5715  emit widgetValueHasChanged( this );
5716  } );
5717 
5718  if ( mDialog && type() != QgsProcessingGui::Modeler )
5719  setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
5720 
5721  return mExtentWidget;
5722  }
5723  }
5724  return nullptr;
5725 }
5726 
5727 void QgsProcessingExtentWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
5728 {
5730  if ( mExtentWidget && context.mapCanvas() && type() != QgsProcessingGui::Modeler )
5731  mExtentWidget->setMapCanvas( context.mapCanvas() );
5732 }
5733 
5734 void QgsProcessingExtentWidgetWrapper::setDialog( QDialog *dialog )
5735 {
5736  mDialog = dialog;
5737  if ( mExtentWidget && mDialog && type() != QgsProcessingGui::Modeler )
5738  {
5739  connect( mExtentWidget, &QgsExtentWidget::toggleDialogVisibility, mDialog, [ = ]( bool visible )
5740  {
5741  if ( !visible )
5742  mDialog->showMinimized();
5743  else
5744  {
5745  mDialog->showNormal();
5746  mDialog->raise();
5747  mDialog->activateWindow();
5748  }
5749  } );
5750  }
5752 }
5753 
5754 void QgsProcessingExtentWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5755 {
5756  if ( mExtentWidget )
5757  {
5758  if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
5759  mExtentWidget->clear();
5760  else
5761  {
5762  QgsRectangle r = QgsProcessingParameters::parameterAsExtent( parameterDefinition(), value, context );
5763  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
5764  mExtentWidget->setCurrentExtent( r, crs );
5765  mExtentWidget->setOutputExtentFromUser( r, crs );
5766  }
5767  }
5768 }
5769 
5770 QVariant QgsProcessingExtentWidgetWrapper::widgetValue() const
5771 {
5772  if ( mExtentWidget )
5773  {
5774  const QString val = mExtentWidget->isValid() ? QStringLiteral( "%1,%2,%3,%4%5" ).arg(
5775  QString::number( mExtentWidget->outputExtent().xMinimum(), 'f', 9 ),
5776  QString::number( mExtentWidget->outputExtent().xMaximum(), 'f', 9 ),
5777  QString::number( mExtentWidget->outputExtent().yMinimum(), 'f', 9 ),
5778  QString::number( mExtentWidget->outputExtent().yMaximum(), 'f', 9 ),
5779  mExtentWidget->outputCrs().isValid() ? QStringLiteral( " [%1]" ).arg( mExtentWidget->outputCrs().authid() ) : QString()
5780  ) : QString();
5781 
5782  return val.isEmpty() ? QVariant() : QVariant( val );
5783  }
5784  else
5785  return QVariant();
5786 }
5787 
5788 QStringList QgsProcessingExtentWidgetWrapper::compatibleParameterTypes() const
5789 {
5790  return QStringList()
5800 }
5801 
5802 QStringList QgsProcessingExtentWidgetWrapper::compatibleOutputTypes() const
5803 {
5804  return QStringList()
5809 }
5810 
5811 QString QgsProcessingExtentWidgetWrapper::modelerExpressionFormatString() const
5812 {
5813  return tr( "string of the format 'x min,x max,y min,y max' or a geometry value (bounding box is used)" );
5814 }
5815 
5816 QString QgsProcessingExtentWidgetWrapper::parameterType() const
5817 {
5819 }
5820 
5821 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExtentWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5822 {
5823  return new QgsProcessingExtentWidgetWrapper( parameter, type );
5824 }
5825 
5826 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingExtentWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5827 {
5828  return new QgsProcessingExtentParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5829 }
5830 
5831 
5832 
5833 //
5834 // QgsProcessingMapLayerWidgetWrapper
5835 //
5836 
5837 QgsProcessingMapLayerParameterDefinitionWidget::QgsProcessingMapLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5838  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5839 {
5840  QVBoxLayout *vlayout = new QVBoxLayout();
5841  vlayout->setContentsMargins( 0, 0, 0, 0 );
5842 
5843  vlayout->addWidget( new QLabel( tr( "Layer type" ) ) );
5844  mLayerTypeComboBox = new QgsCheckableComboBox();
5845  mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), QgsProcessing::TypeMapLayer );
5846  mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), QgsProcessing::TypeVectorPoint );
5847  mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), QgsProcessing::TypeVectorLine );
5848  mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), QgsProcessing::TypeVectorPolygon );
5849  mLayerTypeComboBox->addItem( tr( "Vector (Any Geometry Type)" ), QgsProcessing::TypeVectorAnyGeometry );
5850  mLayerTypeComboBox->addItem( tr( "Raster" ), QgsProcessing::TypeRaster );
5851  mLayerTypeComboBox->addItem( tr( "Mesh" ), QgsProcessing::TypeMesh );
5852  mLayerTypeComboBox->addItem( tr( "Plugin" ), QgsProcessing::TypePlugin );
5853  mLayerTypeComboBox->addItem( tr( "Point Cloud" ), QgsProcessing::TypePointCloud );
5854  mLayerTypeComboBox->addItem( tr( "Annotation" ), QgsProcessing::TypeAnnotation );
5855 
5856  if ( const QgsProcessingParameterMapLayer *layerParam = dynamic_cast<const QgsProcessingParameterMapLayer *>( definition ) )
5857  {
5858  for ( int i : layerParam->dataTypes() )
5859  {
5860  mLayerTypeComboBox->setItemCheckState( mLayerTypeComboBox->findData( i ), Qt::Checked );
5861  }
5862  }
5863 
5864  vlayout->addWidget( mLayerTypeComboBox );
5865 
5866  setLayout( vlayout );
5867 }
5868 
5869 QgsProcessingParameterDefinition *QgsProcessingMapLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5870 {
5871  QList< int > dataTypes;
5872  for ( const QVariant &v : mLayerTypeComboBox->checkedItemsData() )
5873  dataTypes << v.toInt();
5874 
5875  auto param = std::make_unique< QgsProcessingParameterMapLayer >( name, description );
5876  param->setDataTypes( dataTypes );
5877  param->setFlags( flags );
5878  return param.release();
5879 }
5880 
5881 QgsProcessingMapLayerWidgetWrapper::QgsProcessingMapLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5882  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5883 {
5884 
5885 }
5886 
5887 QWidget *QgsProcessingMapLayerWidgetWrapper::createWidget()
5888 {
5889  mComboBox = new QgsProcessingMapLayerComboBox( parameterDefinition(), type() );
5890 
5891  switch ( type() )
5892  {
5895  break;
5897  mComboBox->setEditable( true );
5898  break;
5899  }
5900 
5901  mComboBox->setToolTip( parameterDefinition()->toolTip() );
5902 
5903  connect( mComboBox, &QgsProcessingMapLayerComboBox::valueChanged, this, [ = ]()
5904  {
5905  if ( mBlockSignals )
5906  return;
5907 
5908  emit widgetValueHasChanged( this );
5909  } );
5910 
5911  setWidgetContext( widgetContext() );
5912  return mComboBox;
5913 }
5914 
5915 void QgsProcessingMapLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
5916 {
5918  if ( mComboBox )
5919  {
5920  mComboBox->setWidgetContext( context );
5921 
5922  if ( !( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional ) )
5923  {
5924  // non optional parameter -- if no default value set, default to active layer
5925  if ( !parameterDefinition()->defaultValueForGui().isValid() )
5926  mComboBox->setLayer( context.activeLayer() );
5927  }
5928  }
5929 }
5930 
5931 void QgsProcessingMapLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5932 {
5933  if ( mComboBox )
5934  mComboBox->setValue( value, context );
5935 }
5936 
5937 QVariant QgsProcessingMapLayerWidgetWrapper::widgetValue() const
5938 {
5939  return mComboBox ? mComboBox->value() : QVariant();
5940 }
5941 
5942 QStringList QgsProcessingMapLayerWidgetWrapper::compatibleParameterTypes() const
5943 {
5944  return QStringList()
5953 }
5954 
5955 QStringList QgsProcessingMapLayerWidgetWrapper::compatibleOutputTypes() const
5956 {
5957  return QStringList()
5963 }
5964 
5965 QString QgsProcessingMapLayerWidgetWrapper::modelerExpressionFormatString() const
5966 {
5967  return tr( "path to a map layer" );
5968 }
5969 
5970 QString QgsProcessingMapLayerWidgetWrapper::parameterType() const
5971 {
5973 }
5974 
5975 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5976 {
5977  return new QgsProcessingMapLayerWidgetWrapper( parameter, type );
5978 }
5979 
5980 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5981 {
5982  return new QgsProcessingMapLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5983 }
5984 
5985 
5986 //
5987 // QgsProcessingRasterLayerWidgetWrapper
5988 //
5989 
5990 QgsProcessingRasterLayerWidgetWrapper::QgsProcessingRasterLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5991  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
5992 {
5993 
5994 }
5995 
5996 QStringList QgsProcessingRasterLayerWidgetWrapper::compatibleParameterTypes() const
5997 {
5998  return QStringList()
6003 }
6004 
6005 QStringList QgsProcessingRasterLayerWidgetWrapper::compatibleOutputTypes() const
6006 {
6007  return QStringList()
6013 }
6014 
6015 QString QgsProcessingRasterLayerWidgetWrapper::modelerExpressionFormatString() const
6016 {
6017  return tr( "path to a raster layer" );
6018 }
6019 
6020 QString QgsProcessingRasterLayerWidgetWrapper::parameterType() const
6021 {
6023 }
6024 
6025 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6026 {
6027  return new QgsProcessingRasterLayerWidgetWrapper( parameter, type );
6028 }
6029 
6030 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRasterLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6031 {
6032  Q_UNUSED( context );
6033  Q_UNUSED( widgetContext );
6034  Q_UNUSED( definition );
6035  Q_UNUSED( algorithm );
6036 
6037  return nullptr;
6038 }
6039 
6040 
6041 //
6042 // QgsProcessingVectorLayerWidgetWrapper
6043 //
6044 
6045 QgsProcessingVectorLayerParameterDefinitionWidget::QgsProcessingVectorLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6046  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6047 {
6048  QVBoxLayout *vlayout = new QVBoxLayout();
6049  vlayout->setContentsMargins( 0, 0, 0, 0 );
6050 
6051  vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6052  mGeometryTypeComboBox = new QgsCheckableComboBox();
6053  mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), QgsProcessing::TypeVector );
6054  mGeometryTypeComboBox->addItem( tr( "Point" ), QgsProcessing::TypeVectorPoint );
6055  mGeometryTypeComboBox->addItem( tr( "Line" ), QgsProcessing::TypeVectorLine );
6056  mGeometryTypeComboBox->addItem( tr( "Polygon" ), QgsProcessing::TypeVectorPolygon );
6057  mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
6058 
6059  if ( const QgsProcessingParameterVectorLayer *vectorParam = dynamic_cast<const QgsProcessingParameterVectorLayer *>( definition ) )
6060  {
6061  for ( int i : vectorParam->dataTypes() )
6062  {
6063  mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6064  }
6065  }
6066 
6067  vlayout->addWidget( mGeometryTypeComboBox );
6068 
6069  setLayout( vlayout );
6070 }
6071 
6072 QgsProcessingParameterDefinition *QgsProcessingVectorLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6073 {
6074  QList< int > dataTypes;
6075  for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6076  dataTypes << v.toInt();
6077 
6078  auto param = std::make_unique< QgsProcessingParameterVectorLayer >( name, description, dataTypes );
6079  param->setFlags( flags );
6080  return param.release();
6081 }
6082 
6083 
6084 QgsProcessingVectorLayerWidgetWrapper::QgsProcessingVectorLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6085  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6086 {
6087 
6088 }
6089 
6090 QStringList QgsProcessingVectorLayerWidgetWrapper::compatibleParameterTypes() const
6091 {
6092  return QStringList()
6097 }
6098 
6099 QStringList QgsProcessingVectorLayerWidgetWrapper::compatibleOutputTypes() const
6100 {
6101  return QStringList()
6107 }
6108 
6109 QString QgsProcessingVectorLayerWidgetWrapper::modelerExpressionFormatString() const
6110 {
6111  return tr( "path to a vector layer" );
6112 }
6113 
6114 QList<int> QgsProcessingVectorLayerWidgetWrapper::compatibleDataTypes( const QgsProcessingParameterDefinition *parameter ) const
6115 {
6116  if ( const QgsProcessingParameterVectorLayer *param = dynamic_cast< const QgsProcessingParameterVectorLayer *>( parameter ) )
6117  return param->dataTypes();
6118  else
6119  return QList< int >();
6120 }
6121 
6122 QString QgsProcessingVectorLayerWidgetWrapper::parameterType() const
6123 {
6125 }
6126 
6127 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6128 {
6129  return new QgsProcessingVectorLayerWidgetWrapper( parameter, type );
6130 }
6131 
6132 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingVectorLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6133 {
6134  return new QgsProcessingVectorLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6135 }
6136 
6137 
6138 
6139 //
6140 // QgsProcessingFeatureSourceLayerWidgetWrapper
6141 //
6142 
6143 QgsProcessingFeatureSourceParameterDefinitionWidget::QgsProcessingFeatureSourceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6144  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6145 {
6146  QVBoxLayout *vlayout = new QVBoxLayout();
6147  vlayout->setContentsMargins( 0, 0, 0, 0 );
6148 
6149  vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6150  mGeometryTypeComboBox = new QgsCheckableComboBox();
6151  mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), QgsProcessing::TypeVector );
6152  mGeometryTypeComboBox->addItem( tr( "Point" ), QgsProcessing::TypeVectorPoint );
6153  mGeometryTypeComboBox->addItem( tr( "Line" ), QgsProcessing::TypeVectorLine );
6154  mGeometryTypeComboBox->addItem( tr( "Polygon" ), QgsProcessing::TypeVectorPolygon );
6155  mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
6156 
6157  if ( const QgsProcessingParameterFeatureSource *sourceParam = dynamic_cast<const QgsProcessingParameterFeatureSource *>( definition ) )
6158  {
6159  for ( int i : sourceParam->dataTypes() )
6160  {
6161  mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6162  }
6163  }
6164  else
6165  {
6166  mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( QgsProcessing::TypeVectorAnyGeometry ), Qt::Checked );
6167  }
6168 
6169  vlayout->addWidget( mGeometryTypeComboBox );
6170 
6171  setLayout( vlayout );
6172 }
6173 
6174 QgsProcessingParameterDefinition *QgsProcessingFeatureSourceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6175 {
6176  QList< int > dataTypes;
6177  for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6178  dataTypes << v.toInt();
6179 
6180  auto param = std::make_unique< QgsProcessingParameterFeatureSource >( name, description, dataTypes );
6181  param->setFlags( flags );
6182  return param.release();
6183 }
6184 
6185 QgsProcessingFeatureSourceWidgetWrapper::QgsProcessingFeatureSourceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6186  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6187 {
6188 
6189 }
6190 
6191 QStringList QgsProcessingFeatureSourceWidgetWrapper::compatibleParameterTypes() const
6192 {
6193  return QStringList()
6199 }
6200 
6201 QStringList QgsProcessingFeatureSourceWidgetWrapper::compatibleOutputTypes() const
6202 {
6203  return QStringList()
6209 }
6210 
6211 QString QgsProcessingFeatureSourceWidgetWrapper::modelerExpressionFormatString() const
6212 {
6213  return tr( "path to a vector layer" );
6214 }
6215 
6216 QList<int> QgsProcessingFeatureSourceWidgetWrapper::compatibleDataTypes( const QgsProcessingParameterDefinition *parameter ) const
6217 {
6218  if ( const QgsProcessingParameterFeatureSource *param = dynamic_cast< const QgsProcessingParameterFeatureSource *>( parameter ) )
6219  return param->dataTypes();
6220  else
6221  return QList< int >();
6222 }
6223 
6224 QString QgsProcessingFeatureSourceWidgetWrapper::parameterType() const
6225 {
6227 }
6228 
6229 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSourceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6230 {
6231  return new QgsProcessingFeatureSourceWidgetWrapper( parameter, type );
6232 }
6233 
6234 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFeatureSourceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6235 {
6236  return new QgsProcessingFeatureSourceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6237 }
6238 
6239 //
6240 // QgsProcessingMeshLayerWidgetWrapper
6241 //
6242 
6243 QgsProcessingMeshLayerWidgetWrapper::QgsProcessingMeshLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6244  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6245 {
6246 
6247 }
6248 
6249 QStringList QgsProcessingMeshLayerWidgetWrapper::compatibleParameterTypes() const
6250 {
6251  return QStringList()
6256 }
6257 
6258 QStringList QgsProcessingMeshLayerWidgetWrapper::compatibleOutputTypes() const
6259 {
6260  return QStringList()
6262  // TODO << QgsProcessingOutputMeshLayer::typeName()
6266 }
6267 
6268 QString QgsProcessingMeshLayerWidgetWrapper::modelerExpressionFormatString() const
6269 {
6270  return tr( "path to a mesh layer" );
6271 }
6272 
6273 QString QgsProcessingMeshLayerWidgetWrapper::parameterType() const
6274 {
6276 }
6277 
6278 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6279 {
6280  return new QgsProcessingMeshLayerWidgetWrapper( parameter, type );
6281 }
6282 
6283 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMeshLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6284 {
6285  Q_UNUSED( context );
6286  Q_UNUSED( widgetContext );
6287  Q_UNUSED( definition );
6288  Q_UNUSED( algorithm );
6289 
6290  return nullptr;
6291 }
6292 
6293 
6294 
6295 //
6296 // QgsProcessingRasterBandPanelWidget
6297 //
6298 
6299 QgsProcessingRasterBandPanelWidget::QgsProcessingRasterBandPanelWidget( QWidget *parent, const QgsProcessingParameterBand *param )
6300  : QWidget( parent )
6301  , mParam( param )
6302 {
6303  QHBoxLayout *hl = new QHBoxLayout();
6304  hl->setContentsMargins( 0, 0, 0, 0 );
6305 
6306  mLineEdit = new QLineEdit();
6307  mLineEdit->setEnabled( false );
6308  hl->addWidget( mLineEdit, 1 );
6309 
6310  mToolButton = new QToolButton();
6311  mToolButton->setText( QString( QChar( 0x2026 ) ) );
6312  hl->addWidget( mToolButton );
6313 
6314  setLayout( hl );
6315 
6316  if ( mParam )
6317  {
6318  mLineEdit->setText( tr( "%1 bands selected" ).arg( 0 ) );
6319  }
6320 
6321  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingRasterBandPanelWidget::showDialog );
6322 }
6323 
6324 void QgsProcessingRasterBandPanelWidget::setBands( const QList< int > &bands )
6325 {
6326  mBands = bands;
6327 }
6328 
6329 void QgsProcessingRasterBandPanelWidget::setBandNames( const QHash<int, QString> &names )
6330 {
6331  mBandNames = names;
6332 }
6333 
6334 void QgsProcessingRasterBandPanelWidget::setValue( const QVariant &value )
6335 {
6336  if ( value.isValid() )
6337  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
6338  else
6339  mValue.clear();
6340 
6341  updateSummaryText();
6342  emit changed();
6343 }
6344 
6345 void QgsProcessingRasterBandPanelWidget::showDialog()
6346 {
6347  QVariantList availableOptions;
6348  QStringList fieldNames;
6349  availableOptions.reserve( mBands.size() );
6350  for ( int band : std::as_const( mBands ) )
6351  {
6352  availableOptions << band;
6353  }
6354 
6356  if ( panel && panel->dockMode() )
6357  {
6358  QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
6359  widget->setPanelTitle( mParam->description() );
6360 
6361  widget->setValueFormatter( [this]( const QVariant & v ) -> QString
6362  {
6363  int band = v.toInt();
6364  return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
6365  } );
6366 
6367  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
6368  {
6369  setValue( widget->selectedOptions() );
6370  } );
6371  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
6372  panel->openPanel( widget );
6373  }
6374  else
6375  {
6376  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
6377 
6378  dlg.setValueFormatter( [this]( const QVariant & v ) -> QString
6379  {
6380  int band = v.toInt();
6381  return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
6382  } );
6383  if ( dlg.exec() )
6384  {
6385  setValue( dlg.selectedOptions() );
6386  }
6387  }
6388 }
6389 
6390 void QgsProcessingRasterBandPanelWidget::updateSummaryText()
6391 {
6392  if ( mParam )
6393  mLineEdit->setText( tr( "%1 bands selected" ).arg( mValue.count() ) );
6394 }
6395 
6396 
6397 
6398 //
6399 // QgsProcessingBandWidgetWrapper
6400 //
6401 
6402 QgsProcessingBandParameterDefinitionWidget::QgsProcessingBandParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6403  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6404 {
6405  QVBoxLayout *vlayout = new QVBoxLayout();
6406  vlayout->setContentsMargins( 0, 0, 0, 0 );
6407 
6408  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
6409 
6410  mDefaultLineEdit = new QLineEdit();
6411  mDefaultLineEdit->setToolTip( tr( "Band number (separate bands with ; for multiple band parameters)" ) );
6412  if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6413  {
6414  const QList< int > bands = QgsProcessingParameters::parameterAsInts( bandParam, bandParam->defaultValueForGui(), context );
6415  QStringList defVal;
6416  for ( int b : bands )
6417  {
6418  defVal << QString::number( b );
6419  }
6420 
6421  mDefaultLineEdit->setText( defVal.join( ';' ) );
6422  }
6423  vlayout->addWidget( mDefaultLineEdit );
6424 
6425  vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
6426  mParentLayerComboBox = new QComboBox();
6427 
6428  QString initialParent;
6429  if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6430  initialParent = bandParam->parentLayerParameterName();
6431 
6432  if ( auto *lModel = widgetContext.model() )
6433  {
6434  // populate combo box with other model input choices
6435  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
6436  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
6437  {
6438  if ( const QgsProcessingParameterRasterLayer *definition = dynamic_cast< const QgsProcessingParameterRasterLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
6439  {
6440  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
6441  if ( !initialParent.isEmpty() && initialParent == definition->name() )
6442  {
6443  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
6444  }
6445  }
6446  }
6447  }
6448 
6449  if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
6450  {
6451  // if no parent candidates found, we just add the existing one as a placeholder
6452  mParentLayerComboBox->addItem( initialParent, initialParent );
6453  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
6454  }
6455 
6456  vlayout->addWidget( mParentLayerComboBox );
6457 
6458  mAllowMultipleCheckBox = new QCheckBox( tr( "Allow multiple" ) );
6459  if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6460  mAllowMultipleCheckBox->setChecked( bandParam->allowMultiple() );
6461 
6462  vlayout->addWidget( mAllowMultipleCheckBox );
6463  setLayout( vlayout );
6464 }
6465 
6466 QgsProcessingParameterDefinition *QgsProcessingBandParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6467 {
6468  auto param = std::make_unique< QgsProcessingParameterBand >( name, description, mDefaultLineEdit->text().split( ';' ), mParentLayerComboBox->currentData().toString(), false, mAllowMultipleCheckBox->isChecked() );
6469  param->setFlags( flags );
6470  return param.release();
6471 }
6472 
6473 QgsProcessingBandWidgetWrapper::QgsProcessingBandWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6474  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6475 {
6476 
6477 }
6478 
6479 QWidget *QgsProcessingBandWidgetWrapper::createWidget()
6480 {
6481  const QgsProcessingParameterBand *bandParam = dynamic_cast< const QgsProcessingParameterBand *>( parameterDefinition() );
6482  switch ( type() )
6483  {
6486  {
6487  if ( bandParam->allowMultiple() )
6488  {
6489  mPanel = new QgsProcessingRasterBandPanelWidget( nullptr, bandParam );
6490  mPanel->setToolTip( parameterDefinition()->toolTip() );
6491  connect( mPanel, &QgsProcessingRasterBandPanelWidget::changed, this, [ = ]
6492  {
6493  emit widgetValueHasChanged( this );
6494  } );
6495  return mPanel;
6496  }
6497  else
6498  {
6499  mComboBox = new QgsRasterBandComboBox();
6500  mComboBox->setShowNotSetOption( bandParam->flags() & QgsProcessingParameterDefinition::FlagOptional );
6501 
6502  mComboBox->setToolTip( parameterDefinition()->toolTip() );
6503  connect( mComboBox, &QgsRasterBandComboBox::bandChanged, this, [ = ]( int )
6504  {
6505  emit widgetValueHasChanged( this );
6506  } );
6507  return mComboBox;
6508  }
6509  }
6510 
6512  {
6513  mLineEdit = new QLineEdit();
6514  mLineEdit->setToolTip( QObject::tr( "Band number (separate bands with ; for multiple band parameters)" ) );
6515  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
6516  {
6517  emit widgetValueHasChanged( this );
6518  } );
6519  return mLineEdit;
6520  }
6521 
6522  }
6523  return nullptr;
6524 }
6525 
6526 void QgsProcessingBandWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
6527 {
6529  switch ( type() )
6530  {
6533  {
6534  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
6535  {
6536  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterBand * >( parameterDefinition() )->parentLayerParameterName() )
6537  {
6538  setParentLayerWrapperValue( wrapper );
6540  {
6541  setParentLayerWrapperValue( wrapper );
6542  } );
6543  break;
6544  }
6545  }
6546  break;
6547  }
6548 
6550  break;
6551  }
6552 }
6553 
6554 void QgsProcessingBandWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
6555 {
6556  // evaluate value to layer
6557  QgsProcessingContext *context = nullptr;
6558  std::unique_ptr< QgsProcessingContext > tmpContext;
6559  if ( mProcessingContextGenerator )
6560  context = mProcessingContextGenerator->processingContext();
6561 
6562  if ( !context )
6563  {
6564  tmpContext = std::make_unique< QgsProcessingContext >();
6565  context = tmpContext.get();
6566  }
6567 
6568  QVariant value = parentWrapper->parameterValue();
6569 
6570  QgsRasterLayer *layer = QgsProcessingParameters::parameterAsRasterLayer( parentWrapper->parameterDefinition(), value, *context );
6571  if ( layer && layer->isValid() )
6572  {
6573  // need to grab ownership of layer if required - otherwise layer may be deleted when context
6574  // goes out of scope
6575  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
6576  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::RasterLayer )
6577  {
6578  mParentLayer.reset( qobject_cast< QgsRasterLayer * >( ownedLayer.release() ) );
6579  layer = mParentLayer.get();
6580  }
6581  else
6582  {
6583  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
6584  }
6585 
6586  if ( mComboBox )
6587  mComboBox->setLayer( layer );
6588  else if ( mPanel )
6589  {
6590  QgsRasterDataProvider *provider = layer->dataProvider();
6591  if ( provider && layer->isValid() )
6592  {
6593  //fill available bands
6594  int nBands = provider->bandCount();
6595  QList< int > bands;
6596  QHash< int, QString > bandNames;
6597  for ( int i = 1; i <= nBands; ++i )
6598  {
6599  bandNames.insert( i, QgsRasterBandComboBox::displayBandName( provider, i ) );
6600  bands << i;
6601  }
6602  mPanel->setBands( bands );
6603  mPanel->setBandNames( bandNames );
6604  }
6605  }
6606  }
6607  else
6608  {
6609  if ( mComboBox )
6610  mComboBox->setLayer( nullptr );
6611  else if ( mPanel )
6612  mPanel->setBands( QList< int >() );
6613 
6614  if ( value.isValid() && widgetContext().messageBar() )
6615  {
6616  widgetContext().messageBar()->clearWidgets();
6617  widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent bands could not be populated" ),
6618  Qgis::MessageLevel::Info );
6619  }
6620  }
6621 
6622  if ( parameterDefinition()->defaultValueForGui().isValid() )
6623  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
6624 }
6625 
6626 void QgsProcessingBandWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6627 {
6628  if ( mComboBox )
6629  {
6630  if ( !value.isValid() )
6631  mComboBox->setBand( -1 );
6632  else
6633  {
6634  const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
6635  mComboBox->setBand( v );
6636  }
6637  }
6638  else if ( mPanel )
6639  {
6640  QVariantList opts;
6641  if ( value.isValid() )
6642  {
6643  const QList< int > v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
6644  opts.reserve( v.size() );
6645  for ( int i : v )
6646  opts << i;
6647  }
6648  if ( mPanel )
6649  mPanel->setValue( value.isValid() ? opts : QVariant() );
6650  }
6651  else if ( mLineEdit )
6652  {
6653  const QgsProcessingParameterBand *bandParam = static_cast< const QgsProcessingParameterBand * >( parameterDefinition() );
6654  if ( bandParam->allowMultiple() )
6655  {
6656  const QList< int > v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
6657  QStringList opts;
6658  opts.reserve( v.size() );
6659  for ( int i : v )
6660  opts << QString::number( i );
6661  mLineEdit->setText( value.isValid() && !opts.empty() ? opts.join( ';' ) : QString() );
6662  }
6663  else
6664  {
6665  if ( value.isValid() )
6666  mLineEdit->setText( QString::number( QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context ) ) );
6667  else
6668  mLineEdit->clear();
6669  }
6670  }
6671 }
6672 
6673 QVariant QgsProcessingBandWidgetWrapper::widgetValue() const
6674 {
6675  if ( mComboBox )
6676  return mComboBox->currentBand() == -1 ? QVariant() : mComboBox->currentBand();
6677  else if ( mPanel )
6678  return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
6679  else if ( mLineEdit )
6680  {
6681  const QgsProcessingParameterBand *bandParam = static_cast< const QgsProcessingParameterBand * >( parameterDefinition() );
6682  if ( bandParam->allowMultiple() )
6683  {
6684 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
6685  const QStringList parts = mLineEdit->text().split( ';', QString::SkipEmptyParts );
6686 #else
6687  const QStringList parts = mLineEdit->text().split( ';', Qt::SkipEmptyParts );
6688 #endif
6689  QVariantList res;
6690  res.reserve( parts.count() );
6691  for ( const QString &s : parts )
6692  {
6693  bool ok = false;
6694  int band = s.toInt( &ok );
6695  if ( ok )
6696  res << band;
6697  }
6698  return res.isEmpty() ? QVariant() : res;
6699  }
6700  else
6701  {
6702  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
6703  }
6704  }
6705  else
6706  return QVariant();
6707 }
6708 
6709 QStringList QgsProcessingBandWidgetWrapper::compatibleParameterTypes() const
6710 {
6711  return QStringList()
6714 }
6715 
6716 QStringList QgsProcessingBandWidgetWrapper::compatibleOutputTypes() const
6717 {
6718  return QStringList()
6720 }
6721 
6722 QString QgsProcessingBandWidgetWrapper::modelerExpressionFormatString() const
6723 {
6724  return tr( "selected band numbers as an array of numbers, or semicolon separated string of options (e.g. '1;3')" );
6725 }
6726 
6727 QString QgsProcessingBandWidgetWrapper::parameterType() const
6728 {
6730 }
6731 
6732 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBandWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6733 {
6734  return new QgsProcessingBandWidgetWrapper( parameter, type );
6735 }
6736 
6737 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBandWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6738 {
6739  return new QgsProcessingBandParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6740 }
6741 
6742 
6743 
6744 //
6745 // QgsProcessingMultipleLayerPanelWidget
6746 //
6747 
6748 QgsProcessingMultipleLayerPanelWidget::QgsProcessingMultipleLayerPanelWidget( QWidget *parent, const QgsProcessingParameterMultipleLayers *param )
6749  : QWidget( parent )
6750  , mParam( param )
6751 {
6752  QHBoxLayout *hl = new QHBoxLayout();
6753  hl->setContentsMargins( 0, 0, 0, 0 );
6754 
6755  mLineEdit = new QLineEdit();
6756  mLineEdit->setEnabled( false );
6757  hl->addWidget( mLineEdit, 1 );
6758 
6759  mToolButton = new QToolButton();
6760  mToolButton->setText( QString( QChar( 0x2026 ) ) );
6761  hl->addWidget( mToolButton );
6762 
6763  setLayout( hl );
6764 
6765  if ( mParam )
6766  {
6767  mLineEdit->setText( tr( "%1 inputs selected" ).arg( 0 ) );
6768  }
6769 
6770  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingMultipleLayerPanelWidget::showDialog );
6771 }
6772 
6773 void QgsProcessingMultipleLayerPanelWidget::setValue( const QVariant &value )
6774 {
6775  if ( value.isValid() )
6776  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
6777  else
6778  mValue.clear();
6779 
6780  updateSummaryText();
6781  emit changed();
6782 }
6783 
6784 void QgsProcessingMultipleLayerPanelWidget::setProject( QgsProject *project )
6785 {
6786  mProject = project;
6787  if ( mProject )
6788  {
6789  connect( mProject, &QgsProject::layerRemoved, this, [&]( const QString & layerId )
6790  {
6791  if ( mValue.removeAll( layerId ) )
6792  {
6793  updateSummaryText();
6794  emit changed();
6795  }
6796  } );
6797  }
6798 }
6799 
6800 void QgsProcessingMultipleLayerPanelWidget::setModel( QgsProcessingModelAlgorithm *model, const QString &modelChildAlgorithmID )
6801 {
6802  mModel = model;
6803  if ( !model )
6804  return;
6805 
6806  switch ( mParam->layerType() )
6807  {
6809  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFile::typeName(),
6810  QStringList() << QgsProcessingOutputFile::typeName() );
6811  break;
6812 
6814  {
6815  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterRasterLayer::typeName()
6818  QStringList() << QgsProcessingOutputFile::typeName()
6822  break;
6823  }
6824 
6826  {
6827  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterMeshLayer::typeName()
6830  QStringList() << QgsProcessingOutputFile::typeName()
6833  break;
6834  }
6835 
6837  {
6838  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterMapLayer::typeName()
6841  QStringList() << QgsProcessingOutputFile::typeName()
6844  break;
6845  }
6846 
6848  {
6849  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterPointCloudLayer::typeName()
6852  QStringList() << QgsProcessingOutputFile::typeName()
6855  break;
6856  }
6857 
6859  {
6860  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterAnnotationLayer::typeName()
6862  QStringList() << QgsProcessingOutputMapLayer::typeName()
6864  break;
6865  }
6866 
6868  {
6869  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6873  QStringList() << QgsProcessingOutputFile::typeName()
6877  QList< int >() << QgsProcessing::TypeVector );
6878  break;
6879  }
6880 
6882  {
6883  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6887  QStringList() << QgsProcessingOutputFile::typeName()
6891  break;
6892  }
6893 
6895  {
6896  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6900  QStringList() << QgsProcessingOutputFile::typeName()
6905  break;
6906  }
6907 
6909  {
6910  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6914  QStringList() << QgsProcessingOutputFile::typeName()
6919  break;
6920  }
6921 
6923  {
6924  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6928  QStringList() << QgsProcessingOutputFile::typeName()
6933  break;
6934  }
6935 
6937  {
6938  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6944  QStringList() << QgsProcessingOutputFile::typeName()
6948  // << QgsProcessingOutputMeshLayer::typeName()
6950  break;
6951  }
6952  }
6953 }
6954 
6955 void QgsProcessingMultipleLayerPanelWidget::showDialog()
6956 {
6958  if ( panel && panel->dockMode() )
6959  {
6960  QgsProcessingMultipleInputPanelWidget *widget = new QgsProcessingMultipleInputPanelWidget( mParam, mValue, mModelSources, mModel );
6961  widget->setPanelTitle( mParam->description() );
6962  widget->setProject( mProject );
6963  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
6964  {
6965  setValue( widget->selectedOptions() );
6966  } );
6967  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
6968  panel->openPanel( widget );
6969  }
6970  else
6971  {
6972  QgsProcessingMultipleInputDialog dlg( mParam, mValue, mModelSources, mModel, this, Qt::WindowFlags() );
6973  dlg.setProject( mProject );
6974  if ( dlg.exec() )
6975  {
6976  setValue( dlg.selectedOptions() );
6977  }
6978  }
6979 }
6980 
6981 void QgsProcessingMultipleLayerPanelWidget::updateSummaryText()
6982 {
6983  if ( mParam )
6984  mLineEdit->setText( tr( "%1 inputs selected" ).arg( mValue.count() ) );
6985 }
6986 
6987 //
6988 // QgsProcessingMultipleLayerWidgetWrapper
6989 //
6990 
6991 QgsProcessingMultipleLayerParameterDefinitionWidget::QgsProcessingMultipleLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6992  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6993 {
6994  QVBoxLayout *vlayout = new QVBoxLayout();
6995  vlayout->setContentsMargins( 0, 0, 0, 0 );
6996 
6997  vlayout->addWidget( new QLabel( tr( "Allowed layer type" ) ) );
6998  mLayerTypeComboBox = new QComboBox();
6999  mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), QgsProcessing::TypeMapLayer );
7000  mLayerTypeComboBox->addItem( tr( "Vector (No Geometry Required)" ), QgsProcessing::TypeVector );
7001  mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), QgsProcessing::TypeVectorPoint );
7002  mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), QgsProcessing::TypeVectorLine );
7003  mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), QgsProcessing::TypeVectorPolygon );
7004  mLayerTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
7005  mLayerTypeComboBox->addItem( tr( "Raster" ), QgsProcessing::TypeRaster );
7006  mLayerTypeComboBox->addItem( tr( "File" ), QgsProcessing::TypeFile );
7007  mLayerTypeComboBox->addItem( tr( "Mesh" ), QgsProcessing::TypeMesh );
7008  mLayerTypeComboBox->addItem( tr( "Plugin" ), QgsProcessing::TypePlugin );
7009  mLayerTypeComboBox->addItem( tr( "Point Cloud" ), QgsProcessing::TypePointCloud );
7010  mLayerTypeComboBox->addItem( tr( "Annotation" ), QgsProcessing::TypeAnnotation );
7011  if ( const QgsProcessingParameterMultipleLayers *layersParam = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( definition ) )
7012  mLayerTypeComboBox->setCurrentIndex( mLayerTypeComboBox->findData( layersParam->layerType() ) );
7013 
7014  vlayout->addWidget( mLayerTypeComboBox );
7015  setLayout( vlayout );
7016 }
7017 
7018 QgsProcessingParameterDefinition *QgsProcessingMultipleLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
7019 {
7020  auto param = std::make_unique< QgsProcessingParameterMultipleLayers >( name, description, static_cast< QgsProcessing::SourceType >( mLayerTypeComboBox->currentData().toInt() ) );
7021  param->setFlags( flags );
7022  return param.release();
7023 }
7024 
7025 QgsProcessingMultipleLayerWidgetWrapper::QgsProcessingMultipleLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7026  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7027 {
7028 
7029 }
7030 
7031 QWidget *QgsProcessingMultipleLayerWidgetWrapper::createWidget()
7032 {
7033  const QgsProcessingParameterMultipleLayers *layerParam = dynamic_cast< const QgsProcessingParameterMultipleLayers *>( parameterDefinition() );
7034 
7035  mPanel = new QgsProcessingMultipleLayerPanelWidget( nullptr, layerParam );
7036  mPanel->setToolTip( parameterDefinition()->toolTip() );
7037  mPanel->setProject( widgetContext().project() );
7038  if ( type() == QgsProcessingGui::Modeler )
7039  mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
7040  connect( mPanel, &QgsProcessingMultipleLayerPanelWidget::changed, this, [ = ]
7041  {
7042  emit widgetValueHasChanged( this );
7043  } );
7044  return mPanel;
7045 }
7046 
7047 void QgsProcessingMultipleLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
7048 {
7050  if ( mPanel )
7051  {
7052  mPanel->setProject( context.project() );
7053  if ( type() == QgsProcessingGui::Modeler )
7054  mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
7055  }
7056 }
7057 
7058 void QgsProcessingMultipleLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7059 {
7060  if ( mPanel )
7061  {
7062  QVariantList opts;
7063  if ( value.isValid() )
7064  {
7065  const QList< QgsMapLayer * > v = QgsProcessingParameters::parameterAsLayerList( parameterDefinition(), value, context );
7066  opts.reserve( v.size() );
7067  for ( const QgsMapLayer *l : v )
7068  opts << l->source();
7069  }
7070 
7071  for ( const QVariant &v : value.toList() )
7072  {
7073  if ( v.canConvert< QgsProcessingModelChildParameterSource >() )
7074  {
7075  const QgsProcessingModelChildParameterSource source = v.value< QgsProcessingModelChildParameterSource >();
7076  opts << QVariant::fromValue( source );
7077  }
7078  }
7079 
7080  if ( mPanel )
7081  mPanel->setValue( value.isValid() ? opts : QVariant() );
7082  }
7083 }
7084 
7085 QVariant QgsProcessingMultipleLayerWidgetWrapper::widgetValue() const
7086 {
7087  if ( mPanel )
7088  return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
7089  else
7090  return QVariant();
7091 }
7092 
7093 QStringList QgsProcessingMultipleLayerWidgetWrapper::compatibleParameterTypes() const
7094 {
7095  return QStringList()
7104 }
7105 
7106 QStringList QgsProcessingMultipleLayerWidgetWrapper::compatibleOutputTypes() const
7107 {
7108  return QStringList()
7115 }
7116 
7117 QString QgsProcessingMultipleLayerWidgetWrapper::modelerExpressionFormatString() const
7118 {
7119  return tr( "an array of layer paths, or semicolon separated string of layer paths" );
7120 }
7121 
7122 QString QgsProcessingMultipleLayerWidgetWrapper::parameterType() const
7123 {
7125 }
7126 
7127 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMultipleLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7128 {
7129  return new QgsProcessingMultipleLayerWidgetWrapper( parameter, type );
7130 }
7131 
7132 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMultipleLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7133 {
7134  return new QgsProcessingMultipleLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
7135 }
7136 
7137 
7138 //
7139 // QgsProcessingPointCloudLayerWidgetWrapper
7140 //
7141 
7142 QgsProcessingPointCloudLayerWidgetWrapper::QgsProcessingPointCloudLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7143  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
7144 {
7145 
7146 }
7147 
7148 QStringList QgsProcessingPointCloudLayerWidgetWrapper::compatibleParameterTypes() const
7149 {
7150  return QStringList()
7155 }
7156 
7157 QStringList QgsProcessingPointCloudLayerWidgetWrapper::compatibleOutputTypes() const
7158 {
7159  return QStringList()
7161  // TODO << QgsProcessingOutputPointCloudLayer::typeName()
7165 }
7166 
7167 QString QgsProcessingPointCloudLayerWidgetWrapper::modelerExpressionFormatString() const
7168 {
7169  return tr( "path to a point cloud layer" );
7170 }
7171 
7172 QString QgsProcessingPointCloudLayerWidgetWrapper::parameterType() const
7173 {
7175 }
7176 
7177 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7178 {
7179  return new QgsProcessingPointCloudLayerWidgetWrapper( parameter, type );
7180 }
7181 
7182 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointCloudLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7183 {
7184  Q_UNUSED( context );
7185  Q_UNUSED( widgetContext );
7186  Q_UNUSED( definition );
7187  Q_UNUSED( algorithm );
7188 
7189  return nullptr;
7190 }
7191 
7192 
7193 //
7194 // QgsProcessingAnnotationLayerWidgetWrapper
7195 //
7196 
7197 QgsProcessingAnnotationLayerWidgetWrapper::QgsProcessingAnnotationLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7198  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7199 {
7200 
7201 }
7202 
7203 QStringList QgsProcessingAnnotationLayerWidgetWrapper::compatibleParameterTypes() const
7204 {
7205  return QStringList()
7210 }
7211 
7212 QStringList QgsProcessingAnnotationLayerWidgetWrapper::compatibleOutputTypes() const
7213 {
7214  return QStringList()
7217 }
7218 
7219 QString QgsProcessingAnnotationLayerWidgetWrapper::modelerExpressionFormatString() const
7220 {
7221  return tr( "name of an annotation layer, or \"main\" for the main annotation layer" );
7222 }
7223 
7224 QString QgsProcessingAnnotationLayerWidgetWrapper::parameterType() const
7225 {
7227 }
7228 
7229 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAnnotationLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7230 {
7231  return new QgsProcessingAnnotationLayerWidgetWrapper( parameter, type );
7232 }
7233 
7234 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingAnnotationLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7235 {
7236  Q_UNUSED( context );
7237  Q_UNUSED( widgetContext );
7238  Q_UNUSED( definition );
7239  Q_UNUSED( algorithm );
7240 
7241  return nullptr;
7242 }
7243 
7244 void QgsProcessingAnnotationLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
7245 {
7247  if ( mComboBox )
7248  {
7249  if ( mWidgetContext.project() )
7250  mComboBox->setAdditionalLayers( { mWidgetContext.project()->mainAnnotationLayer() } );
7251  }
7252 }
7253 
7254 QWidget *QgsProcessingAnnotationLayerWidgetWrapper::createWidget()
7255 {
7256  mComboBox = new QgsMapLayerComboBox( );
7257  mComboBox->setFilters( QgsMapLayerProxyModel::AnnotationLayer );
7258 
7259  switch ( type() )
7260  {
7263  break;
7265  mComboBox->setEditable( true );
7266  break;
7267  }
7268 
7269  mComboBox->setToolTip( parameterDefinition()->toolTip() );
7270 
7271  if ( mWidgetContext.project() )
7272  mComboBox->setAdditionalLayers( { mWidgetContext.project()->mainAnnotationLayer() } );
7273 
7274  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
7275  mComboBox->setAllowEmptyLayer( true );
7276 
7277  connect( mComboBox, &QgsMapLayerComboBox::layerChanged, this, [ = ]()
7278  {
7279  if ( mBlockSignals )
7280  return;
7281 
7282  emit widgetValueHasChanged( this );
7283  } );
7284 
7285  setWidgetContext( widgetContext() );
7286  return mComboBox;
7287 }
7288 
7289 void QgsProcessingAnnotationLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7290 {
7291  if ( mComboBox )
7292  {
7293  if ( !value.isValid() && parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
7294  {
7295  mComboBox->setLayer( nullptr );
7296  return;
7297  }
7298 
7299  QVariant val = value;
7300  if ( val.canConvert<QgsProperty>() )
7301  {
7302  if ( val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
7303  {
7304  val = val.value< QgsProperty >().staticValue();
7305  }
7306  else
7307  {
7308  val = val.value< QgsProperty >().valueAsString( context.expressionContext(), parameterDefinition()->defaultValueForGui().toString() );
7309  }
7310  }
7311 
7312  QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( val.value< QObject * >() );
7313  if ( !layer && val.type() == QVariant::String )
7314  {
7315  layer = QgsProcessingUtils::mapLayerFromString( val.toString(), context, false, QgsProcessingUtils::LayerHint::Annotation );
7316  }
7317 
7318  if ( layer )
7319  {
7320  mComboBox->setLayer( layer );
7321  }
7322  }
7323 }
7324 
7325 QVariant QgsProcessingAnnotationLayerWidgetWrapper::widgetValue() const
7326 {
7327  return mComboBox && mComboBox->currentLayer() ?
7328  ( mWidgetContext.project() ? ( mComboBox->currentLayer() == mWidgetContext.project()->mainAnnotationLayer() ? QStringLiteral( "main" ) : mComboBox->currentLayer()->id() ) : mComboBox->currentLayer()->id() )
7329  : QVariant();
7330 }
7331 
7332 
7333 
7334 //
7335 // QgsProcessingOutputWidgetWrapper
7336 //
7337 
7338 QgsProcessingOutputWidgetWrapper::QgsProcessingOutputWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7339  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7340 {
7341 
7342 }
7343 
7344 QWidget *QgsProcessingOutputWidgetWrapper::createWidget()
7345 {
7346  const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( parameterDefinition() );
7347  switch ( type() )
7348  {
7351  {
7352  mOutputWidget = new QgsProcessingLayerOutputDestinationWidget( destParam, false );
7353  if ( mProcessingContextGenerator )
7354  mOutputWidget->setContext( mProcessingContextGenerator->processingContext() );
7355  if ( mParametersGenerator )
7356  mOutputWidget->registerProcessingParametersGenerator( mParametersGenerator );
7357  mOutputWidget->setToolTip( parameterDefinition()->toolTip() );
7358 
7359  connect( mOutputWidget, &QgsProcessingLayerOutputDestinationWidget::destinationChanged, this, [ = ]()
7360  {
7361  if ( mBlockSignals )
7362  return;
7363 
7364  emit widgetValueHasChanged( this );
7365  } );
7366 
7367  if ( type() == QgsProcessingGui::Standard
7371  mOutputWidget->addOpenAfterRunningOption();
7372 
7373  return mOutputWidget;
7374  }
7376  break;
7377  }
7378 
7379  return nullptr;
7380 }
7381 
7382 
7383 void QgsProcessingOutputWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
7384 {
7385  if ( mOutputWidget )
7386  mOutputWidget->setValue( value );
7387 }
7388 
7389 QVariant QgsProcessingOutputWidgetWrapper::widgetValue() const
7390 {
7391  if ( mOutputWidget )
7392  return mOutputWidget->value();
7393 
7394  return QVariant();
7395 }
7396 
7397 QVariantMap QgsProcessingOutputWidgetWrapper::customProperties() const
7398 {
7399  QVariantMap res;
7400  if ( mOutputWidget )
7401  res.insert( QStringLiteral( "OPEN_AFTER_RUNNING" ), mOutputWidget->openAfterRunning() );
7402  return res;
7403 }
7404 
7405 QStringList QgsProcessingOutputWidgetWrapper::compatibleParameterTypes() const
7406 {
7407  return QStringList()
7414 }
7415 
7416 QStringList QgsProcessingOutputWidgetWrapper::compatibleOutputTypes() const
7417 {
7418  return QStringList()
7422 }
7423 
7424 //
7425 // QgsProcessingFeatureSinkWidgetWrapper
7426 //
7427 
7428 QgsProcessingFeatureSinkWidgetWrapper::QgsProcessingFeatureSinkWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7429  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7430 {
7431 
7432 }
7433 
7434 QString QgsProcessingFeatureSinkWidgetWrapper::parameterType() const
7435 {
7437 }
7438 
7439 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSinkWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7440 {
7441  return new QgsProcessingFeatureSinkWidgetWrapper( parameter, type );
7442 }
7443 
7444 QString QgsProcessingFeatureSinkWidgetWrapper::modelerExpressionFormatString() const
7445 {
7446  return tr( "path to layer destination" );
7447 }
7448 
7449 //
7450 // QgsProcessingFeatureSinkWidgetWrapper
7451 //
7452 
7453 QgsProcessingVectorDestinationWidgetWrapper::QgsProcessingVectorDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7454  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7455 {
7456 
7457 }
7458 
7459 QString QgsProcessingVectorDestinationWidgetWrapper::parameterType() const
7460 {
7462 }
7463 
7464 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7465 {
7466  return new QgsProcessingVectorDestinationWidgetWrapper( parameter, type );
7467 }
7468 
7469 QString QgsProcessingVectorDestinationWidgetWrapper::modelerExpressionFormatString() const
7470 {
7471  return tr( "path to layer destination" );
7472 }
7473 
7474 //
7475 // QgsProcessingFeatureSinkWidgetWrapper
7476 //
7477 
7478 QgsProcessingRasterDestinationWidgetWrapper::QgsProcessingRasterDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7479  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7480 {
7481 
7482 }
7483 
7484 QString QgsProcessingRasterDestinationWidgetWrapper::parameterType() const
7485 {
7487 }
7488 
7489 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7490 {
7491  return new QgsProcessingRasterDestinationWidgetWrapper( parameter, type );
7492 }
7493 
7494 QString QgsProcessingRasterDestinationWidgetWrapper::modelerExpressionFormatString() const
7495 {
7496  return tr( "path to layer destination" );
7497 }
7498 
7499 //
7500 // QgsProcessingFileDestinationWidgetWrapper
7501 //
7502 
7503 QgsProcessingFileDestinationWidgetWrapper::QgsProcessingFileDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7504  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7505 {
7506 
7507 }
7508 
7509 QString QgsProcessingFileDestinationWidgetWrapper::parameterType() const
7510 {
7512 }
7513 
7514 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7515 {
7516  return new QgsProcessingFileDestinationWidgetWrapper( parameter, type );
7517 }
7518 
7519 QString QgsProcessingFileDestinationWidgetWrapper::modelerExpressionFormatString() const
7520 {
7521  return tr( "path to file destination" );
7522 }
7523 
7524 //
7525 // QgsProcessingFolderDestinationWidgetWrapper
7526 //
7527 
7528 QgsProcessingFolderDestinationWidgetWrapper::QgsProcessingFolderDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7529  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7530 {
7531 
7532 }
7533 
7534 QString QgsProcessingFolderDestinationWidgetWrapper::parameterType() const
7535 {
7537 }
7538 
7539 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFolderDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7540 {
7541  return new QgsProcessingFolderDestinationWidgetWrapper( parameter, type );
7542 }
7543 
7544 QString QgsProcessingFolderDestinationWidgetWrapper::modelerExpressionFormatString() const
7545 {
7546  return tr( "path to folder destination" );
7547 }
7548 
A widget wrapper for Processing parameter value widgets.
QVariant parameterValue() const
Returns the current value of the parameter.
virtual QLabel * createLabel()
Creates a new label to accompany widgets created by the wrapper.
virtual void registerProcessingContextGenerator(QgsProcessingContextGenerator *generator)
Registers a Processing context generator class that will be used to retrieve a Processing context for...
void widgetValueHasChanged(QgsAbstractProcessingParameterWidgetWrapper *wrapper)
Emitted whenever the parameter value (as defined by the wrapped widget) is changed.
virtual void postInitialize(const QList< QgsAbstractProcessingParameterWidgetWrapper * > &wrappers)
Called after all wrappers have been created within a particular dialog or context,...
virtual const QgsVectorLayer * linkedVectorLayer() const
Returns the optional vector layer associated with this widget wrapper, or nullptr if no vector layer ...
const QgsProcessingParameterDefinition * parameterDefinition() const
Returns the parameter definition associated with this wrapper.
virtual void setDialog(QDialog *dialog)
Sets the parent dialog in which the wrapper is shown.
virtual void setWidgetContext(const QgsProcessingParameterWidgetContext &context)
Sets the context in which the Processing parameter widget is shown, e.g., the parent model algorithm,...
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Selector widget for authentication configs.
void selectedConfigIdChanged(const QString &authcfg)
Emitted when authentication config is changed or missing.
QComboBox subclass which allows selecting multiple items.
A cross platform button subclass for selecting colors.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
A widget for selecting the coordinate operation to use when transforming between a source and destina...
void operationChanged()
Emitted when the operation selected in the dialog is changed.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Q_GADGET QgsUnitTypes::DistanceUnit mapUnits
The QgsDatabaseSchemaComboBox class is a combo box which displays the list of schemas for a specific ...
The QgsDatabaseTableComboBox class is a combo box which displays the list of tables for a specific da...
The QgsDateEdit class is a QDateEdit widget with the capability of setting/reading null dates.
void dateValueChanged(const QDate &date)
Signal emitted whenever the date changes.
The QgsDateTimeEdit class is a QDateTimeEdit with the capability of setting/reading null date/times.
void setAllowNull(bool allowNull)
Determines if the widget allows setting null date/time.
void setNullRepresentation(const QString &null)
Sets the widget's null representation, which defaults to QgsApplication::nullRepresentation().
void valueChanged(const QDateTime &date)
Signal emitted whenever the value changes.
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
static double toDouble(const QString &input, bool *ok)
Converts input string to double value.
A reusable widget that can be used to build a expression string.
void expressionParsed(bool isValid)
Emitted when the user changes the expression in the widget.
The QgsExpressionLineEdit widget includes a line edit for entering expressions together with a button...
void expressionChanged(const QString &expression)
Emitted when the expression is changed.
A widget for configuration of a map extent.
void toggleDialogVisibility(bool visible)
Emitted when the parent dialog visibility must be changed (e.g.
void extentChanged(const QgsRectangle &r)
Emitted when the widget's extent is changed.
The QgsFieldComboBox is a combo box which displays the list of fields of a given layer.
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
@ DateTime
Datetime fieldss.
@ Date
Date or datetime fields.
@ String
String fields.
@ Numeric
All numeric fields.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString name
Definition: qgsfield.h:60
Container of fields for a vector layer.
Definition: qgsfields.h:45
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfields.cpp:212
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
void remove(int fieldIdx)
Removes the field with the given index.
Definition: qgsfields.cpp:101
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
bool isEmpty() const
Checks whether the container is empty.
Definition: qgsfields.cpp:128
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
The QgsFileWidget class creates a widget for selecting a file or a folder.
Definition: qgsfilewidget.h:39
@ GetFile
Select a single file.
Definition: qgsfilewidget.h:68
@ GetDirectory
Select a directory.
Definition: qgsfilewidget.h:69
void fileChanged(const QString &path)
Emitted whenever the current file or directory path is changed.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
Q_GADGET bool isNull
Definition: qgsgeometry.h:127
QString asWkt(int precision=17) const
Exports the geometry to WKT.
The QgsLayoutComboBox class is a combo box which displays available layouts from a QgsLayoutManager.
void layoutChanged(QgsMasterLayoutInterface *layout)
Emitted whenever the currently selected layout changes.
The QgsLayoutItemComboBox class is a combo box which displays items of a matching type from a layout.
void itemChanged(QgsLayoutItem *item)
Emitted whenever the currently selected item changes.
Base class for graphical items within a QgsLayout.
virtual QString uuid() const
Returns the item identification string.
@ FilterPrintLayouts
Includes print layouts.
QList< QgsPrintLayout * > printLayouts() const
Returns a list of all print layouts contained in the manager.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:89
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
The QgsMapLayerComboBox class is a combo box which displays the list of layers.
void layerChanged(QgsMapLayer *layer)
Emitted whenever the currently selected layer changes.
@ AnnotationLayer
QgsAnnotationLayer.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
bool isValid
Definition: qgsmaplayer.h:81
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
QgsPointLocator::Match mapPointMatch() const
Returns the matching data from the most recently snapped point.
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Abstract base class for all map tools.
Definition: qgsmaptool.h:71
virtual void deactivate()
called when map tool is being deactivated
Definition: qgsmaptool.cpp:110
Interface for master layout type objects, such as print layouts and reports.
virtual QString name() const =0
Returns the layout's name.
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
bool clearWidgets()
Removes all items from the bar.
Base class for any widget that can be shown as a inline panel.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
void acceptPanel()
Accept the panel.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
bool dockMode()
Returns the dock mode state.
A class to represent a 2D point.
Definition: qgspointxy.h:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
Print layout, a QgsLayout subclass for static or atlas-based layouts.
Abstract base class for widgets which allow users to specify the properties of a Processing parameter...
Abstract base class for processing algorithms.
An interface for objects which can create Processing contexts.
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
QgsExpressionContext & expressionContext()
Returns the expression context.
QgsMapLayer * takeResultLayer(const QString &id)
Takes the result map layer with matching id from the context and transfers ownership of it back to th...
Base class for all parameter definitions which represent file or layer destinations,...
Encapsulates settings relating to a feature source input to a processing algorithm.
WidgetType
Types of dialogs which Processing widgets can be created for.
@ Modeler
Modeler dialog.
@ Standard
Standard algorithm dialog.
@ Batch
Batch processing dialog.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A raster band parameter for Processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
bool allowMultiple() const
Returns whether multiple band selections are permitted.
A boolean parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A color parameter for processing algorithms.
bool opacityEnabled() const
Returns true if the parameter allows opacity control.
static QString typeName()
Returns the type name for the parameter class.
A coordinate operation parameter for processing algorithms, for selection between available coordinat...
static QString typeName()
Returns the type name for the parameter class.
QVariant sourceCrs() const
Returns the static source CRS, or an invalid value if this is not set.
QVariant destinationCrs() const
Returns the static destination CRS, or an invalid value if this is not set.
A coordinate reference system parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A database schema parameter for processing algorithms, allowing users to select from existing schemas...
static QString typeName()
Returns the type name for the parameter class.
QString parentConnectionParameterName() const
Returns the name of the parent connection parameter, or an empty string if this is not set.
A database table name parameter for processing algorithms, allowing users to select from existing dat...
static QString typeName()
Returns the type name for the parameter class.
QString parentConnectionParameterName() const
Returns the name of the parent connection parameter, or an empty string if this is not set.
QString parentSchemaParameterName() const
Returns the name of the parent schema parameter, or an empty string if this is not set.
bool allowNewTableNames() const
Returns true if the parameter allows users to enter names for a new (non-existing) tables.
A datetime (or pure date or time) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
Type dataType() const
Returns the acceptable data type for the parameter.
Base class for the definition of processing parameters.
QVariantMap metadata() const
Returns the parameter's freeform metadata.
QString description() const
Returns the description for the parameter.
QVariant defaultValueForGui() const
Returns the default value to use for the parameter in a GUI.
virtual QString type() const =0
Unique parameter type name.
Flags flags() const
Returns any flags associated with the parameter.
QString name() const
Returns the name of the parameter.
void setFlags(Flags flags)
Sets the flags associated with the parameter.
A double numeric parameter for distance values.
static QString typeName()
Returns the type name for the parameter class.
QgsUnitTypes::DistanceUnit defaultUnit() const
Returns the default distance unit for the parameter.
A double numeric parameter for duration values.
QgsUnitTypes::TemporalUnit defaultUnit() const
Returns the default duration unit for the parameter.
static QString typeName()
Returns the type name for the parameter class.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
bool allowMultiple() const
Returns true if the parameter allows multiple selected values.
QStringList options() const
Returns the list of acceptable options for the parameter.
bool usesStaticStrings() const
Returns true if the parameter uses static (non-translated) string values for its enumeration choice l...
static QString typeName()
Returns the type name for the parameter class.
An expression parameter for processing algorithms.
QString parentLayerParameterName() const
Returns the name of the parent layer parameter, or an empty string if this is not set.
static QString typeName()
Returns the type name for the parameter class.
A rectangular map extent parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
An input feature source (such as vector layers) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A vector layer or feature source field parameter for processing algorithms.
void setDataType(DataType type)
Sets the acceptable data type for the field.
bool allowMultiple() const
Returns whether multiple field selections are permitted.
bool defaultToAllFields() const
Returns whether a parameter which allows multiple selections (see allowMultiple()) should automatical...
static QString typeName()
Returns the type name for the parameter class.
@ DateTime
Accepts datetime fields.
@ Numeric
Accepts numeric fields.
DataType dataType() const
Returns the acceptable data type for the field.
static QString typeName()
Returns the type name for the parameter class.
An input file or folder parameter for processing algorithms.
QString extension() const
Returns any specified file extension for the parameter.
static QString typeName()
Returns the type name for the parameter class.
@ File
Parameter is a single file.
Behavior behavior() const
Returns the parameter behavior (e.g.
QString fileFilter() const
Returns the file filter string for file destinations compatible with this parameter.
static QString typeName()
Returns the type name for the parameter class.
A geometry parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A print layout item parameter, allowing users to select a particular item from a print layout.
static QString typeName()
Returns the type name for the parameter class.
int itemType() const
Returns the acceptable item type, or -1 if any item type is allowed.
A print layout parameter, allowing users to select a print layout.
static QString typeName()
Returns the type name for the parameter class.
A map layer parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A map theme parameter for processing algorithms, allowing users to select an existing map theme from ...
static QString typeName()
Returns the type name for the parameter class.
A table (matrix) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A parameter for processing algorithms which accepts multiple map layers.
static QString typeName()
Returns the type name for the parameter class.
A numeric parameter for processing algorithms.
double minimum() const
Returns the minimum value acceptable by the parameter.
double maximum() const
Returns the maximum value acceptable by the parameter.
Type dataType() const
Returns the acceptable data type for the parameter.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A point parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A data provider connection parameter for processing algorithms, allowing users to select from availab...
static QString typeName()
Returns the type name for the parameter class.
QString providerId() const
Returns the ID of the provider associated with the connections.
A numeric range parameter for processing algorithms.
QgsProcessingParameterNumber::Type dataType() const
Returns the acceptable data type for the range.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A raster layer parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A double numeric parameter for map scale values.
static QString typeName()
Returns the type name for the parameter class.
A string parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
bool multiLine() const
Returns true if the parameter allows multiline strings.
static QString typeName()
Returns the type name for the parameter class.
A vector layer (with or without geometry) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
Contains settings which reflect the context in which a Processing parameter widget is shown,...
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
QgsProject * project() const
Returns the project associated with the widget.
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
QgsProcessingModelAlgorithm * model() const
Returns the model which the parameter widget is associated with.
QgsMapLayer * activeLayer() const
Returns the current active layer.
static QList< QgsMapLayer * > parameterAsLayerList(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a list of map layers.
static int parameterAsEnum(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a enum value.
static double parameterAsDouble(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static double value.
static QgsPointXY parameterAsPoint(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Evaluates the parameter with matching definition to a point.
static QgsPrintLayout * parameterAsLayout(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a print layout.
static QTime parameterAsTime(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static time value.
static QgsRectangle parameterAsExtent(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Evaluates the parameter with matching definition to a rectangular extent.
static QString parameterAsEnumString(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static enum string.
static QList< double > parameterAsRange(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a range of values.
static QList< int > parameterAsInts(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a list of integer values.
static QString parameterAsConnectionName(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a connection name string.
static QgsProcessingFeatureSource * parameterAsSource(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a feature source.
static QgsCoordinateReferenceSystem parameterAsPointCrs(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Returns the coordinate reference system associated with an point parameter value.
static QgsLayoutItem * parameterAsLayoutItem(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, QgsPrintLayout *layout)
Evaluates the parameter with matching definition to a print layout item, taken from the specified lay...
static bool parameterAsBool(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static boolean value.
static QColor parameterAsColor(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Returns the color associated with an point parameter value, or an invalid color if the parameter was ...
static QgsVectorLayer * parameterAsVectorLayer(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a vector layer.
static int parameterAsInt(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static integer value.
static QString parameterAsDatabaseTableName(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a database table name.
static QString parameterAsSchema(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a database schema name.
static QgsGeometry parameterAsGeometry(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Evaluates the parameter with matching definition to a geometry.
static QString parameterAsExpression(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to an expression.
static QString parameterAsString(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static string value.
static QgsRasterLayer * parameterAsRasterLayer(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a raster layer.
static QList< int > parameterAsEnums(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to list of enum values.
static QStringList parameterAsEnumStrings(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to list of static enum strings.
static QStringList parameterAsFields(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a list of fields.
static QgsCoordinateReferenceSystem parameterAsExtentCrs(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Returns the coordinate reference system associated with an extent parameter value.
static QDateTime parameterAsDateTime(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static datetime value.
static QDate parameterAsDate(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static date value.
static QVariantList parameterAsMatrix(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a matrix/table of values.
static QgsCoordinateReferenceSystem parameterAsCrs(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a coordinate reference system.
@ Annotation
Annotation layer type, since QGIS 3.22.
static QgsCoordinateReferenceSystem variantToCrs(const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue=QVariant())
Converts a variant value to a coordinate reference system.
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType)
Interprets a string as a map layer within the supplied context.
SourceType
Data source types enum.
Definition: qgsprocessing.h:46
@ TypePlugin
Plugin layers.
Definition: qgsprocessing.h:56
@ TypeVectorLine
Vector line layers.
Definition: qgsprocessing.h:50
@ TypeMapLayer
Any map layer type (raster, vector, mesh, point cloud, annotation or plugin layer)
Definition: qgsprocessing.h:47
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:51
@ TypeFile
Files (i.e. non map layer sources, such as text files)
Definition: qgsprocessing.h:53
@ TypeAnnotation
Annotation layers.
Definition: qgsprocessing.h:58
@ TypePointCloud
Point cloud layers.
Definition: qgsprocessing.h:57
@ TypeMesh
Mesh layers.
Definition: qgsprocessing.h:55
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:54
@ TypeRaster
Raster layers.
Definition: qgsprocessing.h:52
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:49
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:48
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:101
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:467
QgsMapThemeCollection * mapThemeCollection
Definition: qgsproject.h:109
const QgsLayoutManager * layoutManager() const
Returns the project's layout manager, which manages print layouts, atlases and reports within the pro...
void layerRemoved(const QString &layerId)
Emitted after a layer was removed from the registry.
A widget for selecting a projection.
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
@ CrsNotSet
Not set (hidden by default)
A store for object properties.
Definition: qgsproperty.h:232
@ StaticProperty
Static property (QgsStaticProperty)
Definition: qgsproperty.h:239
Type propertyType() const
Returns the property type.
The QgsProviderConnectionComboBox class is a combo box which displays the list of connections registe...
A combobox widget which displays the bands present in a raster layer.
void bandChanged(int band)
Emitted when the currently selected band changes.
static QString displayBandName(QgsRasterDataProvider *provider, int band)
Returns a user-friendly band name for the specified band.
Base class for raster data providers.
virtual int bandCount() const =0
Gets number of bands.
Represents a raster layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
A combobox which lets the user select map scale from predefined list and highlights nearest to curren...
void scaleChanged(double scale)
Emitted when user has finished editing/selecting a new scale.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Class that shows snapping marker on map canvas for the current snapping match.
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
Definition: qgsspinbox.h:43
The QgsTimeEdit class is a QTimeEdit widget with the capability of setting/reading null date/times.
void timeValueChanged(const QTime &time)
Signal emitted whenever the time changes.
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:68
@ DistanceMeters
Meters.
Definition: qgsunittypes.h:69
@ DistanceDegrees
Degrees, for planar geographic CRS distance measurements.
Definition: qgsunittypes.h:75
@ DistanceKilometers
Kilometers.
Definition: qgsunittypes.h:70
@ DistanceMiles
Terrestrial miles.
Definition: qgsunittypes.h:74
@ DistanceUnknownUnit
Unknown distance unit.
Definition: qgsunittypes.h:78
@ DistanceYards
Imperial yards.
Definition: qgsunittypes.h:73
@ DistanceFeet
Imperial feet.
Definition: qgsunittypes.h:71
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
static Q_INVOKABLE QgsUnitTypes::DistanceUnitType unitType(QgsUnitTypes::DistanceUnit unit)
Returns the type for a distance unit.
@ Standard
Unit is a standard measurement unit.
Definition: qgsunittypes.h:87
TemporalUnit
Temporal units.
Definition: qgsunittypes.h:150
@ TemporalWeeks
Weeks.
Definition: qgsunittypes.h:156
@ TemporalMilliseconds
Milliseconds.
Definition: qgsunittypes.h:151
@ TemporalDays
Days.
Definition: qgsunittypes.h:155
@ TemporalDecades
Decades.
Definition: qgsunittypes.h:159
@ TemporalCenturies
Centuries.
Definition: qgsunittypes.h:160
@ TemporalSeconds
Seconds.
Definition: qgsunittypes.h:152
@ TemporalMinutes
Minutes.
Definition: qgsunittypes.h:153
@ TemporalYears
Years.
Definition: qgsunittypes.h:158
@ TemporalHours
Hours.
Definition: qgsunittypes.h:154
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define FALLTHROUGH
Definition: qgis.h:1769
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places.
Definition: qgis.h:1300
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1246
const QgsField & field
Definition: qgsfield.h:463
const QgsCoordinateReferenceSystem & crs
QString proj
Proj coordinate operation description, for Proj >= 6.0 builds only.