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