QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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() - mDoubleSpinBox->singleStep();
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  return;
2503 
2504  if ( mValue.empty() )
2505  {
2506  mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
2507  }
2508  else
2509  {
2510  QStringList values;
2511  values.reserve( mValue.size() );
2512  if ( mParam->usesStaticStrings() )
2513  {
2514  for ( const QVariant &val : std::as_const( mValue ) )
2515  {
2516  values << val.toString();
2517  }
2518  }
2519  else
2520  {
2521  const QStringList options = mParam->options();
2522  for ( const QVariant &val : std::as_const( mValue ) )
2523  {
2524  const int i = val.toInt();
2525  values << ( options.size() > i ? options.at( i ) : QString() );
2526  }
2527  }
2528 
2529  const QString concatenated = values.join( tr( "," ) );
2530  if ( concatenated.length() < 100 )
2531  mLineEdit->setText( concatenated );
2532  else
2533  mLineEdit->setText( tr( "%n option(s) selected", nullptr, mValue.count() ) );
2534  }
2535 }
2536 
2537 
2538 //
2539 // QgsProcessingEnumCheckboxPanelWidget
2540 //
2541 QgsProcessingEnumCheckboxPanelWidget::QgsProcessingEnumCheckboxPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param, int columns )
2542  : QWidget( parent )
2543  , mParam( param )
2544  , mButtonGroup( new QButtonGroup( this ) )
2545  , mColumns( columns )
2546 {
2547  mButtonGroup->setExclusive( !mParam->allowMultiple() );
2548 
2549  QGridLayout *l = new QGridLayout();
2550  l->setContentsMargins( 0, 0, 0, 0 );
2551 
2552  int rows = static_cast< int >( std::ceil( mParam->options().count() / static_cast< double >( mColumns ) ) );
2553  for ( int i = 0; i < mParam->options().count(); ++i )
2554  {
2555  QAbstractButton *button = nullptr;
2556  if ( mParam->allowMultiple() )
2557  button = new QCheckBox( mParam->options().at( i ) );
2558  else
2559  button = new QRadioButton( mParam->options().at( i ) );
2560 
2561  connect( button, &QAbstractButton::toggled, this, [ = ]
2562  {
2563  if ( !mBlockChangedSignal )
2564  emit changed();
2565  } );
2566 
2567  mButtons.insert( i, button );
2568 
2569  mButtonGroup->addButton( button, i );
2570  l->addWidget( button, i % rows, i / rows );
2571  }
2572  l->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ), 0, mColumns );
2573  setLayout( l );
2574 
2575  if ( mParam->allowMultiple() )
2576  {
2577  setContextMenuPolicy( Qt::CustomContextMenu );
2578  connect( this, &QWidget::customContextMenuRequested, this, &QgsProcessingEnumCheckboxPanelWidget::showPopupMenu );
2579  }
2580 }
2581 
2582 QVariant QgsProcessingEnumCheckboxPanelWidget::value() const
2583 {
2584  if ( mParam->allowMultiple() )
2585  {
2586  QVariantList value;
2587  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2588  {
2589  if ( it.value()->isChecked() )
2590  value.append( mParam->usesStaticStrings() ? mParam->options().at( it.key().toInt() ) : it.key() );
2591  }
2592  return value;
2593  }
2594  else
2595  {
2596  if ( mParam->usesStaticStrings() )
2597  return mButtonGroup->checkedId() >= 0 ? mParam->options().at( mButtonGroup->checkedId() ) : QVariant();
2598  else
2599  return mButtonGroup->checkedId() >= 0 ? mButtonGroup->checkedId() : QVariant();
2600  }
2601 }
2602 
2603 void QgsProcessingEnumCheckboxPanelWidget::setValue( const QVariant &value )
2604 {
2605  mBlockChangedSignal = true;
2606  if ( mParam->allowMultiple() )
2607  {
2608  QVariantList selected;
2609  if ( value.isValid() )
2610  selected = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
2611  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2612  {
2613  QVariant v = mParam->usesStaticStrings() ? mParam->options().at( it.key().toInt() ) : it.key();
2614  it.value()->setChecked( selected.contains( v ) );
2615  }
2616  }
2617  else
2618  {
2619  QVariant v = value;
2620  if ( v.type() == QVariant::List )
2621  v = v.toList().value( 0 );
2622 
2623  v = mParam->usesStaticStrings() ? mParam->options().indexOf( v.toString() ) : v;
2624  if ( mButtons.contains( v ) )
2625  mButtons.value( v )->setChecked( true );
2626  }
2627  mBlockChangedSignal = false;
2628  emit changed();
2629 }
2630 
2631 void QgsProcessingEnumCheckboxPanelWidget::showPopupMenu()
2632 {
2633  QMenu popupMenu;
2634  QAction *selectAllAction = new QAction( tr( "Select All" ), &popupMenu );
2635  connect( selectAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::selectAll );
2636  QAction *clearAllAction = new QAction( tr( "Clear Selection" ), &popupMenu );
2637  connect( clearAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::deselectAll );
2638  popupMenu.addAction( selectAllAction );
2639  popupMenu.addAction( clearAllAction );
2640  popupMenu.exec( QCursor::pos() );
2641 }
2642 
2643 void QgsProcessingEnumCheckboxPanelWidget::selectAll()
2644 {
2645  mBlockChangedSignal = true;
2646  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2647  it.value()->setChecked( true );
2648  mBlockChangedSignal = false;
2649  emit changed();
2650 }
2651 
2652 void QgsProcessingEnumCheckboxPanelWidget::deselectAll()
2653 {
2654  mBlockChangedSignal = true;
2655  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
2656  it.value()->setChecked( false );
2657  mBlockChangedSignal = false;
2658  emit changed();
2659 }
2660 
2661 
2662 //
2663 // QgsProcessingEnumWidgetWrapper
2664 //
2665 
2666 QgsProcessingEnumParameterDefinitionWidget::QgsProcessingEnumParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2667  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2668 {
2669  QVBoxLayout *vlayout = new QVBoxLayout();
2670  vlayout->setContentsMargins( 0, 0, 0, 0 );
2671 
2672  mEnumWidget = new QgsProcessingEnumModelerWidget();
2673  if ( const QgsProcessingParameterEnum *enumParam = dynamic_cast<const QgsProcessingParameterEnum *>( definition ) )
2674  {
2675  mEnumWidget->setAllowMultiple( enumParam->allowMultiple() );
2676  mEnumWidget->setOptions( enumParam->options() );
2677  mEnumWidget->setDefaultOptions( enumParam->defaultValueForGui() );
2678  }
2679  vlayout->addWidget( mEnumWidget );
2680  setLayout( vlayout );
2681 }
2682 
2683 QgsProcessingParameterDefinition *QgsProcessingEnumParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2684 {
2685  auto param = std::make_unique< QgsProcessingParameterEnum >( name, description, mEnumWidget->options(), mEnumWidget->allowMultiple(), mEnumWidget->defaultOptions() );
2686  param->setFlags( flags );
2687  return param.release();
2688 }
2689 
2690 
2691 QgsProcessingEnumWidgetWrapper::QgsProcessingEnumWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2692  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2693 {
2694 
2695 }
2696 
2697 QWidget *QgsProcessingEnumWidgetWrapper::createWidget()
2698 {
2699  const QgsProcessingParameterEnum *expParam = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
2700  switch ( type() )
2701  {
2703  {
2704  // checkbox panel only for use outside in standard gui!
2705  if ( expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "useCheckBoxes" ), false ).toBool() )
2706  {
2707  const int columns = expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "columns" ), 2 ).toInt();
2708  mCheckboxPanel = new QgsProcessingEnumCheckboxPanelWidget( nullptr, expParam, columns );
2709  mCheckboxPanel->setToolTip( parameterDefinition()->toolTip() );
2710  connect( mCheckboxPanel, &QgsProcessingEnumCheckboxPanelWidget::changed, this, [ = ]
2711  {
2712  emit widgetValueHasChanged( this );
2713  } );
2714  return mCheckboxPanel;
2715  }
2716  }
2717  FALLTHROUGH
2720  {
2721  if ( expParam->allowMultiple() )
2722  {
2723  mPanel = new QgsProcessingEnumPanelWidget( nullptr, expParam );
2724  mPanel->setToolTip( parameterDefinition()->toolTip() );
2725  connect( mPanel, &QgsProcessingEnumPanelWidget::changed, this, [ = ]
2726  {
2727  emit widgetValueHasChanged( this );
2728  } );
2729  return mPanel;
2730  }
2731  else
2732  {
2733  mComboBox = new QComboBox();
2734 
2736  mComboBox->addItem( tr( "[Not selected]" ), QVariant() );
2737  const QStringList options = expParam->options();
2738  const QVariantList iconList = expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "icons" ) ).toList();
2739  for ( int i = 0; i < options.count(); ++i )
2740  {
2741  const QIcon icon = iconList.value( i ).value< QIcon >();
2742 
2743  if ( expParam->usesStaticStrings() )
2744  mComboBox->addItem( icon, options.at( i ), options.at( i ) );
2745  else
2746  mComboBox->addItem( icon, options.at( i ), i );
2747  }
2748 
2749  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2750  connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
2751  {
2752  emit widgetValueHasChanged( this );
2753  } );
2754  return mComboBox;
2755  }
2756  }
2757  }
2758  return nullptr;
2759 }
2760 
2761 void QgsProcessingEnumWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2762 {
2763  if ( mComboBox )
2764  {
2765  if ( !value.isValid() )
2766  mComboBox->setCurrentIndex( mComboBox->findData( QVariant() ) );
2767  else
2768  {
2769  const QgsProcessingParameterEnum *enumDef = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
2770  if ( enumDef->usesStaticStrings() )
2771  {
2772  const QString v = QgsProcessingParameters::parameterAsEnumString( parameterDefinition(), value, context );
2773  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
2774  }
2775  else
2776  {
2777  const int v = QgsProcessingParameters::parameterAsEnum( parameterDefinition(), value, context );
2778  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
2779  }
2780  }
2781  }
2782  else if ( mPanel || mCheckboxPanel )
2783  {
2784  QVariantList opts;
2785  if ( value.isValid() )
2786  {
2787  const QgsProcessingParameterEnum *enumDef = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
2788  if ( enumDef->usesStaticStrings() )
2789  {
2790  const QStringList v = QgsProcessingParameters::parameterAsEnumStrings( parameterDefinition(), value, context );
2791  opts.reserve( v.size() );
2792  for ( QString i : v )
2793  opts << i;
2794  }
2795  else
2796  {
2797  const QList< int > v = QgsProcessingParameters::parameterAsEnums( parameterDefinition(), value, context );
2798  opts.reserve( v.size() );
2799  for ( int i : v )
2800  opts << i;
2801  }
2802  }
2803  if ( mPanel )
2804  mPanel->setValue( opts );
2805  else if ( mCheckboxPanel )
2806  mCheckboxPanel->setValue( opts );
2807  }
2808 }
2809 
2810 QVariant QgsProcessingEnumWidgetWrapper::widgetValue() const
2811 {
2812  if ( mComboBox )
2813  return mComboBox->currentData();
2814  else if ( mPanel )
2815  return mPanel->value();
2816  else if ( mCheckboxPanel )
2817  return mCheckboxPanel->value();
2818  else
2819  return QVariant();
2820 }
2821 
2822 QStringList QgsProcessingEnumWidgetWrapper::compatibleParameterTypes() const
2823 {
2824  return QStringList()
2828 }
2829 
2830 QStringList QgsProcessingEnumWidgetWrapper::compatibleOutputTypes() const
2831 {
2832  return QStringList()
2835 }
2836 
2837 QString QgsProcessingEnumWidgetWrapper::modelerExpressionFormatString() const
2838 {
2839  return tr( "selected option index (starting from 0), array of indices, or comma separated string of options (e.g. '1,3')" );
2840 }
2841 
2842 QString QgsProcessingEnumWidgetWrapper::parameterType() const
2843 {
2845 }
2846 
2847 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingEnumWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2848 {
2849  return new QgsProcessingEnumWidgetWrapper( parameter, type );
2850 }
2851 
2852 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingEnumWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2853 {
2854  return new QgsProcessingEnumParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2855 }
2856 
2857 //
2858 // QgsProcessingLayoutWidgetWrapper
2859 //
2860 
2861 QgsProcessingLayoutWidgetWrapper::QgsProcessingLayoutWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2862  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2863 {
2864 
2865 }
2866 
2867 QWidget *QgsProcessingLayoutWidgetWrapper::createWidget()
2868 {
2869  const QgsProcessingParameterLayout *layoutParam = dynamic_cast< const QgsProcessingParameterLayout *>( parameterDefinition() );
2870  switch ( type() )
2871  {
2874  {
2875  // combobox only for use outside modeler!
2876  mComboBox = new QgsLayoutComboBox( nullptr, widgetContext().project() ? widgetContext().project()->layoutManager() : nullptr );
2878  mComboBox->setAllowEmptyLayout( true );
2879  mComboBox->setFilters( QgsLayoutManagerProxyModel::FilterPrintLayouts );
2880 
2881  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2882  connect( mComboBox, &QgsLayoutComboBox::layoutChanged, this, [ = ]( QgsMasterLayoutInterface * )
2883  {
2884  emit widgetValueHasChanged( this );
2885  } );
2886  return mComboBox;
2887  }
2888 
2890  {
2891  mPlainComboBox = new QComboBox();
2892  mPlainComboBox->setEditable( true );
2893  mPlainComboBox->setToolTip( tr( "Name of an existing print layout" ) );
2894  if ( widgetContext().project() )
2895  {
2896  const QList< QgsPrintLayout * > layouts = widgetContext().project()->layoutManager()->printLayouts();
2897  for ( const QgsPrintLayout *layout : layouts )
2898  mPlainComboBox->addItem( layout->name() );
2899  }
2900 
2901  connect( mPlainComboBox, &QComboBox::currentTextChanged, this, [ = ]( const QString & )
2902  {
2903  emit widgetValueHasChanged( this );
2904  } );
2905  return mPlainComboBox;
2906  }
2907  }
2908  return nullptr;
2909 }
2910 
2911 void QgsProcessingLayoutWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2912 {
2913  if ( mComboBox )
2914  {
2915  if ( !value.isValid() )
2916  mComboBox->setCurrentLayout( nullptr );
2917  else
2918  {
2919  if ( QgsPrintLayout *l = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, context ) )
2920  mComboBox->setCurrentLayout( l );
2921  else
2922  mComboBox->setCurrentLayout( nullptr );
2923  }
2924  }
2925  else if ( mPlainComboBox )
2926  {
2927  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2928  mPlainComboBox->setCurrentText( v );
2929  }
2930 }
2931 
2932 QVariant QgsProcessingLayoutWidgetWrapper::widgetValue() const
2933 {
2934  if ( mComboBox )
2935  {
2936  const QgsMasterLayoutInterface *l = mComboBox->currentLayout();
2937  return l ? l->name() : QVariant();
2938  }
2939  else if ( mPlainComboBox )
2940  return mPlainComboBox->currentText().isEmpty() ? QVariant() : mPlainComboBox->currentText();
2941  else
2942  return QVariant();
2943 }
2944 
2945 void QgsProcessingLayoutWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
2946 {
2948  if ( mPlainComboBox && context.project() )
2949  {
2950  const QList< QgsPrintLayout * > layouts = widgetContext().project()->layoutManager()->printLayouts();
2951  for ( const QgsPrintLayout *layout : layouts )
2952  mPlainComboBox->addItem( layout->name() );
2953  }
2954 }
2955 
2956 QStringList QgsProcessingLayoutWidgetWrapper::compatibleParameterTypes() const
2957 {
2958  return QStringList()
2961 }
2962 
2963 QStringList QgsProcessingLayoutWidgetWrapper::compatibleOutputTypes() const
2964 {
2965  return QStringList()
2967 }
2968 
2969 QString QgsProcessingLayoutWidgetWrapper::modelerExpressionFormatString() const
2970 {
2971  return tr( "string representing the name of an existing print layout" );
2972 }
2973 
2974 QString QgsProcessingLayoutWidgetWrapper::parameterType() const
2975 {
2977 }
2978 
2979 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2980 {
2981  return new QgsProcessingLayoutWidgetWrapper( parameter, type );
2982 }
2983 
2984 
2985 
2986 
2987 //
2988 // QgsProcessingLayoutItemWidgetWrapper
2989 //
2990 
2991 
2992 QgsProcessingLayoutItemParameterDefinitionWidget::QgsProcessingLayoutItemParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2993  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2994 {
2995  QVBoxLayout *vlayout = new QVBoxLayout();
2996  vlayout->setContentsMargins( 0, 0, 0, 0 );
2997 
2998  vlayout->addWidget( new QLabel( tr( "Parent layout" ) ) );
2999 
3000  mParentLayoutComboBox = new QComboBox();
3001  QString initialParent;
3002  if ( const QgsProcessingParameterLayoutItem *itemParam = dynamic_cast<const QgsProcessingParameterLayoutItem *>( definition ) )
3003  initialParent = itemParam->parentLayoutParameterName();
3004 
3005  if ( auto *lModel = widgetContext.model() )
3006  {
3007  // populate combo box with other model input choices
3008  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
3009  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
3010  {
3011  if ( const QgsProcessingParameterLayout *definition = dynamic_cast< const QgsProcessingParameterLayout * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
3012  {
3013  mParentLayoutComboBox-> addItem( definition->description(), definition->name() );
3014  if ( !initialParent.isEmpty() && initialParent == definition->name() )
3015  {
3016  mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
3017  }
3018  }
3019  }
3020  }
3021 
3022  if ( mParentLayoutComboBox->count() == 0 && !initialParent.isEmpty() )
3023  {
3024  // if no parent candidates found, we just add the existing one as a placeholder
3025  mParentLayoutComboBox->addItem( initialParent, initialParent );
3026  mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
3027  }
3028 
3029  vlayout->addWidget( mParentLayoutComboBox );
3030  setLayout( vlayout );
3031 }
3032 QgsProcessingParameterDefinition *QgsProcessingLayoutItemParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3033 {
3034  auto param = std::make_unique< QgsProcessingParameterLayoutItem >( name, description, QVariant(), mParentLayoutComboBox->currentData().toString() );
3035  param->setFlags( flags );
3036  return param.release();
3037 }
3038 
3039 
3040 QgsProcessingLayoutItemWidgetWrapper::QgsProcessingLayoutItemWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3041  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3042 {
3043 
3044 }
3045 
3046 QWidget *QgsProcessingLayoutItemWidgetWrapper::createWidget()
3047 {
3048  const QgsProcessingParameterLayoutItem *layoutParam = dynamic_cast< const QgsProcessingParameterLayoutItem *>( parameterDefinition() );
3049  switch ( type() )
3050  {
3053  {
3054  // combobox only for use outside modeler!
3055  mComboBox = new QgsLayoutItemComboBox( nullptr, nullptr );
3057  mComboBox->setAllowEmptyItem( true );
3058  if ( layoutParam->itemType() >= 0 )
3059  mComboBox->setItemType( static_cast< QgsLayoutItemRegistry::ItemType >( layoutParam->itemType() ) );
3060 
3061  mComboBox->setToolTip( parameterDefinition()->toolTip() );
3062  connect( mComboBox, &QgsLayoutItemComboBox::itemChanged, this, [ = ]( QgsLayoutItem * )
3063  {
3064  emit widgetValueHasChanged( this );
3065  } );
3066  return mComboBox;
3067  }
3068 
3070  {
3071  mLineEdit = new QLineEdit();
3072  mLineEdit->setToolTip( tr( "UUID or ID of an existing print layout item" ) );
3073  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
3074  {
3075  emit widgetValueHasChanged( this );
3076  } );
3077  return mLineEdit;
3078  }
3079  }
3080  return nullptr;
3081 }
3082 
3083 void QgsProcessingLayoutItemWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
3084 {
3086  switch ( type() )
3087  {
3090  {
3091  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
3092  {
3093  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterLayoutItem * >( parameterDefinition() )->parentLayoutParameterName() )
3094  {
3095  setLayoutParameterValue( wrapper->parameterValue() );
3097  {
3098  setLayoutParameterValue( wrapper->parameterValue() );
3099  } );
3100  break;
3101  }
3102  }
3103  break;
3104  }
3105 
3107  break;
3108  }
3109 }
3110 
3111 void QgsProcessingLayoutItemWidgetWrapper::setLayoutParameterValue( const QVariant &value )
3112 {
3113  QgsPrintLayout *layout = nullptr;
3114 
3115  // evaluate value to layout
3116  QgsProcessingContext *context = nullptr;
3117  std::unique_ptr< QgsProcessingContext > tmpContext;
3118  if ( mProcessingContextGenerator )
3119  context = mProcessingContextGenerator->processingContext();
3120 
3121  if ( !context )
3122  {
3123  tmpContext = std::make_unique< QgsProcessingContext >();
3124  context = tmpContext.get();
3125  }
3126 
3127  layout = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, *context );
3128  setLayout( layout );
3129 }
3130 
3131 void QgsProcessingLayoutItemWidgetWrapper::setLayout( QgsPrintLayout *layout )
3132 {
3133  if ( mComboBox )
3134  mComboBox->setCurrentLayout( layout );
3135 }
3136 
3137 void QgsProcessingLayoutItemWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3138 {
3139  if ( mComboBox )
3140  {
3141  if ( !value.isValid() )
3142  mComboBox->setItem( nullptr );
3143  else
3144  {
3145  QgsLayoutItem *item = QgsProcessingParameters::parameterAsLayoutItem( parameterDefinition(), value, context, qobject_cast< QgsPrintLayout * >( mComboBox->currentLayout() ) );
3146  mComboBox->setItem( item );
3147  }
3148  }
3149  else if ( mLineEdit )
3150  {
3151  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3152  mLineEdit->setText( v );
3153  }
3154 }
3155 
3156 QVariant QgsProcessingLayoutItemWidgetWrapper::widgetValue() const
3157 {
3158  if ( mComboBox )
3159  {
3160  const QgsLayoutItem *i = mComboBox->currentItem();
3161  return i ? i->uuid() : QVariant();
3162  }
3163  else if ( mLineEdit )
3164  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3165  else
3166  return QVariant();
3167 }
3168 
3169 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleParameterTypes() const
3170 {
3171  return QStringList()
3174 }
3175 
3176 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleOutputTypes() const
3177 {
3178  return QStringList()
3180 }
3181 
3182 QString QgsProcessingLayoutItemWidgetWrapper::modelerExpressionFormatString() const
3183 {
3184  return tr( "string representing the UUID or ID of an existing print layout item" );
3185 }
3186 
3187 QString QgsProcessingLayoutItemWidgetWrapper::parameterType() const
3188 {
3190 }
3191 
3192 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutItemWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3193 {
3194  return new QgsProcessingLayoutItemWidgetWrapper( parameter, type );
3195 }
3196 
3197 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingLayoutItemWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3198 {
3199  return new QgsProcessingLayoutItemParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3200 }
3201 
3202 //
3203 // QgsProcessingPointMapTool
3204 //
3205 
3206 QgsProcessingPointMapTool::QgsProcessingPointMapTool( QgsMapCanvas *canvas )
3207  : QgsMapTool( canvas )
3208 {
3209  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::CapturePoint ) );
3210  mSnapIndicator.reset( new QgsSnapIndicator( canvas ) );
3211 }
3212 
3213 QgsProcessingPointMapTool::~QgsProcessingPointMapTool() = default;
3214 
3215 void QgsProcessingPointMapTool::deactivate()
3216 {
3217  mSnapIndicator->setMatch( QgsPointLocator::Match() );
3219 }
3220 
3221 void QgsProcessingPointMapTool::canvasMoveEvent( QgsMapMouseEvent *e )
3222 {
3223  e->snapPoint();
3224  mSnapIndicator->setMatch( e->mapPointMatch() );
3225 }
3226 
3227 void QgsProcessingPointMapTool::canvasPressEvent( QgsMapMouseEvent *e )
3228 {
3229  if ( e->button() == Qt::LeftButton )
3230  {
3231  QgsPointXY point = e->snapPoint();
3232  emit clicked( point );
3233  emit complete();
3234  }
3235 }
3236 
3237 void QgsProcessingPointMapTool::keyPressEvent( QKeyEvent *e )
3238 {
3239  if ( e->key() == Qt::Key_Escape )
3240  {
3241 
3242  // Override default shortcut management in MapCanvas
3243  e->ignore();
3244  emit complete();
3245  }
3246 }
3247 
3248 
3249 
3250 //
3251 // QgsProcessingPointPanel
3252 //
3253 
3254 QgsProcessingPointPanel::QgsProcessingPointPanel( QWidget *parent )
3255  : QWidget( parent )
3256 {
3257  QHBoxLayout *l = new QHBoxLayout();
3258  l->setContentsMargins( 0, 0, 0, 0 );
3259  mLineEdit = new QgsFilterLineEdit( );
3260  mLineEdit->setShowClearButton( false );
3261  l->addWidget( mLineEdit, 1 );
3262  mButton = new QToolButton();
3263  mButton->setText( QString( QChar( 0x2026 ) ) );
3264  l->addWidget( mButton );
3265  setLayout( l );
3266 
3267  connect( mLineEdit, &QLineEdit::textChanged, this, &QgsProcessingPointPanel::changed );
3268  connect( mButton, &QToolButton::clicked, this, &QgsProcessingPointPanel::selectOnCanvas );
3269  mButton->setVisible( false );
3270 }
3271 
3272 void QgsProcessingPointPanel::setMapCanvas( QgsMapCanvas *canvas )
3273 {
3274  mCanvas = canvas;
3275  mButton->setVisible( true );
3276 
3277  mCrs = canvas->mapSettings().destinationCrs();
3278  mTool = std::make_unique< QgsProcessingPointMapTool >( mCanvas );
3279  connect( mTool.get(), &QgsProcessingPointMapTool::clicked, this, &QgsProcessingPointPanel::updatePoint );
3280  connect( mTool.get(), &QgsProcessingPointMapTool::complete, this, &QgsProcessingPointPanel::pointPicked );
3281 }
3282 
3283 void QgsProcessingPointPanel::setAllowNull( bool allowNull )
3284 {
3285  mLineEdit->setShowClearButton( allowNull );
3286 }
3287 
3288 QVariant QgsProcessingPointPanel::value() const
3289 {
3290  return mLineEdit->showClearButton() && mLineEdit->text().trimmed().isEmpty() ? QVariant() : QVariant( mLineEdit->text() );
3291 }
3292 
3293 void QgsProcessingPointPanel::clear()
3294 {
3295  mLineEdit->clear();
3296 }
3297 
3298 void QgsProcessingPointPanel::setValue( const QgsPointXY &point, const QgsCoordinateReferenceSystem &crs )
3299 {
3300  QString newText = QStringLiteral( "%1,%2" )
3301  .arg( QString::number( point.x(), 'f' ),
3302  QString::number( point.y(), 'f' ) );
3303 
3304  mCrs = crs;
3305  if ( mCrs.isValid() )
3306  {
3307  newText += QStringLiteral( " [%1]" ).arg( mCrs.authid() );
3308  }
3309  mLineEdit->setText( newText );
3310 }
3311 
3312 void QgsProcessingPointPanel::selectOnCanvas()
3313 {
3314  if ( !mCanvas )
3315  return;
3316 
3317  mPrevTool = mCanvas->mapTool();
3318  mCanvas->setMapTool( mTool.get() );
3319 
3320  emit toggleDialogVisibility( false );
3321 }
3322 
3323 void QgsProcessingPointPanel::updatePoint( const QgsPointXY &point )
3324 {
3325  setValue( point, mCanvas->mapSettings().destinationCrs() );
3326 }
3327 
3328 void QgsProcessingPointPanel::pointPicked()
3329 {
3330  if ( !mCanvas )
3331  return;
3332 
3333  mCanvas->setMapTool( mPrevTool );
3334 
3335  emit toggleDialogVisibility( true );
3336 }
3337 
3338 
3339 
3340 //
3341 // QgsProcessingPointWidgetWrapper
3342 //
3343 
3344 QgsProcessingPointParameterDefinitionWidget::QgsProcessingPointParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3345  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3346 {
3347  QVBoxLayout *vlayout = new QVBoxLayout();
3348  vlayout->setContentsMargins( 0, 0, 0, 0 );
3349 
3350  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3351 
3352  mDefaultLineEdit = new QLineEdit();
3353  mDefaultLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
3354  mDefaultLineEdit->setPlaceholderText( tr( "Point as 'x,y'" ) );
3355  if ( const QgsProcessingParameterPoint *pointParam = dynamic_cast<const QgsProcessingParameterPoint *>( definition ) )
3356  {
3357  QgsPointXY point = QgsProcessingParameters::parameterAsPoint( pointParam, pointParam->defaultValueForGui(), context );
3358  mDefaultLineEdit->setText( QStringLiteral( "%1,%2" ).arg( QString::number( point.x(), 'f' ), QString::number( point.y(), 'f' ) ) );
3359  }
3360 
3361  vlayout->addWidget( mDefaultLineEdit );
3362  setLayout( vlayout );
3363 }
3364 
3365 QgsProcessingParameterDefinition *QgsProcessingPointParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3366 {
3367  auto param = std::make_unique< QgsProcessingParameterPoint >( name, description, mDefaultLineEdit->text() );
3368  param->setFlags( flags );
3369  return param.release();
3370 }
3371 
3372 QgsProcessingPointWidgetWrapper::QgsProcessingPointWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3373  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3374 {
3375 
3376 }
3377 
3378 QWidget *QgsProcessingPointWidgetWrapper::createWidget()
3379 {
3380  const QgsProcessingParameterPoint *pointParam = dynamic_cast< const QgsProcessingParameterPoint *>( parameterDefinition() );
3381  switch ( type() )
3382  {
3385  {
3386  mPanel = new QgsProcessingPointPanel( nullptr );
3387  if ( widgetContext().mapCanvas() )
3388  mPanel->setMapCanvas( widgetContext().mapCanvas() );
3389 
3391  mPanel->setAllowNull( true );
3392 
3393  mPanel->setToolTip( parameterDefinition()->toolTip() );
3394 
3395  connect( mPanel, &QgsProcessingPointPanel::changed, this, [ = ]
3396  {
3397  emit widgetValueHasChanged( this );
3398  } );
3399 
3400  if ( mDialog )
3401  setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
3402  return mPanel;
3403  }
3404 
3406  {
3407  mLineEdit = new QLineEdit();
3408  mLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
3409  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
3410  {
3411  emit widgetValueHasChanged( this );
3412  } );
3413  return mLineEdit;
3414  }
3415  }
3416  return nullptr;
3417 }
3418 
3419 void QgsProcessingPointWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
3420 {
3422  if ( mPanel && context.mapCanvas() )
3423  mPanel->setMapCanvas( context.mapCanvas() );
3424 }
3425 
3426 void QgsProcessingPointWidgetWrapper::setDialog( QDialog *dialog )
3427 {
3428  mDialog = dialog;
3429  if ( mPanel )
3430  {
3431  connect( mPanel, &QgsProcessingPointPanel::toggleDialogVisibility, mDialog, [ = ]( bool visible )
3432  {
3433  if ( !visible )
3434  mDialog->showMinimized();
3435  else
3436  {
3437  mDialog->showNormal();
3438  mDialog->raise();
3439  mDialog->activateWindow();
3440  }
3441  } );
3442  }
3444 }
3445 
3446 void QgsProcessingPointWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3447 {
3448  if ( mPanel )
3449  {
3450  if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
3451  mPanel->clear();
3452  else
3453  {
3454  QgsPointXY p = QgsProcessingParameters::parameterAsPoint( parameterDefinition(), value, context );
3455  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
3456  mPanel->setValue( p, crs );
3457  }
3458  }
3459  else if ( mLineEdit )
3460  {
3461  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3462  mLineEdit->setText( v );
3463  }
3464 }
3465 
3466 QVariant QgsProcessingPointWidgetWrapper::widgetValue() const
3467 {
3468  if ( mPanel )
3469  {
3470  return mPanel->value();
3471  }
3472  else if ( mLineEdit )
3473  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3474  else
3475  return QVariant();
3476 }
3477 
3478 QStringList QgsProcessingPointWidgetWrapper::compatibleParameterTypes() const
3479 {
3480  return QStringList()
3483 }
3484 
3485 QStringList QgsProcessingPointWidgetWrapper::compatibleOutputTypes() const
3486 {
3487  return QStringList()
3489 }
3490 
3491 QString QgsProcessingPointWidgetWrapper::modelerExpressionFormatString() const
3492 {
3493  return tr( "string of the format 'x,y' or a geometry value (centroid is used)" );
3494 }
3495 
3496 QString QgsProcessingPointWidgetWrapper::parameterType() const
3497 {
3499 }
3500 
3501 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3502 {
3503  return new QgsProcessingPointWidgetWrapper( parameter, type );
3504 }
3505 
3506 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3507 {
3508  return new QgsProcessingPointParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3509 }
3510 
3511 
3512 //
3513 // QgsProcessingGeometryWidgetWrapper
3514 //
3515 
3516 
3517 QgsProcessingGeometryParameterDefinitionWidget::QgsProcessingGeometryParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3518  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3519 {
3520  QVBoxLayout *vlayout = new QVBoxLayout();
3521  vlayout->setContentsMargins( 0, 0, 0, 0 );
3522 
3523  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3524 
3525  mDefaultLineEdit = new QLineEdit();
3526  mDefaultLineEdit->setToolTip( tr( "Geometry as WKT" ) );
3527  mDefaultLineEdit->setPlaceholderText( tr( "Geometry as WKT" ) );
3528  if ( const QgsProcessingParameterGeometry *geometryParam = dynamic_cast<const QgsProcessingParameterGeometry *>( definition ) )
3529  {
3530  QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( geometryParam, geometryParam->defaultValueForGui(), context );
3531  if ( !g.isNull() )
3532  mDefaultLineEdit->setText( g.asWkt() );
3533  }
3534 
3535  vlayout->addWidget( mDefaultLineEdit );
3536  setLayout( vlayout );
3537 }
3538 
3539 QgsProcessingParameterDefinition *QgsProcessingGeometryParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3540 {
3541  auto param = std::make_unique< QgsProcessingParameterGeometry >( name, description, mDefaultLineEdit->text() );
3542  param->setFlags( flags );
3543  return param.release();
3544 }
3545 
3546 QgsProcessingGeometryWidgetWrapper::QgsProcessingGeometryWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3547  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3548 {
3549 
3550 }
3551 
3552 QWidget *QgsProcessingGeometryWidgetWrapper::createWidget()
3553 {
3554  switch ( type() )
3555  {
3559  {
3560  mLineEdit = new QLineEdit();
3561  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
3562  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
3563  {
3564  emit widgetValueHasChanged( this );
3565  } );
3566  return mLineEdit;
3567  }
3568  }
3569  return nullptr;
3570 }
3571 
3572 void QgsProcessingGeometryWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3573 {
3574  if ( mLineEdit )
3575  {
3576  QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( parameterDefinition(), value, context );
3577  if ( !g.isNull() )
3578  mLineEdit->setText( g.asWkt() );
3579  else
3580  mLineEdit->clear();
3581  }
3582 }
3583 
3584 QVariant QgsProcessingGeometryWidgetWrapper::widgetValue() const
3585 {
3586  if ( mLineEdit )
3587  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3588  else
3589  return QVariant();
3590 }
3591 
3592 QStringList QgsProcessingGeometryWidgetWrapper::compatibleParameterTypes() const
3593 {
3594  return QStringList()
3599 }
3600 
3601 QStringList QgsProcessingGeometryWidgetWrapper::compatibleOutputTypes() const
3602 {
3603  return QStringList()
3605 }
3606 
3607 QString QgsProcessingGeometryWidgetWrapper::modelerExpressionFormatString() const
3608 {
3609  return tr( "string in the Well-Known-Text format or a geometry value" );
3610 }
3611 
3612 QString QgsProcessingGeometryWidgetWrapper::parameterType() const
3613 {
3615 }
3616 
3617 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingGeometryWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3618 {
3619  return new QgsProcessingGeometryWidgetWrapper( parameter, type );
3620 }
3621 
3622 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingGeometryWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3623 {
3624  return new QgsProcessingGeometryParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3625 }
3626 
3627 
3628 //
3629 // QgsProcessingColorWidgetWrapper
3630 //
3631 
3632 
3633 QgsProcessingColorParameterDefinitionWidget::QgsProcessingColorParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3634  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3635 {
3636  QVBoxLayout *vlayout = new QVBoxLayout();
3637  vlayout->setContentsMargins( 0, 0, 0, 0 );
3638 
3639  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3640 
3641  mDefaultColorButton = new QgsColorButton();
3642  mDefaultColorButton->setShowNull( true );
3643  mAllowOpacity = new QCheckBox( tr( "Allow opacity control" ) );
3644 
3645  if ( const QgsProcessingParameterColor *colorParam = dynamic_cast<const QgsProcessingParameterColor *>( definition ) )
3646  {
3647  const QColor c = QgsProcessingParameters::parameterAsColor( colorParam, colorParam->defaultValueForGui(), context );
3648  if ( !c.isValid() )
3649  mDefaultColorButton->setToNull();
3650  else
3651  mDefaultColorButton->setColor( c );
3652  mAllowOpacity->setChecked( colorParam->opacityEnabled() );
3653  }
3654  else
3655  {
3656  mDefaultColorButton->setToNull();
3657  mAllowOpacity->setChecked( true );
3658  }
3659 
3660  vlayout->addWidget( mDefaultColorButton );
3661  vlayout->addWidget( mAllowOpacity );
3662  setLayout( vlayout );
3663 }
3664 
3665 QgsProcessingParameterDefinition *QgsProcessingColorParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3666 {
3667  auto param = std::make_unique< QgsProcessingParameterColor >( name, description, mDefaultColorButton->color(), mAllowOpacity->isChecked() );
3668  param->setFlags( flags );
3669  return param.release();
3670 }
3671 
3672 QgsProcessingColorWidgetWrapper::QgsProcessingColorWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3673  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3674 {
3675 
3676 }
3677 
3678 QWidget *QgsProcessingColorWidgetWrapper::createWidget()
3679 {
3680  const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor *>( parameterDefinition() );
3681  switch ( type() )
3682  {
3686  {
3687  mColorButton = new QgsColorButton( nullptr );
3688  mColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
3689 
3691  mColorButton->setShowNull( true );
3692 
3693  mColorButton->setAllowOpacity( colorParam->opacityEnabled() );
3694  mColorButton->setToolTip( parameterDefinition()->toolTip() );
3695  mColorButton->setColorDialogTitle( parameterDefinition()->description() );
3696  if ( colorParam->defaultValueForGui().value< QColor >().isValid() )
3697  {
3698  mColorButton->setDefaultColor( colorParam->defaultValueForGui().value< QColor >() );
3699  }
3700 
3701  connect( mColorButton, &QgsColorButton::colorChanged, this, [ = ]
3702  {
3703  emit widgetValueHasChanged( this );
3704  } );
3705 
3706  return mColorButton;
3707  }
3708  }
3709  return nullptr;
3710 }
3711 
3712 void QgsProcessingColorWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3713 {
3714  if ( mColorButton )
3715  {
3716  if ( !value.isValid() ||
3717  ( value.type() == QVariant::String && value.toString().isEmpty() )
3718  || ( value.type() == QVariant::Color && !value.value< QColor >().isValid() ) )
3719  mColorButton->setToNull();
3720  else
3721  {
3722  const QColor c = QgsProcessingParameters::parameterAsColor( parameterDefinition(), value, context );
3723  if ( !c.isValid() && mColorButton->showNull() )
3724  mColorButton->setToNull();
3725  else
3726  mColorButton->setColor( c );
3727  }
3728  }
3729 }
3730 
3731 QVariant QgsProcessingColorWidgetWrapper::widgetValue() const
3732 {
3733  if ( mColorButton )
3734  return mColorButton->isNull() ? QVariant() : mColorButton->color();
3735  else
3736  return QVariant();
3737 }
3738 
3739 QStringList QgsProcessingColorWidgetWrapper::compatibleParameterTypes() const
3740 {
3741  return QStringList()
3744 }
3745 
3746 QStringList QgsProcessingColorWidgetWrapper::compatibleOutputTypes() const
3747 {
3748  return QStringList()
3750 }
3751 
3752 QString QgsProcessingColorWidgetWrapper::modelerExpressionFormatString() const
3753 {
3754  return tr( "color style string, e.g. #ff0000 or 255,0,0" );
3755 }
3756 
3757 QString QgsProcessingColorWidgetWrapper::parameterType() const
3758 {
3760 }
3761 
3762 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingColorWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3763 {
3764  return new QgsProcessingColorWidgetWrapper( parameter, type );
3765 }
3766 
3767 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingColorWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3768 {
3769  return new QgsProcessingColorParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3770 }
3771 
3772 
3773 //
3774 // QgsProcessingCoordinateOperationWidgetWrapper
3775 //
3776 
3777 QgsProcessingCoordinateOperationParameterDefinitionWidget::QgsProcessingCoordinateOperationParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3778  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3779 {
3780  QVBoxLayout *vlayout = new QVBoxLayout();
3781  vlayout->setContentsMargins( 0, 0, 0, 0 );
3782 
3783  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3784 
3785  mDefaultLineEdit = new QLineEdit();
3786  if ( const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
3787  mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( coordParam, coordParam->defaultValueForGui(), context ) );
3788  vlayout->addWidget( mDefaultLineEdit );
3789 
3790  mSourceParamComboBox = new QComboBox();
3791  mDestParamComboBox = new QComboBox();
3792  QString initialSource;
3793  QString initialDest;
3794  QgsCoordinateReferenceSystem sourceCrs;
3796  if ( const QgsProcessingParameterCoordinateOperation *itemParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
3797  {
3798  initialSource = itemParam->sourceCrsParameterName();
3799  initialDest = itemParam->destinationCrsParameterName();
3800  sourceCrs = QgsProcessingUtils::variantToCrs( itemParam->sourceCrs(), context );
3801  destCrs = QgsProcessingUtils::variantToCrs( itemParam->destinationCrs(), context );
3802  }
3803 
3804  mSourceParamComboBox->addItem( QString(), QString() );
3805  mDestParamComboBox->addItem( QString(), QString() );
3806  if ( auto *lModel = widgetContext.model() )
3807  {
3808  // populate combo box with other model input choices
3809  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
3810  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
3811  {
3812  if ( definition && it->parameterName() == definition->name() )
3813  continue;
3814 
3815  // TODO - we should probably filter this list?
3816  mSourceParamComboBox->addItem( it->parameterName(), it->parameterName() );
3817  mDestParamComboBox->addItem( it->parameterName(), it->parameterName() );
3818  if ( !initialSource.isEmpty() && initialSource == it->parameterName() )
3819  {
3820  mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
3821  }
3822  if ( !initialDest.isEmpty() && initialDest == it->parameterName() )
3823  {
3824  mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
3825  }
3826  }
3827  }
3828 
3829  if ( mSourceParamComboBox->count() == 1 && !initialSource.isEmpty() )
3830  {
3831  // if no source candidates found, we just add the existing one as a placeholder
3832  mSourceParamComboBox->addItem( initialSource, initialSource );
3833  mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
3834  }
3835  if ( mDestParamComboBox->count() == 1 && !initialDest.isEmpty() )
3836  {
3837  // if no dest candidates found, we just add the existing one as a placeholder
3838  mDestParamComboBox->addItem( initialDest, initialDest );
3839  mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
3840  }
3841 
3842  vlayout->addWidget( new QLabel( tr( "Source CRS parameter" ) ) );
3843  vlayout->addWidget( mSourceParamComboBox );
3844  vlayout->addWidget( new QLabel( tr( "Destination CRS parameter" ) ) );
3845  vlayout->addWidget( mDestParamComboBox );
3846 
3847  mStaticSourceWidget = new QgsProjectionSelectionWidget();
3848  mStaticSourceWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
3849  mStaticSourceWidget->setCrs( sourceCrs );
3850  mStaticDestWidget = new QgsProjectionSelectionWidget();
3851  mStaticDestWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
3852  mStaticDestWidget->setCrs( destCrs );
3853 
3854  vlayout->addWidget( new QLabel( tr( "Static source CRS" ) ) );
3855  vlayout->addWidget( mStaticSourceWidget );
3856  vlayout->addWidget( new QLabel( tr( "Static destination CRS" ) ) );
3857  vlayout->addWidget( mStaticDestWidget );
3858 
3859  setLayout( vlayout );
3860 }
3861 
3862 QgsProcessingParameterDefinition *QgsProcessingCoordinateOperationParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3863 {
3864  auto param = std::make_unique< QgsProcessingParameterCoordinateOperation >( name, description, mDefaultLineEdit->text(),
3865  mSourceParamComboBox->currentText(),
3866  mDestParamComboBox->currentText(),
3867  mStaticSourceWidget->crs().isValid() ? QVariant::fromValue( mStaticSourceWidget->crs() ) : QVariant(),
3868  mStaticDestWidget->crs().isValid() ? QVariant::fromValue( mStaticDestWidget->crs() ) : QVariant() );
3869  param->setFlags( flags );
3870  return param.release();
3871 }
3872 
3873 QgsProcessingCoordinateOperationWidgetWrapper::QgsProcessingCoordinateOperationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3874  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3875 {
3876 
3877 }
3878 
3879 QWidget *QgsProcessingCoordinateOperationWidgetWrapper::createWidget()
3880 {
3881  const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast< const QgsProcessingParameterCoordinateOperation *>( parameterDefinition() );
3883  mSourceCrs = QgsProcessingUtils::variantToCrs( coordParam->sourceCrs(), c );
3884  mDestCrs = QgsProcessingUtils::variantToCrs( coordParam->destinationCrs(), c );
3885  switch ( type() )
3886  {
3888  {
3889  mOperationWidget = new QgsCoordinateOperationWidget( nullptr );
3890  mOperationWidget->setShowMakeDefault( false );
3891  mOperationWidget->setShowFallbackOption( false );
3892  mOperationWidget->setToolTip( parameterDefinition()->toolTip() );
3893  mOperationWidget->setSourceCrs( mSourceCrs );
3894  mOperationWidget->setDestinationCrs( mDestCrs );
3895  mOperationWidget->setMapCanvas( mCanvas );
3896  if ( !coordParam->defaultValueForGui().toString().isEmpty() )
3897  {
3899  deets.proj = coordParam->defaultValueForGui().toString();
3900  mOperationWidget->setSelectedOperation( deets );
3901  }
3902 
3903  connect( mOperationWidget, &QgsCoordinateOperationWidget::operationChanged, this, [ = ]
3904  {
3905  emit widgetValueHasChanged( this );
3906  } );
3907 
3908  return mOperationWidget;
3909  }
3910 
3913  {
3914  mLineEdit = new QLineEdit();
3915  QHBoxLayout *layout = new QHBoxLayout();
3916  layout->addWidget( mLineEdit, 1 );
3917  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
3918  {
3919  emit widgetValueHasChanged( this );
3920  } );
3921 
3922  QToolButton *button = new QToolButton();
3923  button->setText( QString( QChar( 0x2026 ) ) );
3924  connect( button, &QToolButton::clicked, this, [ = ]
3925  {
3926  QgsDatumTransformDialog dlg( mSourceCrs, mDestCrs, false, false, false, qMakePair( -1, -1 ), button, Qt::WindowFlags(), mLineEdit->text(), mCanvas );
3927  if ( dlg.exec() )
3928  {
3929  mLineEdit->setText( dlg.selectedDatumTransform().proj );
3930  emit widgetValueHasChanged( this );
3931  }
3932  } );
3933  layout->addWidget( button );
3934 
3935  QWidget *w = new QWidget();
3936  layout->setContentsMargins( 0, 0, 0, 0 );
3937  w->setLayout( layout );
3938  return w;
3939  }
3940 
3941  }
3942  return nullptr;
3943 }
3944 
3945 void QgsProcessingCoordinateOperationWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
3946 {
3948  switch ( type() )
3949  {
3952  {
3953  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
3954  {
3955  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterCoordinateOperation * >( parameterDefinition() )->sourceCrsParameterName() )
3956  {
3957  setSourceCrsParameterValue( wrapper->parameterValue() );
3959  {
3960  setSourceCrsParameterValue( wrapper->parameterValue() );
3961  } );
3962  }
3963  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterCoordinateOperation * >( parameterDefinition() )->destinationCrsParameterName() )
3964  {
3965  setDestinationCrsParameterValue( wrapper->parameterValue() );
3967  {
3968  setDestinationCrsParameterValue( wrapper->parameterValue() );
3969  } );
3970  }
3971  }
3972  break;
3973  }
3974 
3976  break;
3977  }
3978 }
3979 
3980 void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
3981 {
3982  mCanvas = context.mapCanvas();
3983  if ( mOperationWidget )
3984  mOperationWidget->setMapCanvas( context.mapCanvas() );
3985 }
3986 
3987 void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
3988 {
3989  if ( mOperationWidget )
3990  {
3991  if ( !value.isValid() ||
3992  ( value.type() == QVariant::String ) )
3993  {
3995  deets.proj = value.toString();
3996  mOperationWidget->setSelectedOperation( deets );
3997  }
3998  }
3999  if ( mLineEdit )
4000  {
4001  if ( !value.isValid() ||
4002  ( value.type() == QVariant::String ) )
4003  {
4004  mLineEdit->setText( value.toString() );
4005  }
4006  }
4007 }
4008 
4009 QVariant QgsProcessingCoordinateOperationWidgetWrapper::widgetValue() const
4010 {
4011  if ( mOperationWidget )
4012  return mOperationWidget->selectedOperation().proj;
4013  else if ( mLineEdit )
4014  return mLineEdit->text();
4015  else
4016  return QVariant();
4017 }
4018 
4019 QStringList QgsProcessingCoordinateOperationWidgetWrapper::compatibleParameterTypes() const
4020 {
4021  return QStringList()
4024 }
4025 
4026 QStringList QgsProcessingCoordinateOperationWidgetWrapper::compatibleOutputTypes() const
4027 {
4028  return QStringList()
4030 }
4031 
4032 QString QgsProcessingCoordinateOperationWidgetWrapper::modelerExpressionFormatString() const
4033 {
4034  return tr( "Proj coordinate operation string, e.g. '+proj=pipeline +step +inv...'" );
4035 }
4036 
4037 void QgsProcessingCoordinateOperationWidgetWrapper::setSourceCrsParameterValue( const QVariant &value )
4038 {
4039  QgsProcessingContext *context = nullptr;
4040  std::unique_ptr< QgsProcessingContext > tmpContext;
4041  if ( mProcessingContextGenerator )
4042  context = mProcessingContextGenerator->processingContext();
4043 
4044  if ( !context )
4045  {
4046  tmpContext = std::make_unique< QgsProcessingContext >();
4047  context = tmpContext.get();
4048  }
4049 
4050  mSourceCrs = QgsProcessingUtils::variantToCrs( value, *context );
4051  if ( mOperationWidget )
4052  {
4053  mOperationWidget->setSourceCrs( mSourceCrs );
4054  mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
4055  }
4056 }
4057 
4058 void QgsProcessingCoordinateOperationWidgetWrapper::setDestinationCrsParameterValue( const QVariant &value )
4059 {
4060  QgsProcessingContext *context = nullptr;
4061  std::unique_ptr< QgsProcessingContext > tmpContext;
4062  if ( mProcessingContextGenerator )
4063  context = mProcessingContextGenerator->processingContext();
4064 
4065  if ( !context )
4066  {
4067  tmpContext = std::make_unique< QgsProcessingContext >();
4068  context = tmpContext.get();
4069  }
4070 
4071  mDestCrs = QgsProcessingUtils::variantToCrs( value, *context );
4072  if ( mOperationWidget )
4073  {
4074  mOperationWidget->setDestinationCrs( mDestCrs );
4075  mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
4076  }
4077 }
4078 
4079 QString QgsProcessingCoordinateOperationWidgetWrapper::parameterType() const
4080 {
4082 }
4083 
4084 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCoordinateOperationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4085 {
4086  return new QgsProcessingCoordinateOperationWidgetWrapper( parameter, type );
4087 }
4088 
4089 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingCoordinateOperationWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4090 {
4091  return new QgsProcessingCoordinateOperationParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4092 }
4093 
4094 
4095 
4096 //
4097 // QgsProcessingFieldPanelWidget
4098 //
4099 
4100 QgsProcessingFieldPanelWidget::QgsProcessingFieldPanelWidget( QWidget *parent, const QgsProcessingParameterField *param )
4101  : QWidget( parent )
4102  , mParam( param )
4103 {
4104  QHBoxLayout *hl = new QHBoxLayout();
4105  hl->setContentsMargins( 0, 0, 0, 0 );
4106 
4107  mLineEdit = new QLineEdit();
4108  mLineEdit->setEnabled( false );
4109  hl->addWidget( mLineEdit, 1 );
4110 
4111  mToolButton = new QToolButton();
4112  mToolButton->setText( QString( QChar( 0x2026 ) ) );
4113  hl->addWidget( mToolButton );
4114 
4115  setLayout( hl );
4116 
4117  if ( mParam )
4118  {
4119  mLineEdit->setText( tr( "%n field(s) selected", nullptr, 0 ) );
4120  }
4121 
4122  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingFieldPanelWidget::showDialog );
4123 }
4124 
4125 void QgsProcessingFieldPanelWidget::setFields( const QgsFields &fields )
4126 {
4127  mFields = fields;
4128 }
4129 
4130 void QgsProcessingFieldPanelWidget::setValue( const QVariant &value )
4131 {
4132  if ( value.isValid() )
4133  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
4134  else
4135  mValue.clear();
4136 
4137  updateSummaryText();
4138  emit changed();
4139 }
4140 
4141 void QgsProcessingFieldPanelWidget::showDialog()
4142 {
4143  QVariantList availableOptions;
4144  QStringList fieldNames;
4145  availableOptions.reserve( mFields.size() );
4146  for ( const QgsField &field : std::as_const( mFields ) )
4147  {
4148  availableOptions << field.name();
4149  }
4150 
4152  if ( panel && panel->dockMode() )
4153  {
4154  QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
4155  widget->setPanelTitle( mParam->description() );
4156 
4157  widget->setValueFormatter( []( const QVariant & v ) -> QString
4158  {
4159  return v.toString();
4160  } );
4161 
4162  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
4163  {
4164  setValue( widget->selectedOptions() );
4165  } );
4166  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
4167  panel->openPanel( widget );
4168  }
4169  else
4170  {
4171  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
4172 
4173  dlg.setValueFormatter( []( const QVariant & v ) -> QString
4174  {
4175  return v.toString();
4176  } );
4177  if ( dlg.exec() )
4178  {
4179  setValue( dlg.selectedOptions() );
4180  }
4181  }
4182 }
4183 
4184 void QgsProcessingFieldPanelWidget::updateSummaryText()
4185 {
4186  if ( !mParam )
4187  return;
4188 
4189  if ( mValue.empty() )
4190  {
4191  mLineEdit->setText( tr( "%n field(s) selected", nullptr, 0 ) );
4192  }
4193  else
4194  {
4195  QStringList values;
4196  values.reserve( mValue.size() );
4197  for ( const QVariant &val : std::as_const( mValue ) )
4198  {
4199  values << val.toString();
4200  }
4201 
4202  const QString concatenated = values.join( tr( "," ) );
4203  if ( concatenated.length() < 100 )
4204  mLineEdit->setText( concatenated );
4205  else
4206  mLineEdit->setText( tr( "%n field(s) selected", nullptr, mValue.count() ) );
4207  }
4208 }
4209 
4210 
4211 //
4212 // QgsProcessingFieldWidgetWrapper
4213 //
4214 
4215 QgsProcessingFieldParameterDefinitionWidget::QgsProcessingFieldParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4216  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4217 {
4218  QVBoxLayout *vlayout = new QVBoxLayout();
4219  vlayout->setContentsMargins( 0, 0, 0, 0 );
4220 
4221  vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
4222  mParentLayerComboBox = new QComboBox();
4223 
4224  QString initialParent;
4225  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4226  initialParent = fieldParam->parentLayerParameterName();
4227 
4228  if ( auto *lModel = widgetContext.model() )
4229  {
4230  // populate combo box with other model input choices
4231  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
4232  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
4233  {
4234  if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast< const QgsProcessingParameterFeatureSource * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
4235  {
4236  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
4237  if ( !initialParent.isEmpty() && initialParent == definition->name() )
4238  {
4239  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4240  }
4241  }
4242  else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast< const QgsProcessingParameterVectorLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
4243  {
4244  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
4245  if ( !initialParent.isEmpty() && initialParent == definition->name() )
4246  {
4247  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4248  }
4249  }
4250  else if ( const QgsProcessingParameterMultipleLayers *definition = dynamic_cast< const QgsProcessingParameterMultipleLayers * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
4251  {
4252  if ( definition->layerType() == QgsProcessing::TypeVector )
4253  {
4254  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
4255  if ( !initialParent.isEmpty() && initialParent == definition->name() )
4256  {
4257  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4258  }
4259  }
4260  }
4261  }
4262  }
4263 
4264  if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
4265  {
4266  // if no parent candidates found, we just add the existing one as a placeholder
4267  mParentLayerComboBox->addItem( initialParent, initialParent );
4268  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4269  }
4270 
4271  vlayout->addWidget( mParentLayerComboBox );
4272 
4273  vlayout->addWidget( new QLabel( tr( "Allowed data type" ) ) );
4274  mDataTypeComboBox = new QComboBox();
4275  mDataTypeComboBox->addItem( tr( "Any" ), QgsProcessingParameterField::Any );
4276  mDataTypeComboBox->addItem( tr( "Number" ), QgsProcessingParameterField::Numeric );
4277  mDataTypeComboBox->addItem( tr( "String" ), QgsProcessingParameterField::String );
4278  mDataTypeComboBox->addItem( tr( "Date/time" ), QgsProcessingParameterField::DateTime );
4279  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4280  mDataTypeComboBox->setCurrentIndex( mDataTypeComboBox->findData( fieldParam->dataType() ) );
4281 
4282  vlayout->addWidget( mDataTypeComboBox );
4283 
4284  mAllowMultipleCheckBox = new QCheckBox( tr( "Accept multiple fields" ) );
4285  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4286  mAllowMultipleCheckBox->setChecked( fieldParam->allowMultiple() );
4287 
4288  vlayout->addWidget( mAllowMultipleCheckBox );
4289 
4290  mDefaultToAllCheckBox = new QCheckBox( tr( "Select all fields by default" ) );
4291  mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
4292  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4293  mDefaultToAllCheckBox->setChecked( fieldParam->defaultToAllFields() );
4294 
4295  vlayout->addWidget( mDefaultToAllCheckBox );
4296 
4297  connect( mAllowMultipleCheckBox, &QCheckBox::stateChanged, this, [ = ]
4298  {
4299  mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
4300  } );
4301 
4302  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4303 
4304  mDefaultLineEdit = new QLineEdit();
4305  mDefaultLineEdit->setToolTip( tr( "Default field name, or ; separated list of field names for multiple field parameters" ) );
4306  if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4307  {
4308  const QStringList fields = QgsProcessingParameters::parameterAsFields( fieldParam, fieldParam->defaultValueForGui(), context );
4309  mDefaultLineEdit->setText( fields.join( ';' ) );
4310  }
4311  vlayout->addWidget( mDefaultLineEdit );
4312 
4313  setLayout( vlayout );
4314 }
4315 
4316 QgsProcessingParameterDefinition *QgsProcessingFieldParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4317 {
4318  QgsProcessingParameterField::DataType dataType = static_cast< QgsProcessingParameterField::DataType >( mDataTypeComboBox->currentData().toInt() );
4319 
4320  QVariant defaultValue;
4321  if ( !mDefaultLineEdit->text().trimmed().isEmpty() )
4322  {
4323  defaultValue = mDefaultLineEdit->text();
4324  }
4325  auto param = std::make_unique< QgsProcessingParameterField >( name, description, defaultValue, mParentLayerComboBox->currentData().toString(), dataType, mAllowMultipleCheckBox->isChecked(), false, mDefaultToAllCheckBox->isChecked() );
4326  param->setFlags( flags );
4327  return param.release();
4328 }
4329 
4330 QgsProcessingFieldWidgetWrapper::QgsProcessingFieldWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4331  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4332 {
4333 
4334 }
4335 
4336 QWidget *QgsProcessingFieldWidgetWrapper::createWidget()
4337 {
4338  const QgsProcessingParameterField *fieldParam = dynamic_cast< const QgsProcessingParameterField *>( parameterDefinition() );
4339  switch ( type() )
4340  {
4343  {
4344  if ( fieldParam->allowMultiple() )
4345  {
4346  mPanel = new QgsProcessingFieldPanelWidget( nullptr, fieldParam );
4347  mPanel->setToolTip( parameterDefinition()->toolTip() );
4348  connect( mPanel, &QgsProcessingFieldPanelWidget::changed, this, [ = ]
4349  {
4350  emit widgetValueHasChanged( this );
4351  } );
4352  return mPanel;
4353  }
4354  else
4355  {
4356  mComboBox = new QgsFieldComboBox();
4357  mComboBox->setAllowEmptyFieldName( fieldParam->flags() & QgsProcessingParameterDefinition::FlagOptional );
4358 
4359  if ( fieldParam->dataType() == QgsProcessingParameterField::Numeric )
4360  mComboBox->setFilters( QgsFieldProxyModel::Numeric );
4361  else if ( fieldParam->dataType() == QgsProcessingParameterField::String )
4362  mComboBox->setFilters( QgsFieldProxyModel::String );
4363  else if ( fieldParam->dataType() == QgsProcessingParameterField::DateTime )
4365 
4366  mComboBox->setToolTip( parameterDefinition()->toolTip() );
4367  connect( mComboBox, &QgsFieldComboBox::fieldChanged, this, [ = ]( const QString & )
4368  {
4369  emit widgetValueHasChanged( this );
4370  } );
4371  return mComboBox;
4372  }
4373  }
4374 
4376  {
4377  mLineEdit = new QLineEdit();
4378  mLineEdit->setToolTip( QObject::tr( "Name of field (separate field names with ; for multiple field parameters)" ) );
4379  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
4380  {
4381  emit widgetValueHasChanged( this );
4382  } );
4383  return mLineEdit;
4384  }
4385 
4386  }
4387  return nullptr;
4388 }
4389 
4390 void QgsProcessingFieldWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
4391 {
4393  switch ( type() )
4394  {
4397  {
4398  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
4399  {
4400  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterField * >( parameterDefinition() )->parentLayerParameterName() )
4401  {
4402  setParentLayerWrapperValue( wrapper );
4404  {
4405  setParentLayerWrapperValue( wrapper );
4406  } );
4407  break;
4408  }
4409  }
4410  break;
4411  }
4412 
4414  break;
4415  }
4416 }
4417 
4418 void QgsProcessingFieldWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
4419 {
4420  // evaluate value to layer
4421  QgsProcessingContext *context = nullptr;
4422  std::unique_ptr< QgsProcessingContext > tmpContext;
4423  if ( mProcessingContextGenerator )
4424  context = mProcessingContextGenerator->processingContext();
4425 
4426  if ( !context )
4427  {
4428  tmpContext = std::make_unique< QgsProcessingContext >();
4429  context = tmpContext.get();
4430  }
4431 
4432  QVariant value = parentWrapper->parameterValue();
4433 
4434  if ( value.canConvert<QgsProcessingFeatureSourceDefinition>() )
4435  {
4436  // input is a QgsProcessingFeatureSourceDefinition - source from it.
4437  // this is normally discouraged, and algorithms should NEVER do this -- but in this case we can make
4438  // certain assumptions due to the fact that we're calling this outside of algorithm/model execution and all sources
4439  // should be real map layers at this stage
4440  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
4441  value = fromVar.source;
4442  }
4443 
4444  bool valueSet = false;
4445  const QList< QgsMapLayer * > layers = QgsProcessingParameters::parameterAsLayerList( parentWrapper->parameterDefinition(), value, *context );
4446 
4447  // several layers, populate with intersection of layers fields
4448  if ( layers.count() > 1 )
4449  {
4450  QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layers.at( 0 ) );
4451  QgsFields fields = vlayer && vlayer->isValid() ? vlayer->fields() : QgsFields();
4452  const QList< QgsMapLayer * > remainingLayers = layers.mid( 1 );
4453  for ( QgsMapLayer *layer : remainingLayers )
4454  {
4455  if ( fields.isEmpty() )
4456  break;
4457 
4458  QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layer );
4459  if ( !vlayer || !vlayer->isValid() )
4460  {
4461  fields = QgsFields();
4462  break;
4463  }
4464 
4465  for ( int fieldIdx = fields.count() - 1; fieldIdx >= 0; fieldIdx-- )
4466  {
4467  if ( vlayer->fields().lookupField( fields.at( fieldIdx ).name() ) < 0 )
4468  fields.remove( fieldIdx );
4469  }
4470  }
4471 
4472  if ( mComboBox )
4473  mComboBox->setFields( fields );
4474  else if ( mPanel )
4475  mPanel->setFields( filterFields( fields ) );
4476 
4477  valueSet = true;
4478  }
4479 
4480  // only one layer
4481  if ( !valueSet && !layers.isEmpty() && layers.at( 0 )->isValid() )
4482  {
4483  QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( layers.at( 0 ) );
4484 
4485  // need to grab ownership of layer if required - otherwise layer may be deleted when context
4486  // goes out of scope
4487  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
4488  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::VectorLayer )
4489  {
4490  mParentLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
4491  layer = mParentLayer.get();
4492  }
4493  else
4494  {
4495  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
4496  }
4497 
4498  if ( mComboBox )
4499  mComboBox->setLayer( layer );
4500  else if ( mPanel )
4501  mPanel->setFields( filterFields( layer->fields() ) );
4502 
4503  valueSet = true;
4504  }
4505 
4506  if ( !valueSet )
4507  {
4508  std::unique_ptr< QgsProcessingFeatureSource > source( QgsProcessingParameters::parameterAsSource( parentWrapper->parameterDefinition(), value, *context ) );
4509  if ( source )
4510  {
4511  const QgsFields fields = source->fields();
4512  if ( mComboBox )
4513  mComboBox->setFields( fields );
4514  else if ( mPanel )
4515  mPanel->setFields( filterFields( fields ) );
4516 
4517  valueSet = true;
4518  }
4519  }
4520 
4521  if ( !valueSet )
4522  {
4523  if ( mComboBox )
4524  mComboBox->setLayer( nullptr );
4525  else if ( mPanel )
4526  mPanel->setFields( QgsFields() );
4527 
4528  if ( value.isValid() && widgetContext().messageBar() )
4529  {
4530  widgetContext().messageBar()->clearWidgets();
4531  widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent field could not be populated" ),
4532  Qgis::MessageLevel::Info );
4533  }
4534  return;
4535  }
4536 
4537  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4538  if ( mPanel && fieldParam->defaultToAllFields() )
4539  {
4540  QVariantList val;
4541  val.reserve( mPanel->fields().size() );
4542  for ( const QgsField &field : mPanel->fields() )
4543  val << field.name();
4544  setWidgetValue( val, *context );
4545  }
4546  else if ( fieldParam->defaultValueForGui().isValid() )
4547  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
4548 }
4549 
4550 void QgsProcessingFieldWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4551 {
4552  if ( mComboBox )
4553  {
4554  if ( !value.isValid() )
4555  mComboBox->setField( QString() );
4556  else
4557  {
4558  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
4559  mComboBox->setField( v );
4560  }
4561  }
4562  else if ( mPanel )
4563  {
4564  QVariantList opts;
4565  if ( value.isValid() )
4566  {
4567  const QStringList v = QgsProcessingParameters::parameterAsFields( parameterDefinition(), value, context );
4568  opts.reserve( v.size() );
4569  for ( const QString &i : v )
4570  opts << i;
4571  }
4572  if ( mPanel )
4573  mPanel->setValue( opts );
4574  }
4575  else if ( mLineEdit )
4576  {
4577  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4578  if ( fieldParam->allowMultiple() )
4579  {
4580  const QStringList v = QgsProcessingParameters::parameterAsFields( parameterDefinition(), value, context );
4581  mLineEdit->setText( v.join( ';' ) );
4582  }
4583  else
4584  {
4585  mLineEdit->setText( QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context ) );
4586  }
4587  }
4588 }
4589 
4590 QVariant QgsProcessingFieldWidgetWrapper::widgetValue() const
4591 {
4592  if ( mComboBox )
4593  return mComboBox->currentField();
4594  else if ( mPanel )
4595  return mPanel->value();
4596  else if ( mLineEdit )
4597  {
4598  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4599  if ( fieldParam->allowMultiple() )
4600  {
4601  return mLineEdit->text().split( ';' );
4602  }
4603  else
4604  return mLineEdit->text();
4605  }
4606  else
4607  return QVariant();
4608 }
4609 
4610 QStringList QgsProcessingFieldWidgetWrapper::compatibleParameterTypes() const
4611 {
4612  return QStringList()
4615 }
4616 
4617 QStringList QgsProcessingFieldWidgetWrapper::compatibleOutputTypes() const
4618 {
4619  return QStringList()
4621 }
4622 
4623 QString QgsProcessingFieldWidgetWrapper::modelerExpressionFormatString() const
4624 {
4625  return tr( "selected field names as an array of names, or semicolon separated string of options (e.g. 'fid;place_name')" );
4626 }
4627 
4628 const QgsVectorLayer *QgsProcessingFieldWidgetWrapper::linkedVectorLayer() const
4629 {
4630  if ( mComboBox && mComboBox->layer() )
4631  return mComboBox->layer();
4632 
4634 }
4635 
4636 QgsFields QgsProcessingFieldWidgetWrapper::filterFields( const QgsFields &fields ) const
4637 {
4638  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4639  QgsFields res;
4640  for ( const QgsField &f : fields )
4641  {
4642  switch ( fieldParam->dataType() )
4643  {
4645  res.append( f );
4646  break;
4647 
4649  if ( f.isNumeric() )
4650  res.append( f );
4651  break;
4652 
4654  if ( f.type() == QVariant::String )
4655  res.append( f );
4656  break;
4657 
4659  if ( f.type() == QVariant::Date || f.type() == QVariant::Time || f.type() == QVariant::DateTime )
4660  res.append( f );
4661  break;
4662  }
4663  }
4664 
4665  return res;
4666 }
4667 
4668 QString QgsProcessingFieldWidgetWrapper::parameterType() const
4669 {
4671 }
4672 
4673 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFieldWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4674 {
4675  return new QgsProcessingFieldWidgetWrapper( parameter, type );
4676 }
4677 
4678 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFieldWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4679 {
4680  return new QgsProcessingFieldParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4681 }
4682 
4683 //
4684 // QgsProcessingMapThemeWidgetWrapper
4685 //
4686 
4687 
4688 QgsProcessingMapThemeParameterDefinitionWidget::QgsProcessingMapThemeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4689  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4690 {
4691  QVBoxLayout *vlayout = new QVBoxLayout();
4692  vlayout->setContentsMargins( 0, 0, 0, 0 );
4693 
4694  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4695 
4696  mDefaultComboBox = new QComboBox();
4697  mDefaultComboBox->addItem( QString(), QVariant( -1 ) );
4698 
4699  const QStringList mapThemes = widgetContext.project() ? widgetContext.project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
4700  for ( const QString &theme : mapThemes )
4701  {
4702  mDefaultComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
4703  }
4704  mDefaultComboBox->setEditable( true );
4705 
4706  if ( const QgsProcessingParameterMapTheme *themeParam = dynamic_cast<const QgsProcessingParameterMapTheme *>( definition ) )
4707  {
4708  if ( themeParam->defaultValueForGui().isValid() )
4709  mDefaultComboBox->setCurrentText( QgsProcessingParameters::parameterAsString( themeParam, themeParam->defaultValueForGui(), context ) );
4710  else
4711  mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
4712  }
4713  else
4714  mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
4715 
4716  vlayout->addWidget( mDefaultComboBox );
4717 
4718  setLayout( vlayout );
4719 }
4720 
4721 QgsProcessingParameterDefinition *QgsProcessingMapThemeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4722 {
4723  QVariant defaultVal;
4724  if ( mDefaultComboBox->currentText().isEmpty() )
4725  defaultVal = QVariant();
4726  else
4727  defaultVal = mDefaultComboBox->currentText();
4728  auto param = std::make_unique< QgsProcessingParameterMapTheme>( name, description, defaultVal );
4729  param->setFlags( flags );
4730  return param.release();
4731 }
4732 
4733 
4734 QgsProcessingMapThemeWidgetWrapper::QgsProcessingMapThemeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4735  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4736 {
4737 
4738 }
4739 
4740 QWidget *QgsProcessingMapThemeWidgetWrapper::createWidget()
4741 {
4742  const QgsProcessingParameterMapTheme *themeParam = dynamic_cast< const QgsProcessingParameterMapTheme *>( parameterDefinition() );
4743 
4744  mComboBox = new QComboBox();
4745 
4747  mComboBox->addItem( tr( "[Not selected]" ), QVariant( -1 ) );
4748 
4749  const QStringList mapThemes = widgetContext().project() ? widgetContext().project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
4750  for ( const QString &theme : mapThemes )
4751  {
4752  mComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
4753  }
4754 
4755  switch ( type() )
4756  {
4759  break;
4760 
4762  mComboBox->setEditable( true );
4763  break;
4764  }
4765 
4766  mComboBox->setToolTip( parameterDefinition()->toolTip() );
4767  connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
4768  {
4769  emit widgetValueHasChanged( this );
4770  } );
4771 
4772  return mComboBox;
4773 }
4774 
4775 void QgsProcessingMapThemeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4776 {
4777  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
4778 
4779  if ( !value.isValid() )
4780  mComboBox->setCurrentIndex( mComboBox->findData( QVariant( -1 ) ) );
4781  else
4782  {
4783  if ( mComboBox->isEditable() && mComboBox->findData( v ) == -1 )
4784  {
4785  const QString prev = mComboBox->currentText();
4786  mComboBox->setCurrentText( v );
4787  if ( prev != v )
4788  emit widgetValueHasChanged( this );
4789  }
4790  else
4791  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
4792  }
4793 }
4794 
4795 QVariant QgsProcessingMapThemeWidgetWrapper::widgetValue() const
4796 {
4797  if ( mComboBox )
4798  return mComboBox->currentData().toInt() == -1 ? QVariant() :
4799  !mComboBox->currentData().isValid() && mComboBox->isEditable() ? mComboBox->currentText().isEmpty() ? QVariant() : QVariant( mComboBox->currentText() )
4800  : mComboBox->currentData();
4801  else
4802  return QVariant();
4803 }
4804 
4805 QStringList QgsProcessingMapThemeWidgetWrapper::compatibleParameterTypes() const
4806 {
4807  return QStringList()
4810 }
4811 
4812 QStringList QgsProcessingMapThemeWidgetWrapper::compatibleOutputTypes() const
4813 {
4814  return QStringList()
4816 }
4817 
4818 QString QgsProcessingMapThemeWidgetWrapper::modelerExpressionFormatString() const
4819 {
4820  return tr( "map theme as a string value (e.g. 'base maps')" );
4821 }
4822 
4823 QString QgsProcessingMapThemeWidgetWrapper::parameterType() const
4824 {
4826 }
4827 
4828 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapThemeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4829 {
4830  return new QgsProcessingMapThemeWidgetWrapper( parameter, type );
4831 }
4832 
4833 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapThemeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4834 {
4835  return new QgsProcessingMapThemeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4836 }
4837 
4838 
4839 
4840 //
4841 // QgsProcessingDateTimeWidgetWrapper
4842 //
4843 
4844 
4845 QgsProcessingDateTimeParameterDefinitionWidget::QgsProcessingDateTimeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4846  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4847 {
4848  QVBoxLayout *vlayout = new QVBoxLayout();
4849  vlayout->setContentsMargins( 0, 0, 0, 0 );
4850 
4851  vlayout->addWidget( new QLabel( tr( "Type" ) ) );
4852 
4853  mTypeComboBox = new QComboBox();
4854  mTypeComboBox->addItem( tr( "Date and Time" ), QgsProcessingParameterDateTime::DateTime );
4855  mTypeComboBox->addItem( tr( "Date" ), QgsProcessingParameterDateTime::Date );
4856  mTypeComboBox->addItem( tr( "Time" ), QgsProcessingParameterDateTime::Time );
4857  if ( const QgsProcessingParameterDateTime *datetimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( definition ) )
4858  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( datetimeParam->dataType() ) );
4859  else
4860  mTypeComboBox->setCurrentIndex( 0 );
4861  vlayout->addWidget( mTypeComboBox );
4862 
4863  setLayout( vlayout );
4864 }
4865 
4866 QgsProcessingParameterDefinition *QgsProcessingDateTimeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4867 {
4868  auto param = std::make_unique< QgsProcessingParameterDateTime >( name, description );
4869  param->setDataType( static_cast< QgsProcessingParameterDateTime::Type >( mTypeComboBox->currentData().toInt() ) );
4870  param->setFlags( flags );
4871  return param.release();
4872 }
4873 
4874 
4875 QgsProcessingDateTimeWidgetWrapper::QgsProcessingDateTimeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4876  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4877 {
4878 
4879 }
4880 
4881 QWidget *QgsProcessingDateTimeWidgetWrapper::createWidget()
4882 {
4883  const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast< const QgsProcessingParameterDateTime *>( parameterDefinition() );
4884 
4885  QgsDateTimeEdit *widget = nullptr;
4886  switch ( dateTimeParam->dataType() )
4887  {
4889  mDateTimeEdit = new QgsDateTimeEdit();
4890  widget = mDateTimeEdit;
4891  break;
4892 
4894  mDateEdit = new QgsDateEdit();
4895  widget = mDateEdit;
4896  break;
4897 
4899  mTimeEdit = new QgsTimeEdit();
4900  widget = mTimeEdit;
4901  break;
4902  }
4903 
4904  if ( dateTimeParam->flags() & QgsProcessingParameterDefinition::FlagOptional )
4905  {
4906  widget->setNullRepresentation( tr( "[Not selected]" ) );
4907  widget->setAllowNull( true );
4908  }
4909  else
4910  {
4911  widget->setAllowNull( false );
4912  }
4913  widget->setToolTip( parameterDefinition()->toolTip() );
4914 
4915  if ( mDateTimeEdit )
4916  {
4917  connect( mDateTimeEdit, &QgsDateTimeEdit::valueChanged, this, [ = ]( const QDateTime & )
4918  {
4919  emit widgetValueHasChanged( this );
4920  } );
4921  }
4922  else if ( mDateEdit )
4923  {
4924  connect( mDateEdit, &QgsDateEdit::dateValueChanged, this, [ = ]( const QDate & )
4925  {
4926  emit widgetValueHasChanged( this );
4927  } );
4928  }
4929  else if ( mTimeEdit )
4930  {
4931  connect( mTimeEdit, &QgsTimeEdit::timeValueChanged, this, [ = ]( const QTime & )
4932  {
4933  emit widgetValueHasChanged( this );
4934  } );
4935  }
4936 
4937  return widget;
4938 }
4939 
4940 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDateTimeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4941 {
4942  return new QgsProcessingDateTimeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4943 }
4944 
4945 void QgsProcessingDateTimeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4946 {
4947  if ( mDateTimeEdit )
4948  {
4949  mDateTimeEdit->setDateTime( QgsProcessingParameters::parameterAsDateTime( parameterDefinition(), value, context ) );
4950  }
4951  else if ( mDateEdit )
4952  {
4953  mDateEdit->setDate( QgsProcessingParameters::parameterAsDate( parameterDefinition(), value, context ) );
4954  }
4955  else if ( mTimeEdit )
4956  {
4957  mTimeEdit->setTime( QgsProcessingParameters::parameterAsTime( parameterDefinition(), value, context ) );
4958  }
4959 }
4960 
4961 QVariant QgsProcessingDateTimeWidgetWrapper::widgetValue() const
4962 {
4963  if ( mDateTimeEdit )
4964  return !mDateTimeEdit->dateTime().isNull() && mDateTimeEdit->dateTime().isValid() ? QVariant( mDateTimeEdit->dateTime() ) : QVariant();
4965  else if ( mDateEdit )
4966  return !mDateEdit->date().isNull() && mDateEdit->date().isValid() ? QVariant( mDateEdit->date() ) : QVariant();
4967  else if ( mTimeEdit )
4968  return !mTimeEdit->time().isNull() && mTimeEdit->time().isValid() ? QVariant( mTimeEdit->time() ) : QVariant();
4969  else
4970  return QVariant();
4971 }
4972 
4973 QStringList QgsProcessingDateTimeWidgetWrapper::compatibleParameterTypes() const
4974 {
4975  return QStringList()
4978 }
4979 
4980 QStringList QgsProcessingDateTimeWidgetWrapper::compatibleOutputTypes() const
4981 {
4982  return QStringList()
4984 }
4985 
4986 QString QgsProcessingDateTimeWidgetWrapper::modelerExpressionFormatString() const
4987 {
4988  const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast< const QgsProcessingParameterDateTime *>( parameterDefinition() );
4989  if ( dateTimeParam )
4990  {
4991  switch ( dateTimeParam->dataType() )
4992  {
4994  return tr( "datetime value, or a ISO string representation of a datetime" );
4995 
4997  return tr( "date value, or a ISO string representation of a date" );
4998 
5000  return tr( "time value, or a ISO string representation of a time" );
5001  }
5002  }
5003  return QString();
5004 }
5005 
5006 QString QgsProcessingDateTimeWidgetWrapper::parameterType() const
5007 {
5009 }
5010 
5011 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDateTimeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5012 {
5013  return new QgsProcessingDateTimeWidgetWrapper( parameter, type );
5014 }
5015 
5016 
5017 
5018 //
5019 // QgsProcessingProviderConnectionWidgetWrapper
5020 //
5021 
5022 QgsProcessingProviderConnectionParameterDefinitionWidget::QgsProcessingProviderConnectionParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5023  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5024 {
5025  const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast< const QgsProcessingParameterProviderConnection *>( definition );
5026 
5027  QVBoxLayout *vlayout = new QVBoxLayout();
5028  vlayout->setContentsMargins( 0, 0, 0, 0 );
5029 
5030  vlayout->addWidget( new QLabel( tr( "Provider" ) ) );
5031  mProviderComboBox = new QComboBox();
5032  mProviderComboBox->addItem( QObject::tr( "Postgres" ), QStringLiteral( "postgres" ) );
5033  mProviderComboBox->addItem( QObject::tr( "GeoPackage" ), QStringLiteral( "ogr" ) );
5034  mProviderComboBox->addItem( QObject::tr( "Spatialite" ), QStringLiteral( "spatialite" ) );
5035 
5036  vlayout->addWidget( mProviderComboBox );
5037 
5038  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5039 
5040  mDefaultEdit = new QLineEdit();
5041  vlayout->addWidget( mDefaultEdit );
5042  setLayout( vlayout );
5043 
5044  if ( connectionParam )
5045  {
5046  mProviderComboBox->setCurrentIndex( mProviderComboBox->findData( connectionParam->providerId() ) );
5047  mDefaultEdit->setText( connectionParam->defaultValueForGui().toString() );
5048  }
5049 }
5050 
5051 QgsProcessingParameterDefinition *QgsProcessingProviderConnectionParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5052 {
5053  QVariant defaultVal;
5054  if ( mDefaultEdit->text().isEmpty() )
5055  defaultVal = QVariant();
5056  else
5057  defaultVal = mDefaultEdit->text();
5058  auto param = std::make_unique< QgsProcessingParameterProviderConnection>( name, description, mProviderComboBox->currentData().toString(), defaultVal );
5059  param->setFlags( flags );
5060  return param.release();
5061 }
5062 
5063 
5064 QgsProcessingProviderConnectionWidgetWrapper::QgsProcessingProviderConnectionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5065  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5066 {
5067 
5068 }
5069 
5070 QWidget *QgsProcessingProviderConnectionWidgetWrapper::createWidget()
5071 {
5072  const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast< const QgsProcessingParameterProviderConnection *>( parameterDefinition() );
5073 
5074  mProviderComboBox = new QgsProviderConnectionComboBox( connectionParam->providerId() );
5075  if ( connectionParam->flags() & QgsProcessingParameterDefinition::FlagOptional )
5076  mProviderComboBox->setAllowEmptyConnection( true );
5077 
5078  switch ( type() )
5079  {
5082  break;
5084  mProviderComboBox->setEditable( true );
5085  break;
5086  }
5087 
5088  mProviderComboBox->setToolTip( parameterDefinition()->toolTip() );
5089  connect( mProviderComboBox, &QgsProviderConnectionComboBox::currentTextChanged, this, [ = ]( const QString & )
5090  {
5091  if ( mBlockSignals )
5092  return;
5093 
5094  emit widgetValueHasChanged( this );
5095  } );
5096 
5097  return mProviderComboBox;
5098 }
5099 
5100 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingProviderConnectionWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5101 {
5102  return new QgsProcessingProviderConnectionParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5103 }
5104 
5105 void QgsProcessingProviderConnectionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5106 {
5107  const QString v = QgsProcessingParameters::parameterAsConnectionName( parameterDefinition(), value, context );
5108 
5109  if ( !value.isValid() )
5110  mProviderComboBox->setCurrentIndex( -1 );
5111  else
5112  {
5113  if ( mProviderComboBox->isEditable() )
5114  {
5115  const QString prev = mProviderComboBox->currentText();
5116  mBlockSignals++;
5117  mProviderComboBox->setConnection( v );
5118  mProviderComboBox->setCurrentText( v );
5119 
5120  mBlockSignals--;
5121  if ( prev != v )
5122  emit widgetValueHasChanged( this );
5123  }
5124  else
5125  mProviderComboBox->setConnection( v );
5126  }
5127 }
5128 
5129 QVariant QgsProcessingProviderConnectionWidgetWrapper::widgetValue() const
5130 {
5131  if ( mProviderComboBox )
5132  if ( mProviderComboBox->isEditable() )
5133  return mProviderComboBox->currentText().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentText() );
5134  else
5135  return mProviderComboBox->currentConnection().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentConnection() );
5136  else
5137  return QVariant();
5138 }
5139 
5140 QStringList QgsProcessingProviderConnectionWidgetWrapper::compatibleParameterTypes() const
5141 {
5142  return QStringList()
5146 }
5147 
5148 QStringList QgsProcessingProviderConnectionWidgetWrapper::compatibleOutputTypes() const
5149 {
5150  return QStringList()
5152 }
5153 
5154 QString QgsProcessingProviderConnectionWidgetWrapper::modelerExpressionFormatString() const
5155 {
5156  return tr( "connection name as a string value" );
5157 }
5158 
5159 QString QgsProcessingProviderConnectionWidgetWrapper::parameterType() const
5160 {
5162 }
5163 
5164 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingProviderConnectionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5165 {
5166  return new QgsProcessingProviderConnectionWidgetWrapper( parameter, type );
5167 }
5168 
5169 
5170 
5171 
5172 //
5173 // QgsProcessingDatabaseSchemaWidgetWrapper
5174 //
5175 
5176 QgsProcessingDatabaseSchemaParameterDefinitionWidget::QgsProcessingDatabaseSchemaParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5177  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5178 {
5179  const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast< const QgsProcessingParameterDatabaseSchema *>( definition );
5180 
5181  QVBoxLayout *vlayout = new QVBoxLayout();
5182  vlayout->setContentsMargins( 0, 0, 0, 0 );
5183 
5184  mConnectionParamComboBox = new QComboBox();
5185  QString initialConnection;
5186  if ( schemaParam )
5187  {
5188  initialConnection = schemaParam->parentConnectionParameterName();
5189  }
5190 
5191  if ( auto *lModel = widgetContext.model() )
5192  {
5193  // populate combo box with other model input choices
5194  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5195  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5196  {
5197  if ( definition && it->parameterName() == definition->name() )
5198  continue;
5199 
5200  if ( !dynamic_cast< const QgsProcessingParameterProviderConnection * >( lModel->parameterDefinition( it->parameterName() ) ) )
5201  continue;
5202 
5203  mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5204  if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5205  {
5206  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5207  }
5208  }
5209  }
5210 
5211  if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5212  {
5213  // if no candidates found, we just add the existing one as a placeholder
5214  mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5215  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5216  }
5217 
5218  vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
5219  vlayout->addWidget( mConnectionParamComboBox );
5220 
5221  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5222 
5223  mDefaultEdit = new QLineEdit();
5224  vlayout->addWidget( mDefaultEdit );
5225  setLayout( vlayout );
5226 
5227  if ( schemaParam )
5228  {
5229  mDefaultEdit->setText( schemaParam->defaultValueForGui().toString() );
5230  }
5231 }
5232 
5233 QgsProcessingParameterDefinition *QgsProcessingDatabaseSchemaParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5234 {
5235  QVariant defaultVal;
5236  if ( mDefaultEdit->text().isEmpty() )
5237  defaultVal = QVariant();
5238  else
5239  defaultVal = mDefaultEdit->text();
5240  auto param = std::make_unique< QgsProcessingParameterDatabaseSchema>( name, description, mConnectionParamComboBox->currentData().toString(), defaultVal );
5241  param->setFlags( flags );
5242  return param.release();
5243 }
5244 
5245 
5246 QgsProcessingDatabaseSchemaWidgetWrapper::QgsProcessingDatabaseSchemaWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5247  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5248 {
5249 
5250 }
5251 
5252 QWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createWidget()
5253 {
5254  const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast< const QgsProcessingParameterDatabaseSchema *>( parameterDefinition() );
5255 
5256  mSchemaComboBox = new QgsDatabaseSchemaComboBox( QString(), QString() );
5258  mSchemaComboBox->setAllowEmptySchema( true );
5259 
5260  switch ( type() )
5261  {
5264  break;
5266  mSchemaComboBox->comboBox()->setEditable( true );
5267  break;
5268  }
5269 
5270  mSchemaComboBox->setToolTip( parameterDefinition()->toolTip() );
5271  connect( mSchemaComboBox->comboBox(), &QComboBox::currentTextChanged, this, [ = ]( const QString & )
5272  {
5273  if ( mBlockSignals )
5274  return;
5275 
5276  emit widgetValueHasChanged( this );
5277  } );
5278 
5279  return mSchemaComboBox;
5280 }
5281 
5282 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5283 {
5284  return new QgsProcessingDatabaseSchemaParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5285 }
5286 
5287 void QgsProcessingDatabaseSchemaWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5288 {
5289  // evaluate value to connection
5290  QgsProcessingContext *context = nullptr;
5291  std::unique_ptr< QgsProcessingContext > tmpContext;
5292  if ( mProcessingContextGenerator )
5293  context = mProcessingContextGenerator->processingContext();
5294 
5295  if ( !context )
5296  {
5297  tmpContext = std::make_unique< QgsProcessingContext >();
5298  context = tmpContext.get();
5299  }
5300 
5301  const QVariant value = parentWrapper->parameterValue();
5302  const QString connection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
5303 
5304  if ( mSchemaComboBox )
5305  mSchemaComboBox->setConnectionName( connection, qgis::down_cast< const QgsProcessingParameterProviderConnection * >( parentWrapper->parameterDefinition() )->providerId() );
5306 
5307  const QgsProcessingParameterDatabaseSchema *schemaParam = qgis::down_cast< const QgsProcessingParameterDatabaseSchema * >( parameterDefinition() );
5308  if ( schemaParam->defaultValueForGui().isValid() )
5309  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5310 }
5311 
5312 void QgsProcessingDatabaseSchemaWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5313 {
5314  const QString v = QgsProcessingParameters::parameterAsSchema( parameterDefinition(), value, context );
5315 
5316  if ( !value.isValid() )
5317  mSchemaComboBox->comboBox()->setCurrentIndex( -1 );
5318  else
5319  {
5320  if ( mSchemaComboBox->comboBox()->isEditable() )
5321  {
5322  const QString prev = mSchemaComboBox->comboBox()->currentText();
5323  mBlockSignals++;
5324  mSchemaComboBox->setSchema( v );
5325  mSchemaComboBox->comboBox()->setCurrentText( v );
5326 
5327  mBlockSignals--;
5328  if ( prev != v )
5329  emit widgetValueHasChanged( this );
5330  }
5331  else
5332  mSchemaComboBox->setSchema( v );
5333  }
5334 }
5335 
5336 QVariant QgsProcessingDatabaseSchemaWidgetWrapper::widgetValue() const
5337 {
5338  if ( mSchemaComboBox )
5339  if ( mSchemaComboBox->comboBox()->isEditable() )
5340  return mSchemaComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->comboBox()->currentText() );
5341  else
5342  return mSchemaComboBox->currentSchema().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->currentSchema() );
5343  else
5344  return QVariant();
5345 }
5346 
5347 QStringList QgsProcessingDatabaseSchemaWidgetWrapper::compatibleParameterTypes() const
5348 {
5349  return QStringList()
5353 }
5354 
5355 QStringList QgsProcessingDatabaseSchemaWidgetWrapper::compatibleOutputTypes() const
5356 {
5357  return QStringList()
5359 }
5360 
5361 QString QgsProcessingDatabaseSchemaWidgetWrapper::modelerExpressionFormatString() const
5362 {
5363  return tr( "database schema name as a string value" );
5364 }
5365 
5366 QString QgsProcessingDatabaseSchemaWidgetWrapper::parameterType() const
5367 {
5369 }
5370 
5371 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseSchemaWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5372 {
5373  return new QgsProcessingDatabaseSchemaWidgetWrapper( parameter, type );
5374 }
5375 
5376 void QgsProcessingDatabaseSchemaWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5377 {
5379  switch ( type() )
5380  {
5383  {
5384  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5385  {
5386  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseSchema * >( parameterDefinition() )->parentConnectionParameterName() )
5387  {
5388  setParentConnectionWrapperValue( wrapper );
5390  {
5391  setParentConnectionWrapperValue( wrapper );
5392  } );
5393  break;
5394  }
5395  }
5396  break;
5397  }
5398 
5400  break;
5401  }
5402 }
5403 
5404 
5405 
5406 //
5407 // QgsProcessingDatabaseTableWidgetWrapper
5408 //
5409 
5410 QgsProcessingDatabaseTableParameterDefinitionWidget::QgsProcessingDatabaseTableParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5411  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5412 {
5413  const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast< const QgsProcessingParameterDatabaseTable *>( definition );
5414 
5415  QVBoxLayout *vlayout = new QVBoxLayout();
5416  vlayout->setContentsMargins( 0, 0, 0, 0 );
5417 
5418  mConnectionParamComboBox = new QComboBox();
5419  mSchemaParamComboBox = new QComboBox();
5420  QString initialConnection;
5421  QString initialSchema;
5422  if ( tableParam )
5423  {
5424  initialConnection = tableParam->parentConnectionParameterName();
5425  initialSchema = tableParam->parentSchemaParameterName();
5426  }
5427 
5428  if ( auto *lModel = widgetContext.model() )
5429  {
5430  // populate combo box with other model input choices
5431  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5432  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5433  {
5434  if ( definition && it->parameterName() == definition->name() )
5435  continue;
5436 
5437  if ( dynamic_cast< const QgsProcessingParameterProviderConnection * >( lModel->parameterDefinition( it->parameterName() ) ) )
5438  {
5439  mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5440  if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5441  {
5442  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5443  }
5444  }
5445  else if ( dynamic_cast< const QgsProcessingParameterDatabaseSchema * >( lModel->parameterDefinition( it->parameterName() ) ) )
5446  {
5447  mSchemaParamComboBox->addItem( it->parameterName(), it->parameterName() );
5448  if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5449  {
5450  mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5451  }
5452  }
5453  }
5454  }
5455 
5456  if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5457  {
5458  // if no candidates found, we just add the existing one as a placeholder
5459  mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5460  mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5461  }
5462 
5463  if ( mSchemaParamComboBox->count() == 0 && !initialSchema.isEmpty() )
5464  {
5465  // if no candidates found, we just add the existing one as a placeholder
5466  mSchemaParamComboBox->addItem( initialSchema, initialSchema );
5467  mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5468  }
5469 
5470  vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
5471  vlayout->addWidget( mConnectionParamComboBox );
5472 
5473  vlayout->addWidget( new QLabel( tr( "Database schema parameter" ) ) );
5474  vlayout->addWidget( mSchemaParamComboBox );
5475 
5476  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5477 
5478  mDefaultEdit = new QLineEdit();
5479  vlayout->addWidget( mDefaultEdit );
5480  setLayout( vlayout );
5481 
5482  if ( tableParam )
5483  {
5484  mDefaultEdit->setText( tableParam->defaultValueForGui().toString() );
5485  }
5486 }
5487 
5488 QgsProcessingParameterDefinition *QgsProcessingDatabaseTableParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5489 {
5490  QVariant defaultVal;
5491  if ( mDefaultEdit->text().isEmpty() )
5492  defaultVal = QVariant();
5493  else
5494  defaultVal = mDefaultEdit->text();
5495  auto param = std::make_unique< QgsProcessingParameterDatabaseTable>( name, description,
5496  mConnectionParamComboBox->currentData().toString(),
5497  mSchemaParamComboBox->currentData().toString(),
5498  defaultVal );
5499  param->setFlags( flags );
5500  return param.release();
5501 }
5502 
5503 
5504 QgsProcessingDatabaseTableWidgetWrapper::QgsProcessingDatabaseTableWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5505  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5506 {
5507 
5508 }
5509 
5510 QWidget *QgsProcessingDatabaseTableWidgetWrapper::createWidget()
5511 {
5512  const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast< const QgsProcessingParameterDatabaseTable *>( parameterDefinition() );
5513 
5514  mTableComboBox = new QgsDatabaseTableComboBox( QString(), QString() );
5516  mTableComboBox->setAllowEmptyTable( true );
5517 
5518  if ( type() == QgsProcessingGui::Modeler || tableParam->allowNewTableNames() )
5519  mTableComboBox->comboBox()->setEditable( true );
5520 
5521  mTableComboBox->setToolTip( parameterDefinition()->toolTip() );
5522  connect( mTableComboBox->comboBox(), &QComboBox::currentTextChanged, this, [ = ]( const QString & )
5523  {
5524  if ( mBlockSignals )
5525  return;
5526 
5527  emit widgetValueHasChanged( this );
5528  } );
5529 
5530  return mTableComboBox;
5531 }
5532 
5533 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseTableWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5534 {
5535  return new QgsProcessingDatabaseTableParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5536 }
5537 
5538 void QgsProcessingDatabaseTableWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5539 {
5540  // evaluate value to connection
5541  QgsProcessingContext *context = nullptr;
5542  std::unique_ptr< QgsProcessingContext > tmpContext;
5543  if ( mProcessingContextGenerator )
5544  context = mProcessingContextGenerator->processingContext();
5545 
5546  if ( !context )
5547  {
5548  tmpContext = std::make_unique< QgsProcessingContext >();
5549  context = tmpContext.get();
5550  }
5551 
5552  QVariant value = parentWrapper->parameterValue();
5553  mConnection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
5554  mProvider = qgis::down_cast< const QgsProcessingParameterProviderConnection * >( parentWrapper->parameterDefinition() )->providerId();
5555  if ( mTableComboBox && !mSchema.isEmpty() )
5556  {
5557  mTableComboBox->setSchema( mSchema );
5558  mTableComboBox->setConnectionName( mConnection, mProvider );
5559 
5560  const QgsProcessingParameterDatabaseTable *tableParam = qgis::down_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() );
5561  if ( tableParam->defaultValueForGui().isValid() )
5562  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5563  }
5564 }
5565 
5566 void QgsProcessingDatabaseTableWidgetWrapper::setParentSchemaWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5567 {
5568  // evaluate value to schema
5569  QgsProcessingContext *context = nullptr;
5570  std::unique_ptr< QgsProcessingContext > tmpContext;
5571  if ( mProcessingContextGenerator )
5572  context = mProcessingContextGenerator->processingContext();
5573 
5574  if ( !context )
5575  {
5576  tmpContext = std::make_unique< QgsProcessingContext >();
5577  context = tmpContext.get();
5578  }
5579 
5580  QVariant value = parentWrapper->parameterValue();
5581  mSchema = value.isValid() ? QgsProcessingParameters::parameterAsSchema( parentWrapper->parameterDefinition(), value, *context ) : QString();
5582 
5583  if ( mTableComboBox && !mSchema.isEmpty() && !mConnection.isEmpty() )
5584  {
5585  mTableComboBox->setSchema( mSchema );
5586  mTableComboBox->setConnectionName( mConnection, mProvider );
5587 
5588  const QgsProcessingParameterDatabaseTable *tableParam = static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() );
5589  if ( tableParam->defaultValueForGui().isValid() )
5590  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5591  }
5592 
5593 }
5594 
5595 void QgsProcessingDatabaseTableWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5596 {
5597  const QString v = QgsProcessingParameters::parameterAsDatabaseTableName( parameterDefinition(), value, context );
5598 
5599  if ( !value.isValid() )
5600  mTableComboBox->comboBox()->setCurrentIndex( -1 );
5601  else
5602  {
5603  if ( mTableComboBox->comboBox()->isEditable() )
5604  {
5605  const QString prev = mTableComboBox->comboBox()->currentText();
5606  mBlockSignals++;
5607  mTableComboBox->setTable( v );
5608  mTableComboBox->comboBox()->setCurrentText( v );
5609 
5610  mBlockSignals--;
5611  if ( prev != v )
5612  emit widgetValueHasChanged( this );
5613  }
5614  else
5615  mTableComboBox->setTable( v );
5616  }
5617 }
5618 
5619 QVariant QgsProcessingDatabaseTableWidgetWrapper::widgetValue() const
5620 {
5621  if ( mTableComboBox )
5622  if ( mTableComboBox->comboBox()->isEditable() )
5623  return mTableComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mTableComboBox->comboBox()->currentText() );
5624  else
5625  return mTableComboBox->currentTable().isEmpty() ? QVariant() : QVariant( mTableComboBox->currentTable() );
5626  else
5627  return QVariant();
5628 }
5629 
5630 QStringList QgsProcessingDatabaseTableWidgetWrapper::compatibleParameterTypes() const
5631 {
5632  return QStringList()
5636 }
5637 
5638 QStringList QgsProcessingDatabaseTableWidgetWrapper::compatibleOutputTypes() const
5639 {
5640  return QStringList()
5642 }
5643 
5644 QString QgsProcessingDatabaseTableWidgetWrapper::modelerExpressionFormatString() const
5645 {
5646  return tr( "database table name as a string value" );
5647 }
5648 
5649 QString QgsProcessingDatabaseTableWidgetWrapper::parameterType() const
5650 {
5652 }
5653 
5654 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseTableWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5655 {
5656  return new QgsProcessingDatabaseTableWidgetWrapper( parameter, type );
5657 }
5658 
5659 void QgsProcessingDatabaseTableWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5660 {
5662  switch ( type() )
5663  {
5666  {
5667  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5668  {
5669  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() )->parentConnectionParameterName() )
5670  {
5671  setParentConnectionWrapperValue( wrapper );
5673  {
5674  setParentConnectionWrapperValue( wrapper );
5675  } );
5676  }
5677  else if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() )->parentSchemaParameterName() )
5678  {
5679  setParentSchemaWrapperValue( wrapper );
5681  {
5682  setParentSchemaWrapperValue( wrapper );
5683  } );
5684  }
5685  }
5686  break;
5687  }
5688 
5690  break;
5691  }
5692 }
5693 
5694 
5695 //
5696 // QgsProcessingExtentWidgetWrapper
5697 //
5698 
5699 QgsProcessingExtentParameterDefinitionWidget::QgsProcessingExtentParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5700  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5701 {
5702  QVBoxLayout *vlayout = new QVBoxLayout();
5703  vlayout->setContentsMargins( 0, 0, 0, 0 );
5704 
5705  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5706 
5707  mDefaultWidget = new QgsExtentWidget();
5708  mDefaultWidget->setNullValueAllowed( true, tr( "Not set" ) );
5709  if ( const QgsProcessingParameterExtent *extentParam = dynamic_cast<const QgsProcessingParameterExtent *>( definition ) )
5710  {
5711  if ( extentParam->defaultValueForGui().isValid() )
5712  {
5713  QgsRectangle rect = QgsProcessingParameters::parameterAsExtent( extentParam, extentParam->defaultValueForGui(), context );
5714  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsExtentCrs( extentParam, extentParam->defaultValueForGui(), context );
5715  mDefaultWidget->setCurrentExtent( rect, crs );
5716  mDefaultWidget->setOutputExtentFromCurrent();
5717  }
5718  else
5719  {
5720  mDefaultWidget->clear();
5721  }
5722  }
5723 
5724  vlayout->addWidget( mDefaultWidget );
5725  setLayout( vlayout );
5726 }
5727 
5728 QgsProcessingParameterDefinition *QgsProcessingExtentParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5729 {
5730  const QString defaultVal = mDefaultWidget->isValid() ? QStringLiteral( "%1,%2,%3,%4%5" ).arg(
5731  QString::number( mDefaultWidget->outputExtent().xMinimum(), 'f', 9 ),
5732  QString::number( mDefaultWidget->outputExtent().xMaximum(), 'f', 9 ),
5733  QString::number( mDefaultWidget->outputExtent().yMinimum(), 'f', 9 ),
5734  QString::number( mDefaultWidget->outputExtent().yMaximum(), 'f', 9 ),
5735  mDefaultWidget->outputCrs().isValid() ? QStringLiteral( " [%1]" ).arg( mDefaultWidget->outputCrs().authid() ) : QString()
5736  ) : QString();
5737  auto param = std::make_unique< QgsProcessingParameterExtent >( name, description, !defaultVal.isEmpty() ? QVariant( defaultVal ) : QVariant() );
5738  param->setFlags( flags );
5739  return param.release();
5740 }
5741 
5742 
5743 
5744 QgsProcessingExtentWidgetWrapper::QgsProcessingExtentWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5745  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5746 {
5747 
5748 }
5749 
5750 QWidget *QgsProcessingExtentWidgetWrapper::createWidget()
5751 {
5752  const QgsProcessingParameterExtent *extentParam = dynamic_cast< const QgsProcessingParameterExtent *>( parameterDefinition() );
5753  switch ( type() )
5754  {
5758  {
5759  mExtentWidget = new QgsExtentWidget( nullptr );
5760  if ( widgetContext().mapCanvas() )
5761  mExtentWidget->setMapCanvas( widgetContext().mapCanvas() );
5762 
5764  mExtentWidget->setNullValueAllowed( true, tr( "Not set" ) );
5765 
5766  mExtentWidget->setToolTip( parameterDefinition()->toolTip() );
5767 
5768  connect( mExtentWidget, &QgsExtentWidget::extentChanged, this, [ = ]
5769  {
5770  emit widgetValueHasChanged( this );
5771  } );
5772 
5773  if ( mDialog && type() != QgsProcessingGui::Modeler )
5774  setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
5775 
5776  return mExtentWidget;
5777  }
5778  }
5779  return nullptr;
5780 }
5781 
5782 void QgsProcessingExtentWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
5783 {
5785  if ( mExtentWidget && context.mapCanvas() && type() != QgsProcessingGui::Modeler )
5786  mExtentWidget->setMapCanvas( context.mapCanvas() );
5787 }
5788 
5789 void QgsProcessingExtentWidgetWrapper::setDialog( QDialog *dialog )
5790 {
5791  mDialog = dialog;
5792  if ( mExtentWidget && mDialog && type() != QgsProcessingGui::Modeler )
5793  {
5794  connect( mExtentWidget, &QgsExtentWidget::toggleDialogVisibility, mDialog, [ = ]( bool visible )
5795  {
5796  if ( !visible )
5797  mDialog->showMinimized();
5798  else
5799  {
5800  mDialog->showNormal();
5801  mDialog->raise();
5802  mDialog->activateWindow();
5803  }
5804  } );
5805  }
5807 }
5808 
5809 void QgsProcessingExtentWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5810 {
5811  if ( mExtentWidget )
5812  {
5813  if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
5814  mExtentWidget->clear();
5815  else
5816  {
5817  QgsRectangle r = QgsProcessingParameters::parameterAsExtent( parameterDefinition(), value, context );
5818  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
5819  mExtentWidget->setCurrentExtent( r, crs );
5820  mExtentWidget->setOutputExtentFromUser( r, crs );
5821  }
5822  }
5823 }
5824 
5825 QVariant QgsProcessingExtentWidgetWrapper::widgetValue() const
5826 {
5827  if ( mExtentWidget )
5828  {
5829  const QString val = mExtentWidget->isValid() ? QStringLiteral( "%1,%2,%3,%4%5" ).arg(
5830  QString::number( mExtentWidget->outputExtent().xMinimum(), 'f', 9 ),
5831  QString::number( mExtentWidget->outputExtent().xMaximum(), 'f', 9 ),
5832  QString::number( mExtentWidget->outputExtent().yMinimum(), 'f', 9 ),
5833  QString::number( mExtentWidget->outputExtent().yMaximum(), 'f', 9 ),
5834  mExtentWidget->outputCrs().isValid() ? QStringLiteral( " [%1]" ).arg( mExtentWidget->outputCrs().authid() ) : QString()
5835  ) : QString();
5836 
5837  return val.isEmpty() ? QVariant() : QVariant( val );
5838  }
5839  else
5840  return QVariant();
5841 }
5842 
5843 QStringList QgsProcessingExtentWidgetWrapper::compatibleParameterTypes() const
5844 {
5845  return QStringList()
5855 }
5856 
5857 QStringList QgsProcessingExtentWidgetWrapper::compatibleOutputTypes() const
5858 {
5859  return QStringList()
5864 }
5865 
5866 QString QgsProcessingExtentWidgetWrapper::modelerExpressionFormatString() const
5867 {
5868  return tr( "string of the format 'x min,x max,y min,y max' or a geometry value (bounding box is used)" );
5869 }
5870 
5871 QString QgsProcessingExtentWidgetWrapper::parameterType() const
5872 {
5874 }
5875 
5876 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExtentWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5877 {
5878  return new QgsProcessingExtentWidgetWrapper( parameter, type );
5879 }
5880 
5881 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingExtentWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5882 {
5883  return new QgsProcessingExtentParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5884 }
5885 
5886 
5887 
5888 //
5889 // QgsProcessingMapLayerWidgetWrapper
5890 //
5891 
5892 QgsProcessingMapLayerParameterDefinitionWidget::QgsProcessingMapLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5893  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5894 {
5895  QVBoxLayout *vlayout = new QVBoxLayout();
5896  vlayout->setContentsMargins( 0, 0, 0, 0 );
5897 
5898  vlayout->addWidget( new QLabel( tr( "Layer type" ) ) );
5899  mLayerTypeComboBox = new QgsCheckableComboBox();
5900  mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), QgsProcessing::TypeMapLayer );
5901  mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), QgsProcessing::TypeVectorPoint );
5902  mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), QgsProcessing::TypeVectorLine );
5903  mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), QgsProcessing::TypeVectorPolygon );
5904  mLayerTypeComboBox->addItem( tr( "Vector (Any Geometry Type)" ), QgsProcessing::TypeVectorAnyGeometry );
5905  mLayerTypeComboBox->addItem( tr( "Raster" ), QgsProcessing::TypeRaster );
5906  mLayerTypeComboBox->addItem( tr( "Mesh" ), QgsProcessing::TypeMesh );
5907  mLayerTypeComboBox->addItem( tr( "Plugin" ), QgsProcessing::TypePlugin );
5908  mLayerTypeComboBox->addItem( tr( "Point Cloud" ), QgsProcessing::TypePointCloud );
5909  mLayerTypeComboBox->addItem( tr( "Annotation" ), QgsProcessing::TypeAnnotation );
5910 
5911  if ( const QgsProcessingParameterMapLayer *layerParam = dynamic_cast<const QgsProcessingParameterMapLayer *>( definition ) )
5912  {
5913  for ( int i : layerParam->dataTypes() )
5914  {
5915  mLayerTypeComboBox->setItemCheckState( mLayerTypeComboBox->findData( i ), Qt::Checked );
5916  }
5917  }
5918 
5919  vlayout->addWidget( mLayerTypeComboBox );
5920 
5921  setLayout( vlayout );
5922 }
5923 
5924 QgsProcessingParameterDefinition *QgsProcessingMapLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5925 {
5926  QList< int > dataTypes;
5927  for ( const QVariant &v : mLayerTypeComboBox->checkedItemsData() )
5928  dataTypes << v.toInt();
5929 
5930  auto param = std::make_unique< QgsProcessingParameterMapLayer >( name, description );
5931  param->setDataTypes( dataTypes );
5932  param->setFlags( flags );
5933  return param.release();
5934 }
5935 
5936 QgsProcessingMapLayerWidgetWrapper::QgsProcessingMapLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5937  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5938 {
5939 
5940 }
5941 
5942 QWidget *QgsProcessingMapLayerWidgetWrapper::createWidget()
5943 {
5944  mComboBox = new QgsProcessingMapLayerComboBox( parameterDefinition(), type() );
5945 
5946  switch ( type() )
5947  {
5950  break;
5952  mComboBox->setEditable( true );
5953  break;
5954  }
5955 
5956  mComboBox->setToolTip( parameterDefinition()->toolTip() );
5957 
5958  connect( mComboBox, &QgsProcessingMapLayerComboBox::valueChanged, this, [ = ]()
5959  {
5960  if ( mBlockSignals )
5961  return;
5962 
5963  emit widgetValueHasChanged( this );
5964  } );
5965 
5966  setWidgetContext( widgetContext() );
5967  return mComboBox;
5968 }
5969 
5970 void QgsProcessingMapLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
5971 {
5973  if ( mComboBox )
5974  {
5975  mComboBox->setWidgetContext( context );
5976 
5977  if ( !( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional ) )
5978  {
5979  // non optional parameter -- if no default value set, default to active layer
5980  if ( !parameterDefinition()->defaultValueForGui().isValid() )
5981  mComboBox->setLayer( context.activeLayer() );
5982  }
5983  }
5984 }
5985 
5986 void QgsProcessingMapLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5987 {
5988  if ( mComboBox )
5989  mComboBox->setValue( value, context );
5990 }
5991 
5992 QVariant QgsProcessingMapLayerWidgetWrapper::widgetValue() const
5993 {
5994  return mComboBox ? mComboBox->value() : QVariant();
5995 }
5996 
5997 QStringList QgsProcessingMapLayerWidgetWrapper::compatibleParameterTypes() const
5998 {
5999  return QStringList()
6008 }
6009 
6010 QStringList QgsProcessingMapLayerWidgetWrapper::compatibleOutputTypes() const
6011 {
6012  return QStringList()
6018 }
6019 
6020 QString QgsProcessingMapLayerWidgetWrapper::modelerExpressionFormatString() const
6021 {
6022  return tr( "path to a map layer" );
6023 }
6024 
6025 QgsProcessingModelChildParameterSource::Source QgsProcessingMapLayerWidgetWrapper::defaultModelSource( const QgsProcessingParameterDefinition * ) const
6026 {
6027  return QgsProcessingModelChildParameterSource::ModelParameter;
6028 }
6029 
6030 QString QgsProcessingMapLayerWidgetWrapper::parameterType() const
6031 {
6033 }
6034 
6035 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6036 {
6037  return new QgsProcessingMapLayerWidgetWrapper( parameter, type );
6038 }
6039 
6040 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6041 {
6042  return new QgsProcessingMapLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6043 }
6044 
6045 
6046 //
6047 // QgsProcessingRasterLayerWidgetWrapper
6048 //
6049 
6050 QgsProcessingRasterLayerWidgetWrapper::QgsProcessingRasterLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6051  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6052 {
6053 
6054 }
6055 
6056 QStringList QgsProcessingRasterLayerWidgetWrapper::compatibleParameterTypes() const
6057 {
6058  return QStringList()
6063 }
6064 
6065 QStringList QgsProcessingRasterLayerWidgetWrapper::compatibleOutputTypes() const
6066 {
6067  return QStringList()
6073 }
6074 
6075 QString QgsProcessingRasterLayerWidgetWrapper::modelerExpressionFormatString() const
6076 {
6077  return tr( "path to a raster layer" );
6078 }
6079 
6080 QString QgsProcessingRasterLayerWidgetWrapper::parameterType() const
6081 {
6083 }
6084 
6085 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6086 {
6087  return new QgsProcessingRasterLayerWidgetWrapper( parameter, type );
6088 }
6089 
6090 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRasterLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6091 {
6092  Q_UNUSED( context );
6093  Q_UNUSED( widgetContext );
6094  Q_UNUSED( definition );
6095  Q_UNUSED( algorithm );
6096 
6097  return nullptr;
6098 }
6099 
6100 
6101 //
6102 // QgsProcessingVectorLayerWidgetWrapper
6103 //
6104 
6105 QgsProcessingVectorLayerParameterDefinitionWidget::QgsProcessingVectorLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6106  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6107 {
6108  QVBoxLayout *vlayout = new QVBoxLayout();
6109  vlayout->setContentsMargins( 0, 0, 0, 0 );
6110 
6111  vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6112  mGeometryTypeComboBox = new QgsCheckableComboBox();
6113  mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), QgsProcessing::TypeVector );
6114  mGeometryTypeComboBox->addItem( tr( "Point" ), QgsProcessing::TypeVectorPoint );
6115  mGeometryTypeComboBox->addItem( tr( "Line" ), QgsProcessing::TypeVectorLine );
6116  mGeometryTypeComboBox->addItem( tr( "Polygon" ), QgsProcessing::TypeVectorPolygon );
6117  mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
6118 
6119  if ( const QgsProcessingParameterVectorLayer *vectorParam = dynamic_cast<const QgsProcessingParameterVectorLayer *>( definition ) )
6120  {
6121  for ( int i : vectorParam->dataTypes() )
6122  {
6123  mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6124  }
6125  }
6126 
6127  vlayout->addWidget( mGeometryTypeComboBox );
6128 
6129  setLayout( vlayout );
6130 }
6131 
6132 QgsProcessingParameterDefinition *QgsProcessingVectorLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6133 {
6134  QList< int > dataTypes;
6135  for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6136  dataTypes << v.toInt();
6137 
6138  auto param = std::make_unique< QgsProcessingParameterVectorLayer >( name, description, dataTypes );
6139  param->setFlags( flags );
6140  return param.release();
6141 }
6142 
6143 
6144 QgsProcessingVectorLayerWidgetWrapper::QgsProcessingVectorLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6145  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6146 {
6147 
6148 }
6149 
6150 QStringList QgsProcessingVectorLayerWidgetWrapper::compatibleParameterTypes() const
6151 {
6152  return QStringList()
6157 }
6158 
6159 QStringList QgsProcessingVectorLayerWidgetWrapper::compatibleOutputTypes() const
6160 {
6161  return QStringList()
6167 }
6168 
6169 QString QgsProcessingVectorLayerWidgetWrapper::modelerExpressionFormatString() const
6170 {
6171  return tr( "path to a vector layer" );
6172 }
6173 
6174 QList<int> QgsProcessingVectorLayerWidgetWrapper::compatibleDataTypes( const QgsProcessingParameterDefinition *parameter ) const
6175 {
6176  if ( const QgsProcessingParameterVectorLayer *param = dynamic_cast< const QgsProcessingParameterVectorLayer *>( parameter ) )
6177  return param->dataTypes();
6178  else
6179  return QList< int >();
6180 }
6181 
6182 QString QgsProcessingVectorLayerWidgetWrapper::parameterType() const
6183 {
6185 }
6186 
6187 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6188 {
6189  return new QgsProcessingVectorLayerWidgetWrapper( parameter, type );
6190 }
6191 
6192 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingVectorLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6193 {
6194  return new QgsProcessingVectorLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6195 }
6196 
6197 
6198 
6199 //
6200 // QgsProcessingFeatureSourceLayerWidgetWrapper
6201 //
6202 
6203 QgsProcessingFeatureSourceParameterDefinitionWidget::QgsProcessingFeatureSourceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6204  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6205 {
6206  QVBoxLayout *vlayout = new QVBoxLayout();
6207  vlayout->setContentsMargins( 0, 0, 0, 0 );
6208 
6209  vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6210  mGeometryTypeComboBox = new QgsCheckableComboBox();
6211  mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), QgsProcessing::TypeVector );
6212  mGeometryTypeComboBox->addItem( tr( "Point" ), QgsProcessing::TypeVectorPoint );
6213  mGeometryTypeComboBox->addItem( tr( "Line" ), QgsProcessing::TypeVectorLine );
6214  mGeometryTypeComboBox->addItem( tr( "Polygon" ), QgsProcessing::TypeVectorPolygon );
6215  mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
6216 
6217  if ( const QgsProcessingParameterFeatureSource *sourceParam = dynamic_cast<const QgsProcessingParameterFeatureSource *>( definition ) )
6218  {
6219  for ( int i : sourceParam->dataTypes() )
6220  {
6221  mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6222  }
6223  }
6224  else
6225  {
6226  mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( QgsProcessing::TypeVectorAnyGeometry ), Qt::Checked );
6227  }
6228 
6229  vlayout->addWidget( mGeometryTypeComboBox );
6230 
6231  setLayout( vlayout );
6232 }
6233 
6234 QgsProcessingParameterDefinition *QgsProcessingFeatureSourceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6235 {
6236  QList< int > dataTypes;
6237  for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6238  dataTypes << v.toInt();
6239 
6240  auto param = std::make_unique< QgsProcessingParameterFeatureSource >( name, description, dataTypes );
6241  param->setFlags( flags );
6242  return param.release();
6243 }
6244 
6245 QgsProcessingFeatureSourceWidgetWrapper::QgsProcessingFeatureSourceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6246  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6247 {
6248 
6249 }
6250 
6251 QStringList QgsProcessingFeatureSourceWidgetWrapper::compatibleParameterTypes() const
6252 {
6253  return QStringList()
6259 }
6260 
6261 QStringList QgsProcessingFeatureSourceWidgetWrapper::compatibleOutputTypes() const
6262 {
6263  return QStringList()
6269 }
6270 
6271 QString QgsProcessingFeatureSourceWidgetWrapper::modelerExpressionFormatString() const
6272 {
6273  return tr( "path to a vector layer" );
6274 }
6275 
6276 QList<int> QgsProcessingFeatureSourceWidgetWrapper::compatibleDataTypes( const QgsProcessingParameterDefinition *parameter ) const
6277 {
6278  if ( const QgsProcessingParameterFeatureSource *param = dynamic_cast< const QgsProcessingParameterFeatureSource *>( parameter ) )
6279  return param->dataTypes();
6280  else
6281  return QList< int >();
6282 }
6283 
6284 QString QgsProcessingFeatureSourceWidgetWrapper::parameterType() const
6285 {
6287 }
6288 
6289 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSourceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6290 {
6291  return new QgsProcessingFeatureSourceWidgetWrapper( parameter, type );
6292 }
6293 
6294 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFeatureSourceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6295 {
6296  return new QgsProcessingFeatureSourceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6297 }
6298 
6299 //
6300 // QgsProcessingMeshLayerWidgetWrapper
6301 //
6302 
6303 QgsProcessingMeshLayerWidgetWrapper::QgsProcessingMeshLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6304  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6305 {
6306 
6307 }
6308 
6309 QStringList QgsProcessingMeshLayerWidgetWrapper::compatibleParameterTypes() const
6310 {
6311  return QStringList()
6316 }
6317 
6318 QStringList QgsProcessingMeshLayerWidgetWrapper::compatibleOutputTypes() const
6319 {
6320  return QStringList()
6322  // TODO << QgsProcessingOutputMeshLayer::typeName()
6326 }
6327 
6328 QString QgsProcessingMeshLayerWidgetWrapper::modelerExpressionFormatString() const
6329 {
6330  return tr( "path to a mesh layer" );
6331 }
6332 
6333 QString QgsProcessingMeshLayerWidgetWrapper::parameterType() const
6334 {
6336 }
6337 
6338 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6339 {
6340  return new QgsProcessingMeshLayerWidgetWrapper( parameter, type );
6341 }
6342 
6343 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMeshLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6344 {
6345  Q_UNUSED( context );
6346  Q_UNUSED( widgetContext );
6347  Q_UNUSED( definition );
6348  Q_UNUSED( algorithm );
6349 
6350  return nullptr;
6351 }
6352 
6353 
6354 
6355 //
6356 // QgsProcessingRasterBandPanelWidget
6357 //
6358 
6359 QgsProcessingRasterBandPanelWidget::QgsProcessingRasterBandPanelWidget( QWidget *parent, const QgsProcessingParameterBand *param )
6360  : QWidget( parent )
6361  , mParam( param )
6362 {
6363  QHBoxLayout *hl = new QHBoxLayout();
6364  hl->setContentsMargins( 0, 0, 0, 0 );
6365 
6366  mLineEdit = new QLineEdit();
6367  mLineEdit->setEnabled( false );
6368  hl->addWidget( mLineEdit, 1 );
6369 
6370  mToolButton = new QToolButton();
6371  mToolButton->setText( QString( QChar( 0x2026 ) ) );
6372  hl->addWidget( mToolButton );
6373 
6374  setLayout( hl );
6375 
6376  if ( mParam )
6377  {
6378  mLineEdit->setText( tr( "%n band(s) selected", nullptr, 0 ) );
6379  }
6380 
6381  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingRasterBandPanelWidget::showDialog );
6382 }
6383 
6384 void QgsProcessingRasterBandPanelWidget::setBands( const QList< int > &bands )
6385 {
6386  mBands = bands;
6387 }
6388 
6389 void QgsProcessingRasterBandPanelWidget::setBandNames( const QHash<int, QString> &names )
6390 {
6391  mBandNames = names;
6392 }
6393 
6394 void QgsProcessingRasterBandPanelWidget::setValue( const QVariant &value )
6395 {
6396  if ( value.isValid() )
6397  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
6398  else
6399  mValue.clear();
6400 
6401  updateSummaryText();
6402  emit changed();
6403 }
6404 
6405 void QgsProcessingRasterBandPanelWidget::showDialog()
6406 {
6407  QVariantList availableOptions;
6408  QStringList fieldNames;
6409  availableOptions.reserve( mBands.size() );
6410  for ( int band : std::as_const( mBands ) )
6411  {
6412  availableOptions << band;
6413  }
6414 
6416  if ( panel && panel->dockMode() )
6417  {
6418  QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
6419  widget->setPanelTitle( mParam->description() );
6420 
6421  widget->setValueFormatter( [this]( const QVariant & v ) -> QString
6422  {
6423  int band = v.toInt();
6424  return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
6425  } );
6426 
6427  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
6428  {
6429  setValue( widget->selectedOptions() );
6430  } );
6431  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
6432  panel->openPanel( widget );
6433  }
6434  else
6435  {
6436  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
6437 
6438  dlg.setValueFormatter( [this]( const QVariant & v ) -> QString
6439  {
6440  int band = v.toInt();
6441  return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
6442  } );
6443  if ( dlg.exec() )
6444  {
6445  setValue( dlg.selectedOptions() );
6446  }
6447  }
6448 }
6449 
6450 void QgsProcessingRasterBandPanelWidget::updateSummaryText()
6451 {
6452  if ( mParam )
6453  mLineEdit->setText( tr( "%n band(s) selected", nullptr, mValue.count() ) );
6454 }
6455 
6456 
6457 
6458 //
6459 // QgsProcessingBandWidgetWrapper
6460 //
6461 
6462 QgsProcessingBandParameterDefinitionWidget::QgsProcessingBandParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6463  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6464 {
6465  QVBoxLayout *vlayout = new QVBoxLayout();
6466  vlayout->setContentsMargins( 0, 0, 0, 0 );
6467 
6468  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
6469 
6470  mDefaultLineEdit = new QLineEdit();
6471  mDefaultLineEdit->setToolTip( tr( "Band number (separate bands with ; for multiple band parameters)" ) );
6472  if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6473  {
6474  const QList< int > bands = QgsProcessingParameters::parameterAsInts( bandParam, bandParam->defaultValueForGui(), context );
6475  QStringList defVal;
6476  for ( int b : bands )
6477  {
6478  defVal << QString::number( b );
6479  }
6480 
6481  mDefaultLineEdit->setText( defVal.join( ';' ) );
6482  }
6483  vlayout->addWidget( mDefaultLineEdit );
6484 
6485  vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
6486  mParentLayerComboBox = new QComboBox();
6487 
6488  QString initialParent;
6489  if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6490  initialParent = bandParam->parentLayerParameterName();
6491 
6492  if ( auto *lModel = widgetContext.model() )
6493  {
6494  // populate combo box with other model input choices
6495  const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
6496  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
6497  {
6498  if ( const QgsProcessingParameterRasterLayer *definition = dynamic_cast< const QgsProcessingParameterRasterLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
6499  {
6500  mParentLayerComboBox-> addItem( definition->description(), definition->name() );
6501  if ( !initialParent.isEmpty() && initialParent == definition->name() )
6502  {
6503  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
6504  }
6505  }
6506  }
6507  }
6508 
6509  if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
6510  {
6511  // if no parent candidates found, we just add the existing one as a placeholder
6512  mParentLayerComboBox->addItem( initialParent, initialParent );
6513  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
6514  }
6515 
6516  vlayout->addWidget( mParentLayerComboBox );
6517 
6518  mAllowMultipleCheckBox = new QCheckBox( tr( "Allow multiple" ) );
6519  if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6520  mAllowMultipleCheckBox->setChecked( bandParam->allowMultiple() );
6521 
6522  vlayout->addWidget( mAllowMultipleCheckBox );
6523  setLayout( vlayout );
6524 }
6525 
6526 QgsProcessingParameterDefinition *QgsProcessingBandParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6527 {
6528  auto param = std::make_unique< QgsProcessingParameterBand >( name, description, mDefaultLineEdit->text().split( ';' ), mParentLayerComboBox->currentData().toString(), false, mAllowMultipleCheckBox->isChecked() );
6529  param->setFlags( flags );
6530  return param.release();
6531 }
6532 
6533 QgsProcessingBandWidgetWrapper::QgsProcessingBandWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6534  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6535 {
6536 
6537 }
6538 
6539 QWidget *QgsProcessingBandWidgetWrapper::createWidget()
6540 {
6541  const QgsProcessingParameterBand *bandParam = dynamic_cast< const QgsProcessingParameterBand *>( parameterDefinition() );
6542  switch ( type() )
6543  {
6546  {
6547  if ( bandParam->allowMultiple() )
6548  {
6549  mPanel = new QgsProcessingRasterBandPanelWidget( nullptr, bandParam );
6550  mPanel->setToolTip( parameterDefinition()->toolTip() );
6551  connect( mPanel, &QgsProcessingRasterBandPanelWidget::changed, this, [ = ]
6552  {
6553  emit widgetValueHasChanged( this );
6554  } );
6555  return mPanel;
6556  }
6557  else
6558  {
6559  mComboBox = new QgsRasterBandComboBox();
6560  mComboBox->setShowNotSetOption( bandParam->flags() & QgsProcessingParameterDefinition::FlagOptional );
6561 
6562  mComboBox->setToolTip( parameterDefinition()->toolTip() );
6563  connect( mComboBox, &QgsRasterBandComboBox::bandChanged, this, [ = ]( int )
6564  {
6565  emit widgetValueHasChanged( this );
6566  } );
6567  return mComboBox;
6568  }
6569  }
6570 
6572  {
6573  mLineEdit = new QLineEdit();
6574  mLineEdit->setToolTip( QObject::tr( "Band number (separate bands with ; for multiple band parameters)" ) );
6575  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
6576  {
6577  emit widgetValueHasChanged( this );
6578  } );
6579  return mLineEdit;
6580  }
6581 
6582  }
6583  return nullptr;
6584 }
6585 
6586 void QgsProcessingBandWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
6587 {
6589  switch ( type() )
6590  {
6593  {
6594  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
6595  {
6596  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterBand * >( parameterDefinition() )->parentLayerParameterName() )
6597  {
6598  setParentLayerWrapperValue( wrapper );
6600  {
6601  setParentLayerWrapperValue( wrapper );
6602  } );
6603  break;
6604  }
6605  }
6606  break;
6607  }
6608 
6610  break;
6611  }
6612 }
6613 
6614 void QgsProcessingBandWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
6615 {
6616  // evaluate value to layer
6617  QgsProcessingContext *context = nullptr;
6618  std::unique_ptr< QgsProcessingContext > tmpContext;
6619  if ( mProcessingContextGenerator )
6620  context = mProcessingContextGenerator->processingContext();
6621 
6622  if ( !context )
6623  {
6624  tmpContext = std::make_unique< QgsProcessingContext >();
6625  context = tmpContext.get();
6626  }
6627 
6628  QVariant value = parentWrapper->parameterValue();
6629 
6630  QgsRasterLayer *layer = QgsProcessingParameters::parameterAsRasterLayer( parentWrapper->parameterDefinition(), value, *context );
6631  if ( layer && layer->isValid() )
6632  {
6633  // need to grab ownership of layer if required - otherwise layer may be deleted when context
6634  // goes out of scope
6635  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
6636  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::RasterLayer )
6637  {
6638  mParentLayer.reset( qobject_cast< QgsRasterLayer * >( ownedLayer.release() ) );
6639  layer = mParentLayer.get();
6640  }
6641  else
6642  {
6643  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
6644  }
6645 
6646  if ( mComboBox )
6647  mComboBox->setLayer( layer );
6648  else if ( mPanel )
6649  {
6650  QgsRasterDataProvider *provider = layer->dataProvider();
6651  if ( provider && layer->isValid() )
6652  {
6653  //fill available bands
6654  int nBands = provider->bandCount();
6655  QList< int > bands;
6656  QHash< int, QString > bandNames;
6657  for ( int i = 1; i <= nBands; ++i )
6658  {
6659  bandNames.insert( i, QgsRasterBandComboBox::displayBandName( provider, i ) );
6660  bands << i;
6661  }
6662  mPanel->setBands( bands );
6663  mPanel->setBandNames( bandNames );
6664  }
6665  }
6666  }
6667  else
6668  {
6669  if ( mComboBox )
6670  mComboBox->setLayer( nullptr );
6671  else if ( mPanel )
6672  mPanel->setBands( QList< int >() );
6673 
6674  if ( value.isValid() && widgetContext().messageBar() )
6675  {
6676  widgetContext().messageBar()->clearWidgets();
6677  widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent bands could not be populated" ),
6678  Qgis::MessageLevel::Info );
6679  }
6680  }
6681 
6682  if ( parameterDefinition()->defaultValueForGui().isValid() )
6683  setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
6684 }
6685 
6686 void QgsProcessingBandWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6687 {
6688  if ( mComboBox )
6689  {
6690  if ( !value.isValid() )
6691  mComboBox->setBand( -1 );
6692  else
6693  {
6694  const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
6695  mComboBox->setBand( v );
6696  }
6697  }
6698  else if ( mPanel )
6699  {
6700  QVariantList opts;
6701  if ( value.isValid() )
6702  {
6703  const QList< int > v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
6704  opts.reserve( v.size() );
6705  for ( int i : v )
6706  opts << i;
6707  }
6708  if ( mPanel )
6709  mPanel->setValue( value.isValid() ? opts : QVariant() );
6710  }
6711  else if ( mLineEdit )
6712  {
6713  const QgsProcessingParameterBand *bandParam = static_cast< const QgsProcessingParameterBand * >( parameterDefinition() );
6714  if ( bandParam->allowMultiple() )
6715  {
6716  const QList< int > v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
6717  QStringList opts;
6718  opts.reserve( v.size() );
6719  for ( int i : v )
6720  opts << QString::number( i );
6721  mLineEdit->setText( value.isValid() && !opts.empty() ? opts.join( ';' ) : QString() );
6722  }
6723  else
6724  {
6725  if ( value.isValid() )
6726  mLineEdit->setText( QString::number( QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context ) ) );
6727  else
6728  mLineEdit->clear();
6729  }
6730  }
6731 }
6732 
6733 QVariant QgsProcessingBandWidgetWrapper::widgetValue() const
6734 {
6735  if ( mComboBox )
6736  return mComboBox->currentBand() == -1 ? QVariant() : mComboBox->currentBand();
6737  else if ( mPanel )
6738  return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
6739  else if ( mLineEdit )
6740  {
6741  const QgsProcessingParameterBand *bandParam = static_cast< const QgsProcessingParameterBand * >( parameterDefinition() );
6742  if ( bandParam->allowMultiple() )
6743  {
6744 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
6745  const QStringList parts = mLineEdit->text().split( ';', QString::SkipEmptyParts );
6746 #else
6747  const QStringList parts = mLineEdit->text().split( ';', Qt::SkipEmptyParts );
6748 #endif
6749  QVariantList res;
6750  res.reserve( parts.count() );
6751  for ( const QString &s : parts )
6752  {
6753  bool ok = false;
6754  int band = s.toInt( &ok );
6755  if ( ok )
6756  res << band;
6757  }
6758  return res.isEmpty() ? QVariant() : res;
6759  }
6760  else
6761  {
6762  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
6763  }
6764  }
6765  else
6766  return QVariant();
6767 }
6768 
6769 QStringList QgsProcessingBandWidgetWrapper::compatibleParameterTypes() const
6770 {
6771  return QStringList()
6774 }
6775 
6776 QStringList QgsProcessingBandWidgetWrapper::compatibleOutputTypes() const
6777 {
6778  return QStringList()
6780 }
6781 
6782 QString QgsProcessingBandWidgetWrapper::modelerExpressionFormatString() const
6783 {
6784  return tr( "selected band numbers as an array of numbers, or semicolon separated string of options (e.g. '1;3')" );
6785 }
6786 
6787 QString QgsProcessingBandWidgetWrapper::parameterType() const
6788 {
6790 }
6791 
6792 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBandWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6793 {
6794  return new QgsProcessingBandWidgetWrapper( parameter, type );
6795 }
6796 
6797 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBandWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6798 {
6799  return new QgsProcessingBandParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6800 }
6801 
6802 
6803 
6804 //
6805 // QgsProcessingMultipleLayerPanelWidget
6806 //
6807 
6808 QgsProcessingMultipleLayerPanelWidget::QgsProcessingMultipleLayerPanelWidget( QWidget *parent, const QgsProcessingParameterMultipleLayers *param )
6809  : QWidget( parent )
6810  , mParam( param )
6811 {
6812  QHBoxLayout *hl = new QHBoxLayout();
6813  hl->setContentsMargins( 0, 0, 0, 0 );
6814 
6815  mLineEdit = new QLineEdit();
6816  mLineEdit->setEnabled( false );
6817  hl->addWidget( mLineEdit, 1 );
6818 
6819  mToolButton = new QToolButton();
6820  mToolButton->setText( QString( QChar( 0x2026 ) ) );
6821  hl->addWidget( mToolButton );
6822 
6823  setLayout( hl );
6824 
6825  if ( mParam )
6826  {
6827  mLineEdit->setText( tr( "%n input(s) selected", nullptr, 0 ) );
6828  }
6829 
6830  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingMultipleLayerPanelWidget::showDialog );
6831 }
6832 
6833 void QgsProcessingMultipleLayerPanelWidget::setValue( const QVariant &value )
6834 {
6835  if ( value.isValid() )
6836  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
6837  else
6838  mValue.clear();
6839 
6840  updateSummaryText();
6841  emit changed();
6842 }
6843 
6844 void QgsProcessingMultipleLayerPanelWidget::setProject( QgsProject *project )
6845 {
6846  mProject = project;
6847  if ( mProject )
6848  {
6849  connect( mProject, &QgsProject::layerRemoved, this, [&]( const QString & layerId )
6850  {
6851  if ( mValue.removeAll( layerId ) )
6852  {
6853  updateSummaryText();
6854  emit changed();
6855  }
6856  } );
6857  }
6858 }
6859 
6860 void QgsProcessingMultipleLayerPanelWidget::setModel( QgsProcessingModelAlgorithm *model, const QString &modelChildAlgorithmID )
6861 {
6862  mModel = model;
6863  if ( !model )
6864  return;
6865 
6866  switch ( mParam->layerType() )
6867  {
6869  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFile::typeName(),
6870  QStringList() << QgsProcessingOutputFile::typeName() );
6871  break;
6872 
6874  {
6875  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterRasterLayer::typeName()
6878  QStringList() << QgsProcessingOutputFile::typeName()
6882  break;
6883  }
6884 
6886  {
6887  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterMeshLayer::typeName()
6890  QStringList() << QgsProcessingOutputFile::typeName()
6893  break;
6894  }
6895 
6897  {
6898  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterMapLayer::typeName()
6901  QStringList() << QgsProcessingOutputFile::typeName()
6904  break;
6905  }
6906 
6908  {
6909  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterPointCloudLayer::typeName()
6912  QStringList() << QgsProcessingOutputFile::typeName()
6915  break;
6916  }
6917 
6919  {
6920  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterAnnotationLayer::typeName()
6922  QStringList() << QgsProcessingOutputMapLayer::typeName()
6924  break;
6925  }
6926 
6928  {
6929  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6933  QStringList() << QgsProcessingOutputFile::typeName()
6937  QList< int >() << QgsProcessing::TypeVector );
6938  break;
6939  }
6940 
6942  {
6943  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6947  QStringList() << QgsProcessingOutputFile::typeName()
6951  break;
6952  }
6953 
6955  {
6956  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6960  QStringList() << QgsProcessingOutputFile::typeName()
6965  break;
6966  }
6967 
6969  {
6970  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6974  QStringList() << QgsProcessingOutputFile::typeName()
6979  break;
6980  }
6981 
6983  {
6984  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6988  QStringList() << QgsProcessingOutputFile::typeName()
6993  break;
6994  }
6995 
6997  {
6998  mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
7004  QStringList() << QgsProcessingOutputFile::typeName()
7008  // << QgsProcessingOutputMeshLayer::typeName()
7010  break;
7011  }
7012  }
7013 }
7014 
7015 void QgsProcessingMultipleLayerPanelWidget::showDialog()
7016 {
7018  if ( panel && panel->dockMode() )
7019  {
7020  QgsProcessingMultipleInputPanelWidget *widget = new QgsProcessingMultipleInputPanelWidget( mParam, mValue, mModelSources, mModel );
7021  widget->setPanelTitle( mParam->description() );
7022  widget->setProject( mProject );
7023  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
7024  {
7025  setValue( widget->selectedOptions() );
7026  } );
7027  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
7028  panel->openPanel( widget );
7029  }
7030  else
7031  {
7032  QgsProcessingMultipleInputDialog dlg( mParam, mValue, mModelSources, mModel, this, Qt::WindowFlags() );
7033  dlg.setProject( mProject );
7034  if ( dlg.exec() )
7035  {
7036  setValue( dlg.selectedOptions() );
7037  }
7038  }
7039 }
7040 
7041 void QgsProcessingMultipleLayerPanelWidget::updateSummaryText()
7042 {
7043  if ( mParam )
7044  mLineEdit->setText( tr( "%n input(s) selected", nullptr, mValue.count() ) );
7045 }
7046 
7047 //
7048 // QgsProcessingMultipleLayerWidgetWrapper
7049 //
7050 
7051 QgsProcessingMultipleLayerParameterDefinitionWidget::QgsProcessingMultipleLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
7052  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
7053 {
7054  QVBoxLayout *vlayout = new QVBoxLayout();
7055  vlayout->setContentsMargins( 0, 0, 0, 0 );
7056 
7057  vlayout->addWidget( new QLabel( tr( "Allowed layer type" ) ) );
7058  mLayerTypeComboBox = new QComboBox();
7059  mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), QgsProcessing::TypeMapLayer );
7060  mLayerTypeComboBox->addItem( tr( "Vector (No Geometry Required)" ), QgsProcessing::TypeVector );
7061  mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), QgsProcessing::TypeVectorPoint );
7062  mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), QgsProcessing::TypeVectorLine );
7063  mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), QgsProcessing::TypeVectorPolygon );
7064  mLayerTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
7065  mLayerTypeComboBox->addItem( tr( "Raster" ), QgsProcessing::TypeRaster );
7066  mLayerTypeComboBox->addItem( tr( "File" ), QgsProcessing::TypeFile );
7067  mLayerTypeComboBox->addItem( tr( "Mesh" ), QgsProcessing::TypeMesh );
7068  mLayerTypeComboBox->addItem( tr( "Plugin" ), QgsProcessing::TypePlugin );
7069  mLayerTypeComboBox->addItem( tr( "Point Cloud" ), QgsProcessing::TypePointCloud );
7070  mLayerTypeComboBox->addItem( tr( "Annotation" ), QgsProcessing::TypeAnnotation );
7071  if ( const QgsProcessingParameterMultipleLayers *layersParam = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( definition ) )
7072  mLayerTypeComboBox->setCurrentIndex( mLayerTypeComboBox->findData( layersParam->layerType() ) );
7073 
7074  vlayout->addWidget( mLayerTypeComboBox );
7075  setLayout( vlayout );
7076 }
7077 
7078 QgsProcessingParameterDefinition *QgsProcessingMultipleLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
7079 {
7080  auto param = std::make_unique< QgsProcessingParameterMultipleLayers >( name, description, static_cast< QgsProcessing::SourceType >( mLayerTypeComboBox->currentData().toInt() ) );
7081  param->setFlags( flags );
7082  return param.release();
7083 }
7084 
7085 QgsProcessingMultipleLayerWidgetWrapper::QgsProcessingMultipleLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7086  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7087 {
7088 
7089 }
7090 
7091 QWidget *QgsProcessingMultipleLayerWidgetWrapper::createWidget()
7092 {
7093  const QgsProcessingParameterMultipleLayers *layerParam = dynamic_cast< const QgsProcessingParameterMultipleLayers *>( parameterDefinition() );
7094 
7095  mPanel = new QgsProcessingMultipleLayerPanelWidget( nullptr, layerParam );
7096  mPanel->setToolTip( parameterDefinition()->toolTip() );
7097  mPanel->setProject( widgetContext().project() );
7098  if ( type() == QgsProcessingGui::Modeler )
7099  mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
7100  connect( mPanel, &QgsProcessingMultipleLayerPanelWidget::changed, this, [ = ]
7101  {
7102  emit widgetValueHasChanged( this );
7103  } );
7104  return mPanel;
7105 }
7106 
7107 void QgsProcessingMultipleLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
7108 {
7110  if ( mPanel )
7111  {
7112  mPanel->setProject( context.project() );
7113  if ( type() == QgsProcessingGui::Modeler )
7114  mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
7115  }
7116 }
7117 
7118 void QgsProcessingMultipleLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7119 {
7120  if ( mPanel )
7121  {
7122  QVariantList opts;
7123  if ( value.isValid() )
7124  {
7125  const QList< QgsMapLayer * > v = QgsProcessingParameters::parameterAsLayerList( parameterDefinition(), value, context );
7126  opts.reserve( v.size() );
7127  for ( const QgsMapLayer *l : v )
7128  opts << l->source();
7129  }
7130 
7131  for ( const QVariant &v : value.toList() )
7132  {
7133  if ( v.canConvert< QgsProcessingModelChildParameterSource >() )
7134  {
7135  const QgsProcessingModelChildParameterSource source = v.value< QgsProcessingModelChildParameterSource >();
7136  opts << QVariant::fromValue( source );
7137  }
7138  }
7139 
7140  if ( mPanel )
7141  mPanel->setValue( value.isValid() ? opts : QVariant() );
7142  }
7143 }
7144 
7145 QVariant QgsProcessingMultipleLayerWidgetWrapper::widgetValue() const
7146 {
7147  if ( mPanel )
7148  return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
7149  else
7150  return QVariant();
7151 }
7152 
7153 QStringList QgsProcessingMultipleLayerWidgetWrapper::compatibleParameterTypes() const
7154 {
7155  return QStringList()
7164 }
7165 
7166 QStringList QgsProcessingMultipleLayerWidgetWrapper::compatibleOutputTypes() const
7167 {
7168  return QStringList()
7175 }
7176 
7177 QString QgsProcessingMultipleLayerWidgetWrapper::modelerExpressionFormatString() const
7178 {
7179  return tr( "an array of layer paths, or semicolon separated string of layer paths" );
7180 }
7181 
7182 QString QgsProcessingMultipleLayerWidgetWrapper::parameterType() const
7183 {
7185 }
7186 
7187 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMultipleLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7188 {
7189  return new QgsProcessingMultipleLayerWidgetWrapper( parameter, type );
7190 }
7191 
7192 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMultipleLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7193 {
7194  return new QgsProcessingMultipleLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
7195 }
7196 
7197 
7198 //
7199 // QgsProcessingPointCloudLayerWidgetWrapper
7200 //
7201 
7202 QgsProcessingPointCloudLayerWidgetWrapper::QgsProcessingPointCloudLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7203  : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
7204 {
7205 
7206 }
7207 
7208 QStringList QgsProcessingPointCloudLayerWidgetWrapper::compatibleParameterTypes() const
7209 {
7210  return QStringList()
7215 }
7216 
7217 QStringList QgsProcessingPointCloudLayerWidgetWrapper::compatibleOutputTypes() const
7218 {
7219  return QStringList()
7221  // TODO << QgsProcessingOutputPointCloudLayer::typeName()
7225 }
7226 
7227 QString QgsProcessingPointCloudLayerWidgetWrapper::modelerExpressionFormatString() const
7228 {
7229  return tr( "path to a point cloud layer" );
7230 }
7231 
7232 QString QgsProcessingPointCloudLayerWidgetWrapper::parameterType() const
7233 {
7235 }
7236 
7237 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7238 {
7239  return new QgsProcessingPointCloudLayerWidgetWrapper( parameter, type );
7240 }
7241 
7242 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointCloudLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7243 {
7244  Q_UNUSED( context );
7245  Q_UNUSED( widgetContext );
7246  Q_UNUSED( definition );
7247  Q_UNUSED( algorithm );
7248 
7249  return nullptr;
7250 }
7251 
7252 
7253 //
7254 // QgsProcessingAnnotationLayerWidgetWrapper
7255 //
7256 
7257 QgsProcessingAnnotationLayerWidgetWrapper::QgsProcessingAnnotationLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7258  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7259 {
7260 
7261 }
7262 
7263 QStringList QgsProcessingAnnotationLayerWidgetWrapper::compatibleParameterTypes() const
7264 {
7265  return QStringList()
7270 }
7271 
7272 QStringList QgsProcessingAnnotationLayerWidgetWrapper::compatibleOutputTypes() const
7273 {
7274  return QStringList()
7277 }
7278 
7279 QString QgsProcessingAnnotationLayerWidgetWrapper::modelerExpressionFormatString() const
7280 {
7281  return tr( "name of an annotation layer, or \"main\" for the main annotation layer" );
7282 }
7283 
7284 QString QgsProcessingAnnotationLayerWidgetWrapper::parameterType() const
7285 {
7287 }
7288 
7289 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAnnotationLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7290 {
7291  return new QgsProcessingAnnotationLayerWidgetWrapper( parameter, type );
7292 }
7293 
7294 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingAnnotationLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7295 {
7296  Q_UNUSED( context );
7297  Q_UNUSED( widgetContext );
7298  Q_UNUSED( definition );
7299  Q_UNUSED( algorithm );
7300 
7301  return nullptr;
7302 }
7303 
7304 void QgsProcessingAnnotationLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
7305 {
7307  if ( mComboBox )
7308  {
7309  if ( mWidgetContext.project() )
7310  mComboBox->setAdditionalLayers( { mWidgetContext.project()->mainAnnotationLayer() } );
7311  }
7312 }
7313 
7314 QWidget *QgsProcessingAnnotationLayerWidgetWrapper::createWidget()
7315 {
7316  mComboBox = new QgsMapLayerComboBox( );
7317  mComboBox->setFilters( QgsMapLayerProxyModel::AnnotationLayer );
7318 
7319  switch ( type() )
7320  {
7323  break;
7325  mComboBox->setEditable( true );
7326  break;
7327  }
7328 
7329  mComboBox->setToolTip( parameterDefinition()->toolTip() );
7330 
7331  if ( mWidgetContext.project() )
7332  mComboBox->setAdditionalLayers( { mWidgetContext.project()->mainAnnotationLayer() } );
7333 
7334  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
7335  mComboBox->setAllowEmptyLayer( true );
7336 
7337  connect( mComboBox, &QgsMapLayerComboBox::layerChanged, this, [ = ]()
7338  {
7339  if ( mBlockSignals )
7340  return;
7341 
7342  emit widgetValueHasChanged( this );
7343  } );
7344 
7345  setWidgetContext( widgetContext() );
7346  return mComboBox;
7347 }
7348 
7349 void QgsProcessingAnnotationLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7350 {
7351  if ( mComboBox )
7352  {
7353  if ( !value.isValid() && parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
7354  {
7355  mComboBox->setLayer( nullptr );
7356  return;
7357  }
7358 
7359  QVariant val = value;
7360  if ( val.canConvert<QgsProperty>() )
7361  {
7362  if ( val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
7363  {
7364  val = val.value< QgsProperty >().staticValue();
7365  }
7366  else
7367  {
7368  val = val.value< QgsProperty >().valueAsString( context.expressionContext(), parameterDefinition()->defaultValueForGui().toString() );
7369  }
7370  }
7371 
7372  QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( val.value< QObject * >() );
7373  if ( !layer && val.type() == QVariant::String )
7374  {
7375  layer = QgsProcessingUtils::mapLayerFromString( val.toString(), context, false, QgsProcessingUtils::LayerHint::Annotation );
7376  }
7377 
7378  if ( layer )
7379  {
7380  mComboBox->setLayer( layer );
7381  }
7382  }
7383 }
7384 
7385 QVariant QgsProcessingAnnotationLayerWidgetWrapper::widgetValue() const
7386 {
7387  return mComboBox && mComboBox->currentLayer() ?
7388  ( mWidgetContext.project() ? ( mComboBox->currentLayer() == mWidgetContext.project()->mainAnnotationLayer() ? QStringLiteral( "main" ) : mComboBox->currentLayer()->id() ) : mComboBox->currentLayer()->id() )
7389  : QVariant();
7390 }
7391 
7392 
7393 
7394 //
7395 // QgsProcessingOutputWidgetWrapper
7396 //
7397 
7398 QgsProcessingOutputWidgetWrapper::QgsProcessingOutputWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7399  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7400 {
7401 
7402 }
7403 
7404 QWidget *QgsProcessingOutputWidgetWrapper::createWidget()
7405 {
7406  const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( parameterDefinition() );
7407  switch ( type() )
7408  {
7411  {
7412  mOutputWidget = new QgsProcessingLayerOutputDestinationWidget( destParam, false );
7413  if ( mProcessingContextGenerator )
7414  mOutputWidget->setContext( mProcessingContextGenerator->processingContext() );
7415  if ( mParametersGenerator )
7416  mOutputWidget->registerProcessingParametersGenerator( mParametersGenerator );
7417  mOutputWidget->setToolTip( parameterDefinition()->toolTip() );
7418 
7419  connect( mOutputWidget, &QgsProcessingLayerOutputDestinationWidget::destinationChanged, this, [ = ]()
7420  {
7421  if ( mBlockSignals )
7422  return;
7423 
7424  emit widgetValueHasChanged( this );
7425  } );
7426 
7427  if ( type() == QgsProcessingGui::Standard
7432  mOutputWidget->addOpenAfterRunningOption();
7433 
7434  return mOutputWidget;
7435  }
7437  break;
7438  }
7439 
7440  return nullptr;
7441 }
7442 
7443 
7444 void QgsProcessingOutputWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
7445 {
7446  if ( mOutputWidget )
7447  mOutputWidget->setValue( value );
7448 }
7449 
7450 QVariant QgsProcessingOutputWidgetWrapper::widgetValue() const
7451 {
7452  if ( mOutputWidget )
7453  return mOutputWidget->value();
7454 
7455  return QVariant();
7456 }
7457 
7458 QVariantMap QgsProcessingOutputWidgetWrapper::customProperties() const
7459 {
7460  QVariantMap res;
7461  if ( mOutputWidget )
7462  res.insert( QStringLiteral( "OPEN_AFTER_RUNNING" ), mOutputWidget->openAfterRunning() );
7463  return res;
7464 }
7465 
7466 QStringList QgsProcessingOutputWidgetWrapper::compatibleParameterTypes() const
7467 {
7468  return QStringList()
7475 }
7476 
7477 QStringList QgsProcessingOutputWidgetWrapper::compatibleOutputTypes() const
7478 {
7479  return QStringList()
7483 }
7484 
7485 //
7486 // QgsProcessingFeatureSinkWidgetWrapper
7487 //
7488 
7489 QgsProcessingFeatureSinkWidgetWrapper::QgsProcessingFeatureSinkWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7490  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7491 {
7492 
7493 }
7494 
7495 QString QgsProcessingFeatureSinkWidgetWrapper::parameterType() const
7496 {
7498 }
7499 
7500 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSinkWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7501 {
7502  return new QgsProcessingFeatureSinkWidgetWrapper( parameter, type );
7503 }
7504 
7505 QString QgsProcessingFeatureSinkWidgetWrapper::modelerExpressionFormatString() const
7506 {
7507  return tr( "path to layer destination" );
7508 }
7509 
7510 //
7511 // QgsProcessingFeatureSinkWidgetWrapper
7512 //
7513 
7514 QgsProcessingVectorDestinationWidgetWrapper::QgsProcessingVectorDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7515  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7516 {
7517 
7518 }
7519 
7520 QString QgsProcessingVectorDestinationWidgetWrapper::parameterType() const
7521 {
7523 }
7524 
7525 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7526 {
7527  return new QgsProcessingVectorDestinationWidgetWrapper( parameter, type );
7528 }
7529 
7530 QString QgsProcessingVectorDestinationWidgetWrapper::modelerExpressionFormatString() const
7531 {
7532  return tr( "path to layer destination" );
7533 }
7534 
7535 //
7536 // QgsProcessingRasterDestinationWidgetWrapper
7537 //
7538 
7539 QgsProcessingRasterDestinationWidgetWrapper::QgsProcessingRasterDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7540  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7541 {
7542 
7543 }
7544 
7545 QString QgsProcessingRasterDestinationWidgetWrapper::parameterType() const
7546 {
7548 }
7549 
7550 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7551 {
7552  return new QgsProcessingRasterDestinationWidgetWrapper( parameter, type );
7553 }
7554 
7555 QString QgsProcessingRasterDestinationWidgetWrapper::modelerExpressionFormatString() const
7556 {
7557  return tr( "path to layer destination" );
7558 }
7559 
7560 //
7561 // QgsProcessingPointCloudDestinationWidgetWrapper
7562 //
7563 
7564 QgsProcessingPointCloudDestinationWidgetWrapper::QgsProcessingPointCloudDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7565  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7566 {
7567 
7568 }
7569 
7570 QString QgsProcessingPointCloudDestinationWidgetWrapper::parameterType() const
7571 {
7573 }
7574 
7575 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7576 {
7577  return new QgsProcessingPointCloudDestinationWidgetWrapper( parameter, type );
7578 }
7579 
7580 QString QgsProcessingPointCloudDestinationWidgetWrapper::modelerExpressionFormatString() const
7581 {
7582  return tr( "path to layer destination" );
7583 }
7584 
7585 //
7586 // QgsProcessingFileDestinationWidgetWrapper
7587 //
7588 
7589 QgsProcessingFileDestinationWidgetWrapper::QgsProcessingFileDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7590  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7591 {
7592 
7593 }
7594 
7595 QString QgsProcessingFileDestinationWidgetWrapper::parameterType() const
7596 {
7598 }
7599 
7600 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7601 {
7602  return new QgsProcessingFileDestinationWidgetWrapper( parameter, type );
7603 }
7604 
7605 QString QgsProcessingFileDestinationWidgetWrapper::modelerExpressionFormatString() const
7606 {
7607  return tr( "path to file destination" );
7608 }
7609 
7610 //
7611 // QgsProcessingFolderDestinationWidgetWrapper
7612 //
7613 
7614 QgsProcessingFolderDestinationWidgetWrapper::QgsProcessingFolderDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7615  : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7616 {
7617 
7618 }
7619 
7620 QString QgsProcessingFolderDestinationWidgetWrapper::parameterType() const
7621 {
7623 }
7624 
7625 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFolderDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7626 {
7627  return new QgsProcessingFolderDestinationWidgetWrapper( parameter, type );
7628 }
7629 
7630 QString QgsProcessingFolderDestinationWidgetWrapper::modelerExpressionFormatString() const
7631 {
7632  return tr( "path to folder destination" );
7633 }
7634 
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:349
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:90
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.
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:470
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:231
@ StaticProperty
Static property (QgsStaticProperty)
Definition: qgsproperty.h:238
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.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster 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:2092
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places.
Definition: qgis.h:1632
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1578
const QgsField & field
Definition: qgsfield.h:463
const QgsCoordinateReferenceSystem & crs
QString proj
Proj coordinate operation description, for Proj >= 6.0 builds only.