QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
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"
34 #include "qgslayoutmanager.h"
35 #include "qgsproject.h"
36 #include "qgslayoutcombobox.h"
37 #include "qgslayoutitemcombobox.h"
38 #include "qgsprintlayout.h"
39 #include "qgsscalewidget.h"
40 #include "qgssnapindicator.h"
41 #include "qgsmapmouseevent.h"
42 #include "qgsfilterlineedit.h"
43 #include "qgsmapcanvas.h"
44 #include "qgsmessagebar.h"
45 #include "qgscolorbutton.h"
48 #include "qgsfieldcombobox.h"
49 #include "qgsmapthemecollection.h"
50 #include <QToolButton>
51 #include <QLabel>
52 #include <QHBoxLayout>
53 #include <QVBoxLayout>
54 #include <QCheckBox>
55 #include <QComboBox>
56 #include <QLineEdit>
57 #include <QPlainTextEdit>
58 #include <QRadioButton>
59 #include <QButtonGroup>
60 #include <QMenu>
61 
63 
64 //
65 // QgsProcessingBooleanWidgetWrapper
66 //
67 
68 
69 QgsProcessingBooleanParameterDefinitionWidget::QgsProcessingBooleanParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
70  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
71 {
72  QVBoxLayout *vlayout = new QVBoxLayout();
73  vlayout->setMargin( 0 );
74  vlayout->setContentsMargins( 0, 0, 0, 0 );
75 
76  mDefaultCheckBox = new QCheckBox( tr( "Checked" ) );
77  if ( const QgsProcessingParameterBoolean *boolParam = dynamic_cast<const QgsProcessingParameterBoolean *>( definition ) )
78  mDefaultCheckBox->setChecked( QgsProcessingParameters::parameterAsBool( boolParam, boolParam->defaultValue(), context ) );
79  else
80  mDefaultCheckBox->setChecked( false );
81  vlayout->addWidget( mDefaultCheckBox );
82  setLayout( vlayout );
83 }
84 
85 QgsProcessingParameterDefinition *QgsProcessingBooleanParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
86 {
87  auto param = qgis::make_unique< QgsProcessingParameterBoolean >( name, description, mDefaultCheckBox->isChecked() );
88  param->setFlags( flags );
89  return param.release();
90 }
91 
92 
93 QgsProcessingBooleanWidgetWrapper::QgsProcessingBooleanWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
94  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
95 {
96 
97 }
98 
99 QWidget *QgsProcessingBooleanWidgetWrapper::createWidget()
100 {
101  switch ( type() )
102  {
104  {
105  QString description = parameterDefinition()->description();
106  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
107  description = QObject::tr( "%1 [optional]" ).arg( description );
108 
109  mCheckBox = new QCheckBox( description );
110  mCheckBox->setToolTip( parameterDefinition()->toolTip() );
111 
112  connect( mCheckBox, &QCheckBox::toggled, this, [ = ]
113  {
114  emit widgetValueHasChanged( this );
115  } );
116  return mCheckBox;
117  }
118 
121  {
122  mComboBox = new QComboBox();
123  mComboBox->addItem( tr( "Yes" ), true );
124  mComboBox->addItem( tr( "No" ), false );
125  mComboBox->setToolTip( parameterDefinition()->toolTip() );
126 
127  connect( mComboBox, qgis::overload< int>::of( &QComboBox::currentIndexChanged ), this, [ = ]
128  {
129  emit widgetValueHasChanged( this );
130  } );
131 
132  return mComboBox;
133  }
134  }
135  return nullptr;
136 }
137 
138 QLabel *QgsProcessingBooleanWidgetWrapper::createLabel()
139 {
140  // avoid creating labels in standard dialogs
141  if ( type() == QgsProcessingGui::Standard )
142  return nullptr;
143  else
145 }
146 
147 void QgsProcessingBooleanWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
148 {
149  switch ( type() )
150  {
152  {
153  const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
154  mCheckBox->setChecked( v );
155  break;
156  }
157 
160  {
161  const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
162  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
163  break;
164  }
165  }
166 }
167 
168 QVariant QgsProcessingBooleanWidgetWrapper::widgetValue() const
169 {
170  switch ( type() )
171  {
173  return mCheckBox->isChecked();
174 
177  return mComboBox->currentData();
178  }
179  return QVariant();
180 }
181 
182 QStringList QgsProcessingBooleanWidgetWrapper::compatibleParameterTypes() const
183 {
184  //pretty much everything is compatible here and can be converted to a bool!
185  return QStringList() << QgsProcessingParameterBoolean::typeName()
198 }
199 
200 QStringList QgsProcessingBooleanWidgetWrapper::compatibleOutputTypes() const
201 {
202  return QStringList() << QgsProcessingOutputNumber::typeName()
209 }
210 
211 QList<int> QgsProcessingBooleanWidgetWrapper::compatibleDataTypes() const
212 {
213  return QList< int >();
214 }
215 
216 QString QgsProcessingBooleanWidgetWrapper::parameterType() const
217 {
219 }
220 
221 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBooleanWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
222 {
223  return new QgsProcessingBooleanWidgetWrapper( parameter, type );
224 }
225 
226 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBooleanWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
227 {
228  return new QgsProcessingBooleanParameterDefinitionWidget( context, widgetContext, definition, algorithm );
229 }
230 
231 
232 //
233 // QgsProcessingCrsWidgetWrapper
234 //
235 
236 QgsProcessingCrsWidgetWrapper::QgsProcessingCrsWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
237  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
238 {
239 
240 }
241 
242 QWidget *QgsProcessingCrsWidgetWrapper::createWidget()
243 {
244  mProjectionSelectionWidget = new QgsProjectionSelectionWidget();
245  mProjectionSelectionWidget->setToolTip( parameterDefinition()->toolTip() );
246 
247  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
248  mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
249  else
250  mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, false );
251 
252  connect( mProjectionSelectionWidget, &QgsProjectionSelectionWidget::crsChanged, this, [ = ]
253  {
254  emit widgetValueHasChanged( this );
255  } );
256 
257  switch ( type() )
258  {
261  {
262  return mProjectionSelectionWidget;
263  }
264 
266  {
267  QWidget *w = new QWidget();
268  w->setToolTip( parameterDefinition()->toolTip() );
269 
270  QVBoxLayout *vl = new QVBoxLayout();
271  vl->setMargin( 0 );
272  vl->setContentsMargins( 0, 0, 0, 0 );
273  w->setLayout( vl );
274 
275  mUseProjectCrsCheckBox = new QCheckBox( tr( "Use project CRS" ) );
276  mUseProjectCrsCheckBox->setToolTip( tr( "Always use the current project CRS when running the model" ) );
277  vl->addWidget( mUseProjectCrsCheckBox );
278  connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, mProjectionSelectionWidget, &QgsProjectionSelectionWidget::setDisabled );
279  connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, this, [ = ]
280  {
281  emit widgetValueHasChanged( this );
282  } );
283 
284  vl->addWidget( mProjectionSelectionWidget );
285 
286  return w;
287  }
288  }
289  return nullptr;
290 }
291 
292 void QgsProcessingCrsWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
293 {
294  if ( mUseProjectCrsCheckBox )
295  {
296  if ( value.toString().compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
297  {
298  mUseProjectCrsCheckBox->setChecked( true );
299  return;
300  }
301  else
302  {
303  mUseProjectCrsCheckBox->setChecked( false );
304  }
305  }
306 
307  const QgsCoordinateReferenceSystem v = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, context );
308  if ( mProjectionSelectionWidget )
309  mProjectionSelectionWidget->setCrs( v );
310 }
311 
312 QVariant QgsProcessingCrsWidgetWrapper::widgetValue() const
313 {
314  if ( mUseProjectCrsCheckBox && mUseProjectCrsCheckBox->isChecked() )
315  return QStringLiteral( "ProjectCrs" );
316  else if ( mProjectionSelectionWidget )
317  return mProjectionSelectionWidget->crs().isValid() ? mProjectionSelectionWidget->crs() : QVariant();
318  else
319  return QVariant();
320 }
321 
322 QStringList QgsProcessingCrsWidgetWrapper::compatibleParameterTypes() const
323 {
324  return QStringList()
332 }
333 
334 QStringList QgsProcessingCrsWidgetWrapper::compatibleOutputTypes() const
335 {
336  return QStringList() << QgsProcessingOutputVectorLayer::typeName()
340 }
341 
342 QList<int> QgsProcessingCrsWidgetWrapper::compatibleDataTypes() const
343 {
344  return QList< int >();
345 }
346 
347 QString QgsProcessingCrsWidgetWrapper::modelerExpressionFormatString() const
348 {
349  return tr( "string as EPSG code, WKT or PROJ format, or a string identifying a map layer" );
350 }
351 
352 QString QgsProcessingCrsWidgetWrapper::parameterType() const
353 {
355 }
356 
357 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCrsWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
358 {
359  return new QgsProcessingCrsWidgetWrapper( parameter, type );
360 }
361 
362 
363 
364 //
365 // QgsProcessingStringWidgetWrapper
366 //
367 
368 
369 QgsProcessingStringParameterDefinitionWidget::QgsProcessingStringParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
370  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
371 {
372  QVBoxLayout *vlayout = new QVBoxLayout();
373  vlayout->setMargin( 0 );
374  vlayout->setContentsMargins( 0, 0, 0, 0 );
375 
376  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
377 
378  mDefaultLineEdit = new QLineEdit();
379  if ( const QgsProcessingParameterString *stringParam = dynamic_cast<const QgsProcessingParameterString *>( definition ) )
380  mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( stringParam, stringParam->defaultValue(), context ) );
381  vlayout->addWidget( mDefaultLineEdit );
382 
383  mMultiLineCheckBox = new QCheckBox( tr( "Multiline input" ) );
384  if ( const QgsProcessingParameterString *stringParam = dynamic_cast<const QgsProcessingParameterString *>( definition ) )
385  mMultiLineCheckBox->setChecked( stringParam->multiLine() );
386  vlayout->addWidget( mMultiLineCheckBox );
387 
388  setLayout( vlayout );
389 }
390 
391 QgsProcessingParameterDefinition *QgsProcessingStringParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
392 {
393  auto param = qgis::make_unique< QgsProcessingParameterString >( name, description, mDefaultLineEdit->text(), mMultiLineCheckBox->isChecked() );
394  param->setFlags( flags );
395  return param.release();
396 }
397 
398 
399 
400 QgsProcessingStringWidgetWrapper::QgsProcessingStringWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
401  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
402 {
403 
404 }
405 
406 QWidget *QgsProcessingStringWidgetWrapper::createWidget()
407 {
408  switch ( type() )
409  {
412  {
413  if ( static_cast< const QgsProcessingParameterString * >( parameterDefinition() )->multiLine() )
414  {
415  mPlainTextEdit = new QPlainTextEdit();
416  mPlainTextEdit->setToolTip( parameterDefinition()->toolTip() );
417 
418  connect( mPlainTextEdit, &QPlainTextEdit::textChanged, this, [ = ]
419  {
420  emit widgetValueHasChanged( this );
421  } );
422  return mPlainTextEdit;
423  }
424  else
425  {
426  mLineEdit = new QLineEdit();
427  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
428 
429  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
430  {
431  emit widgetValueHasChanged( this );
432  } );
433  return mLineEdit;
434  }
435  }
436 
438  {
439  mLineEdit = new QLineEdit();
440  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
441 
442  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
443  {
444  emit widgetValueHasChanged( this );
445  } );
446  return mLineEdit;
447  }
448  }
449  return nullptr;
450 }
451 
452 void QgsProcessingStringWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
453 {
454  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
455  if ( mLineEdit )
456  mLineEdit->setText( v );
457  if ( mPlainTextEdit )
458  mPlainTextEdit->setPlainText( v );
459 }
460 
461 QVariant QgsProcessingStringWidgetWrapper::widgetValue() const
462 {
463  if ( mLineEdit )
464  return mLineEdit->text();
465  else if ( mPlainTextEdit )
466  return mPlainTextEdit->toPlainText();
467  else
468  return QVariant();
469 }
470 
471 QStringList QgsProcessingStringWidgetWrapper::compatibleParameterTypes() const
472 {
473  return QStringList()
483 }
484 
485 QStringList QgsProcessingStringWidgetWrapper::compatibleOutputTypes() const
486 {
487  return QStringList() << QgsProcessingOutputNumber::typeName()
490 }
491 
492 QList<int> QgsProcessingStringWidgetWrapper::compatibleDataTypes() const
493 {
494  return QList< int >();
495 }
496 
497 QString QgsProcessingStringWidgetWrapper::parameterType() const
498 {
500 }
501 
502 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingStringWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
503 {
504  return new QgsProcessingStringWidgetWrapper( parameter, type );
505 }
506 
507 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingStringWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
508 {
509  return new QgsProcessingStringParameterDefinitionWidget( context, widgetContext, definition, algorithm );
510 }
511 
512 
513 
514 //
515 // QgsProcessingAuthConfigWidgetWrapper
516 //
517 
518 QgsProcessingAuthConfigWidgetWrapper::QgsProcessingAuthConfigWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
519  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
520 {
521 
522 }
523 
524 QWidget *QgsProcessingAuthConfigWidgetWrapper::createWidget()
525 {
526  switch ( type() )
527  {
531  {
532  mAuthConfigSelect = new QgsAuthConfigSelect();
533  mAuthConfigSelect->setToolTip( parameterDefinition()->toolTip() );
534 
535  connect( mAuthConfigSelect, &QgsAuthConfigSelect::selectedConfigIdChanged, this, [ = ]
536  {
537  emit widgetValueHasChanged( this );
538  } );
539  return mAuthConfigSelect;
540  }
541  }
542  return nullptr;
543 }
544 
545 void QgsProcessingAuthConfigWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
546 {
547  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
548  if ( mAuthConfigSelect )
549  mAuthConfigSelect->setConfigId( v );
550 }
551 
552 QVariant QgsProcessingAuthConfigWidgetWrapper::widgetValue() const
553 {
554  if ( mAuthConfigSelect )
555  return mAuthConfigSelect->configId();
556  else
557  return QVariant();
558 }
559 
560 QStringList QgsProcessingAuthConfigWidgetWrapper::compatibleParameterTypes() const
561 {
562  return QStringList()
566 }
567 
568 QStringList QgsProcessingAuthConfigWidgetWrapper::compatibleOutputTypes() const
569 {
570  return QStringList() << QgsProcessingOutputString::typeName();
571 }
572 
573 QList<int> QgsProcessingAuthConfigWidgetWrapper::compatibleDataTypes() const
574 {
575  return QList< int >();
576 }
577 
578 QString QgsProcessingAuthConfigWidgetWrapper::parameterType() const
579 {
581 }
582 
583 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAuthConfigWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
584 {
585  return new QgsProcessingAuthConfigWidgetWrapper( parameter, type );
586 }
587 
588 //
589 // QgsProcessingNumericWidgetWrapper
590 //
591 
592 QgsProcessingNumericWidgetWrapper::QgsProcessingNumericWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
593  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
594 {
595 
596 }
597 
598 QWidget *QgsProcessingNumericWidgetWrapper::createWidget()
599 {
600  const QgsProcessingParameterNumber *numberDef = static_cast< const QgsProcessingParameterNumber * >( parameterDefinition() );
601  const QVariantMap metadata = numberDef->metadata();
602  const int decimals = metadata.value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "decimals" ), 6 ).toInt();
603  switch ( type() )
604  {
608  {
609  // lots of duplicate code here -- but there's no common interface between QSpinBox/QDoubleSpinBox which would allow us to avoid this
610  QAbstractSpinBox *spinBox = nullptr;
611  switch ( numberDef->dataType() )
612  {
614  mDoubleSpinBox = new QgsDoubleSpinBox();
615  mDoubleSpinBox->setExpressionsEnabled( true );
616  mDoubleSpinBox->setDecimals( decimals );
617 
618  // guess reasonable step value for double spin boxes
619  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) &&
620  !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() + 1 ) )
621  {
622  double singleStep = calculateStep( numberDef->minimum(), numberDef->maximum() );
623  singleStep = std::max( singleStep, std::pow( 10, -decimals ) );
624  mDoubleSpinBox->setSingleStep( singleStep );
625  }
626 
627  spinBox = mDoubleSpinBox;
628  break;
629 
631  mSpinBox = new QgsSpinBox();
632  mSpinBox->setExpressionsEnabled( true );
633  spinBox = mSpinBox;
634  break;
635  }
636  spinBox->setToolTip( parameterDefinition()->toolTip() );
637 
638  double max = 999999999;
639  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) )
640  {
641  max = numberDef->maximum();
642  }
643  double min = -999999999;
644  if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
645  {
646  min = numberDef->minimum();
647  }
648  if ( mDoubleSpinBox )
649  {
650  mDoubleSpinBox->setMinimum( min );
651  mDoubleSpinBox->setMaximum( max );
652  }
653  else
654  {
655  mSpinBox->setMinimum( static_cast< int >( min ) );
656  mSpinBox->setMaximum( static_cast< int >( max ) );
657  }
658 
660  {
661  mAllowingNull = true;
662  if ( mDoubleSpinBox )
663  {
664  mDoubleSpinBox->setShowClearButton( true );
665  const double min = mDoubleSpinBox->minimum() - 1;
666  mDoubleSpinBox->setMinimum( min );
667  mDoubleSpinBox->setValue( min );
668  }
669  else
670  {
671  mSpinBox->setShowClearButton( true );
672  const int min = mSpinBox->minimum() - 1;
673  mSpinBox->setMinimum( min );
674  mSpinBox->setValue( min );
675  }
676  spinBox->setSpecialValueText( tr( "Not set" ) );
677  }
678  else
679  {
680  if ( numberDef->defaultValue().isValid() )
681  {
682  // if default value for parameter, we clear to that
683  bool ok = false;
684  if ( mDoubleSpinBox )
685  {
686  double defaultVal = numberDef->defaultValue().toDouble( &ok );
687  if ( ok )
688  mDoubleSpinBox->setClearValue( defaultVal );
689  }
690  else
691  {
692  int intVal = numberDef->defaultValue().toInt( &ok );
693  if ( ok )
694  mSpinBox->setClearValue( intVal );
695  }
696  }
697  else if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
698  {
699  // otherwise we clear to the minimum, if it's set
700  if ( mDoubleSpinBox )
701  mDoubleSpinBox->setClearValue( numberDef->minimum() );
702  else
703  mSpinBox->setClearValue( static_cast< int >( numberDef->minimum() ) );
704  }
705  else
706  {
707  // last resort, we clear to 0
708  if ( mDoubleSpinBox )
709  {
710  mDoubleSpinBox->setValue( 0 );
711  mDoubleSpinBox->setClearValue( 0 );
712  }
713  else
714  {
715  mSpinBox->setValue( 0 );
716  mSpinBox->setClearValue( 0 );
717  }
718  }
719  }
720 
721  if ( mDoubleSpinBox )
722  connect( mDoubleSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
723  else if ( mSpinBox )
724  connect( mSpinBox, qgis::overload<int>::of( &QgsSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
725 
726  return spinBox;
727  }
728  }
729  return nullptr;
730 }
731 
732 void QgsProcessingNumericWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
733 {
734  if ( mDoubleSpinBox )
735  {
736  if ( mAllowingNull && !value.isValid() )
737  mDoubleSpinBox->clear();
738  else
739  {
740  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
741  mDoubleSpinBox->setValue( v );
742  }
743  }
744  else if ( mSpinBox )
745  {
746  if ( mAllowingNull && !value.isValid() )
747  mSpinBox->clear();
748  else
749  {
750  const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
751  mSpinBox->setValue( v );
752  }
753  }
754 }
755 
756 QVariant QgsProcessingNumericWidgetWrapper::widgetValue() const
757 {
758  if ( mDoubleSpinBox )
759  {
760  if ( mAllowingNull && qgsDoubleNear( mDoubleSpinBox->value(), mDoubleSpinBox->minimum() ) )
761  return QVariant();
762  else
763  return mDoubleSpinBox->value();
764  }
765  else if ( mSpinBox )
766  {
767  if ( mAllowingNull && mSpinBox->value() == mSpinBox->minimum() )
768  return QVariant();
769  else
770  return mSpinBox->value();
771  }
772  else
773  return QVariant();
774 }
775 
776 QStringList QgsProcessingNumericWidgetWrapper::compatibleParameterTypes() const
777 {
778  return QStringList()
783 }
784 
785 QStringList QgsProcessingNumericWidgetWrapper::compatibleOutputTypes() const
786 {
787  return QStringList() << QgsProcessingOutputNumber::typeName()
789 }
790 
791 QList<int> QgsProcessingNumericWidgetWrapper::compatibleDataTypes() const
792 {
793  return QList< int >();
794 }
795 
796 double QgsProcessingNumericWidgetWrapper::calculateStep( const double minimum, const double maximum )
797 {
798  const double valueRange = maximum - minimum;
799  if ( valueRange <= 1.0 )
800  {
801  const double step = valueRange / 10.0;
802  // round to 1 significant figure
803  return qgsRound( step, -std::floor( std::log( step ) ) );
804  }
805  else
806  {
807  return 1.0;
808  }
809 }
810 
811 QString QgsProcessingNumericWidgetWrapper::parameterType() const
812 {
814 }
815 
816 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingNumericWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
817 {
818  return new QgsProcessingNumericWidgetWrapper( parameter, type );
819 }
820 
821 //
822 // QgsProcessingDistanceWidgetWrapper
823 //
824 
825 QgsProcessingDistanceWidgetWrapper::QgsProcessingDistanceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
826  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
827 {
828 
829 }
830 
831 QString QgsProcessingDistanceWidgetWrapper::parameterType() const
832 {
834 }
835 
836 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDistanceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
837 {
838  return new QgsProcessingDistanceWidgetWrapper( parameter, type );
839 }
840 
841 QWidget *QgsProcessingDistanceWidgetWrapper::createWidget()
842 {
843  const QgsProcessingParameterDistance *distanceDef = static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() );
844 
845  QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
846  switch ( type() )
847  {
849  {
850  mLabel = new QLabel();
851  mUnitsCombo = new QComboBox();
852 
858 
859 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
860  const int labelMargin = static_cast< int >( std::round( mUnitsCombo->fontMetrics().width( 'X' ) ) );
861 #else
862  const int labelMargin = static_cast< int >( std::round( mUnitsCombo->fontMetrics().horizontalAdvance( 'X' ) ) );
863 #endif
864  QHBoxLayout *layout = new QHBoxLayout();
865  layout->addWidget( spin, 1 );
866  layout->insertSpacing( 1, labelMargin / 2 );
867  layout->insertWidget( 2, mLabel );
868  layout->insertWidget( 3, mUnitsCombo );
869 
870  // bit of fiddlyness here -- we want the initial spacing to only be visible
871  // when the warning label is shown, so it's embedded inside mWarningLabel
872  // instead of outside it
873  mWarningLabel = new QWidget();
874  QHBoxLayout *warningLayout = new QHBoxLayout();
875  warningLayout->setMargin( 0 );
876  warningLayout->setContentsMargins( 0, 0, 0, 0 );
877  QLabel *warning = new QLabel();
878  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
879  const int size = static_cast< int >( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
880  warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
881  warning->setToolTip( tr( "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
882  warningLayout->insertSpacing( 0, labelMargin / 2 );
883  warningLayout->insertWidget( 1, warning );
884  mWarningLabel->setLayout( warningLayout );
885  layout->insertWidget( 4, mWarningLabel );
886 
887  QWidget *w = new QWidget();
888  layout->setMargin( 0 );
889  layout->setContentsMargins( 0, 0, 0, 0 );
890  w->setLayout( layout );
891 
892  setUnits( distanceDef->defaultUnit() );
893 
894  return w;
895  }
896 
899  return spin;
900 
901  }
902  return nullptr;
903 }
904 
905 void QgsProcessingDistanceWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
906 {
907  QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
908  switch ( type() )
909  {
911  {
912  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
913  {
914  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() )->parentParameterName() )
915  {
916  setUnitParameterValue( wrapper->parameterValue() );
918  {
919  setUnitParameterValue( wrapper->parameterValue() );
920  } );
921  break;
922  }
923  }
924  break;
925  }
926 
929  break;
930  }
931 }
932 
933 void QgsProcessingDistanceWidgetWrapper::setUnitParameterValue( const QVariant &value )
934 {
936 
937  // evaluate value to layer
938  QgsProcessingContext *context = nullptr;
939  std::unique_ptr< QgsProcessingContext > tmpContext;
940  if ( mProcessingContextGenerator )
941  context = mProcessingContextGenerator->processingContext();
942 
943  if ( !context )
944  {
945  tmpContext = qgis::make_unique< QgsProcessingContext >();
946  context = tmpContext.get();
947  }
948 
949  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, *context );
950  if ( crs.isValid() )
951  {
952  units = crs.mapUnits();
953  }
954 
955  setUnits( units );
956 }
957 
958 void QgsProcessingDistanceWidgetWrapper::setUnits( const QgsUnitTypes::DistanceUnit units )
959 {
960  mLabel->setText( QgsUnitTypes::toString( units ) );
962  {
963  mUnitsCombo->hide();
964  mLabel->show();
965  }
966  else
967  {
968  mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( units ) );
969  mUnitsCombo->show();
970  mLabel->hide();
971  }
972  mWarningLabel->setVisible( units == QgsUnitTypes::DistanceDegrees );
973  mBaseUnit = units;
974 }
975 
976 QVariant QgsProcessingDistanceWidgetWrapper::widgetValue() const
977 {
978  const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
979  if ( val.type() == QVariant::Double && mUnitsCombo && mUnitsCombo->isVisible() )
980  {
981  QgsUnitTypes::DistanceUnit displayUnit = static_cast<QgsUnitTypes::DistanceUnit >( mUnitsCombo->currentData().toInt() );
982  return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
983  }
984  else
985  {
986  return val;
987  }
988 }
989 
990 //
991 // QgsProcessingScaleWidgetWrapper
992 //
993 
994 QgsProcessingScaleWidgetWrapper::QgsProcessingScaleWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
995  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
996 {
997 
998 }
999 
1000 QString QgsProcessingScaleWidgetWrapper::parameterType() const
1001 {
1003 }
1004 
1005 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingScaleWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1006 {
1007  return new QgsProcessingScaleWidgetWrapper( parameter, type );
1008 }
1009 
1010 QWidget *QgsProcessingScaleWidgetWrapper::createWidget()
1011 {
1012  const QgsProcessingParameterScale *scaleDef = static_cast< const QgsProcessingParameterScale * >( parameterDefinition() );
1013 
1014  switch ( type() )
1015  {
1019  {
1020  mScaleWidget = new QgsScaleWidget( nullptr );
1022  mScaleWidget->setAllowNull( true );
1023 
1024  mScaleWidget->setMapCanvas( widgetContext().mapCanvas() );
1025  mScaleWidget->setShowCurrentScaleButton( true );
1026 
1027  mScaleWidget->setToolTip( parameterDefinition()->toolTip() );
1028  connect( mScaleWidget, &QgsScaleWidget::scaleChanged, this, [ = ]( double )
1029  {
1030  emit widgetValueHasChanged( this );
1031  } );
1032  return mScaleWidget;
1033  }
1034  }
1035  return nullptr;
1036 }
1037 
1038 void QgsProcessingScaleWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
1039 {
1040  if ( mScaleWidget )
1041  mScaleWidget->setMapCanvas( context.mapCanvas() );
1043 }
1044 
1045 
1046 QVariant QgsProcessingScaleWidgetWrapper::widgetValue() const
1047 {
1048  return mScaleWidget && !mScaleWidget->isNull() ? QVariant( mScaleWidget->scale() ) : QVariant();
1049 }
1050 
1051 void QgsProcessingScaleWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1052 {
1053  if ( mScaleWidget )
1054  {
1055  if ( mScaleWidget->allowNull() && !value.isValid() )
1056  mScaleWidget->setNull();
1057  else
1058  {
1059  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
1060  mScaleWidget->setScale( v );
1061  }
1062  }
1063 }
1064 
1065 
1066 //
1067 // QgsProcessingRangeWidgetWrapper
1068 //
1069 
1070 QgsProcessingRangeWidgetWrapper::QgsProcessingRangeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1071  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1072 {
1073 
1074 }
1075 
1076 QWidget *QgsProcessingRangeWidgetWrapper::createWidget()
1077 {
1078  const QgsProcessingParameterRange *rangeDef = static_cast< const QgsProcessingParameterRange * >( parameterDefinition() );
1079  switch ( type() )
1080  {
1084  {
1085  QHBoxLayout *layout = new QHBoxLayout();
1086 
1087  mMinSpinBox = new QgsDoubleSpinBox();
1088  mMaxSpinBox = new QgsDoubleSpinBox();
1089 
1090  mMinSpinBox->setExpressionsEnabled( true );
1091  mMinSpinBox->setShowClearButton( false );
1092  mMaxSpinBox->setExpressionsEnabled( true );
1093  mMaxSpinBox->setShowClearButton( false );
1094 
1095  QLabel *minLabel = new QLabel( tr( "Min" ) );
1096  layout->addWidget( minLabel );
1097  layout->addWidget( mMinSpinBox, 1 );
1098 
1099  QLabel *maxLabel = new QLabel( tr( "Max" ) );
1100  layout->addWidget( maxLabel );
1101  layout->addWidget( mMaxSpinBox, 1 );
1102 
1103  QWidget *w = new QWidget();
1104  layout->setMargin( 0 );
1105  layout->setContentsMargins( 0, 0, 0, 0 );
1106  w->setLayout( layout );
1107 
1108  if ( rangeDef->dataType() == QgsProcessingParameterNumber::Double )
1109  {
1110  mMinSpinBox->setDecimals( 6 );
1111  mMaxSpinBox->setDecimals( 6 );
1112  }
1113  else
1114  {
1115  mMinSpinBox->setDecimals( 0 );
1116  mMaxSpinBox->setDecimals( 0 );
1117  }
1118 
1119  mMinSpinBox->setMinimum( -99999999.999999 );
1120  mMaxSpinBox->setMinimum( -99999999.999999 );
1121  mMinSpinBox->setMaximum( 99999999.999999 );
1122  mMaxSpinBox->setMaximum( 99999999.999999 );
1123 
1125  {
1126  mAllowingNull = true;
1127 
1128  const double min = mMinSpinBox->minimum() - 1;
1129  mMinSpinBox->setMinimum( min );
1130  mMaxSpinBox->setMinimum( min );
1131  mMinSpinBox->setValue( min );
1132  mMaxSpinBox->setValue( min );
1133 
1134  mMinSpinBox->setShowClearButton( true );
1135  mMaxSpinBox->setShowClearButton( true );
1136  mMinSpinBox->setSpecialValueText( tr( "Not set" ) );
1137  mMaxSpinBox->setSpecialValueText( tr( "Not set" ) );
1138  }
1139 
1140  w->setToolTip( parameterDefinition()->toolTip() );
1141 
1142  connect( mMinSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
1143  {
1144  mBlockChangedSignal++;
1145  if ( !mAllowingNull && v > mMaxSpinBox->value() )
1146  mMaxSpinBox->setValue( v );
1147  mBlockChangedSignal--;
1148 
1149  if ( !mBlockChangedSignal )
1150  emit widgetValueHasChanged( this );
1151  } );
1152  connect( mMaxSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
1153  {
1154  mBlockChangedSignal++;
1155  if ( !mAllowingNull && v < mMinSpinBox->value() )
1156  mMinSpinBox->setValue( v );
1157  mBlockChangedSignal--;
1158 
1159  if ( !mBlockChangedSignal )
1160  emit widgetValueHasChanged( this );
1161  } );
1162 
1163  return w;
1164  }
1165  }
1166  return nullptr;
1167 }
1168 
1169 void QgsProcessingRangeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1170 {
1171  const QList< double > v = QgsProcessingParameters::parameterAsRange( parameterDefinition(), value, context );
1172  if ( mAllowingNull && v.empty() )
1173  {
1174  mMinSpinBox->clear();
1175  mMaxSpinBox->clear();
1176  }
1177  else
1178  {
1179  if ( v.empty() )
1180  return;
1181 
1182  if ( mAllowingNull )
1183  {
1184  mBlockChangedSignal++;
1185  if ( std::isnan( v.at( 0 ) ) )
1186  mMinSpinBox->clear();
1187  else
1188  mMinSpinBox->setValue( v.at( 0 ) );
1189 
1190  if ( v.count() >= 2 )
1191  {
1192  if ( std::isnan( v.at( 1 ) ) )
1193  mMaxSpinBox->clear();
1194  else
1195  mMaxSpinBox->setValue( v.at( 1 ) );
1196  }
1197  mBlockChangedSignal--;
1198  }
1199  else
1200  {
1201  mBlockChangedSignal++;
1202  mMinSpinBox->setValue( v.at( 0 ) );
1203  if ( v.count() >= 2 )
1204  mMaxSpinBox->setValue( v.at( 1 ) );
1205  mBlockChangedSignal--;
1206  }
1207  }
1208 
1209  if ( !mBlockChangedSignal )
1210  emit widgetValueHasChanged( this );
1211 }
1212 
1213 QVariant QgsProcessingRangeWidgetWrapper::widgetValue() const
1214 {
1215  if ( mAllowingNull )
1216  {
1217  QString value;
1218  if ( qgsDoubleNear( mMinSpinBox->value(), mMinSpinBox->minimum() ) )
1219  value = QStringLiteral( "None" );
1220  else
1221  value = QStringLiteral( "%1" ).arg( mMinSpinBox->value() );
1222 
1223  if ( qgsDoubleNear( mMaxSpinBox->value(), mMaxSpinBox->minimum() ) )
1224  value += QStringLiteral( ",None" );
1225  else
1226  value += QStringLiteral( ",%1" ).arg( mMaxSpinBox->value() );
1227 
1228  return value;
1229  }
1230  else
1231  return QStringLiteral( "%1,%2" ).arg( mMinSpinBox->value() ).arg( mMaxSpinBox->value() );
1232 }
1233 
1234 QStringList QgsProcessingRangeWidgetWrapper::compatibleParameterTypes() const
1235 {
1236  return QStringList()
1239 }
1240 
1241 QStringList QgsProcessingRangeWidgetWrapper::compatibleOutputTypes() const
1242 {
1243  return QStringList() << QgsProcessingOutputString::typeName();
1244 }
1245 
1246 QList<int> QgsProcessingRangeWidgetWrapper::compatibleDataTypes() const
1247 {
1248  return QList< int >();
1249 }
1250 
1251 QString QgsProcessingRangeWidgetWrapper::modelerExpressionFormatString() const
1252 {
1253  return tr( "string as two comma delimited floats, e.g. '1,10'" );
1254 }
1255 
1256 QString QgsProcessingRangeWidgetWrapper::parameterType() const
1257 {
1259 }
1260 
1261 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRangeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1262 {
1263  return new QgsProcessingRangeWidgetWrapper( parameter, type );
1264 }
1265 
1266 
1267 
1268 //
1269 // QgsProcessingMatrixWidgetWrapper
1270 //
1271 
1272 QgsProcessingMatrixWidgetWrapper::QgsProcessingMatrixWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1273  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1274 {
1275 
1276 }
1277 
1278 QWidget *QgsProcessingMatrixWidgetWrapper::createWidget()
1279 {
1280  mMatrixWidget = new QgsProcessingMatrixParameterPanel( nullptr, dynamic_cast< const QgsProcessingParameterMatrix *>( parameterDefinition() ) );
1281  mMatrixWidget->setToolTip( parameterDefinition()->toolTip() );
1282 
1283  connect( mMatrixWidget, &QgsProcessingMatrixParameterPanel::changed, this, [ = ]
1284  {
1285  emit widgetValueHasChanged( this );
1286  } );
1287 
1288  switch ( type() )
1289  {
1293  {
1294  return mMatrixWidget;
1295  }
1296  }
1297  return nullptr;
1298 }
1299 
1300 void QgsProcessingMatrixWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1301 {
1302  const QVariantList v = QgsProcessingParameters::parameterAsMatrix( parameterDefinition(), value, context );
1303  if ( mMatrixWidget )
1304  mMatrixWidget->setValue( v );
1305 }
1306 
1307 QVariant QgsProcessingMatrixWidgetWrapper::widgetValue() const
1308 {
1309  if ( mMatrixWidget )
1310  return mMatrixWidget->value().isEmpty() ? QVariant() : mMatrixWidget->value();
1311  else
1312  return QVariant();
1313 }
1314 
1315 QStringList QgsProcessingMatrixWidgetWrapper::compatibleParameterTypes() const
1316 {
1317  return QStringList()
1319 }
1320 
1321 QStringList QgsProcessingMatrixWidgetWrapper::compatibleOutputTypes() const
1322 {
1323  return QStringList();
1324 }
1325 
1326 QList<int> QgsProcessingMatrixWidgetWrapper::compatibleDataTypes() const
1327 {
1328  return QList< int >();
1329 }
1330 
1331 QString QgsProcessingMatrixWidgetWrapper::modelerExpressionFormatString() const
1332 {
1333  return tr( "comma delimited string of values, or an array of values" );
1334 }
1335 
1336 QString QgsProcessingMatrixWidgetWrapper::parameterType() const
1337 {
1339 }
1340 
1341 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMatrixWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1342 {
1343  return new QgsProcessingMatrixWidgetWrapper( parameter, type );
1344 }
1345 
1346 
1347 
1348 
1349 //
1350 // QgsProcessingFileWidgetWrapper
1351 //
1352 
1353 
1354 QgsProcessingFileParameterDefinitionWidget::QgsProcessingFileParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1355  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1356 {
1357  QVBoxLayout *vlayout = new QVBoxLayout();
1358  vlayout->setMargin( 0 );
1359  vlayout->setContentsMargins( 0, 0, 0, 0 );
1360 
1361  vlayout->addWidget( new QLabel( tr( "Type" ) ) );
1362 
1363  mTypeComboBox = new QComboBox();
1364  mTypeComboBox->addItem( tr( "File" ), QgsProcessingParameterFile::File );
1365  mTypeComboBox->addItem( tr( "Folder" ), QgsProcessingParameterFile::Folder );
1366  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1367  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( fileParam->behavior() ) );
1368  else
1369  mTypeComboBox->setCurrentIndex( 0 );
1370  vlayout->addWidget( mTypeComboBox );
1371 
1372  vlayout->addWidget( new QLabel( tr( "File filter" ) ) );
1373 
1374  mFilterComboBox = new QComboBox();
1375  mFilterComboBox->setEditable( true );
1376  // add some standard ones -- these also act as a demonstration of the required format
1377  mFilterComboBox->addItem( tr( "All Files (*.*)" ) );
1378  mFilterComboBox->addItem( tr( "CSV Files (*.csv)" ) );
1379  mFilterComboBox->addItem( tr( "HTML Files (*.html *.htm)" ) );
1380  mFilterComboBox->addItem( tr( "Text Files (*.txt)" ) );
1381  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1382  mFilterComboBox->setCurrentText( fileParam->fileFilter() );
1383  else
1384  mFilterComboBox->setCurrentIndex( 0 );
1385  vlayout->addWidget( mFilterComboBox );
1386 
1387  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1388 
1389  mDefaultFileWidget = new QgsFileWidget();
1390  mDefaultFileWidget->lineEdit()->setShowClearButton( true );
1391  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1392  {
1393  mDefaultFileWidget->setStorageMode( fileParam->behavior() == QgsProcessingParameterFile::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
1394  mDefaultFileWidget->setFilePath( fileParam->defaultValue().toString() );
1395  }
1396  else
1397  mDefaultFileWidget->setStorageMode( QgsFileWidget::GetFile );
1398  vlayout->addWidget( mDefaultFileWidget );
1399 
1400  connect( mTypeComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, [ = ]
1401  {
1402  QgsProcessingParameterFile::Behavior behavior = static_cast< QgsProcessingParameterFile::Behavior >( mTypeComboBox->currentData().toInt() );
1403  mFilterComboBox->setEnabled( behavior == QgsProcessingParameterFile::File );
1404  mDefaultFileWidget->setStorageMode( behavior == QgsProcessingParameterFile::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
1405  } );
1406  mFilterComboBox->setEnabled( static_cast< QgsProcessingParameterFile::Behavior >( mTypeComboBox->currentData().toInt() ) == QgsProcessingParameterFile::File );
1407 
1408 
1409  setLayout( vlayout );
1410 }
1411 
1412 QgsProcessingParameterDefinition *QgsProcessingFileParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1413 {
1414  auto param = qgis::make_unique< QgsProcessingParameterFile >( name, description );
1415  param->setBehavior( static_cast< QgsProcessingParameterFile::Behavior>( mTypeComboBox->currentData().toInt() ) );
1416  if ( param->behavior() == QgsProcessingParameterFile::File )
1417  param->setFileFilter( mFilterComboBox->currentText() );
1418  if ( !mDefaultFileWidget->filePath().isEmpty() )
1419  param->setDefaultValue( mDefaultFileWidget->filePath() );
1420  param->setFlags( flags );
1421  return param.release();
1422 }
1423 
1424 
1425 QgsProcessingFileWidgetWrapper::QgsProcessingFileWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1426  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1427 {
1428 
1429 }
1430 
1431 QWidget *QgsProcessingFileWidgetWrapper::createWidget()
1432 {
1433  const QgsProcessingParameterFile *fileParam = dynamic_cast< const QgsProcessingParameterFile *>( parameterDefinition() );
1434  switch ( type() )
1435  {
1439  {
1440  mFileWidget = new QgsFileWidget();
1441  mFileWidget->setToolTip( parameterDefinition()->toolTip() );
1442  mFileWidget->setDialogTitle( parameterDefinition()->description() );
1443 
1444  mFileWidget->setDefaultRoot( QgsSettings().value( QStringLiteral( "/Processing/LastInputPath" ), QDir::homePath() ).toString() );
1445 
1446  switch ( fileParam->behavior() )
1447  {
1449  mFileWidget->setStorageMode( QgsFileWidget::GetFile );
1450  if ( !fileParam->fileFilter().isEmpty() )
1451  mFileWidget->setFilter( fileParam->fileFilter() );
1452  else if ( !fileParam->extension().isEmpty() )
1453  mFileWidget->setFilter( tr( "%1 files" ).arg( fileParam->extension().toUpper() ) + QStringLiteral( " (*." ) + fileParam->extension().toLower() + ')' );
1454  break;
1455 
1457  mFileWidget->setStorageMode( QgsFileWidget::GetDirectory );
1458  break;
1459  }
1460 
1461  connect( mFileWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & path )
1462  {
1463  QgsSettings().setValue( QStringLiteral( "/Processing/LastInputPath" ), QFileInfo( path ).canonicalPath() );
1464  emit widgetValueHasChanged( this );
1465  } );
1466  return mFileWidget;
1467  }
1468  }
1469  return nullptr;
1470 }
1471 
1472 void QgsProcessingFileWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1473 {
1474  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
1475  if ( mFileWidget )
1476  mFileWidget->setFilePath( v );
1477 }
1478 
1479 QVariant QgsProcessingFileWidgetWrapper::widgetValue() const
1480 {
1481  if ( mFileWidget )
1482  return mFileWidget->filePath();
1483  else
1484  return QVariant();
1485 }
1486 
1487 QStringList QgsProcessingFileWidgetWrapper::compatibleParameterTypes() const
1488 {
1489  return QStringList()
1492 }
1493 
1494 QStringList QgsProcessingFileWidgetWrapper::compatibleOutputTypes() const
1495 {
1496  return QStringList() << QgsProcessingOutputFile::typeName()
1501 }
1502 
1503 QList<int> QgsProcessingFileWidgetWrapper::compatibleDataTypes() const
1504 {
1505  return QList< int >();
1506 }
1507 
1508 QString QgsProcessingFileWidgetWrapper::modelerExpressionFormatString() const
1509 {
1510  return tr( "string representing a path to a file or folder" );
1511 }
1512 
1513 QString QgsProcessingFileWidgetWrapper::parameterType() const
1514 {
1516 }
1517 
1518 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1519 {
1520  return new QgsProcessingFileWidgetWrapper( parameter, type );
1521 }
1522 
1523 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFileWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1524 {
1525  return new QgsProcessingFileParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1526 }
1527 
1528 
1529 
1530 
1531 //
1532 // QgsProcessingExpressionWidgetWrapper
1533 //
1534 
1535 QgsProcessingExpressionWidgetWrapper::QgsProcessingExpressionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1536  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1537 {
1538 
1539 }
1540 
1541 QWidget *QgsProcessingExpressionWidgetWrapper::createWidget()
1542 {
1543  const QgsProcessingParameterExpression *expParam = dynamic_cast< const QgsProcessingParameterExpression *>( parameterDefinition() );
1544  switch ( type() )
1545  {
1549  {
1550  if ( expParam->parentLayerParameterName().isEmpty() )
1551  {
1552  mExpLineEdit = new QgsExpressionLineEdit();
1553  mExpLineEdit->setToolTip( parameterDefinition()->toolTip() );
1554  mExpLineEdit->setExpressionDialogTitle( parameterDefinition()->description() );
1555  mExpLineEdit->registerExpressionContextGenerator( this );
1556  connect( mExpLineEdit, &QgsExpressionLineEdit::expressionChanged, this, [ = ]( const QString & )
1557  {
1558  emit widgetValueHasChanged( this );
1559  } );
1560  return mExpLineEdit;
1561  }
1562  else
1563  {
1564  mFieldExpWidget = new QgsFieldExpressionWidget();
1565  mFieldExpWidget->setToolTip( parameterDefinition()->toolTip() );
1566  mFieldExpWidget->setExpressionDialogTitle( parameterDefinition()->description() );
1567  mFieldExpWidget->registerExpressionContextGenerator( this );
1568  connect( mFieldExpWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString & ) >( &QgsFieldExpressionWidget::fieldChanged ), this, [ = ]( const QString & )
1569  {
1570  emit widgetValueHasChanged( this );
1571  } );
1572  return mFieldExpWidget;
1573  }
1574  }
1575  }
1576  return nullptr;
1577 }
1578 
1579 void QgsProcessingExpressionWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1580 {
1582  switch ( type() )
1583  {
1586  {
1587  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1588  {
1589  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterExpression * >( parameterDefinition() )->parentLayerParameterName() )
1590  {
1591  setParentLayerWrapperValue( wrapper );
1593  {
1594  setParentLayerWrapperValue( wrapper );
1595  } );
1596  break;
1597  }
1598  }
1599  break;
1600  }
1601 
1603  break;
1604  }
1605 }
1606 
1607 void QgsProcessingExpressionWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
1608 {
1609  // evaluate value to layer
1610  QgsProcessingContext *context = nullptr;
1611  std::unique_ptr< QgsProcessingContext > tmpContext;
1612  if ( mProcessingContextGenerator )
1613  context = mProcessingContextGenerator->processingContext();
1614 
1615  if ( !context )
1616  {
1617  tmpContext = qgis::make_unique< QgsProcessingContext >();
1618  context = tmpContext.get();
1619  }
1620 
1621  QgsVectorLayer *layer = QgsProcessingParameters::parameterAsVectorLayer( parentWrapper->parameterDefinition(), parentWrapper->parameterValue(), *context );
1622  if ( !layer )
1623  {
1624  if ( mFieldExpWidget )
1625  mFieldExpWidget->setLayer( nullptr );
1626  else if ( mExpLineEdit )
1627  mExpLineEdit->setLayer( nullptr );
1628  return;
1629  }
1630 
1631  // need to grab ownership of layer if required - otherwise layer may be deleted when context
1632  // goes out of scope
1633  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
1634  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::VectorLayer )
1635  {
1636  mParentLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
1637  layer = mParentLayer.get();
1638  }
1639  else
1640  {
1641  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
1642  }
1643 
1644  if ( mFieldExpWidget )
1645  mFieldExpWidget->setLayer( layer );
1646  else if ( mExpLineEdit )
1647  mExpLineEdit->setLayer( layer );
1648 }
1649 
1650 void QgsProcessingExpressionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1651 {
1652  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
1653  if ( mFieldExpWidget )
1654  mFieldExpWidget->setExpression( v );
1655  else if ( mExpLineEdit )
1656  mExpLineEdit->setExpression( v );
1657 }
1658 
1659 QVariant QgsProcessingExpressionWidgetWrapper::widgetValue() const
1660 {
1661  if ( mFieldExpWidget )
1662  return mFieldExpWidget->expression();
1663  else if ( mExpLineEdit )
1664  return mExpLineEdit->expression();
1665  else
1666  return QVariant();
1667 }
1668 
1669 QStringList QgsProcessingExpressionWidgetWrapper::compatibleParameterTypes() const
1670 {
1671  return QStringList()
1677 }
1678 
1679 QStringList QgsProcessingExpressionWidgetWrapper::compatibleOutputTypes() const
1680 {
1681  return QStringList()
1684 }
1685 
1686 QList<int> QgsProcessingExpressionWidgetWrapper::compatibleDataTypes() const
1687 {
1688  return QList< int >();
1689 }
1690 
1691 QString QgsProcessingExpressionWidgetWrapper::modelerExpressionFormatString() const
1692 {
1693  return tr( "string representation of an expression" );
1694 }
1695 
1696 const QgsVectorLayer *QgsProcessingExpressionWidgetWrapper::linkedVectorLayer() const
1697 {
1698  if ( mFieldExpWidget && mFieldExpWidget->layer() )
1699  return mFieldExpWidget->layer();
1700 
1702 }
1703 
1704 QString QgsProcessingExpressionWidgetWrapper::parameterType() const
1705 {
1707 }
1708 
1709 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExpressionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1710 {
1711  return new QgsProcessingExpressionWidgetWrapper( parameter, type );
1712 }
1713 
1714 
1715 
1716 //
1717 // QgsProcessingEnumPanelWidget
1718 //
1719 
1720 QgsProcessingEnumPanelWidget::QgsProcessingEnumPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param )
1721  : QWidget( parent )
1722  , mParam( param )
1723 {
1724  QHBoxLayout *hl = new QHBoxLayout();
1725  hl->setMargin( 0 );
1726  hl->setContentsMargins( 0, 0, 0, 0 );
1727 
1728  mLineEdit = new QLineEdit();
1729  mLineEdit->setEnabled( false );
1730  hl->addWidget( mLineEdit, 1 );
1731 
1732  mToolButton = new QToolButton();
1733  mToolButton->setText( QString( QChar( 0x2026 ) ) );
1734  hl->addWidget( mToolButton );
1735 
1736  setLayout( hl );
1737 
1738  if ( mParam )
1739  {
1740  mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
1741  }
1742 
1743  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingEnumPanelWidget::showDialog );
1744 }
1745 
1746 void QgsProcessingEnumPanelWidget::setValue( const QVariant &value )
1747 {
1748  if ( value.isValid() )
1749  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
1750  else
1751  mValue.clear();
1752 
1753  updateSummaryText();
1754  emit changed();
1755 }
1756 
1757 void QgsProcessingEnumPanelWidget::showDialog()
1758 {
1759  QVariantList availableOptions;
1760  if ( mParam )
1761  {
1762  availableOptions.reserve( mParam->options().size() );
1763  for ( int i = 0; i < mParam->options().count(); ++i )
1764  availableOptions << i;
1765  }
1766 
1767  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, nullptr );
1768  const QStringList options = mParam ? mParam->options() : QStringList();
1769  dlg.setValueFormatter( [options]( const QVariant & v ) -> QString
1770  {
1771  const int i = v.toInt();
1772  return options.size() > i ? options.at( i ) : QString();
1773  } );
1774  if ( dlg.exec() )
1775  {
1776  setValue( dlg.selectedOptions() );
1777  }
1778 }
1779 
1780 void QgsProcessingEnumPanelWidget::updateSummaryText()
1781 {
1782  if ( mParam )
1783  mLineEdit->setText( tr( "%1 options selected" ).arg( mValue.count() ) );
1784 }
1785 
1786 
1787 //
1788 // QgsProcessingEnumCheckboxPanelWidget
1789 //
1790 QgsProcessingEnumCheckboxPanelWidget::QgsProcessingEnumCheckboxPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param, int columns )
1791  : QWidget( parent )
1792  , mParam( param )
1793  , mButtonGroup( new QButtonGroup( this ) )
1794  , mColumns( columns )
1795 {
1796  mButtonGroup->setExclusive( !mParam->allowMultiple() );
1797 
1798  QGridLayout *l = new QGridLayout();
1799  l->setContentsMargins( 0, 0, 0, 0 );
1800  l->setMargin( 0 );
1801 
1802  int rows = static_cast< int >( std::ceil( mParam->options().count() / static_cast< double >( mColumns ) ) );
1803  for ( int i = 0; i < mParam->options().count(); ++i )
1804  {
1805  QAbstractButton *button = nullptr;
1806  if ( mParam->allowMultiple() )
1807  button = new QCheckBox( mParam->options().at( i ) );
1808  else
1809  button = new QRadioButton( mParam->options().at( i ) );
1810 
1811  connect( button, &QAbstractButton::toggled, this, [ = ]
1812  {
1813  if ( !mBlockChangedSignal )
1814  emit changed();
1815  } );
1816 
1817  mButtons.insert( i, button );
1818  mButtonGroup->addButton( button, i );
1819  l->addWidget( button, i % rows, i / rows );
1820  }
1821  l->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ), 0, mColumns );
1822  setLayout( l );
1823 
1824  if ( mParam->allowMultiple() )
1825  {
1826  setContextMenuPolicy( Qt::CustomContextMenu );
1827  connect( this, &QWidget::customContextMenuRequested, this, &QgsProcessingEnumCheckboxPanelWidget::showPopupMenu );
1828  }
1829 }
1830 
1831 QVariant QgsProcessingEnumCheckboxPanelWidget::value() const
1832 {
1833  if ( mParam->allowMultiple() )
1834  {
1835  QVariantList value;
1836  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
1837  {
1838  if ( it.value()->isChecked() )
1839  value.append( it.key() );
1840  }
1841  return value;
1842  }
1843  else
1844  {
1845  return mButtonGroup->checkedId() >= 0 ? mButtonGroup->checkedId() : QVariant();
1846  }
1847 }
1848 
1849 void QgsProcessingEnumCheckboxPanelWidget::setValue( const QVariant &value )
1850 {
1851  mBlockChangedSignal = true;
1852  if ( mParam->allowMultiple() )
1853  {
1854  QVariantList selected;
1855  if ( value.isValid() )
1856  selected = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
1857  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
1858  {
1859  it.value()->setChecked( selected.contains( it.key() ) );
1860  }
1861  }
1862  else
1863  {
1864  QVariant v = value;
1865  if ( v.type() == QVariant::List )
1866  v = v.toList().value( 0 );
1867  if ( mButtons.contains( v ) )
1868  mButtons.value( v )->setChecked( true );
1869  }
1870  mBlockChangedSignal = false;
1871  emit changed();
1872 }
1873 
1874 void QgsProcessingEnumCheckboxPanelWidget::showPopupMenu()
1875 {
1876  QMenu popupMenu;
1877  QAction *selectAllAction = new QAction( tr( "Select All" ), &popupMenu );
1878  connect( selectAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::selectAll );
1879  QAction *clearAllAction = new QAction( tr( "Clear Selection" ), &popupMenu );
1880  connect( clearAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::deselectAll );
1881  popupMenu.addAction( selectAllAction );
1882  popupMenu.addAction( clearAllAction );
1883  popupMenu.exec( QCursor::pos() );
1884 }
1885 
1886 void QgsProcessingEnumCheckboxPanelWidget::selectAll()
1887 {
1888  mBlockChangedSignal = true;
1889  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
1890  it.value()->setChecked( true );
1891  mBlockChangedSignal = false;
1892  emit changed();
1893 }
1894 
1895 void QgsProcessingEnumCheckboxPanelWidget::deselectAll()
1896 {
1897  mBlockChangedSignal = true;
1898  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
1899  it.value()->setChecked( false );
1900  mBlockChangedSignal = false;
1901  emit changed();
1902 }
1903 
1904 
1905 //
1906 // QgsProcessingEnumWidgetWrapper
1907 //
1908 
1909 QgsProcessingEnumWidgetWrapper::QgsProcessingEnumWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1910  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1911 {
1912 
1913 }
1914 
1915 QWidget *QgsProcessingEnumWidgetWrapper::createWidget()
1916 {
1917  const QgsProcessingParameterEnum *expParam = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
1918  switch ( type() )
1919  {
1921  {
1922  // checkbox panel only for use outside in standard gui!
1923  if ( expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "useCheckBoxes" ), false ).toBool() )
1924  {
1925  const int columns = expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "columns" ), 2 ).toInt();
1926  mCheckboxPanel = new QgsProcessingEnumCheckboxPanelWidget( nullptr, expParam, columns );
1927  mCheckboxPanel->setToolTip( parameterDefinition()->toolTip() );
1928  connect( mCheckboxPanel, &QgsProcessingEnumCheckboxPanelWidget::changed, this, [ = ]
1929  {
1930  emit widgetValueHasChanged( this );
1931  } );
1932  return mCheckboxPanel;
1933  }
1934  }
1935  FALLTHROUGH
1938  {
1939  if ( expParam->allowMultiple() )
1940  {
1941  mPanel = new QgsProcessingEnumPanelWidget( nullptr, expParam );
1942  mPanel->setToolTip( parameterDefinition()->toolTip() );
1943  connect( mPanel, &QgsProcessingEnumPanelWidget::changed, this, [ = ]
1944  {
1945  emit widgetValueHasChanged( this );
1946  } );
1947  return mPanel;
1948  }
1949  else
1950  {
1951  mComboBox = new QComboBox();
1952 
1954  mComboBox->addItem( tr( "[Not selected]" ), QVariant() );
1955  const QStringList options = expParam->options();
1956  for ( int i = 0; i < options.count(); ++i )
1957  mComboBox->addItem( options.at( i ), i );
1958 
1959  mComboBox->setToolTip( parameterDefinition()->toolTip() );
1960  connect( mComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, [ = ]( int )
1961  {
1962  emit widgetValueHasChanged( this );
1963  } );
1964  return mComboBox;
1965  }
1966  }
1967  }
1968  return nullptr;
1969 }
1970 
1971 void QgsProcessingEnumWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1972 {
1973  if ( mComboBox )
1974  {
1975  if ( !value.isValid() )
1976  mComboBox->setCurrentIndex( mComboBox->findData( QVariant() ) );
1977  else
1978  {
1979  const int v = QgsProcessingParameters::parameterAsEnum( parameterDefinition(), value, context );
1980  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
1981  }
1982  }
1983  else if ( mPanel || mCheckboxPanel )
1984  {
1985  QVariantList opts;
1986  if ( value.isValid() )
1987  {
1988  const QList< int > v = QgsProcessingParameters::parameterAsEnums( parameterDefinition(), value, context );
1989  opts.reserve( v.size() );
1990  for ( int i : v )
1991  opts << i;
1992  }
1993  if ( mPanel )
1994  mPanel->setValue( opts );
1995  else if ( mCheckboxPanel )
1996  mCheckboxPanel->setValue( opts );
1997  }
1998 }
1999 
2000 QVariant QgsProcessingEnumWidgetWrapper::widgetValue() const
2001 {
2002  if ( mComboBox )
2003  return mComboBox->currentData();
2004  else if ( mPanel )
2005  return mPanel->value();
2006  else if ( mCheckboxPanel )
2007  return mCheckboxPanel->value();
2008  else
2009  return QVariant();
2010 }
2011 
2012 QStringList QgsProcessingEnumWidgetWrapper::compatibleParameterTypes() const
2013 {
2014  return QStringList()
2018 }
2019 
2020 QStringList QgsProcessingEnumWidgetWrapper::compatibleOutputTypes() const
2021 {
2022  return QStringList()
2025 }
2026 
2027 QList<int> QgsProcessingEnumWidgetWrapper::compatibleDataTypes() const
2028 {
2029  return QList<int>();
2030 }
2031 
2032 QString QgsProcessingEnumWidgetWrapper::modelerExpressionFormatString() const
2033 {
2034  return tr( "selected option index (starting from 0), array of indices, or comma separated string of options (e.g. '1,3')" );
2035 }
2036 
2037 QString QgsProcessingEnumWidgetWrapper::parameterType() const
2038 {
2040 }
2041 
2042 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingEnumWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2043 {
2044  return new QgsProcessingEnumWidgetWrapper( parameter, type );
2045 }
2046 
2047 //
2048 // QgsProcessingLayoutWidgetWrapper
2049 //
2050 
2051 QgsProcessingLayoutWidgetWrapper::QgsProcessingLayoutWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2052  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2053 {
2054 
2055 }
2056 
2057 QWidget *QgsProcessingLayoutWidgetWrapper::createWidget()
2058 {
2059  const QgsProcessingParameterLayout *layoutParam = dynamic_cast< const QgsProcessingParameterLayout *>( parameterDefinition() );
2060  switch ( type() )
2061  {
2064  {
2065  // combobox only for use outside modeler!
2066  mComboBox = new QgsLayoutComboBox( nullptr, widgetContext().project() ? widgetContext().project()->layoutManager() : nullptr );
2068  mComboBox->setAllowEmptyLayout( true );
2069  mComboBox->setFilters( QgsLayoutManagerProxyModel::FilterPrintLayouts );
2070 
2071  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2072  connect( mComboBox, &QgsLayoutComboBox::layoutChanged, this, [ = ]( QgsMasterLayoutInterface * )
2073  {
2074  emit widgetValueHasChanged( this );
2075  } );
2076  return mComboBox;
2077  }
2078 
2080  {
2081  mLineEdit = new QLineEdit();
2082  mLineEdit->setToolTip( tr( "Name of an existing print layout" ) );
2083  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
2084  {
2085  emit widgetValueHasChanged( this );
2086  } );
2087  return mLineEdit;
2088  }
2089  }
2090  return nullptr;
2091 }
2092 
2093 void QgsProcessingLayoutWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2094 {
2095  if ( mComboBox )
2096  {
2097  if ( !value.isValid() )
2098  mComboBox->setCurrentLayout( nullptr );
2099  else
2100  {
2101  if ( QgsPrintLayout *l = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, context ) )
2102  mComboBox->setCurrentLayout( l );
2103  else
2104  mComboBox->setCurrentLayout( nullptr );
2105  }
2106  }
2107  else if ( mLineEdit )
2108  {
2109  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2110  mLineEdit->setText( v );
2111  }
2112 }
2113 
2114 QVariant QgsProcessingLayoutWidgetWrapper::widgetValue() const
2115 {
2116  if ( mComboBox )
2117  {
2118  const QgsMasterLayoutInterface *l = mComboBox->currentLayout();
2119  return l ? l->name() : QVariant();
2120  }
2121  else if ( mLineEdit )
2122  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
2123  else
2124  return QVariant();
2125 }
2126 
2127 QStringList QgsProcessingLayoutWidgetWrapper::compatibleParameterTypes() const
2128 {
2129  return QStringList()
2132 }
2133 
2134 QStringList QgsProcessingLayoutWidgetWrapper::compatibleOutputTypes() const
2135 {
2136  return QStringList()
2138 }
2139 
2140 QList<int> QgsProcessingLayoutWidgetWrapper::compatibleDataTypes() const
2141 {
2142  return QList<int>();
2143 }
2144 
2145 QString QgsProcessingLayoutWidgetWrapper::modelerExpressionFormatString() const
2146 {
2147  return tr( "string representing the name of an existing print layout" );
2148 }
2149 
2150 QString QgsProcessingLayoutWidgetWrapper::parameterType() const
2151 {
2153 }
2154 
2155 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2156 {
2157  return new QgsProcessingLayoutWidgetWrapper( parameter, type );
2158 }
2159 
2160 
2161 
2162 
2163 //
2164 // QgsProcessingLayoutItemWidgetWrapper
2165 //
2166 
2167 
2168 QgsProcessingLayoutItemParameterDefinitionWidget::QgsProcessingLayoutItemParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2169  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2170 {
2171  QVBoxLayout *vlayout = new QVBoxLayout();
2172  vlayout->setMargin( 0 );
2173  vlayout->setContentsMargins( 0, 0, 0, 0 );
2174 
2175  vlayout->addWidget( new QLabel( tr( "Parent layout" ) ) );
2176 
2177  mParentLayoutComboBox = new QComboBox();
2178  QString initialParent;
2179  if ( const QgsProcessingParameterLayoutItem *itemParam = dynamic_cast<const QgsProcessingParameterLayoutItem *>( definition ) )
2180  initialParent = itemParam->parentLayoutParameterName();
2181 
2182  if ( widgetContext.model() )
2183  {
2184  // populate combo box with other model input choices
2185  const QMap<QString, QgsProcessingModelParameter> components = widgetContext.model()->parameterComponents();
2186  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
2187  {
2188  if ( const QgsProcessingParameterLayout *definition = dynamic_cast< const QgsProcessingParameterLayout * >( widgetContext.model()->parameterDefinition( it.value().parameterName() ) ) )
2189  {
2190  mParentLayoutComboBox-> addItem( definition->description(), definition->name() );
2191  if ( !initialParent.isEmpty() && initialParent == definition->name() )
2192  {
2193  mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
2194  }
2195  }
2196  }
2197  }
2198 
2199  if ( mParentLayoutComboBox->count() == 0 && !initialParent.isEmpty() )
2200  {
2201  // if no parent candidates found, we just add the existing one as a placeholder
2202  mParentLayoutComboBox->addItem( initialParent, initialParent );
2203  mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
2204  }
2205 
2206  vlayout->addWidget( mParentLayoutComboBox );
2207  setLayout( vlayout );
2208 }
2209 QgsProcessingParameterDefinition *QgsProcessingLayoutItemParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2210 {
2211  auto param = qgis::make_unique< QgsProcessingParameterLayoutItem >( name, description, QVariant(), mParentLayoutComboBox->currentData().toString() );
2212  param->setFlags( flags );
2213  return param.release();
2214 }
2215 
2216 
2217 QgsProcessingLayoutItemWidgetWrapper::QgsProcessingLayoutItemWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2218  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2219 {
2220 
2221 }
2222 
2223 QWidget *QgsProcessingLayoutItemWidgetWrapper::createWidget()
2224 {
2225  const QgsProcessingParameterLayoutItem *layoutParam = dynamic_cast< const QgsProcessingParameterLayoutItem *>( parameterDefinition() );
2226  switch ( type() )
2227  {
2230  {
2231  // combobox only for use outside modeler!
2232  mComboBox = new QgsLayoutItemComboBox( nullptr, nullptr );
2234  mComboBox->setAllowEmptyItem( true );
2235  if ( layoutParam->itemType() >= 0 )
2236  mComboBox->setItemType( static_cast< QgsLayoutItemRegistry::ItemType >( layoutParam->itemType() ) );
2237 
2238  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2239  connect( mComboBox, &QgsLayoutItemComboBox::itemChanged, this, [ = ]( QgsLayoutItem * )
2240  {
2241  emit widgetValueHasChanged( this );
2242  } );
2243  return mComboBox;
2244  }
2245 
2247  {
2248  mLineEdit = new QLineEdit();
2249  mLineEdit->setToolTip( tr( "UUID or ID of an existing print layout item" ) );
2250  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
2251  {
2252  emit widgetValueHasChanged( this );
2253  } );
2254  return mLineEdit;
2255  }
2256  }
2257  return nullptr;
2258 }
2259 
2260 void QgsProcessingLayoutItemWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
2261 {
2263  switch ( type() )
2264  {
2267  {
2268  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
2269  {
2270  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterLayoutItem * >( parameterDefinition() )->parentLayoutParameterName() )
2271  {
2272  setLayoutParameterValue( wrapper->parameterValue() );
2274  {
2275  setLayoutParameterValue( wrapper->parameterValue() );
2276  } );
2277  break;
2278  }
2279  }
2280  break;
2281  }
2282 
2284  break;
2285  }
2286 }
2287 
2288 void QgsProcessingLayoutItemWidgetWrapper::setLayoutParameterValue( const QVariant &value )
2289 {
2290  QgsPrintLayout *layout = nullptr;
2291 
2292  // evaluate value to layout
2293  QgsProcessingContext *context = nullptr;
2294  std::unique_ptr< QgsProcessingContext > tmpContext;
2295  if ( mProcessingContextGenerator )
2296  context = mProcessingContextGenerator->processingContext();
2297 
2298  if ( !context )
2299  {
2300  tmpContext = qgis::make_unique< QgsProcessingContext >();
2301  context = tmpContext.get();
2302  }
2303 
2304  layout = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, *context );
2305  setLayout( layout );
2306 }
2307 
2308 void QgsProcessingLayoutItemWidgetWrapper::setLayout( QgsPrintLayout *layout )
2309 {
2310  if ( mComboBox )
2311  mComboBox->setCurrentLayout( layout );
2312 }
2313 
2314 void QgsProcessingLayoutItemWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2315 {
2316  if ( mComboBox )
2317  {
2318  if ( !value.isValid() )
2319  mComboBox->setItem( nullptr );
2320  else
2321  {
2322  QgsLayoutItem *item = QgsProcessingParameters::parameterAsLayoutItem( parameterDefinition(), value, context, qobject_cast< QgsPrintLayout * >( mComboBox->currentLayout() ) );
2323  mComboBox->setItem( item );
2324  }
2325  }
2326  else if ( mLineEdit )
2327  {
2328  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2329  mLineEdit->setText( v );
2330  }
2331 }
2332 
2333 QVariant QgsProcessingLayoutItemWidgetWrapper::widgetValue() const
2334 {
2335  if ( mComboBox )
2336  {
2337  const QgsLayoutItem *i = mComboBox->currentItem();
2338  return i ? i->uuid() : QVariant();
2339  }
2340  else if ( mLineEdit )
2341  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
2342  else
2343  return QVariant();
2344 }
2345 
2346 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleParameterTypes() const
2347 {
2348  return QStringList()
2351 }
2352 
2353 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleOutputTypes() const
2354 {
2355  return QStringList()
2357 }
2358 
2359 QList<int> QgsProcessingLayoutItemWidgetWrapper::compatibleDataTypes() const
2360 {
2361  return QList<int>();
2362 }
2363 
2364 QString QgsProcessingLayoutItemWidgetWrapper::modelerExpressionFormatString() const
2365 {
2366  return tr( "string representing the UUID or ID of an existing print layout item" );
2367 }
2368 
2369 QString QgsProcessingLayoutItemWidgetWrapper::parameterType() const
2370 {
2372 }
2373 
2374 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutItemWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2375 {
2376  return new QgsProcessingLayoutItemWidgetWrapper( parameter, type );
2377 }
2378 
2379 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingLayoutItemWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2380 {
2381  return new QgsProcessingLayoutItemParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2382 }
2383 
2384 //
2385 // QgsProcessingPointMapTool
2386 //
2387 
2388 QgsProcessingPointMapTool::QgsProcessingPointMapTool( QgsMapCanvas *canvas )
2389  : QgsMapTool( canvas )
2390 {
2391  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::CapturePoint ) );
2392  mSnapIndicator.reset( new QgsSnapIndicator( canvas ) );
2393 }
2394 
2395 QgsProcessingPointMapTool::~QgsProcessingPointMapTool() = default;
2396 
2397 void QgsProcessingPointMapTool::deactivate()
2398 {
2399  mSnapIndicator->setMatch( QgsPointLocator::Match() );
2401 }
2402 
2403 void QgsProcessingPointMapTool::canvasMoveEvent( QgsMapMouseEvent *e )
2404 {
2405  e->snapPoint();
2406  mSnapIndicator->setMatch( e->mapPointMatch() );
2407 }
2408 
2409 void QgsProcessingPointMapTool::canvasPressEvent( QgsMapMouseEvent *e )
2410 {
2411  if ( e->button() == Qt::LeftButton )
2412  {
2413  QgsPointXY point = e->snapPoint();
2414  emit clicked( point );
2415  emit complete();
2416  }
2417 }
2418 
2419 void QgsProcessingPointMapTool::keyPressEvent( QKeyEvent *e )
2420 {
2421  if ( e->key() == Qt::Key_Escape )
2422  {
2423 
2424  // Override default shortcut management in MapCanvas
2425  e->ignore();
2426  emit complete();
2427  }
2428 }
2429 
2430 
2431 
2432 //
2433 // QgsProcessingPointPanel
2434 //
2435 
2436 QgsProcessingPointPanel::QgsProcessingPointPanel( QWidget *parent )
2437  : QWidget( parent )
2438 {
2439  QHBoxLayout *l = new QHBoxLayout();
2440  l->setContentsMargins( 0, 0, 0, 0 );
2441  l->setMargin( 0 );
2442  mLineEdit = new QgsFilterLineEdit( );
2443  mLineEdit->setShowClearButton( false );
2444  l->addWidget( mLineEdit, 1 );
2445  mButton = new QToolButton();
2446  mButton->setText( QString( QChar( 0x2026 ) ) );
2447  l->addWidget( mButton );
2448  setLayout( l );
2449 
2450  connect( mLineEdit, &QLineEdit::textChanged, this, &QgsProcessingPointPanel::changed );
2451  connect( mButton, &QToolButton::clicked, this, &QgsProcessingPointPanel::selectOnCanvas );
2452  mButton->setVisible( false );
2453 }
2454 
2455 void QgsProcessingPointPanel::setMapCanvas( QgsMapCanvas *canvas )
2456 {
2457  mCanvas = canvas;
2458  mButton->setVisible( true );
2459 
2460  mCrs = canvas->mapSettings().destinationCrs();
2461  mTool = qgis::make_unique< QgsProcessingPointMapTool >( mCanvas );
2462  connect( mTool.get(), &QgsProcessingPointMapTool::clicked, this, &QgsProcessingPointPanel::updatePoint );
2463  connect( mTool.get(), &QgsProcessingPointMapTool::complete, this, &QgsProcessingPointPanel::pointPicked );
2464 }
2465 
2466 void QgsProcessingPointPanel::setAllowNull( bool allowNull )
2467 {
2468  mLineEdit->setShowClearButton( allowNull );
2469 }
2470 
2471 QVariant QgsProcessingPointPanel::value() const
2472 {
2473  return mLineEdit->showClearButton() && mLineEdit->text().trimmed().isEmpty() ? QVariant() : QVariant( mLineEdit->text() );
2474 }
2475 
2476 void QgsProcessingPointPanel::clear()
2477 {
2478  mLineEdit->clear();
2479 }
2480 
2481 void QgsProcessingPointPanel::setValue( const QgsPointXY &point, const QgsCoordinateReferenceSystem &crs )
2482 {
2483  QString newText = QStringLiteral( "%1,%2" )
2484  .arg( QString::number( point.x(), 'f' ),
2485  QString::number( point.y(), 'f' ) );
2486 
2487  mCrs = crs;
2488  if ( mCrs.isValid() )
2489  {
2490  newText += QStringLiteral( " [%1]" ).arg( mCrs.authid() );
2491  }
2492  mLineEdit->setText( newText );
2493 }
2494 
2495 void QgsProcessingPointPanel::selectOnCanvas()
2496 {
2497  if ( !mCanvas )
2498  return;
2499 
2500  mPrevTool = mCanvas->mapTool();
2501  mCanvas->setMapTool( mTool.get() );
2502 
2503  emit toggleDialogVisibility( false );
2504 }
2505 
2506 void QgsProcessingPointPanel::updatePoint( const QgsPointXY &point )
2507 {
2508  setValue( point, mCanvas->mapSettings().destinationCrs() );
2509 }
2510 
2511 void QgsProcessingPointPanel::pointPicked()
2512 {
2513  if ( !mCanvas )
2514  return;
2515 
2516  mCanvas->setMapTool( mPrevTool );
2517 
2518  emit toggleDialogVisibility( true );
2519 }
2520 
2521 
2522 
2523 
2524 //
2525 // QgsProcessingPointWidgetWrapper
2526 //
2527 
2528 QgsProcessingPointWidgetWrapper::QgsProcessingPointWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2529  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2530 {
2531 
2532 }
2533 
2534 QWidget *QgsProcessingPointWidgetWrapper::createWidget()
2535 {
2536  const QgsProcessingParameterPoint *pointParam = dynamic_cast< const QgsProcessingParameterPoint *>( parameterDefinition() );
2537  switch ( type() )
2538  {
2541  {
2542  mPanel = new QgsProcessingPointPanel( nullptr );
2543  if ( widgetContext().mapCanvas() )
2544  mPanel->setMapCanvas( widgetContext().mapCanvas() );
2545 
2547  mPanel->setAllowNull( true );
2548 
2549  mPanel->setToolTip( parameterDefinition()->toolTip() );
2550 
2551  connect( mPanel, &QgsProcessingPointPanel::changed, this, [ = ]
2552  {
2553  emit widgetValueHasChanged( this );
2554  } );
2555 
2556  if ( mDialog )
2557  setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
2558  return mPanel;
2559  }
2560 
2562  {
2563  mLineEdit = new QLineEdit();
2564  mLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
2565  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
2566  {
2567  emit widgetValueHasChanged( this );
2568  } );
2569  return mLineEdit;
2570  }
2571  }
2572  return nullptr;
2573 }
2574 
2575 void QgsProcessingPointWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
2576 {
2578  if ( mPanel && context.mapCanvas() )
2579  mPanel->setMapCanvas( context.mapCanvas() );
2580 }
2581 
2582 void QgsProcessingPointWidgetWrapper::setDialog( QDialog *dialog )
2583 {
2584  mDialog = dialog;
2585  if ( mPanel )
2586  {
2587  connect( mPanel, &QgsProcessingPointPanel::toggleDialogVisibility, mDialog, [ = ]( bool visible )
2588  {
2589  if ( !visible )
2590  mDialog->showMinimized();
2591  else
2592  {
2593  mDialog->showNormal();
2594  mDialog->raise();
2595  mDialog->activateWindow();
2596  }
2597  } );
2598  }
2600 }
2601 
2602 void QgsProcessingPointWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2603 {
2604  if ( mPanel )
2605  {
2606  if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
2607  mPanel->clear();
2608  else
2609  {
2610  QgsPointXY p = QgsProcessingParameters::parameterAsPoint( parameterDefinition(), value, context );
2611  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
2612  mPanel->setValue( p, crs );
2613  }
2614  }
2615  else if ( mLineEdit )
2616  {
2617  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2618  mLineEdit->setText( v );
2619  }
2620 }
2621 
2622 QVariant QgsProcessingPointWidgetWrapper::widgetValue() const
2623 {
2624  if ( mPanel )
2625  {
2626  return mPanel->value();
2627  }
2628  else if ( mLineEdit )
2629  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
2630  else
2631  return QVariant();
2632 }
2633 
2634 QStringList QgsProcessingPointWidgetWrapper::compatibleParameterTypes() const
2635 {
2636  return QStringList()
2639 }
2640 
2641 QStringList QgsProcessingPointWidgetWrapper::compatibleOutputTypes() const
2642 {
2643  return QStringList()
2645 }
2646 
2647 QList<int> QgsProcessingPointWidgetWrapper::compatibleDataTypes() const
2648 {
2649  return QList<int>();
2650 }
2651 
2652 QString QgsProcessingPointWidgetWrapper::modelerExpressionFormatString() const
2653 {
2654  return tr( "string of the format 'x,y' or a geometry value (centroid is used)" );
2655 }
2656 
2657 QString QgsProcessingPointWidgetWrapper::parameterType() const
2658 {
2660 }
2661 
2662 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2663 {
2664  return new QgsProcessingPointWidgetWrapper( parameter, type );
2665 }
2666 
2667 
2668 
2669 
2670 //
2671 // QgsProcessingColorWidgetWrapper
2672 //
2673 
2674 
2675 QgsProcessingColorParameterDefinitionWidget::QgsProcessingColorParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2676  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2677 {
2678  QVBoxLayout *vlayout = new QVBoxLayout();
2679  vlayout->setMargin( 0 );
2680  vlayout->setContentsMargins( 0, 0, 0, 0 );
2681 
2682  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
2683 
2684  mDefaultColorButton = new QgsColorButton();
2685  mDefaultColorButton->setShowNull( true );
2686  mAllowOpacity = new QCheckBox( tr( "Allow opacity control" ) );
2687 
2688  if ( const QgsProcessingParameterColor *colorParam = dynamic_cast<const QgsProcessingParameterColor *>( definition ) )
2689  {
2690  const QColor c = QgsProcessingParameters::parameterAsColor( colorParam, colorParam->defaultValue(), context );
2691  if ( !c.isValid() )
2692  mDefaultColorButton->setToNull();
2693  else
2694  mDefaultColorButton->setColor( c );
2695  mAllowOpacity->setChecked( colorParam->opacityEnabled() );
2696  }
2697  else
2698  {
2699  mDefaultColorButton->setToNull();
2700  mAllowOpacity->setChecked( true );
2701  }
2702 
2703  vlayout->addWidget( mDefaultColorButton );
2704  vlayout->addWidget( mAllowOpacity );
2705  setLayout( vlayout );
2706 }
2707 
2708 QgsProcessingParameterDefinition *QgsProcessingColorParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2709 {
2710  auto param = qgis::make_unique< QgsProcessingParameterColor >( name, description, mDefaultColorButton->color(), mAllowOpacity->isChecked() );
2711  param->setFlags( flags );
2712  return param.release();
2713 }
2714 
2715 QgsProcessingColorWidgetWrapper::QgsProcessingColorWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2716  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2717 {
2718 
2719 }
2720 
2721 QWidget *QgsProcessingColorWidgetWrapper::createWidget()
2722 {
2723  const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor *>( parameterDefinition() );
2724  switch ( type() )
2725  {
2729  {
2730  mColorButton = new QgsColorButton( nullptr );
2731  mColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
2732 
2734  mColorButton->setShowNull( true );
2735 
2736  mColorButton->setAllowOpacity( colorParam->opacityEnabled() );
2737  mColorButton->setToolTip( parameterDefinition()->toolTip() );
2738  mColorButton->setColorDialogTitle( parameterDefinition()->description() );
2739  if ( colorParam->defaultValue().value< QColor >().isValid() )
2740  {
2741  mColorButton->setDefaultColor( colorParam->defaultValue().value< QColor >() );
2742  }
2743 
2744  connect( mColorButton, &QgsColorButton::colorChanged, this, [ = ]
2745  {
2746  emit widgetValueHasChanged( this );
2747  } );
2748 
2749  return mColorButton;
2750  }
2751  }
2752  return nullptr;
2753 }
2754 
2755 void QgsProcessingColorWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2756 {
2757  if ( mColorButton )
2758  {
2759  if ( !value.isValid() ||
2760  ( value.type() == QVariant::String && value.toString().isEmpty() )
2761  || ( value.type() == QVariant::Color && !value.value< QColor >().isValid() ) )
2762  mColorButton->setToNull();
2763  else
2764  {
2765  const QColor c = QgsProcessingParameters::parameterAsColor( parameterDefinition(), value, context );
2766  if ( !c.isValid() && mColorButton->showNull() )
2767  mColorButton->setToNull();
2768  else
2769  mColorButton->setColor( c );
2770  }
2771  }
2772 }
2773 
2774 QVariant QgsProcessingColorWidgetWrapper::widgetValue() const
2775 {
2776  if ( mColorButton )
2777  return mColorButton->isNull() ? QVariant() : mColorButton->color();
2778  else
2779  return QVariant();
2780 }
2781 
2782 QStringList QgsProcessingColorWidgetWrapper::compatibleParameterTypes() const
2783 {
2784  return QStringList()
2787 }
2788 
2789 QStringList QgsProcessingColorWidgetWrapper::compatibleOutputTypes() const
2790 {
2791  return QStringList()
2793 }
2794 
2795 QList<int> QgsProcessingColorWidgetWrapper::compatibleDataTypes() const
2796 {
2797  return QList<int>();
2798 }
2799 
2800 QString QgsProcessingColorWidgetWrapper::modelerExpressionFormatString() const
2801 {
2802  return tr( "color style string, e.g. #ff0000 or 255,0,0" );
2803 }
2804 
2805 QString QgsProcessingColorWidgetWrapper::parameterType() const
2806 {
2808 }
2809 
2810 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingColorWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2811 {
2812  return new QgsProcessingColorWidgetWrapper( parameter, type );
2813 }
2814 
2815 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingColorWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2816 {
2817  return new QgsProcessingColorParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2818 }
2819 
2820 
2821 //
2822 // QgsProcessingCoordinateOperationWidgetWrapper
2823 //
2824 
2825 QgsProcessingCoordinateOperationParameterDefinitionWidget::QgsProcessingCoordinateOperationParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2826  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2827 {
2828  QVBoxLayout *vlayout = new QVBoxLayout();
2829  vlayout->setMargin( 0 );
2830  vlayout->setContentsMargins( 0, 0, 0, 0 );
2831 
2832  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
2833 
2834  mDefaultLineEdit = new QLineEdit();
2835  if ( const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
2836  mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( coordParam, coordParam->defaultValue(), context ) );
2837  vlayout->addWidget( mDefaultLineEdit );
2838 
2839  mSourceParamComboBox = new QComboBox();
2840  mDestParamComboBox = new QComboBox();
2841  QString initialSource;
2842  QString initialDest;
2843  QgsCoordinateReferenceSystem sourceCrs;
2845  if ( const QgsProcessingParameterCoordinateOperation *itemParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
2846  {
2847  initialSource = itemParam->sourceCrsParameterName();
2848  initialDest = itemParam->destinationCrsParameterName();
2849  sourceCrs = QgsProcessingUtils::variantToCrs( itemParam->sourceCrs(), context );
2850  destCrs = QgsProcessingUtils::variantToCrs( itemParam->destinationCrs(), context );
2851  }
2852 
2853  mSourceParamComboBox->addItem( QString(), QString() );
2854  mDestParamComboBox->addItem( QString(), QString() );
2855  if ( widgetContext.model() )
2856  {
2857  // populate combo box with other model input choices
2858  const QMap<QString, QgsProcessingModelParameter> components = widgetContext.model()->parameterComponents();
2859  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
2860  {
2861  if ( it->parameterName() == definition->name() )
2862  continue;
2863 
2864  // TODO - we should probably filter this list?
2865  mSourceParamComboBox->addItem( it->parameterName(), it->parameterName() );
2866  mDestParamComboBox->addItem( it->parameterName(), it->parameterName() );
2867  if ( !initialSource.isEmpty() && initialSource == it->parameterName() )
2868  {
2869  mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
2870  }
2871  if ( !initialDest.isEmpty() && initialDest == it->parameterName() )
2872  {
2873  mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
2874  }
2875  }
2876  }
2877 
2878  if ( mSourceParamComboBox->count() == 1 && !initialSource.isEmpty() )
2879  {
2880  // if no source candidates found, we just add the existing one as a placeholder
2881  mSourceParamComboBox->addItem( initialSource, initialSource );
2882  mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
2883  }
2884  if ( mDestParamComboBox->count() == 1 && !initialDest.isEmpty() )
2885  {
2886  // if no dest candidates found, we just add the existing one as a placeholder
2887  mDestParamComboBox->addItem( initialDest, initialDest );
2888  mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
2889  }
2890 
2891  vlayout->addWidget( new QLabel( tr( "Source CRS parameter" ) ) );
2892  vlayout->addWidget( mSourceParamComboBox );
2893  vlayout->addWidget( new QLabel( tr( "Destination CRS parameter" ) ) );
2894  vlayout->addWidget( mDestParamComboBox );
2895 
2896  mStaticSourceWidget = new QgsProjectionSelectionWidget();
2897  mStaticSourceWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
2898  mStaticSourceWidget->setCrs( sourceCrs );
2899  mStaticDestWidget = new QgsProjectionSelectionWidget();
2900  mStaticDestWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
2901  mStaticDestWidget->setCrs( destCrs );
2902 
2903  vlayout->addWidget( new QLabel( tr( "Static source CRS" ) ) );
2904  vlayout->addWidget( mStaticSourceWidget );
2905  vlayout->addWidget( new QLabel( tr( "Static destination CRS" ) ) );
2906  vlayout->addWidget( mStaticDestWidget );
2907 
2908  setLayout( vlayout );
2909 }
2910 
2911 QgsProcessingParameterDefinition *QgsProcessingCoordinateOperationParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2912 {
2913  auto param = qgis::make_unique< QgsProcessingParameterCoordinateOperation >( name, description, mDefaultLineEdit->text(),
2914  mSourceParamComboBox->currentText(),
2915  mDestParamComboBox->currentText(),
2916  mStaticSourceWidget->crs().isValid() ? QVariant::fromValue( mStaticSourceWidget->crs() ) : QVariant(),
2917  mStaticDestWidget->crs().isValid() ? QVariant::fromValue( mStaticDestWidget->crs() ) : QVariant() );
2918  param->setFlags( flags );
2919  return param.release();
2920 }
2921 
2922 QgsProcessingCoordinateOperationWidgetWrapper::QgsProcessingCoordinateOperationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2923  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2924 {
2925 
2926 }
2927 
2928 QWidget *QgsProcessingCoordinateOperationWidgetWrapper::createWidget()
2929 {
2930  const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast< const QgsProcessingParameterCoordinateOperation *>( parameterDefinition() );
2932  mSourceCrs = QgsProcessingUtils::variantToCrs( coordParam->sourceCrs(), c );
2933  mDestCrs = QgsProcessingUtils::variantToCrs( coordParam->destinationCrs(), c );
2934  switch ( type() )
2935  {
2937  {
2938  mOperationWidget = new QgsCoordinateOperationWidget( nullptr );
2939  mOperationWidget->setShowMakeDefault( false );
2940  mOperationWidget->setShowFallbackOption( false );
2941  mOperationWidget->setToolTip( parameterDefinition()->toolTip() );
2942  mOperationWidget->setSourceCrs( mSourceCrs );
2943  mOperationWidget->setDestinationCrs( mDestCrs );
2944  mOperationWidget->setMapCanvas( mCanvas );
2945  if ( !coordParam->defaultValue().toString().isEmpty() )
2946  {
2948  deets.proj = coordParam->defaultValue().toString();
2949  mOperationWidget->setSelectedOperation( deets );
2950  }
2951 
2952  connect( mOperationWidget, &QgsCoordinateOperationWidget::operationChanged, this, [ = ]
2953  {
2954  emit widgetValueHasChanged( this );
2955  } );
2956 
2957  return mOperationWidget;
2958  }
2959 
2962  {
2963  mLineEdit = new QLineEdit();
2964  QHBoxLayout *layout = new QHBoxLayout();
2965  layout->addWidget( mLineEdit, 1 );
2966  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
2967  {
2968  emit widgetValueHasChanged( this );
2969  } );
2970 
2971  QToolButton *button = new QToolButton();
2972  button->setText( QString( QChar( 0x2026 ) ) );
2973  connect( button, &QToolButton::clicked, this, [ = ]
2974  {
2975  QgsDatumTransformDialog dlg( mSourceCrs, mDestCrs, false, false, false, qMakePair( -1, -1 ), button, nullptr, mLineEdit->text(), mCanvas );
2976  if ( dlg.exec() )
2977  {
2978  mLineEdit->setText( dlg.selectedDatumTransform().proj );
2979  emit widgetValueHasChanged( this );
2980  }
2981  } );
2982  layout->addWidget( button );
2983 
2984  QWidget *w = new QWidget();
2985  layout->setMargin( 0 );
2986  layout->setContentsMargins( 0, 0, 0, 0 );
2987  w->setLayout( layout );
2988  return w;
2989  }
2990 
2991  }
2992  return nullptr;
2993 }
2994 
2995 void QgsProcessingCoordinateOperationWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
2996 {
2998  switch ( type() )
2999  {
3002  {
3003  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
3004  {
3005  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterCoordinateOperation * >( parameterDefinition() )->sourceCrsParameterName() )
3006  {
3007  setSourceCrsParameterValue( wrapper->parameterValue() );
3009  {
3010  setSourceCrsParameterValue( wrapper->parameterValue() );
3011  } );
3012  }
3013  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterCoordinateOperation * >( parameterDefinition() )->destinationCrsParameterName() )
3014  {
3015  setDestinationCrsParameterValue( wrapper->parameterValue() );
3017  {
3018  setDestinationCrsParameterValue( wrapper->parameterValue() );
3019  } );
3020  }
3021  }
3022  break;
3023  }
3024 
3026  break;
3027  }
3028 }
3029 
3030 void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
3031 {
3032  mCanvas = context.mapCanvas();
3033  if ( mOperationWidget )
3034  mOperationWidget->setMapCanvas( context.mapCanvas() );
3035 }
3036 
3037 void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
3038 {
3039  if ( mOperationWidget )
3040  {
3041  if ( !value.isValid() ||
3042  ( value.type() == QVariant::String ) )
3043  {
3045  deets.proj = value.toString();
3046  mOperationWidget->setSelectedOperation( deets );
3047  }
3048  }
3049  if ( mLineEdit )
3050  {
3051  if ( !value.isValid() ||
3052  ( value.type() == QVariant::String ) )
3053  {
3054  mLineEdit->setText( value.toString() );
3055  }
3056  }
3057 }
3058 
3059 QVariant QgsProcessingCoordinateOperationWidgetWrapper::widgetValue() const
3060 {
3061  if ( mOperationWidget )
3062  return mOperationWidget->selectedOperation().proj;
3063  else if ( mLineEdit )
3064  return mLineEdit->text();
3065  else
3066  return QVariant();
3067 }
3068 
3069 QStringList QgsProcessingCoordinateOperationWidgetWrapper::compatibleParameterTypes() const
3070 {
3071  return QStringList()
3074 }
3075 
3076 QStringList QgsProcessingCoordinateOperationWidgetWrapper::compatibleOutputTypes() const
3077 {
3078  return QStringList()
3080 }
3081 
3082 QList<int> QgsProcessingCoordinateOperationWidgetWrapper::compatibleDataTypes() const
3083 {
3084  return QList<int>();
3085 }
3086 
3087 QString QgsProcessingCoordinateOperationWidgetWrapper::modelerExpressionFormatString() const
3088 {
3089  return tr( "Proj coordinate operation string, e.g. '+proj=pipeline +step +inv...'" );
3090 }
3091 
3092 void QgsProcessingCoordinateOperationWidgetWrapper::setSourceCrsParameterValue( const QVariant &value )
3093 {
3094  QgsProcessingContext *context = nullptr;
3095  std::unique_ptr< QgsProcessingContext > tmpContext;
3096  if ( mProcessingContextGenerator )
3097  context = mProcessingContextGenerator->processingContext();
3098 
3099  if ( !context )
3100  {
3101  tmpContext = qgis::make_unique< QgsProcessingContext >();
3102  context = tmpContext.get();
3103  }
3104 
3105  mSourceCrs = QgsProcessingUtils::variantToCrs( value, *context );
3106  if ( mOperationWidget )
3107  {
3108  mOperationWidget->setSourceCrs( mSourceCrs );
3109  mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
3110  }
3111 }
3112 
3113 void QgsProcessingCoordinateOperationWidgetWrapper::setDestinationCrsParameterValue( const QVariant &value )
3114 {
3115  QgsProcessingContext *context = nullptr;
3116  std::unique_ptr< QgsProcessingContext > tmpContext;
3117  if ( mProcessingContextGenerator )
3118  context = mProcessingContextGenerator->processingContext();
3119 
3120  if ( !context )
3121  {
3122  tmpContext = qgis::make_unique< QgsProcessingContext >();
3123  context = tmpContext.get();
3124  }
3125 
3126  mDestCrs = QgsProcessingUtils::variantToCrs( value, *context );
3127  if ( mOperationWidget )
3128  {
3129  mOperationWidget->setDestinationCrs( mDestCrs );
3130  mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
3131  }
3132 }
3133 
3134 QString QgsProcessingCoordinateOperationWidgetWrapper::parameterType() const
3135 {
3137 }
3138 
3139 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCoordinateOperationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3140 {
3141  return new QgsProcessingCoordinateOperationWidgetWrapper( parameter, type );
3142 }
3143 
3144 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingCoordinateOperationWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3145 {
3146  return new QgsProcessingCoordinateOperationParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3147 }
3148 
3149 
3150 
3151 //
3152 // QgsProcessingFieldPanelWidget
3153 //
3154 
3155 QgsProcessingFieldPanelWidget::QgsProcessingFieldPanelWidget( QWidget *parent, const QgsProcessingParameterField *param )
3156  : QWidget( parent )
3157  , mParam( param )
3158 {
3159  QHBoxLayout *hl = new QHBoxLayout();
3160  hl->setMargin( 0 );
3161  hl->setContentsMargins( 0, 0, 0, 0 );
3162 
3163  mLineEdit = new QLineEdit();
3164  mLineEdit->setEnabled( false );
3165  hl->addWidget( mLineEdit, 1 );
3166 
3167  mToolButton = new QToolButton();
3168  mToolButton->setText( QString( QChar( 0x2026 ) ) );
3169  hl->addWidget( mToolButton );
3170 
3171  setLayout( hl );
3172 
3173  if ( mParam )
3174  {
3175  mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
3176  }
3177 
3178  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingFieldPanelWidget::showDialog );
3179 }
3180 
3181 void QgsProcessingFieldPanelWidget::setFields( const QgsFields &fields )
3182 {
3183  mFields = fields;
3184 }
3185 
3186 void QgsProcessingFieldPanelWidget::setValue( const QVariant &value )
3187 {
3188  if ( value.isValid() )
3189  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
3190  else
3191  mValue.clear();
3192 
3193  updateSummaryText();
3194  emit changed();
3195 }
3196 
3197 void QgsProcessingFieldPanelWidget::showDialog()
3198 {
3199  QVariantList availableOptions;
3200  QStringList fieldNames;
3201  availableOptions.reserve( mFields.size() );
3202  for ( const QgsField &field : qgis::as_const( mFields ) )
3203  {
3204  availableOptions << field.name();
3205  }
3206 
3207  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, nullptr );
3208  dlg.setValueFormatter( []( const QVariant & v ) -> QString
3209  {
3210  return v.toString();
3211  } );
3212  if ( dlg.exec() )
3213  {
3214  setValue( dlg.selectedOptions() );
3215  }
3216 }
3217 
3218 void QgsProcessingFieldPanelWidget::updateSummaryText()
3219 {
3220  if ( mParam )
3221  mLineEdit->setText( tr( "%1 options selected" ).arg( mValue.count() ) );
3222 }
3223 
3224 
3225 //
3226 // QgsProcessingFieldWidgetWrapper
3227 //
3228 
3229 QgsProcessingFieldWidgetWrapper::QgsProcessingFieldWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3230  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3231 {
3232 
3233 }
3234 
3235 QWidget *QgsProcessingFieldWidgetWrapper::createWidget()
3236 {
3237  const QgsProcessingParameterField *fieldParam = dynamic_cast< const QgsProcessingParameterField *>( parameterDefinition() );
3238  switch ( type() )
3239  {
3242  {
3243  if ( fieldParam->allowMultiple() )
3244  {
3245  mPanel = new QgsProcessingFieldPanelWidget( nullptr, fieldParam );
3246  mPanel->setToolTip( parameterDefinition()->toolTip() );
3247  connect( mPanel, &QgsProcessingFieldPanelWidget::changed, this, [ = ]
3248  {
3249  emit widgetValueHasChanged( this );
3250  } );
3251  return mPanel;
3252  }
3253  else
3254  {
3255  mComboBox = new QgsFieldComboBox();
3256  mComboBox->setAllowEmptyFieldName( fieldParam->flags() & QgsProcessingParameterDefinition::FlagOptional );
3257 
3258  if ( fieldParam->dataType() == QgsProcessingParameterField::Numeric )
3259  mComboBox->setFilters( QgsFieldProxyModel::Numeric );
3260  else if ( fieldParam->dataType() == QgsProcessingParameterField::String )
3261  mComboBox->setFilters( QgsFieldProxyModel::String );
3262  else if ( fieldParam->dataType() == QgsProcessingParameterField::DateTime )
3264 
3265  mComboBox->setToolTip( parameterDefinition()->toolTip() );
3266  connect( mComboBox, &QgsFieldComboBox::fieldChanged, this, [ = ]( const QString & )
3267  {
3268  emit widgetValueHasChanged( this );
3269  } );
3270  return mComboBox;
3271  }
3272  }
3273 
3275  {
3276  mLineEdit = new QLineEdit();
3277  mLineEdit->setToolTip( QObject::tr( "Name of field (separate field names with ; for multiple field parameters)" ) );
3278  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
3279  {
3280  emit widgetValueHasChanged( this );
3281  } );
3282  return mLineEdit;
3283  }
3284 
3285  }
3286  return nullptr;
3287 }
3288 
3289 void QgsProcessingFieldWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
3290 {
3292  switch ( type() )
3293  {
3296  {
3297  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
3298  {
3299  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterField * >( parameterDefinition() )->parentLayerParameterName() )
3300  {
3301  setParentLayerWrapperValue( wrapper );
3303  {
3304  setParentLayerWrapperValue( wrapper );
3305  } );
3306  break;
3307  }
3308  }
3309  break;
3310  }
3311 
3313  break;
3314  }
3315 }
3316 
3317 void QgsProcessingFieldWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
3318 {
3319  // evaluate value to layer
3320  QgsProcessingContext *context = nullptr;
3321  std::unique_ptr< QgsProcessingContext > tmpContext;
3322  if ( mProcessingContextGenerator )
3323  context = mProcessingContextGenerator->processingContext();
3324 
3325  if ( !context )
3326  {
3327  tmpContext = qgis::make_unique< QgsProcessingContext >();
3328  context = tmpContext.get();
3329  }
3330 
3331  QVariant value = parentWrapper->parameterValue();
3332 
3333  if ( value.canConvert<QgsProcessingFeatureSourceDefinition>() )
3334  {
3335  // input is a QgsProcessingFeatureSourceDefinition - source from it.
3336  // this is normally discouraged, and algorithms should NEVER do this -- but in this case we can make
3337  // certain assumptions due to the fact that we're calling this outside of algorithm/model execution and all sources
3338  // should be real map layers at this stage
3340  value = fromVar.source;
3341  }
3342  QgsVectorLayer *layer = QgsProcessingParameters::parameterAsVectorLayer( parentWrapper->parameterDefinition(), value, *context );
3343  if ( layer && layer->isValid() )
3344  {
3345  // need to grab ownership of layer if required - otherwise layer may be deleted when context
3346  // goes out of scope
3347  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
3348  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::VectorLayer )
3349  {
3350  mParentLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
3351  layer = mParentLayer.get();
3352  }
3353  else
3354  {
3355  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
3356  }
3357 
3358  if ( mComboBox )
3359  mComboBox->setLayer( layer );
3360  else if ( mPanel )
3361  mPanel->setFields( filterFields( layer->fields() ) );
3362  }
3363  else
3364  {
3365  std::unique_ptr< QgsProcessingFeatureSource > source( QgsProcessingParameters::parameterAsSource( parentWrapper->parameterDefinition(), value, *context ) );
3366  if ( source )
3367  {
3368  const QgsFields fields = source->fields();
3369  if ( mComboBox )
3370  mComboBox->setFields( fields );
3371  else if ( mPanel )
3372  mPanel->setFields( filterFields( fields ) );
3373  }
3374  else
3375  {
3376  if ( mComboBox )
3377  mComboBox->setLayer( nullptr );
3378  else if ( mPanel )
3379  mPanel->setFields( QgsFields() );
3380 
3381  if ( value.isValid() && widgetContext().messageBar() )
3382  {
3383  widgetContext().messageBar()->clearWidgets();
3384  widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent field could not be populated" ),
3385  Qgis::Warning, 5 );
3386  }
3387  }
3388  return;
3389  }
3390 
3391  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
3392  if ( mPanel && fieldParam->defaultToAllFields() )
3393  {
3394  QVariantList val;
3395  val.reserve( mPanel->fields().size() );
3396  for ( const QgsField &field : mPanel->fields() )
3397  val << field.name();
3398  setWidgetValue( val, *context );
3399  }
3400  else if ( fieldParam->defaultValue().isValid() )
3401  setWidgetValue( parameterDefinition()->defaultValue(), *context );
3402 }
3403 
3404 void QgsProcessingFieldWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3405 {
3406  if ( mComboBox )
3407  {
3408  if ( !value.isValid() )
3409  mComboBox->setField( QString() );
3410  else
3411  {
3412  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3413  mComboBox->setField( v );
3414  }
3415  }
3416  else if ( mPanel )
3417  {
3418  QVariantList opts;
3419  if ( value.isValid() )
3420  {
3421  const QStringList v = QgsProcessingParameters::parameterAsFields( parameterDefinition(), value, context );
3422  opts.reserve( v.size() );
3423  for ( const QString &i : v )
3424  opts << i;
3425  }
3426  if ( mPanel )
3427  mPanel->setValue( opts );
3428  }
3429  else if ( mLineEdit )
3430  {
3431  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
3432  if ( fieldParam->allowMultiple() )
3433  {
3434  const QStringList v = QgsProcessingParameters::parameterAsFields( parameterDefinition(), value, context );
3435  mLineEdit->setText( v.join( ';' ) );
3436  }
3437  else
3438  {
3439  mLineEdit->setText( QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context ) );
3440  }
3441  }
3442 }
3443 
3444 QVariant QgsProcessingFieldWidgetWrapper::widgetValue() const
3445 {
3446  if ( mComboBox )
3447  return mComboBox->currentField();
3448  else if ( mPanel )
3449  return mPanel->value();
3450  else if ( mLineEdit )
3451  {
3452  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
3453  if ( fieldParam->allowMultiple() )
3454  {
3455  return mLineEdit->text().split( ';' );
3456  }
3457  else
3458  return mLineEdit->text();
3459  }
3460  else
3461  return QVariant();
3462 }
3463 
3464 QStringList QgsProcessingFieldWidgetWrapper::compatibleParameterTypes() const
3465 {
3466  return QStringList()
3469 }
3470 
3471 QStringList QgsProcessingFieldWidgetWrapper::compatibleOutputTypes() const
3472 {
3473  return QStringList()
3475 }
3476 
3477 QList<int> QgsProcessingFieldWidgetWrapper::compatibleDataTypes() const
3478 {
3479  return QList<int>();
3480 }
3481 
3482 QString QgsProcessingFieldWidgetWrapper::modelerExpressionFormatString() const
3483 {
3484  return tr( "selected field names as an array of names, or semicolon separated string of options (e.g. 'fid;place_name')" );
3485 }
3486 
3487 const QgsVectorLayer *QgsProcessingFieldWidgetWrapper::linkedVectorLayer() const
3488 {
3489  if ( mComboBox && mComboBox->layer() )
3490  return mComboBox->layer();
3491 
3493 }
3494 
3495 QgsFields QgsProcessingFieldWidgetWrapper::filterFields( const QgsFields &fields ) const
3496 {
3497  const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
3498  QgsFields res;
3499  for ( const QgsField &f : fields )
3500  {
3501  switch ( fieldParam->dataType() )
3502  {
3504  res.append( f );
3505  break;
3506 
3508  if ( f.isNumeric() )
3509  res.append( f );
3510  break;
3511 
3513  if ( f.type() == QVariant::String )
3514  res.append( f );
3515  break;
3516 
3518  if ( f.type() == QVariant::Date || f.type() == QVariant::Time || f.type() == QVariant::DateTime )
3519  res.append( f );
3520  break;
3521  }
3522  }
3523 
3524  return res;
3525 }
3526 
3527 QString QgsProcessingFieldWidgetWrapper::parameterType() const
3528 {
3530 }
3531 
3532 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFieldWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3533 {
3534  return new QgsProcessingFieldWidgetWrapper( parameter, type );
3535 }
3536 
3537 //
3538 // QgsProcessingMapThemeWidgetWrapper
3539 //
3540 
3541 
3542 QgsProcessingMapThemeParameterDefinitionWidget::QgsProcessingMapThemeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3543  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3544 {
3545  QVBoxLayout *vlayout = new QVBoxLayout();
3546  vlayout->setMargin( 0 );
3547  vlayout->setContentsMargins( 0, 0, 0, 0 );
3548 
3549  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3550 
3551  mDefaultComboBox = new QComboBox();
3552  mDefaultComboBox->addItem( QString(), QVariant( -1 ) );
3553 
3554  const QStringList mapThemes = widgetContext.project() ? widgetContext.project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
3555  for ( const QString &theme : mapThemes )
3556  {
3557  mDefaultComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
3558  }
3559  mDefaultComboBox->setEditable( true );
3560 
3561  if ( const QgsProcessingParameterMapTheme *themeParam = dynamic_cast<const QgsProcessingParameterMapTheme *>( definition ) )
3562  {
3563  if ( themeParam->defaultValue().isValid() )
3564  mDefaultComboBox->setCurrentText( QgsProcessingParameters::parameterAsString( themeParam, themeParam->defaultValue(), context ) );
3565  else
3566  mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
3567  }
3568  else
3569  mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
3570 
3571  vlayout->addWidget( mDefaultComboBox );
3572 
3573  setLayout( vlayout );
3574 }
3575 
3576 QgsProcessingParameterDefinition *QgsProcessingMapThemeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
3577 {
3578  QVariant defaultVal;
3579  if ( mDefaultComboBox->currentText().isEmpty() )
3580  defaultVal = QVariant();
3581  else
3582  defaultVal = mDefaultComboBox->currentText();
3583  auto param = qgis::make_unique< QgsProcessingParameterMapTheme>( name, description, defaultVal );
3584  param->setFlags( flags );
3585  return param.release();
3586 }
3587 
3588 
3589 QgsProcessingMapThemeWidgetWrapper::QgsProcessingMapThemeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3590  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3591 {
3592 
3593 }
3594 
3595 QWidget *QgsProcessingMapThemeWidgetWrapper::createWidget()
3596 {
3597  const QgsProcessingParameterMapTheme *themeParam = dynamic_cast< const QgsProcessingParameterMapTheme *>( parameterDefinition() );
3598 
3599  mComboBox = new QComboBox();
3600 
3602  mComboBox->addItem( tr( "[Not selected]" ), QVariant( -1 ) );
3603 
3604  const QStringList mapThemes = widgetContext().project() ? widgetContext().project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
3605  for ( const QString &theme : mapThemes )
3606  {
3607  mComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
3608  }
3609 
3610  switch ( type() )
3611  {
3614  break;
3615 
3617  mComboBox->setEditable( true );
3618  break;
3619  }
3620 
3621  mComboBox->setToolTip( parameterDefinition()->toolTip() );
3622  connect( mComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, [ = ]( int )
3623  {
3624  emit widgetValueHasChanged( this );
3625  } );
3626 
3627  return mComboBox;
3628 }
3629 
3630 void QgsProcessingMapThemeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3631 {
3632  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3633 
3634  if ( !value.isValid() )
3635  mComboBox->setCurrentIndex( mComboBox->findData( QVariant( -1 ) ) );
3636  else
3637  {
3638  if ( mComboBox->isEditable() && mComboBox->findData( v ) == -1 )
3639  {
3640  const QString prev = mComboBox->currentText();
3641  mComboBox->setCurrentText( v );
3642  if ( prev != v )
3643  emit widgetValueHasChanged( this );
3644  }
3645  else
3646  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
3647  }
3648 }
3649 
3650 QVariant QgsProcessingMapThemeWidgetWrapper::widgetValue() const
3651 {
3652  if ( mComboBox )
3653  return mComboBox->currentData().toInt() == -1 ? QVariant() :
3654  !mComboBox->currentData().isValid() && mComboBox->isEditable() ? mComboBox->currentText().isEmpty() ? QVariant() : QVariant( mComboBox->currentText() )
3655  : mComboBox->currentData();
3656  else
3657  return QVariant();
3658 }
3659 
3660 QStringList QgsProcessingMapThemeWidgetWrapper::compatibleParameterTypes() const
3661 {
3662  return QStringList()
3665 }
3666 
3667 QStringList QgsProcessingMapThemeWidgetWrapper::compatibleOutputTypes() const
3668 {
3669  return QStringList()
3671 }
3672 
3673 QList<int> QgsProcessingMapThemeWidgetWrapper::compatibleDataTypes() const
3674 {
3675  return QList< int >();
3676 }
3677 
3678 QString QgsProcessingMapThemeWidgetWrapper::modelerExpressionFormatString() const
3679 {
3680  return tr( "map theme as a string value (e.g. 'base maps')" );
3681 }
3682 
3683 QString QgsProcessingMapThemeWidgetWrapper::parameterType() const
3684 {
3686 }
3687 
3688 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapThemeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3689 {
3690  return new QgsProcessingMapThemeWidgetWrapper( parameter, type );
3691 }
3692 
3693 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapThemeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3694 {
3695  return new QgsProcessingMapThemeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3696 }
3697 
3698 
static QgsCoordinateReferenceSystem parameterAsCrs(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a coordinate reference system.
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value...
A boolean parameter for processing algorithms.
int itemType() const
Returns the acceptable item type, or -1 if any item type is allowed.
static QString typeName()
Returns the type name for the parameter class.
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
An input file or folder parameter for processing algorithms.
static QString parameterAsString(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static string value.
A widget wrapper for Processing parameter value widgets.
bool defaultToAllFields() const
Returns whether a parameter which allows multiple selections (see allowMultiple()) should automatical...
virtual void setWidgetContext(const QgsProcessingParameterWidgetContext &context)
Sets the context in which the Processing parameter widget is shown, e.g., the parent model algorithm...
static int parameterAsEnum(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a enum value.
static QString typeName()
Returns the type name for the parameter class.
static QVariantList parameterAsMatrix(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a matrix/table of values.
Base class for graphical items within a QgsLayout.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
Abstract base class for widgets which allow users to specify the properties of a Processing parameter...
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
static QString typeName()
Returns the type name for the output class.
A vector layer or feature source field parameter for processing algorithms.
DataType dataType() const
Returns the acceptable data type for the field.
void layoutChanged(QgsMasterLayoutInterface *layout)
Emitted whenever the currently selected layout changes.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
QVariantMap metadata() const
Returns the parameter&#39;s freeform metadata.
static QString typeName()
Returns the type name for the parameter class.
Select a directory.
Definition: qgsfilewidget.h:66
static QList< int > parameterAsEnums(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to list of enum values.
A combobox which lets the user select map scale from predefined list and highlights nearest to curren...
A print layout parameter, allowing users to select a print layout.
WidgetType
Types of dialogs which Processing widgets can be created for.
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
A color parameter for processing algorithms.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
An expression parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A cross platform button subclass for selecting colors.
static QString typeName()
Returns the type name for the parameter class.
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value...
Definition: qgsspinbox.h:42
static QString typeName()
Returns the type name for the parameter class.
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
double minimum() const
Returns the minimum value acceptable by the parameter.
Container of fields for a vector layer.
Definition: qgsfields.h:42
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
static QString typeName()
Returns the type name for the parameter class.
virtual QLabel * createLabel()
Creates a new label to accompany widgets created by the wrapper.
bool allowMultiple() const
Returns true if the parameter allows multiple selected values.
void setFlags(Flags flags)
Sets the flags associated with the parameter.
bool clearWidgets()
Remove all items from the bar&#39;s widget list.
QgsUnitTypes::DistanceUnit defaultUnit() const
Returns the default distance unit for the parameter.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
const QgsCoordinateReferenceSystem & crs
bool isValid() const
Returns the status of the layer.
static QString typeName()
Returns the type name for the parameter class.
void scaleChanged(double scale)
Emitted when user has finished editing/selecting a new scale.
static QString typeName()
Returns the type name for the output class.
static QgsVectorLayer * parameterAsVectorLayer(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a vector layer.
Abstract base class for processing algorithms.
A coordinate operation parameter for processing algorithms, for selection between available coordinat...
static QgsPointXY parameterAsPoint(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Evaluates the parameter with matching definition to a point.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:75
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
virtual void setDialog(QDialog *dialog)
Sets the parent dialog in which the wrapper is shown.
static QgsCoordinateReferenceSystem variantToCrs(const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue=QVariant())
Converts a variant value to a coordinate reference system.
The QgsFieldComboBox is a combo box which displays the list of fields of a given layer.
static QString typeName()
Returns the type name for the parameter class.
void operationChanged()
Emitted when the operation selected in the dialog is changed.
A numeric range parameter for processing algorithms.
A double numeric parameter for map scale values.
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
virtual const QgsVectorLayer * linkedVectorLayer() const
Returns the optional vector layer associated with this widget wrapper, or nullptr if no vector layer ...
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
QString parentLayerParameterName() const
Returns the name of the parent layer parameter, or an empty string if this is not set...
The QgsLayoutItemComboBox class is a combo box which displays items of a matching type from a layout...
QString fileFilter() const
Returns the file filter string for file destinations compatible with this parameter.
static QgsCoordinateReferenceSystem parameterAsPointCrs(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Returns the coordinate reference system associated with an point parameter value. ...
static QString typeName()
Returns the type name for the parameter class.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
#define FALLTHROUGH
Definition: qgis.h:763
QgsMapThemeCollection mapThemeCollection
Definition: qgsproject.h:100
QgsProperty source
Source definition.
The QgsFileWidget class creates a widget for selecting a file or a folder.
Definition: qgsfilewidget.h:35
An enum based parameter for processing algorithms, allowing for selection from predefined values...
Date or datetime fields.
Flags flags() const
Returns any flags associated with the parameter.
QVariant parameterValue() const
Returns the current value of the parameter.
static QString typeName()
Returns the type name for the parameter class.
bool opacityEnabled() const
Returns true if the parameter allows opacity control.
QVariant defaultValue() const
Returns the default value for the parameter.
Select a single file.
Definition: qgsfilewidget.h:65
QVariant sourceCrs() const
Returns the static source CRS, or an invalid value if this is not set.
void widgetValueHasChanged(QgsAbstractProcessingParameterWidgetWrapper *wrapper)
Emitted whenever the parameter value (as defined by the wrapped widget) is changed.
static QString typeName()
Returns the type name for the parameter class.
void fileChanged(const QString &path)
Emitted whenever the current file or directory path is changed.
A double numeric parameter for distance values.
virtual void postInitialize(const QList< QgsAbstractProcessingParameterWidgetWrapper * > &wrappers)
Called after all wrappers have been created within a particular dialog or context, allowing the wrapper to connect to the wrappers of other, related parameters.
static QString typeName()
Returns the type name for the output class.
static QList< double > parameterAsRange(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a range of values.
Degrees, for planar geographic CRS distance measurements.
Definition: qgsunittypes.h:74
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
const QgsProcessingParameterDefinition * parameterDefinition() const
Returns the parameter definition associated with this wrapper.
QLineEdit subclass with built in support for clearing the widget&#39;s value and handling custom null val...
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 setDefaultValue(const QVariant &value)
Sets the default value for the parameter.
static QString typeName()
Returns the type name for the output class.
QString proj
Proj coordinate operation description, for Proj >= 6.0 builds only.
QStringList options() const
Returns the list of acceptable options for the parameter.
static QString typeName()
Returns the type name for the parameter class.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:49
virtual void deactivate()
called when map tool is being deactivated
Definition: qgsmaptool.cpp:99
QgsProject * project() const
Returns the project associated with the widget.
A print layout item parameter, allowing users to select a particular item from a print layout...
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::Info, int duration=5)
convenience method for pushing a message to the bar
Definition: qgsmessagebar.h:88
static QString typeName()
Returns the type name for the output class.
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
A numeric parameter for processing algorithms.
void itemChanged(QgsLayoutItem *item)
Emitted whenever the currently selected item changes.
double x
Definition: qgspointxy.h:47
static QgsPrintLayout * parameterAsLayout(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a print layout.
QString name() const
Returns the name of the parameter.
void expressionChanged(const QString &expression)
Emitted when the expression is changed.
Encapsulates settings relating to a feature source input to a processing algorithm.
Behavior behavior() const
Returns the parameter behavior (e.g.
QVariant destinationCrs() const
Returns the static destination CRS, or an invalid value if this is not set.
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:66
A widget for selecting a projection.
static Q_INVOKABLE QgsUnitTypes::DistanceUnitType unitType(QgsUnitTypes::DistanceUnit unit)
Returns the type for a distance unit.
QString extension() const
Returns any specified file extension for the parameter.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
void selectedConfigIdChanged(const QString &authcfg)
Emitted when authentication config is changed or missing.
Abstract base class for all map tools.
Definition: qgsmaptool.h:62
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
QgsPointLocator::Match mapPointMatch() const
Returns the matching data from the most recently snapped point.
static QString typeName()
Returns the type name for the parameter class.
Unknown distance unit.
Definition: qgsunittypes.h:77
QgsProcessingModelAlgorithm * model() const
Returns the model which the parameter widget is associated with.
A point parameter for processing algorithms.
Contains settings which reflect the context in which a Processing parameter widget is shown...
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
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...
The QgsExpressionLineEdit widget includes a line edit for entering expressions together with a button...
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places...
Definition: qgis.h:363
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the parameter class.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:450
virtual QString uuid() const
Returns the item identification string.
This class represents a coordinate reference system (CRS).
Base class for the definition of processing parameters.
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfields.cpp:212
Class that shows snapping marker on map canvas for the current snapping match.
static double parameterAsDouble(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static double value.
virtual QString name() const =0
Returns the layout&#39;s name.
static int parameterAsInt(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static integer value.
static QgsProcessingFeatureSource * parameterAsSource(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a feature source.
static bool parameterAsBool(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static boolean value.
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
Type dataType() const
Returns the acceptable data type for the parameter.
Print layout, a QgsLayout subclass for static or atlas-based layouts.
Terrestrial miles.
Definition: qgsunittypes.h:73
Interface for master layout type objects, such as print layouts and reports.
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
Represents a vector layer which manages a vector based data sets.
A map theme parameter for processing algorithms, allowing users to select an existing map theme from ...
Contains information about the context in which a processing algorithm is executed.
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 ...
A widget for selecting the coordinate operation to use when transforming between a source and destina...
A string parameter for processing algorithms.
The QgsLayoutComboBox class is a combo box which displays available layouts from a QgsLayoutManager...
QString description() const
Returns the description for the parameter.
static QString typeName()
Returns the type name for the output class.
QgsProcessingParameterNumber::Type dataType() const
Returns the acceptable data type for the range.
bool allowMultiple() const
Returns whether multiple field selections are permitted.
Unit is a standard measurement unit.
Definition: qgsunittypes.h:86
static QString typeName()
Returns the type name for the parameter class.
double maximum() const
Returns the maximum value acceptable by the parameter.
static QString typeName()
Returns the type name for the parameter class.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Standard algorithm dialog.
Batch processing dialog.
static QStringList parameterAsFields(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a list of fields.