QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 "qgscolorbutton.h"
45 #include <QToolButton>
46 #include <QLabel>
47 #include <QHBoxLayout>
48 #include <QVBoxLayout>
49 #include <QCheckBox>
50 #include <QComboBox>
51 #include <QLineEdit>
52 #include <QPlainTextEdit>
53 #include <QRadioButton>
54 #include <QButtonGroup>
55 #include <QMenu>
56 
58 
59 //
60 // QgsProcessingBooleanWidgetWrapper
61 //
62 
63 
64 QgsProcessingBooleanParameterDefinitionWidget::QgsProcessingBooleanParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
65  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
66 {
67  QVBoxLayout *vlayout = new QVBoxLayout();
68  vlayout->setMargin( 0 );
69  vlayout->setContentsMargins( 0, 0, 0, 0 );
70 
71  mDefaultCheckBox = new QCheckBox( tr( "Checked" ) );
72  if ( const QgsProcessingParameterBoolean *boolParam = dynamic_cast<const QgsProcessingParameterBoolean *>( definition ) )
73  mDefaultCheckBox->setChecked( QgsProcessingParameters::parameterAsBool( boolParam, boolParam->defaultValue(), context ) );
74  else
75  mDefaultCheckBox->setChecked( false );
76  vlayout->addWidget( mDefaultCheckBox );
77  setLayout( vlayout );
78 }
79 
80 QgsProcessingParameterDefinition *QgsProcessingBooleanParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
81 {
82  auto param = qgis::make_unique< QgsProcessingParameterBoolean >( name, description, mDefaultCheckBox->isChecked() );
83  param->setFlags( flags );
84  return param.release();
85 }
86 
87 
88 QgsProcessingBooleanWidgetWrapper::QgsProcessingBooleanWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
89  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
90 {
91 
92 }
93 
94 QWidget *QgsProcessingBooleanWidgetWrapper::createWidget()
95 {
96  switch ( type() )
97  {
99  {
100  QString description = parameterDefinition()->description();
101  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
102  description = QObject::tr( "%1 [optional]" ).arg( description );
103 
104  mCheckBox = new QCheckBox( description );
105  mCheckBox->setToolTip( parameterDefinition()->toolTip() );
106 
107  connect( mCheckBox, &QCheckBox::toggled, this, [ = ]
108  {
109  emit widgetValueHasChanged( this );
110  } );
111  return mCheckBox;
112  };
113 
116  {
117  mComboBox = new QComboBox();
118  mComboBox->addItem( tr( "Yes" ), true );
119  mComboBox->addItem( tr( "No" ), false );
120  mComboBox->setToolTip( parameterDefinition()->toolTip() );
121 
122  connect( mComboBox, qgis::overload< int>::of( &QComboBox::currentIndexChanged ), this, [ = ]
123  {
124  emit widgetValueHasChanged( this );
125  } );
126 
127  return mComboBox;
128  }
129  }
130  return nullptr;
131 }
132 
133 QLabel *QgsProcessingBooleanWidgetWrapper::createLabel()
134 {
135  // avoid creating labels in standard dialogs
136  if ( type() == QgsProcessingGui::Standard )
137  return nullptr;
138  else
140 }
141 
142 void QgsProcessingBooleanWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
143 {
144  switch ( type() )
145  {
147  {
148  const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
149  mCheckBox->setChecked( v );
150  break;
151  }
152 
155  {
156  const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
157  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
158  break;
159  }
160  }
161 }
162 
163 QVariant QgsProcessingBooleanWidgetWrapper::widgetValue() const
164 {
165  switch ( type() )
166  {
168  return mCheckBox->isChecked();
169 
172  return mComboBox->currentData();
173  }
174  return QVariant();
175 }
176 
177 QStringList QgsProcessingBooleanWidgetWrapper::compatibleParameterTypes() const
178 {
179  //pretty much everything is compatible here and can be converted to a bool!
180  return QStringList() << QgsProcessingParameterBoolean::typeName()
193 }
194 
195 QStringList QgsProcessingBooleanWidgetWrapper::compatibleOutputTypes() const
196 {
197  return QStringList() << QgsProcessingOutputNumber::typeName()
204 }
205 
206 QList<int> QgsProcessingBooleanWidgetWrapper::compatibleDataTypes() const
207 {
208  return QList< int >();
209 }
210 
211 QString QgsProcessingBooleanWidgetWrapper::parameterType() const
212 {
214 }
215 
216 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBooleanWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
217 {
218  return new QgsProcessingBooleanWidgetWrapper( parameter, type );
219 }
220 
221 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBooleanWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
222 {
223  return new QgsProcessingBooleanParameterDefinitionWidget( context, widgetContext, definition, algorithm );
224 }
225 
226 
227 //
228 // QgsProcessingCrsWidgetWrapper
229 //
230 
231 QgsProcessingCrsWidgetWrapper::QgsProcessingCrsWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
232  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
233 {
234 
235 }
236 
237 QWidget *QgsProcessingCrsWidgetWrapper::createWidget()
238 {
239  mProjectionSelectionWidget = new QgsProjectionSelectionWidget();
240  mProjectionSelectionWidget->setToolTip( parameterDefinition()->toolTip() );
241 
242  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
243  mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
244  else
245  mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, false );
246 
247  connect( mProjectionSelectionWidget, &QgsProjectionSelectionWidget::crsChanged, this, [ = ]
248  {
249  emit widgetValueHasChanged( this );
250  } );
251 
252  switch ( type() )
253  {
256  {
257  return mProjectionSelectionWidget;
258  };
259 
261  {
262  QWidget *w = new QWidget();
263  w->setToolTip( parameterDefinition()->toolTip() );
264 
265  QVBoxLayout *vl = new QVBoxLayout();
266  vl->setMargin( 0 );
267  vl->setContentsMargins( 0, 0, 0, 0 );
268  w->setLayout( vl );
269 
270  mUseProjectCrsCheckBox = new QCheckBox( tr( "Use project CRS" ) );
271  mUseProjectCrsCheckBox->setToolTip( tr( "Always use the current project CRS when running the model" ) );
272  vl->addWidget( mUseProjectCrsCheckBox );
273  connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, mProjectionSelectionWidget, &QgsProjectionSelectionWidget::setDisabled );
274  connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, this, [ = ]
275  {
276  emit widgetValueHasChanged( this );
277  } );
278 
279  vl->addWidget( mProjectionSelectionWidget );
280 
281  return w;
282  }
283  }
284  return nullptr;
285 }
286 
287 void QgsProcessingCrsWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
288 {
289  if ( mUseProjectCrsCheckBox )
290  {
291  if ( value.toString().compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
292  {
293  mUseProjectCrsCheckBox->setChecked( true );
294  return;
295  }
296  else
297  {
298  mUseProjectCrsCheckBox->setChecked( false );
299  }
300  }
301 
302  const QgsCoordinateReferenceSystem v = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, context );
303  if ( mProjectionSelectionWidget )
304  mProjectionSelectionWidget->setCrs( v );
305 }
306 
307 QVariant QgsProcessingCrsWidgetWrapper::widgetValue() const
308 {
309  if ( mUseProjectCrsCheckBox && mUseProjectCrsCheckBox->isChecked() )
310  return QStringLiteral( "ProjectCrs" );
311  else if ( mProjectionSelectionWidget )
312  return mProjectionSelectionWidget->crs().isValid() ? mProjectionSelectionWidget->crs() : QVariant();
313  else
314  return QVariant();
315 }
316 
317 QStringList QgsProcessingCrsWidgetWrapper::compatibleParameterTypes() const
318 {
319  return QStringList()
327 }
328 
329 QStringList QgsProcessingCrsWidgetWrapper::compatibleOutputTypes() const
330 {
331  return QStringList() << QgsProcessingOutputVectorLayer::typeName()
335 }
336 
337 QList<int> QgsProcessingCrsWidgetWrapper::compatibleDataTypes() const
338 {
339  return QList< int >();
340 }
341 
342 QString QgsProcessingCrsWidgetWrapper::modelerExpressionFormatString() const
343 {
344  return tr( "string as EPSG code, WKT or PROJ format, or a string identifying a map layer" );
345 }
346 
347 QString QgsProcessingCrsWidgetWrapper::parameterType() const
348 {
350 }
351 
352 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCrsWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
353 {
354  return new QgsProcessingCrsWidgetWrapper( parameter, type );
355 }
356 
357 
358 
359 //
360 // QgsProcessingStringWidgetWrapper
361 //
362 
363 
364 QgsProcessingStringParameterDefinitionWidget::QgsProcessingStringParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
365  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
366 {
367  QVBoxLayout *vlayout = new QVBoxLayout();
368  vlayout->setMargin( 0 );
369  vlayout->setContentsMargins( 0, 0, 0, 0 );
370 
371  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
372 
373  mDefaultLineEdit = new QLineEdit();
374  if ( const QgsProcessingParameterString *stringParam = dynamic_cast<const QgsProcessingParameterString *>( definition ) )
375  mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( stringParam, stringParam->defaultValue(), context ) );
376  vlayout->addWidget( mDefaultLineEdit );
377 
378  mMultiLineCheckBox = new QCheckBox( tr( "Multiline input" ) );
379  if ( const QgsProcessingParameterString *stringParam = dynamic_cast<const QgsProcessingParameterString *>( definition ) )
380  mMultiLineCheckBox->setChecked( stringParam->multiLine() );
381  vlayout->addWidget( mMultiLineCheckBox );
382 
383  setLayout( vlayout );
384 }
385 
386 QgsProcessingParameterDefinition *QgsProcessingStringParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
387 {
388  auto param = qgis::make_unique< QgsProcessingParameterString >( name, description, mDefaultLineEdit->text(), mMultiLineCheckBox->isChecked() );
389  param->setFlags( flags );
390  return param.release();
391 }
392 
393 
394 
395 QgsProcessingStringWidgetWrapper::QgsProcessingStringWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
396  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
397 {
398 
399 }
400 
401 QWidget *QgsProcessingStringWidgetWrapper::createWidget()
402 {
403  switch ( type() )
404  {
407  {
408  if ( static_cast< const QgsProcessingParameterString * >( parameterDefinition() )->multiLine() )
409  {
410  mPlainTextEdit = new QPlainTextEdit();
411  mPlainTextEdit->setToolTip( parameterDefinition()->toolTip() );
412 
413  connect( mPlainTextEdit, &QPlainTextEdit::textChanged, this, [ = ]
414  {
415  emit widgetValueHasChanged( this );
416  } );
417  return mPlainTextEdit;
418  }
419  else
420  {
421  mLineEdit = new QLineEdit();
422  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
423 
424  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
425  {
426  emit widgetValueHasChanged( this );
427  } );
428  return mLineEdit;
429  }
430  };
431 
433  {
434  mLineEdit = new QLineEdit();
435  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
436 
437  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
438  {
439  emit widgetValueHasChanged( this );
440  } );
441  return mLineEdit;
442  }
443  }
444  return nullptr;
445 }
446 
447 void QgsProcessingStringWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
448 {
449  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
450  if ( mLineEdit )
451  mLineEdit->setText( v );
452  if ( mPlainTextEdit )
453  mPlainTextEdit->setPlainText( v );
454 }
455 
456 QVariant QgsProcessingStringWidgetWrapper::widgetValue() const
457 {
458  if ( mLineEdit )
459  return mLineEdit->text();
460  else if ( mPlainTextEdit )
461  return mPlainTextEdit->toPlainText();
462  else
463  return QVariant();
464 }
465 
466 QStringList QgsProcessingStringWidgetWrapper::compatibleParameterTypes() const
467 {
468  return QStringList()
477 }
478 
479 QStringList QgsProcessingStringWidgetWrapper::compatibleOutputTypes() const
480 {
481  return QStringList() << QgsProcessingOutputNumber::typeName()
484 }
485 
486 QList<int> QgsProcessingStringWidgetWrapper::compatibleDataTypes() const
487 {
488  return QList< int >();
489 }
490 
491 QString QgsProcessingStringWidgetWrapper::parameterType() const
492 {
494 }
495 
496 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingStringWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
497 {
498  return new QgsProcessingStringWidgetWrapper( parameter, type );
499 }
500 
501 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingStringWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
502 {
503  return new QgsProcessingStringParameterDefinitionWidget( context, widgetContext, definition, algorithm );
504 }
505 
506 
507 
508 //
509 // QgsProcessingAuthConfigWidgetWrapper
510 //
511 
512 QgsProcessingAuthConfigWidgetWrapper::QgsProcessingAuthConfigWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
513  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
514 {
515 
516 }
517 
518 QWidget *QgsProcessingAuthConfigWidgetWrapper::createWidget()
519 {
520  switch ( type() )
521  {
525  {
526  mAuthConfigSelect = new QgsAuthConfigSelect();
527  mAuthConfigSelect->setToolTip( parameterDefinition()->toolTip() );
528 
529  connect( mAuthConfigSelect, &QgsAuthConfigSelect::selectedConfigIdChanged, this, [ = ]
530  {
531  emit widgetValueHasChanged( this );
532  } );
533  return mAuthConfigSelect;
534  };
535  }
536  return nullptr;
537 }
538 
539 void QgsProcessingAuthConfigWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
540 {
541  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
542  if ( mAuthConfigSelect )
543  mAuthConfigSelect->setConfigId( v );
544 }
545 
546 QVariant QgsProcessingAuthConfigWidgetWrapper::widgetValue() const
547 {
548  if ( mAuthConfigSelect )
549  return mAuthConfigSelect->configId();
550  else
551  return QVariant();
552 }
553 
554 QStringList QgsProcessingAuthConfigWidgetWrapper::compatibleParameterTypes() const
555 {
556  return QStringList()
560 }
561 
562 QStringList QgsProcessingAuthConfigWidgetWrapper::compatibleOutputTypes() const
563 {
564  return QStringList() << QgsProcessingOutputString::typeName();
565 }
566 
567 QList<int> QgsProcessingAuthConfigWidgetWrapper::compatibleDataTypes() const
568 {
569  return QList< int >();
570 }
571 
572 QString QgsProcessingAuthConfigWidgetWrapper::parameterType() const
573 {
575 }
576 
577 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAuthConfigWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
578 {
579  return new QgsProcessingAuthConfigWidgetWrapper( parameter, type );
580 }
581 
582 //
583 // QgsProcessingNumericWidgetWrapper
584 //
585 
586 QgsProcessingNumericWidgetWrapper::QgsProcessingNumericWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
587  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
588 {
589 
590 }
591 
592 QWidget *QgsProcessingNumericWidgetWrapper::createWidget()
593 {
594  const QgsProcessingParameterNumber *numberDef = static_cast< const QgsProcessingParameterNumber * >( parameterDefinition() );
595  const QVariantMap metadata = numberDef->metadata();
596  const int decimals = metadata.value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "decimals" ), 6 ).toInt();
597  switch ( type() )
598  {
602  {
603  // lots of duplicate code here -- but there's no common interface between QSpinBox/QDoubleSpinBox which would allow us to avoid this
604  QAbstractSpinBox *spinBox = nullptr;
605  switch ( numberDef->dataType() )
606  {
608  mDoubleSpinBox = new QgsDoubleSpinBox();
609  mDoubleSpinBox->setExpressionsEnabled( true );
610  mDoubleSpinBox->setDecimals( decimals );
611 
612  // guess reasonable step value for double spin boxes
613  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) &&
614  !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() + 1 ) )
615  {
616  double singleStep = calculateStep( numberDef->minimum(), numberDef->maximum() );
617  singleStep = std::max( singleStep, std::pow( 10, -decimals ) );
618  mDoubleSpinBox->setSingleStep( singleStep );
619  }
620 
621  spinBox = mDoubleSpinBox;
622  break;
623 
625  mSpinBox = new QgsSpinBox();
626  mSpinBox->setExpressionsEnabled( true );
627  spinBox = mSpinBox;
628  break;
629  }
630  spinBox->setToolTip( parameterDefinition()->toolTip() );
631 
632  double max = 999999999;
633  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) )
634  {
635  max = numberDef->maximum();
636  }
637  double min = -999999999;
638  if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
639  {
640  min = numberDef->minimum();
641  }
642  if ( mDoubleSpinBox )
643  {
644  mDoubleSpinBox->setMinimum( min );
645  mDoubleSpinBox->setMaximum( max );
646  }
647  else
648  {
649  mSpinBox->setMinimum( static_cast< int >( min ) );
650  mSpinBox->setMaximum( static_cast< int >( max ) );
651  }
652 
654  {
655  mAllowingNull = true;
656  if ( mDoubleSpinBox )
657  {
658  mDoubleSpinBox->setShowClearButton( true );
659  const double min = mDoubleSpinBox->minimum() - 1;
660  mDoubleSpinBox->setMinimum( min );
661  mDoubleSpinBox->setValue( min );
662  }
663  else
664  {
665  mSpinBox->setShowClearButton( true );
666  const int min = mSpinBox->minimum() - 1;
667  mSpinBox->setMinimum( min );
668  mSpinBox->setValue( min );
669  }
670  spinBox->setSpecialValueText( tr( "Not set" ) );
671  }
672  else
673  {
674  if ( numberDef->defaultValue().isValid() )
675  {
676  // if default value for parameter, we clear to that
677  bool ok = false;
678  if ( mDoubleSpinBox )
679  {
680  double defaultVal = numberDef->defaultValue().toDouble( &ok );
681  if ( ok )
682  mDoubleSpinBox->setClearValue( defaultVal );
683  }
684  else
685  {
686  int intVal = numberDef->defaultValue().toInt( &ok );
687  if ( ok )
688  mSpinBox->setClearValue( intVal );
689  }
690  }
691  else if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
692  {
693  // otherwise we clear to the minimum, if it's set
694  if ( mDoubleSpinBox )
695  mDoubleSpinBox->setClearValue( numberDef->minimum() );
696  else
697  mSpinBox->setClearValue( static_cast< int >( numberDef->minimum() ) );
698  }
699  else
700  {
701  // last resort, we clear to 0
702  if ( mDoubleSpinBox )
703  {
704  mDoubleSpinBox->setValue( 0 );
705  mDoubleSpinBox->setClearValue( 0 );
706  }
707  else
708  {
709  mSpinBox->setValue( 0 );
710  mSpinBox->setClearValue( 0 );
711  }
712  }
713  }
714 
715  if ( mDoubleSpinBox )
716  connect( mDoubleSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
717  else if ( mSpinBox )
718  connect( mSpinBox, qgis::overload<int>::of( &QgsSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
719 
720  return spinBox;
721  };
722  }
723  return nullptr;
724 }
725 
726 void QgsProcessingNumericWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
727 {
728  if ( mDoubleSpinBox )
729  {
730  if ( mAllowingNull && !value.isValid() )
731  mDoubleSpinBox->clear();
732  else
733  {
734  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
735  mDoubleSpinBox->setValue( v );
736  }
737  }
738  else if ( mSpinBox )
739  {
740  if ( mAllowingNull && !value.isValid() )
741  mSpinBox->clear();
742  else
743  {
744  const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
745  mSpinBox->setValue( v );
746  }
747  }
748 }
749 
750 QVariant QgsProcessingNumericWidgetWrapper::widgetValue() const
751 {
752  if ( mDoubleSpinBox )
753  {
754  if ( mAllowingNull && qgsDoubleNear( mDoubleSpinBox->value(), mDoubleSpinBox->minimum() ) )
755  return QVariant();
756  else
757  return mDoubleSpinBox->value();
758  }
759  else if ( mSpinBox )
760  {
761  if ( mAllowingNull && mSpinBox->value() == mSpinBox->minimum() )
762  return QVariant();
763  else
764  return mSpinBox->value();
765  }
766  else
767  return QVariant();
768 }
769 
770 QStringList QgsProcessingNumericWidgetWrapper::compatibleParameterTypes() const
771 {
772  return QStringList()
777 }
778 
779 QStringList QgsProcessingNumericWidgetWrapper::compatibleOutputTypes() const
780 {
781  return QStringList() << QgsProcessingOutputNumber::typeName()
783 }
784 
785 QList<int> QgsProcessingNumericWidgetWrapper::compatibleDataTypes() const
786 {
787  return QList< int >();
788 }
789 
790 double QgsProcessingNumericWidgetWrapper::calculateStep( const double minimum, const double maximum )
791 {
792  const double valueRange = maximum - minimum;
793  if ( valueRange <= 1.0 )
794  {
795  const double step = valueRange / 10.0;
796  // round to 1 significant figure
797  return qgsRound( step, -std::floor( std::log( step ) ) );
798  }
799  else
800  {
801  return 1.0;
802  }
803 }
804 
805 QString QgsProcessingNumericWidgetWrapper::parameterType() const
806 {
808 }
809 
810 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingNumericWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
811 {
812  return new QgsProcessingNumericWidgetWrapper( parameter, type );
813 }
814 
815 //
816 // QgsProcessingDistanceWidgetWrapper
817 //
818 
819 QgsProcessingDistanceWidgetWrapper::QgsProcessingDistanceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
820  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
821 {
822 
823 }
824 
825 QString QgsProcessingDistanceWidgetWrapper::parameterType() const
826 {
828 }
829 
830 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDistanceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
831 {
832  return new QgsProcessingDistanceWidgetWrapper( parameter, type );
833 }
834 
835 QWidget *QgsProcessingDistanceWidgetWrapper::createWidget()
836 {
837  const QgsProcessingParameterDistance *distanceDef = static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() );
838 
839  QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
840  switch ( type() )
841  {
843  {
844  mLabel = new QLabel();
845  mUnitsCombo = new QComboBox();
846 
852 
853  const int labelMargin = static_cast< int >( std::round( mUnitsCombo->fontMetrics().width( 'X' ) ) );
854  QHBoxLayout *layout = new QHBoxLayout();
855  layout->addWidget( spin, 1 );
856  layout->insertSpacing( 1, labelMargin / 2 );
857  layout->insertWidget( 2, mLabel );
858  layout->insertWidget( 3, mUnitsCombo );
859 
860  // bit of fiddlyness here -- we want the initial spacing to only be visible
861  // when the warning label is shown, so it's embedded inside mWarningLabel
862  // instead of outside it
863  mWarningLabel = new QWidget();
864  QHBoxLayout *warningLayout = new QHBoxLayout();
865  warningLayout->setMargin( 0 );
866  warningLayout->setContentsMargins( 0, 0, 0, 0 );
867  QLabel *warning = new QLabel();
868  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
869  const int size = static_cast< int >( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
870  warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
871  warning->setToolTip( tr( "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
872  warningLayout->insertSpacing( 0, labelMargin / 2 );
873  warningLayout->insertWidget( 1, warning );
874  mWarningLabel->setLayout( warningLayout );
875  layout->insertWidget( 4, mWarningLabel );
876 
877  setUnits( distanceDef->defaultUnit() );
878 
879  QWidget *w = new QWidget();
880  layout->setMargin( 0 );
881  layout->setContentsMargins( 0, 0, 0, 0 );
882  w->setLayout( layout );
883  return w;
884  }
885 
888  return spin;
889 
890  }
891  return nullptr;
892 }
893 
894 void QgsProcessingDistanceWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
895 {
896  QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
897  switch ( type() )
898  {
900  {
901  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
902  {
903  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() )->parentParameterName() )
904  {
905  setUnitParameterValue( wrapper->parameterValue() );
907  {
908  setUnitParameterValue( wrapper->parameterValue() );
909  } );
910  break;
911  }
912  }
913  break;
914  }
915 
918  break;
919  }
920 }
921 
922 void QgsProcessingDistanceWidgetWrapper::setUnitParameterValue( const QVariant &value )
923 {
925 
926  // evaluate value to layer
927  QgsProcessingContext *context = nullptr;
928  std::unique_ptr< QgsProcessingContext > tmpContext;
929  if ( mProcessingContextGenerator )
930  context = mProcessingContextGenerator->processingContext();
931 
932  if ( !context )
933  {
934  tmpContext = qgis::make_unique< QgsProcessingContext >();
935  context = tmpContext.get();
936  }
937 
938  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, *context );
939  if ( crs.isValid() )
940  {
941  units = crs.mapUnits();
942  }
943 
944  setUnits( units );
945 }
946 
947 void QgsProcessingDistanceWidgetWrapper::setUnits( const QgsUnitTypes::DistanceUnit units )
948 {
949  mLabel->setText( QgsUnitTypes::toString( units ) );
951  {
952  mUnitsCombo->hide();
953  mLabel->show();
954  }
955  else
956  {
957  mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( units ) );
958  mUnitsCombo->show();
959  mLabel->hide();
960  }
961  mWarningLabel->setVisible( units == QgsUnitTypes::DistanceDegrees );
962  mBaseUnit = units;
963 }
964 
965 QVariant QgsProcessingDistanceWidgetWrapper::widgetValue() const
966 {
967  const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
968  if ( val.type() == QVariant::Double && mUnitsCombo && mUnitsCombo->isVisible() )
969  {
970  QgsUnitTypes::DistanceUnit displayUnit = static_cast<QgsUnitTypes::DistanceUnit >( mUnitsCombo->currentData().toInt() );
971  return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
972  }
973  else
974  {
975  return val;
976  }
977 }
978 
979 //
980 // QgsProcessingScaleWidgetWrapper
981 //
982 
983 QgsProcessingScaleWidgetWrapper::QgsProcessingScaleWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
984  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
985 {
986 
987 }
988 
989 QString QgsProcessingScaleWidgetWrapper::parameterType() const
990 {
992 }
993 
994 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingScaleWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
995 {
996  return new QgsProcessingScaleWidgetWrapper( parameter, type );
997 }
998 
999 QWidget *QgsProcessingScaleWidgetWrapper::createWidget()
1000 {
1001  const QgsProcessingParameterScale *scaleDef = static_cast< const QgsProcessingParameterScale * >( parameterDefinition() );
1002 
1003  switch ( type() )
1004  {
1008  {
1009  mScaleWidget = new QgsScaleWidget( nullptr );
1011  mScaleWidget->setAllowNull( true );
1012 
1013  mScaleWidget->setMapCanvas( widgetContext().mapCanvas() );
1014  mScaleWidget->setShowCurrentScaleButton( true );
1015 
1016  mScaleWidget->setToolTip( parameterDefinition()->toolTip() );
1017  connect( mScaleWidget, &QgsScaleWidget::scaleChanged, this, [ = ]( double )
1018  {
1019  emit widgetValueHasChanged( this );
1020  } );
1021  return mScaleWidget;
1022  }
1023  }
1024  return nullptr;
1025 }
1026 
1027 void QgsProcessingScaleWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
1028 {
1029  if ( mScaleWidget )
1030  mScaleWidget->setMapCanvas( context.mapCanvas() );
1032 }
1033 
1034 
1035 QVariant QgsProcessingScaleWidgetWrapper::widgetValue() const
1036 {
1037  return mScaleWidget && !mScaleWidget->isNull() ? QVariant( mScaleWidget->scale() ) : QVariant();
1038 }
1039 
1040 void QgsProcessingScaleWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1041 {
1042  if ( mScaleWidget )
1043  {
1044  if ( mScaleWidget->allowNull() && !value.isValid() )
1045  mScaleWidget->setNull();
1046  else
1047  {
1048  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
1049  mScaleWidget->setScale( v );
1050  }
1051  }
1052 }
1053 
1054 
1055 //
1056 // QgsProcessingRangeWidgetWrapper
1057 //
1058 
1059 QgsProcessingRangeWidgetWrapper::QgsProcessingRangeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1060  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1061 {
1062 
1063 }
1064 
1065 QWidget *QgsProcessingRangeWidgetWrapper::createWidget()
1066 {
1067  const QgsProcessingParameterRange *rangeDef = static_cast< const QgsProcessingParameterRange * >( parameterDefinition() );
1068  switch ( type() )
1069  {
1073  {
1074  QHBoxLayout *layout = new QHBoxLayout();
1075 
1076  mMinSpinBox = new QgsDoubleSpinBox();
1077  mMaxSpinBox = new QgsDoubleSpinBox();
1078 
1079  mMinSpinBox->setExpressionsEnabled( true );
1080  mMinSpinBox->setShowClearButton( false );
1081  mMaxSpinBox->setExpressionsEnabled( true );
1082  mMaxSpinBox->setShowClearButton( false );
1083 
1084  QLabel *minLabel = new QLabel( tr( "Min" ) );
1085  layout->addWidget( minLabel );
1086  layout->addWidget( mMinSpinBox, 1 );
1087 
1088  QLabel *maxLabel = new QLabel( tr( "Max" ) );
1089  layout->addWidget( maxLabel );
1090  layout->addWidget( mMaxSpinBox, 1 );
1091 
1092  QWidget *w = new QWidget();
1093  layout->setMargin( 0 );
1094  layout->setContentsMargins( 0, 0, 0, 0 );
1095  w->setLayout( layout );
1096 
1097  if ( rangeDef->dataType() == QgsProcessingParameterNumber::Double )
1098  {
1099  mMinSpinBox->setDecimals( 6 );
1100  mMaxSpinBox->setDecimals( 6 );
1101  }
1102  else
1103  {
1104  mMinSpinBox->setDecimals( 0 );
1105  mMaxSpinBox->setDecimals( 0 );
1106  }
1107 
1108  mMinSpinBox->setMinimum( -99999999.999999 );
1109  mMaxSpinBox->setMinimum( -99999999.999999 );
1110  mMinSpinBox->setMaximum( 99999999.999999 );
1111  mMaxSpinBox->setMaximum( 99999999.999999 );
1112 
1113  w->setToolTip( parameterDefinition()->toolTip() );
1114 
1115  connect( mMinSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
1116  {
1117  mBlockChangedSignal++;
1118  if ( v > mMaxSpinBox->value() )
1119  mMaxSpinBox->setValue( v );
1120  mBlockChangedSignal--;
1121 
1122  if ( !mBlockChangedSignal )
1123  emit widgetValueHasChanged( this );
1124  } );
1125  connect( mMaxSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
1126  {
1127  mBlockChangedSignal++;
1128  if ( v < mMinSpinBox->value() )
1129  mMinSpinBox->setValue( v );
1130  mBlockChangedSignal--;
1131 
1132  if ( !mBlockChangedSignal )
1133  emit widgetValueHasChanged( this );
1134  } );
1135 
1136  return w;
1137  };
1138  }
1139  return nullptr;
1140 }
1141 
1142 void QgsProcessingRangeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1143 {
1144  const QList< double > v = QgsProcessingParameters::parameterAsRange( parameterDefinition(), value, context );
1145  if ( v.empty() )
1146  return;
1147 
1148  mBlockChangedSignal++;
1149  mMinSpinBox->setValue( v.at( 0 ) );
1150  if ( v.count() >= 2 )
1151  mMaxSpinBox->setValue( v.at( 1 ) );
1152  mBlockChangedSignal--;
1153 
1154  if ( !mBlockChangedSignal )
1155  emit widgetValueHasChanged( this );
1156 }
1157 
1158 QVariant QgsProcessingRangeWidgetWrapper::widgetValue() const
1159 {
1160  return QStringLiteral( "%1,%2" ).arg( mMinSpinBox->value() ).arg( mMaxSpinBox->value() );
1161 }
1162 
1163 QStringList QgsProcessingRangeWidgetWrapper::compatibleParameterTypes() const
1164 {
1165  return QStringList()
1168 }
1169 
1170 QStringList QgsProcessingRangeWidgetWrapper::compatibleOutputTypes() const
1171 {
1172  return QStringList() << QgsProcessingOutputString::typeName();
1173 }
1174 
1175 QList<int> QgsProcessingRangeWidgetWrapper::compatibleDataTypes() const
1176 {
1177  return QList< int >();
1178 }
1179 
1180 QString QgsProcessingRangeWidgetWrapper::modelerExpressionFormatString() const
1181 {
1182  return tr( "string as two comma delimited floats, e.g. '1,10'" );
1183 }
1184 
1185 QString QgsProcessingRangeWidgetWrapper::parameterType() const
1186 {
1188 }
1189 
1190 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRangeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1191 {
1192  return new QgsProcessingRangeWidgetWrapper( parameter, type );
1193 }
1194 
1195 
1196 
1197 //
1198 // QgsProcessingMatrixWidgetWrapper
1199 //
1200 
1201 QgsProcessingMatrixWidgetWrapper::QgsProcessingMatrixWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1202  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1203 {
1204 
1205 }
1206 
1207 QWidget *QgsProcessingMatrixWidgetWrapper::createWidget()
1208 {
1209  mMatrixWidget = new QgsProcessingMatrixParameterPanel( nullptr, dynamic_cast< const QgsProcessingParameterMatrix *>( parameterDefinition() ) );
1210  mMatrixWidget->setToolTip( parameterDefinition()->toolTip() );
1211 
1212  connect( mMatrixWidget, &QgsProcessingMatrixParameterPanel::changed, this, [ = ]
1213  {
1214  emit widgetValueHasChanged( this );
1215  } );
1216 
1217  switch ( type() )
1218  {
1222  {
1223  return mMatrixWidget;
1224  };
1225  }
1226  return nullptr;
1227 }
1228 
1229 void QgsProcessingMatrixWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1230 {
1231  const QVariantList v = QgsProcessingParameters::parameterAsMatrix( parameterDefinition(), value, context );
1232  if ( mMatrixWidget )
1233  mMatrixWidget->setValue( v );
1234 }
1235 
1236 QVariant QgsProcessingMatrixWidgetWrapper::widgetValue() const
1237 {
1238  if ( mMatrixWidget )
1239  return mMatrixWidget->value().isEmpty() ? QVariant() : mMatrixWidget->value();
1240  else
1241  return QVariant();
1242 }
1243 
1244 QStringList QgsProcessingMatrixWidgetWrapper::compatibleParameterTypes() const
1245 {
1246  return QStringList()
1248 }
1249 
1250 QStringList QgsProcessingMatrixWidgetWrapper::compatibleOutputTypes() const
1251 {
1252  return QStringList();
1253 }
1254 
1255 QList<int> QgsProcessingMatrixWidgetWrapper::compatibleDataTypes() const
1256 {
1257  return QList< int >();
1258 }
1259 
1260 QString QgsProcessingMatrixWidgetWrapper::modelerExpressionFormatString() const
1261 {
1262  return tr( "comma delimited string of values, or an array of values" );
1263 }
1264 
1265 QString QgsProcessingMatrixWidgetWrapper::parameterType() const
1266 {
1268 }
1269 
1270 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMatrixWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1271 {
1272  return new QgsProcessingMatrixWidgetWrapper( parameter, type );
1273 }
1274 
1275 
1276 
1277 
1278 //
1279 // QgsProcessingFileWidgetWrapper
1280 //
1281 
1282 
1283 QgsProcessingFileParameterDefinitionWidget::QgsProcessingFileParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1284  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1285 {
1286  QVBoxLayout *vlayout = new QVBoxLayout();
1287  vlayout->setMargin( 0 );
1288  vlayout->setContentsMargins( 0, 0, 0, 0 );
1289 
1290  vlayout->addWidget( new QLabel( tr( "Type" ) ) );
1291 
1292  mTypeComboBox = new QComboBox();
1293  mTypeComboBox->addItem( tr( "File" ), QgsProcessingParameterFile::File );
1294  mTypeComboBox->addItem( tr( "Folder" ), QgsProcessingParameterFile::Folder );
1295  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1296  mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( fileParam->behavior() ) );
1297  else
1298  mTypeComboBox->setCurrentIndex( 0 );
1299  vlayout->addWidget( mTypeComboBox );
1300 
1301  vlayout->addWidget( new QLabel( tr( "File filter" ) ) );
1302 
1303  mFilterComboBox = new QComboBox();
1304  mFilterComboBox->setEditable( true );
1305  // add some standard ones -- these also act as a demonstration of the required format
1306  mFilterComboBox->addItem( tr( "All Files (*.*)" ) );
1307  mFilterComboBox->addItem( tr( "CSV Files (*.csv)" ) );
1308  mFilterComboBox->addItem( tr( "HTML Files (*.html *.htm)" ) );
1309  mFilterComboBox->addItem( tr( "Text Files (*.txt)" ) );
1310  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1311  mFilterComboBox->setCurrentText( fileParam->fileFilter() );
1312  else
1313  mFilterComboBox->setCurrentIndex( 0 );
1314  vlayout->addWidget( mFilterComboBox );
1315 
1316  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1317 
1318  mDefaultFileWidget = new QgsFileWidget();
1319  mDefaultFileWidget->lineEdit()->setShowClearButton( true );
1320  if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
1321  {
1322  mDefaultFileWidget->setStorageMode( fileParam->behavior() == QgsProcessingParameterFile::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
1323  mDefaultFileWidget->setFilePath( fileParam->defaultValue().toString() );
1324  }
1325  else
1326  mDefaultFileWidget->setStorageMode( QgsFileWidget::GetFile );
1327  vlayout->addWidget( mDefaultFileWidget );
1328 
1329  connect( mTypeComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, [ = ]
1330  {
1331  QgsProcessingParameterFile::Behavior behavior = static_cast< QgsProcessingParameterFile::Behavior >( mTypeComboBox->currentData().toInt() );
1332  mFilterComboBox->setEnabled( behavior == QgsProcessingParameterFile::File );
1333  mDefaultFileWidget->setStorageMode( behavior == QgsProcessingParameterFile::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
1334  } );
1335  mFilterComboBox->setEnabled( static_cast< QgsProcessingParameterFile::Behavior >( mTypeComboBox->currentData().toInt() ) == QgsProcessingParameterFile::File );
1336 
1337 
1338  setLayout( vlayout );
1339 }
1340 
1341 QgsProcessingParameterDefinition *QgsProcessingFileParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
1342 {
1343  auto param = qgis::make_unique< QgsProcessingParameterFile >( name, description );
1344  param->setBehavior( static_cast< QgsProcessingParameterFile::Behavior>( mTypeComboBox->currentData().toInt() ) );
1345  if ( param->behavior() == QgsProcessingParameterFile::File )
1346  param->setFileFilter( mFilterComboBox->currentText() );
1347  if ( !mDefaultFileWidget->filePath().isEmpty() )
1348  param->setDefaultValue( mDefaultFileWidget->filePath() );
1349  param->setFlags( flags );
1350  return param.release();
1351 }
1352 
1353 
1354 QgsProcessingFileWidgetWrapper::QgsProcessingFileWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1355  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1356 {
1357 
1358 }
1359 
1360 QWidget *QgsProcessingFileWidgetWrapper::createWidget()
1361 {
1362  const QgsProcessingParameterFile *fileParam = dynamic_cast< const QgsProcessingParameterFile *>( parameterDefinition() );
1363  switch ( type() )
1364  {
1368  {
1369  mFileWidget = new QgsFileWidget();
1370  mFileWidget->setToolTip( parameterDefinition()->toolTip() );
1371  mFileWidget->setDialogTitle( parameterDefinition()->description() );
1372 
1373  mFileWidget->setDefaultRoot( QgsSettings().value( QStringLiteral( "/Processing/LastInputPath" ), QDir::homePath() ).toString() );
1374 
1375  switch ( fileParam->behavior() )
1376  {
1378  mFileWidget->setStorageMode( QgsFileWidget::GetFile );
1379  if ( !fileParam->fileFilter().isEmpty() )
1380  mFileWidget->setFilter( fileParam->fileFilter() );
1381  else if ( !fileParam->extension().isEmpty() )
1382  mFileWidget->setFilter( tr( "%1 files" ).arg( fileParam->extension().toUpper() ) + QStringLiteral( " (*." ) + fileParam->extension().toLower() + ')' );
1383  break;
1384 
1386  mFileWidget->setStorageMode( QgsFileWidget::GetDirectory );
1387  break;
1388  }
1389 
1390  connect( mFileWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & path )
1391  {
1392  QgsSettings().setValue( QStringLiteral( "/Processing/LastInputPath" ), QFileInfo( path ).canonicalPath() );
1393  emit widgetValueHasChanged( this );
1394  } );
1395  return mFileWidget;
1396  };
1397  }
1398  return nullptr;
1399 }
1400 
1401 void QgsProcessingFileWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1402 {
1403  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
1404  if ( mFileWidget )
1405  mFileWidget->setFilePath( v );
1406 }
1407 
1408 QVariant QgsProcessingFileWidgetWrapper::widgetValue() const
1409 {
1410  if ( mFileWidget )
1411  return mFileWidget->filePath();
1412  else
1413  return QVariant();
1414 }
1415 
1416 QStringList QgsProcessingFileWidgetWrapper::compatibleParameterTypes() const
1417 {
1418  return QStringList()
1421 }
1422 
1423 QStringList QgsProcessingFileWidgetWrapper::compatibleOutputTypes() const
1424 {
1425  return QStringList() << QgsProcessingOutputFile::typeName()
1430 }
1431 
1432 QList<int> QgsProcessingFileWidgetWrapper::compatibleDataTypes() const
1433 {
1434  return QList< int >();
1435 }
1436 
1437 QString QgsProcessingFileWidgetWrapper::modelerExpressionFormatString() const
1438 {
1439  return tr( "string representing a path to a file or folder" );
1440 }
1441 
1442 QString QgsProcessingFileWidgetWrapper::parameterType() const
1443 {
1445 }
1446 
1447 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1448 {
1449  return new QgsProcessingFileWidgetWrapper( parameter, type );
1450 }
1451 
1452 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFileWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1453 {
1454  return new QgsProcessingFileParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1455 }
1456 
1457 
1458 
1459 
1460 //
1461 // QgsProcessingExpressionWidgetWrapper
1462 //
1463 
1464 QgsProcessingExpressionWidgetWrapper::QgsProcessingExpressionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1465  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1466 {
1467 
1468 }
1469 
1470 QWidget *QgsProcessingExpressionWidgetWrapper::createWidget()
1471 {
1472  const QgsProcessingParameterExpression *expParam = dynamic_cast< const QgsProcessingParameterExpression *>( parameterDefinition() );
1473  switch ( type() )
1474  {
1478  {
1479  if ( expParam->parentLayerParameterName().isEmpty() )
1480  {
1481  mExpLineEdit = new QgsExpressionLineEdit();
1482  mExpLineEdit->setToolTip( parameterDefinition()->toolTip() );
1483  mExpLineEdit->setExpressionDialogTitle( parameterDefinition()->description() );
1484  mExpLineEdit->registerExpressionContextGenerator( this );
1485  connect( mExpLineEdit, &QgsExpressionLineEdit::expressionChanged, this, [ = ]( const QString & )
1486  {
1487  emit widgetValueHasChanged( this );
1488  } );
1489  return mExpLineEdit;
1490  }
1491  else
1492  {
1493  mFieldExpWidget = new QgsFieldExpressionWidget();
1494  mFieldExpWidget->setToolTip( parameterDefinition()->toolTip() );
1495  mFieldExpWidget->setExpressionDialogTitle( parameterDefinition()->description() );
1496  mFieldExpWidget->registerExpressionContextGenerator( this );
1497  connect( mFieldExpWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString & ) >( &QgsFieldExpressionWidget::fieldChanged ), this, [ = ]( const QString & )
1498  {
1499  emit widgetValueHasChanged( this );
1500  } );
1501  return mFieldExpWidget;
1502  }
1503  };
1504  }
1505  return nullptr;
1506 }
1507 
1508 void QgsProcessingExpressionWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1509 {
1511  switch ( type() )
1512  {
1515  {
1516  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1517  {
1518  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterExpression * >( parameterDefinition() )->parentLayerParameterName() )
1519  {
1520  setParentLayerWrapperValue( wrapper );
1522  {
1523  setParentLayerWrapperValue( wrapper );
1524  } );
1525  break;
1526  }
1527  }
1528  break;
1529  }
1530 
1532  break;
1533  }
1534 }
1535 
1536 void QgsProcessingExpressionWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
1537 {
1538  // evaluate value to layer
1539  QgsProcessingContext *context = nullptr;
1540  std::unique_ptr< QgsProcessingContext > tmpContext;
1541  if ( mProcessingContextGenerator )
1542  context = mProcessingContextGenerator->processingContext();
1543 
1544  if ( !context )
1545  {
1546  tmpContext = qgis::make_unique< QgsProcessingContext >();
1547  context = tmpContext.get();
1548  }
1549 
1550  QgsVectorLayer *layer = QgsProcessingParameters::parameterAsVectorLayer( parentWrapper->parameterDefinition(), parentWrapper->parameterValue(), *context );
1551  if ( !layer )
1552  {
1553  if ( mFieldExpWidget )
1554  mFieldExpWidget->setLayer( nullptr );
1555  else if ( mExpLineEdit )
1556  mExpLineEdit->setLayer( nullptr );
1557  return;
1558  }
1559 
1560  // need to grab ownership of layer if required - otherwise layer may be deleted when context
1561  // goes out of scope
1562  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
1563  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::VectorLayer )
1564  {
1565  mParentLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
1566  layer = mParentLayer.get();
1567  }
1568  else
1569  {
1570  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
1571  }
1572 
1573  if ( mFieldExpWidget )
1574  mFieldExpWidget->setLayer( layer );
1575  else if ( mExpLineEdit )
1576  mExpLineEdit->setLayer( layer );
1577 }
1578 
1579 void QgsProcessingExpressionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1580 {
1581  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
1582  if ( mFieldExpWidget )
1583  mFieldExpWidget->setExpression( v );
1584  else if ( mExpLineEdit )
1585  mExpLineEdit->setExpression( v );
1586 }
1587 
1588 QVariant QgsProcessingExpressionWidgetWrapper::widgetValue() const
1589 {
1590  if ( mFieldExpWidget )
1591  return mFieldExpWidget->expression();
1592  else if ( mExpLineEdit )
1593  return mExpLineEdit->expression();
1594  else
1595  return QVariant();
1596 }
1597 
1598 QStringList QgsProcessingExpressionWidgetWrapper::compatibleParameterTypes() const
1599 {
1600  return QStringList()
1606 }
1607 
1608 QStringList QgsProcessingExpressionWidgetWrapper::compatibleOutputTypes() const
1609 {
1610  return QStringList()
1613 }
1614 
1615 QList<int> QgsProcessingExpressionWidgetWrapper::compatibleDataTypes() const
1616 {
1617  return QList< int >();
1618 }
1619 
1620 QString QgsProcessingExpressionWidgetWrapper::modelerExpressionFormatString() const
1621 {
1622  return tr( "string representation of an expression" );
1623 }
1624 
1625 const QgsVectorLayer *QgsProcessingExpressionWidgetWrapper::linkedVectorLayer() const
1626 {
1627  if ( mFieldExpWidget && mFieldExpWidget->layer() )
1628  return mFieldExpWidget->layer();
1629 
1631 }
1632 
1633 QString QgsProcessingExpressionWidgetWrapper::parameterType() const
1634 {
1636 }
1637 
1638 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExpressionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1639 {
1640  return new QgsProcessingExpressionWidgetWrapper( parameter, type );
1641 }
1642 
1643 
1644 
1645 //
1646 // QgsProcessingEnumPanelWidget
1647 //
1648 
1649 QgsProcessingEnumPanelWidget::QgsProcessingEnumPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param )
1650  : QWidget( parent )
1651  , mParam( param )
1652 {
1653  QHBoxLayout *hl = new QHBoxLayout();
1654  hl->setMargin( 0 );
1655  hl->setContentsMargins( 0, 0, 0, 0 );
1656 
1657  mLineEdit = new QLineEdit();
1658  mLineEdit->setEnabled( false );
1659  hl->addWidget( mLineEdit, 1 );
1660 
1661  mToolButton = new QToolButton();
1662  mToolButton->setText( QStringLiteral( "…" ) );
1663  hl->addWidget( mToolButton );
1664 
1665  setLayout( hl );
1666 
1667  if ( mParam )
1668  {
1669  mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
1670  }
1671 
1672  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingEnumPanelWidget::showDialog );
1673 }
1674 
1675 void QgsProcessingEnumPanelWidget::setValue( const QVariant &value )
1676 {
1677  if ( value.isValid() )
1678  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
1679  else
1680  mValue.clear();
1681 
1682  updateSummaryText();
1683  emit changed();
1684 }
1685 
1686 void QgsProcessingEnumPanelWidget::showDialog()
1687 {
1688  QVariantList availableOptions;
1689  if ( mParam )
1690  {
1691  availableOptions.reserve( mParam->options().size() );
1692  for ( int i = 0; i < mParam->options().count(); ++i )
1693  availableOptions << i;
1694  }
1695 
1696  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, nullptr );
1697  const QStringList options = mParam ? mParam->options() : QStringList();
1698  dlg.setValueFormatter( [options]( const QVariant & v ) -> QString
1699  {
1700  const int i = v.toInt();
1701  return options.size() > i ? options.at( i ) : QString();
1702  } );
1703  if ( dlg.exec() )
1704  {
1705  setValue( dlg.selectedOptions() );
1706  }
1707 }
1708 
1709 void QgsProcessingEnumPanelWidget::updateSummaryText()
1710 {
1711  if ( mParam )
1712  mLineEdit->setText( tr( "%1 options selected" ).arg( mValue.count() ) );
1713 }
1714 
1715 
1716 //
1717 // QgsProcessingEnumCheckboxPanelWidget
1718 //
1719 QgsProcessingEnumCheckboxPanelWidget::QgsProcessingEnumCheckboxPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param, int columns )
1720  : QWidget( parent )
1721  , mParam( param )
1722  , mButtonGroup( new QButtonGroup( this ) )
1723  , mColumns( columns )
1724 {
1725  mButtonGroup->setExclusive( !mParam->allowMultiple() );
1726 
1727  QGridLayout *l = new QGridLayout();
1728  l->setContentsMargins( 0, 0, 0, 0 );
1729  l->setMargin( 0 );
1730 
1731  int rows = static_cast< int >( std::ceil( mParam->options().count() / static_cast< double >( mColumns ) ) );
1732  for ( int i = 0; i < mParam->options().count(); ++i )
1733  {
1734  QAbstractButton *button = nullptr;
1735  if ( mParam->allowMultiple() )
1736  button = new QCheckBox( mParam->options().at( i ) );
1737  else
1738  button = new QRadioButton( mParam->options().at( i ) );
1739 
1740  connect( button, &QAbstractButton::toggled, this, [ = ]
1741  {
1742  if ( !mBlockChangedSignal )
1743  emit changed();
1744  } );
1745 
1746  mButtons.insert( i, button );
1747  mButtonGroup->addButton( button, i );
1748  l->addWidget( button, i % rows, i / rows );
1749  }
1750  l->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ), 0, mColumns );
1751  setLayout( l );
1752 
1753  if ( mParam->allowMultiple() )
1754  {
1755  setContextMenuPolicy( Qt::CustomContextMenu );
1756  connect( this, &QWidget::customContextMenuRequested, this, &QgsProcessingEnumCheckboxPanelWidget::showPopupMenu );
1757  }
1758 }
1759 
1760 QVariant QgsProcessingEnumCheckboxPanelWidget::value() const
1761 {
1762  if ( mParam->allowMultiple() )
1763  {
1764  QVariantList value;
1765  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
1766  {
1767  if ( it.value()->isChecked() )
1768  value.append( it.key() );
1769  }
1770  return value;
1771  }
1772  else
1773  {
1774  return mButtonGroup->checkedId() >= 0 ? mButtonGroup->checkedId() : QVariant();
1775  }
1776 }
1777 
1778 void QgsProcessingEnumCheckboxPanelWidget::setValue( const QVariant &value )
1779 {
1780  mBlockChangedSignal = true;
1781  if ( mParam->allowMultiple() )
1782  {
1783  QVariantList selected;
1784  if ( value.isValid() )
1785  selected = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
1786  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
1787  {
1788  it.value()->setChecked( selected.contains( it.key() ) );
1789  }
1790  }
1791  else
1792  {
1793  QVariant v = value;
1794  if ( v.type() == QVariant::List )
1795  v = v.toList().value( 0 );
1796  if ( mButtons.contains( v ) )
1797  mButtons.value( v )->setChecked( true );
1798  }
1799  mBlockChangedSignal = false;
1800  emit changed();
1801 }
1802 
1803 void QgsProcessingEnumCheckboxPanelWidget::showPopupMenu()
1804 {
1805  QMenu popupMenu;
1806  QAction *selectAllAction = new QAction( tr( "Select All" ), &popupMenu );
1807  connect( selectAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::selectAll );
1808  QAction *clearAllAction = new QAction( tr( "Clear Selection" ), &popupMenu );
1809  connect( clearAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::deselectAll );
1810  popupMenu.addAction( selectAllAction );
1811  popupMenu.addAction( clearAllAction );
1812  popupMenu.exec( QCursor::pos() );
1813 }
1814 
1815 void QgsProcessingEnumCheckboxPanelWidget::selectAll()
1816 {
1817  mBlockChangedSignal = true;
1818  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
1819  it.value()->setChecked( true );
1820  mBlockChangedSignal = false;
1821  emit changed();
1822 }
1823 
1824 void QgsProcessingEnumCheckboxPanelWidget::deselectAll()
1825 {
1826  mBlockChangedSignal = true;
1827  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
1828  it.value()->setChecked( false );
1829  mBlockChangedSignal = false;
1830  emit changed();
1831 }
1832 
1833 
1834 //
1835 // QgsProcessingEnumWidgetWrapper
1836 //
1837 
1838 QgsProcessingEnumWidgetWrapper::QgsProcessingEnumWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1839  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1840 {
1841 
1842 }
1843 
1844 QWidget *QgsProcessingEnumWidgetWrapper::createWidget()
1845 {
1846  const QgsProcessingParameterEnum *expParam = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
1847  switch ( type() )
1848  {
1850  {
1851  // checkbox panel only for use outside in standard gui!
1852  if ( expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "useCheckBoxes" ), false ).toBool() )
1853  {
1854  const int columns = expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "columns" ), 2 ).toInt();
1855  mCheckboxPanel = new QgsProcessingEnumCheckboxPanelWidget( nullptr, expParam, columns );
1856  mCheckboxPanel->setToolTip( parameterDefinition()->toolTip() );
1857  connect( mCheckboxPanel, &QgsProcessingEnumCheckboxPanelWidget::changed, this, [ = ]
1858  {
1859  emit widgetValueHasChanged( this );
1860  } );
1861  return mCheckboxPanel;
1862  }
1863  }
1864  FALLTHROUGH
1867  {
1868  if ( expParam->allowMultiple() )
1869  {
1870  mPanel = new QgsProcessingEnumPanelWidget( nullptr, expParam );
1871  mPanel->setToolTip( parameterDefinition()->toolTip() );
1872  connect( mPanel, &QgsProcessingEnumPanelWidget::changed, this, [ = ]
1873  {
1874  emit widgetValueHasChanged( this );
1875  } );
1876  return mPanel;
1877  }
1878  else
1879  {
1880  mComboBox = new QComboBox();
1881 
1883  mComboBox->addItem( tr( "[Not selected]" ), QVariant() );
1884  const QStringList options = expParam->options();
1885  for ( int i = 0; i < options.count(); ++i )
1886  mComboBox->addItem( options.at( i ), i );
1887 
1888  mComboBox->setToolTip( parameterDefinition()->toolTip() );
1889  connect( mComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, [ = ]( int )
1890  {
1891  emit widgetValueHasChanged( this );
1892  } );
1893  return mComboBox;
1894  }
1895  };
1896  }
1897  return nullptr;
1898 }
1899 
1900 void QgsProcessingEnumWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1901 {
1902  if ( mComboBox )
1903  {
1904  if ( !value.isValid() )
1905  mComboBox->setCurrentIndex( mComboBox->findData( QVariant() ) );
1906  else
1907  {
1908  const int v = QgsProcessingParameters::parameterAsEnum( parameterDefinition(), value, context );
1909  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
1910  }
1911  }
1912  else if ( mPanel || mCheckboxPanel )
1913  {
1914  QVariantList opts;
1915  if ( value.isValid() )
1916  {
1917  const QList< int > v = QgsProcessingParameters::parameterAsEnums( parameterDefinition(), value, context );
1918  opts.reserve( v.size() );
1919  for ( int i : v )
1920  opts << i;
1921  }
1922  if ( mPanel )
1923  mPanel->setValue( opts );
1924  else if ( mCheckboxPanel )
1925  mCheckboxPanel->setValue( opts );
1926  }
1927 }
1928 
1929 QVariant QgsProcessingEnumWidgetWrapper::widgetValue() const
1930 {
1931  if ( mComboBox )
1932  return mComboBox->currentData();
1933  else if ( mPanel )
1934  return mPanel->value();
1935  else if ( mCheckboxPanel )
1936  return mCheckboxPanel->value();
1937  else
1938  return QVariant();
1939 }
1940 
1941 QStringList QgsProcessingEnumWidgetWrapper::compatibleParameterTypes() const
1942 {
1943  return QStringList()
1947 }
1948 
1949 QStringList QgsProcessingEnumWidgetWrapper::compatibleOutputTypes() const
1950 {
1951  return QStringList()
1954 }
1955 
1956 QList<int> QgsProcessingEnumWidgetWrapper::compatibleDataTypes() const
1957 {
1958  return QList<int>();
1959 }
1960 
1961 QString QgsProcessingEnumWidgetWrapper::modelerExpressionFormatString() const
1962 {
1963  return tr( "selected option index (starting from 0), array of indices, or comma separated string of options (e.g. '1,3')" );
1964 }
1965 
1966 QString QgsProcessingEnumWidgetWrapper::parameterType() const
1967 {
1969 }
1970 
1971 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingEnumWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1972 {
1973  return new QgsProcessingEnumWidgetWrapper( parameter, type );
1974 }
1975 
1976 //
1977 // QgsProcessingLayoutWidgetWrapper
1978 //
1979 
1980 QgsProcessingLayoutWidgetWrapper::QgsProcessingLayoutWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1981  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1982 {
1983 
1984 }
1985 
1986 QWidget *QgsProcessingLayoutWidgetWrapper::createWidget()
1987 {
1988  const QgsProcessingParameterLayout *layoutParam = dynamic_cast< const QgsProcessingParameterLayout *>( parameterDefinition() );
1989  switch ( type() )
1990  {
1993  {
1994  // combobox only for use outside modeler!
1995  mComboBox = new QgsLayoutComboBox( nullptr, widgetContext().project() ? widgetContext().project()->layoutManager() : nullptr );
1997  mComboBox->setAllowEmptyLayout( true );
1998  mComboBox->setFilters( QgsLayoutManagerProxyModel::FilterPrintLayouts );
1999 
2000  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2001  connect( mComboBox, &QgsLayoutComboBox::layoutChanged, this, [ = ]( QgsMasterLayoutInterface * )
2002  {
2003  emit widgetValueHasChanged( this );
2004  } );
2005  return mComboBox;
2006  }
2007 
2009  {
2010  mLineEdit = new QLineEdit();
2011  mLineEdit->setToolTip( tr( "Name of an existing print layout" ) );
2012  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
2013  {
2014  emit widgetValueHasChanged( this );
2015  } );
2016  return mLineEdit;
2017  }
2018  }
2019  return nullptr;
2020 }
2021 
2022 void QgsProcessingLayoutWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2023 {
2024  if ( mComboBox )
2025  {
2026  if ( !value.isValid() )
2027  mComboBox->setCurrentLayout( nullptr );
2028  else
2029  {
2030  if ( QgsPrintLayout *l = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, context ) )
2031  mComboBox->setCurrentLayout( l );
2032  else
2033  mComboBox->setCurrentLayout( nullptr );
2034  }
2035  }
2036  else if ( mLineEdit )
2037  {
2038  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2039  mLineEdit->setText( v );
2040  }
2041 }
2042 
2043 QVariant QgsProcessingLayoutWidgetWrapper::widgetValue() const
2044 {
2045  if ( mComboBox )
2046  {
2047  const QgsMasterLayoutInterface *l = mComboBox->currentLayout();
2048  return l ? l->name() : QVariant();
2049  }
2050  else if ( mLineEdit )
2051  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
2052  else
2053  return QVariant();
2054 }
2055 
2056 QStringList QgsProcessingLayoutWidgetWrapper::compatibleParameterTypes() const
2057 {
2058  return QStringList()
2061 }
2062 
2063 QStringList QgsProcessingLayoutWidgetWrapper::compatibleOutputTypes() const
2064 {
2065  return QStringList()
2067 }
2068 
2069 QList<int> QgsProcessingLayoutWidgetWrapper::compatibleDataTypes() const
2070 {
2071  return QList<int>();
2072 }
2073 
2074 QString QgsProcessingLayoutWidgetWrapper::modelerExpressionFormatString() const
2075 {
2076  return tr( "string representing the name of an existing print layout" );
2077 }
2078 
2079 QString QgsProcessingLayoutWidgetWrapper::parameterType() const
2080 {
2082 }
2083 
2084 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2085 {
2086  return new QgsProcessingLayoutWidgetWrapper( parameter, type );
2087 }
2088 
2089 
2090 
2091 
2092 //
2093 // QgsProcessingLayoutItemWidgetWrapper
2094 //
2095 
2096 
2097 QgsProcessingLayoutItemParameterDefinitionWidget::QgsProcessingLayoutItemParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2098  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2099 {
2100  QVBoxLayout *vlayout = new QVBoxLayout();
2101  vlayout->setMargin( 0 );
2102  vlayout->setContentsMargins( 0, 0, 0, 0 );
2103 
2104  vlayout->addWidget( new QLabel( tr( "Parent layout" ) ) );
2105 
2106  mParentLayoutComboBox = new QComboBox();
2107  QString initialParent;
2108  if ( const QgsProcessingParameterLayoutItem *itemParam = dynamic_cast<const QgsProcessingParameterLayoutItem *>( definition ) )
2109  initialParent = itemParam->parentLayoutParameterName();
2110 
2111  if ( widgetContext.model() )
2112  {
2113  // populate combo box with other model input choices
2114  const QMap<QString, QgsProcessingModelParameter> components = widgetContext.model()->parameterComponents();
2115  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
2116  {
2117  if ( const QgsProcessingParameterLayout *definition = dynamic_cast< const QgsProcessingParameterLayout * >( widgetContext.model()->parameterDefinition( it.value().parameterName() ) ) )
2118  {
2119  mParentLayoutComboBox-> addItem( definition->description(), definition->name() );
2120  if ( !initialParent.isEmpty() && initialParent == definition->name() )
2121  {
2122  mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
2123  }
2124  }
2125  }
2126  }
2127 
2128  if ( mParentLayoutComboBox->count() == 0 && !initialParent.isEmpty() )
2129  {
2130  // if no parent candidates found, we just add the existing one as a placeholder
2131  mParentLayoutComboBox->addItem( initialParent, initialParent );
2132  mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
2133  }
2134 
2135  vlayout->addWidget( mParentLayoutComboBox );
2136  setLayout( vlayout );
2137 }
2138 QgsProcessingParameterDefinition *QgsProcessingLayoutItemParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2139 {
2140  auto param = qgis::make_unique< QgsProcessingParameterLayoutItem >( name, description, QVariant(), mParentLayoutComboBox->currentData().toString() );
2141  param->setFlags( flags );
2142  return param.release();
2143 }
2144 
2145 
2146 QgsProcessingLayoutItemWidgetWrapper::QgsProcessingLayoutItemWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2147  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2148 {
2149 
2150 }
2151 
2152 QWidget *QgsProcessingLayoutItemWidgetWrapper::createWidget()
2153 {
2154  const QgsProcessingParameterLayoutItem *layoutParam = dynamic_cast< const QgsProcessingParameterLayoutItem *>( parameterDefinition() );
2155  switch ( type() )
2156  {
2159  {
2160  // combobox only for use outside modeler!
2161  mComboBox = new QgsLayoutItemComboBox( nullptr, nullptr );
2163  mComboBox->setAllowEmptyItem( true );
2164  if ( layoutParam->itemType() >= 0 )
2165  mComboBox->setItemType( static_cast< QgsLayoutItemRegistry::ItemType >( layoutParam->itemType() ) );
2166 
2167  mComboBox->setToolTip( parameterDefinition()->toolTip() );
2168  connect( mComboBox, &QgsLayoutItemComboBox::itemChanged, this, [ = ]( QgsLayoutItem * )
2169  {
2170  emit widgetValueHasChanged( this );
2171  } );
2172  return mComboBox;
2173  }
2174 
2176  {
2177  mLineEdit = new QLineEdit();
2178  mLineEdit->setToolTip( tr( "UUID or ID of an existing print layout item" ) );
2179  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
2180  {
2181  emit widgetValueHasChanged( this );
2182  } );
2183  return mLineEdit;
2184  }
2185  }
2186  return nullptr;
2187 }
2188 
2189 void QgsProcessingLayoutItemWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
2190 {
2191  switch ( type() )
2192  {
2195  {
2196  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
2197  {
2198  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterLayoutItem * >( parameterDefinition() )->parentLayoutParameterName() )
2199  {
2200  setLayoutParameterValue( wrapper->parameterValue() );
2202  {
2203  setLayoutParameterValue( wrapper->parameterValue() );
2204  } );
2205  break;
2206  }
2207  }
2208  break;
2209  }
2210 
2212  break;
2213  }
2214 }
2215 
2216 void QgsProcessingLayoutItemWidgetWrapper::setLayoutParameterValue( const QVariant &value )
2217 {
2218  QgsPrintLayout *layout = nullptr;
2219 
2220  // evaluate value to layout
2221  QgsProcessingContext *context = nullptr;
2222  std::unique_ptr< QgsProcessingContext > tmpContext;
2223  if ( mProcessingContextGenerator )
2224  context = mProcessingContextGenerator->processingContext();
2225 
2226  if ( !context )
2227  {
2228  tmpContext = qgis::make_unique< QgsProcessingContext >();
2229  context = tmpContext.get();
2230  }
2231 
2232  layout = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, *context );
2233  setLayout( layout );
2234 }
2235 
2236 void QgsProcessingLayoutItemWidgetWrapper::setLayout( QgsPrintLayout *layout )
2237 {
2238  if ( mComboBox )
2239  mComboBox->setCurrentLayout( layout );
2240 }
2241 
2242 void QgsProcessingLayoutItemWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2243 {
2244  if ( mComboBox )
2245  {
2246  if ( !value.isValid() )
2247  mComboBox->setItem( nullptr );
2248  else
2249  {
2250  QgsLayoutItem *item = QgsProcessingParameters::parameterAsLayoutItem( parameterDefinition(), value, context, qobject_cast< QgsPrintLayout * >( mComboBox->currentLayout() ) );
2251  mComboBox->setItem( item );
2252  }
2253  }
2254  else if ( mLineEdit )
2255  {
2256  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2257  mLineEdit->setText( v );
2258  }
2259 }
2260 
2261 QVariant QgsProcessingLayoutItemWidgetWrapper::widgetValue() const
2262 {
2263  if ( mComboBox )
2264  {
2265  const QgsLayoutItem *i = mComboBox->currentItem();
2266  return i ? i->uuid() : QVariant();
2267  }
2268  else if ( mLineEdit )
2269  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
2270  else
2271  return QVariant();
2272 }
2273 
2274 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleParameterTypes() const
2275 {
2276  return QStringList()
2279 }
2280 
2281 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleOutputTypes() const
2282 {
2283  return QStringList()
2285 }
2286 
2287 QList<int> QgsProcessingLayoutItemWidgetWrapper::compatibleDataTypes() const
2288 {
2289  return QList<int>();
2290 }
2291 
2292 QString QgsProcessingLayoutItemWidgetWrapper::modelerExpressionFormatString() const
2293 {
2294  return tr( "string representing the UUID or ID of an existing print layout item" );
2295 }
2296 
2297 QString QgsProcessingLayoutItemWidgetWrapper::parameterType() const
2298 {
2300 }
2301 
2302 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutItemWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2303 {
2304  return new QgsProcessingLayoutItemWidgetWrapper( parameter, type );
2305 }
2306 
2307 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingLayoutItemWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2308 {
2309  return new QgsProcessingLayoutItemParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2310 }
2311 
2312 //
2313 // QgsProcessingPointMapTool
2314 //
2315 
2316 QgsProcessingPointMapTool::QgsProcessingPointMapTool( QgsMapCanvas *canvas )
2317  : QgsMapTool( canvas )
2318 {
2319  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::CapturePoint ) );
2320  mSnapIndicator.reset( new QgsSnapIndicator( canvas ) );
2321 }
2322 
2323 QgsProcessingPointMapTool::~QgsProcessingPointMapTool() = default;
2324 
2325 void QgsProcessingPointMapTool::deactivate()
2326 {
2327  mSnapIndicator->setMatch( QgsPointLocator::Match() );
2329 }
2330 
2331 void QgsProcessingPointMapTool::canvasMoveEvent( QgsMapMouseEvent *e )
2332 {
2333  e->snapPoint();
2334  mSnapIndicator->setMatch( e->mapPointMatch() );
2335 }
2336 
2337 void QgsProcessingPointMapTool::canvasPressEvent( QgsMapMouseEvent *e )
2338 {
2339  if ( e->button() == Qt::LeftButton )
2340  {
2341  QgsPointXY point = e->snapPoint();
2342  emit clicked( point );
2343  emit complete();
2344  }
2345 }
2346 
2347 void QgsProcessingPointMapTool::keyPressEvent( QKeyEvent *e )
2348 {
2349  if ( e->key() == Qt::Key_Escape )
2350  {
2351 
2352  // Override default shortcut management in MapCanvas
2353  e->ignore();
2354  emit complete();
2355  }
2356 }
2357 
2358 
2359 
2360 //
2361 // QgsProcessingPointPanel
2362 //
2363 
2364 QgsProcessingPointPanel::QgsProcessingPointPanel( QWidget *parent )
2365  : QWidget( parent )
2366 {
2367  QHBoxLayout *l = new QHBoxLayout();
2368  l->setContentsMargins( 0, 0, 0, 0 );
2369  l->setMargin( 0 );
2370  mLineEdit = new QgsFilterLineEdit( );
2371  mLineEdit->setShowClearButton( false );
2372  l->addWidget( mLineEdit, 1 );
2373  mButton = new QToolButton();
2374  mButton->setText( QStringLiteral( "…" ) );
2375  l->addWidget( mButton );
2376  setLayout( l );
2377 
2378  connect( mLineEdit, &QLineEdit::textChanged, this, &QgsProcessingPointPanel::changed );
2379  connect( mButton, &QToolButton::clicked, this, &QgsProcessingPointPanel::selectOnCanvas );
2380  mButton->setVisible( false );
2381 }
2382 
2383 void QgsProcessingPointPanel::setMapCanvas( QgsMapCanvas *canvas )
2384 {
2385  mCanvas = canvas;
2386  mButton->setVisible( true );
2387 
2388  mCrs = canvas->mapSettings().destinationCrs();
2389  mTool = qgis::make_unique< QgsProcessingPointMapTool >( mCanvas );
2390  connect( mTool.get(), &QgsProcessingPointMapTool::clicked, this, &QgsProcessingPointPanel::updatePoint );
2391  connect( mTool.get(), &QgsProcessingPointMapTool::complete, this, &QgsProcessingPointPanel::pointPicked );
2392 }
2393 
2394 void QgsProcessingPointPanel::setAllowNull( bool allowNull )
2395 {
2396  mLineEdit->setShowClearButton( allowNull );
2397 }
2398 
2399 QVariant QgsProcessingPointPanel::value() const
2400 {
2401  return mLineEdit->showClearButton() && mLineEdit->text().trimmed().isEmpty() ? QVariant() : QVariant( mLineEdit->text() );
2402 }
2403 
2404 void QgsProcessingPointPanel::clear()
2405 {
2406  mLineEdit->clear();
2407 }
2408 
2409 void QgsProcessingPointPanel::setValue( const QgsPointXY &point, const QgsCoordinateReferenceSystem &crs )
2410 {
2411  QString newText = QStringLiteral( "%1,%2" )
2412  .arg( QString::number( point.x(), 'f' ) )
2413  .arg( QString::number( point.y(), 'f' ) );
2414 
2415  mCrs = crs;
2416  if ( mCrs.isValid() )
2417  {
2418  newText += QStringLiteral( " [%1]" ).arg( mCrs.authid() );
2419  }
2420  mLineEdit->setText( newText );
2421 }
2422 
2423 void QgsProcessingPointPanel::selectOnCanvas()
2424 {
2425  if ( !mCanvas )
2426  return;
2427 
2428  mPrevTool = mCanvas->mapTool();
2429  mCanvas->setMapTool( mTool.get() );
2430 
2431  emit toggleDialogVisibility( false );
2432 }
2433 
2434 void QgsProcessingPointPanel::updatePoint( const QgsPointXY &point )
2435 {
2436  setValue( point, mCanvas->mapSettings().destinationCrs() );
2437 }
2438 
2439 void QgsProcessingPointPanel::pointPicked()
2440 {
2441  if ( !mCanvas )
2442  return;
2443 
2444  mCanvas->setMapTool( mPrevTool );
2445 
2446  emit toggleDialogVisibility( true );
2447 }
2448 
2449 
2450 
2451 
2452 //
2453 // QgsProcessingPointWidgetWrapper
2454 //
2455 
2456 QgsProcessingPointWidgetWrapper::QgsProcessingPointWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2457  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2458 {
2459 
2460 }
2461 
2462 QWidget *QgsProcessingPointWidgetWrapper::createWidget()
2463 {
2464  const QgsProcessingParameterPoint *pointParam = dynamic_cast< const QgsProcessingParameterPoint *>( parameterDefinition() );
2465  switch ( type() )
2466  {
2469  {
2470  mPanel = new QgsProcessingPointPanel( nullptr );
2471  if ( widgetContext().mapCanvas() )
2472  mPanel->setMapCanvas( widgetContext().mapCanvas() );
2473 
2475  mPanel->setAllowNull( true );
2476 
2477  mPanel->setToolTip( parameterDefinition()->toolTip() );
2478 
2479  connect( mPanel, &QgsProcessingPointPanel::changed, this, [ = ]
2480  {
2481  emit widgetValueHasChanged( this );
2482  } );
2483 
2484  if ( mDialog )
2485  setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
2486  return mPanel;
2487  }
2488 
2490  {
2491  mLineEdit = new QLineEdit();
2492  mLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
2493  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
2494  {
2495  emit widgetValueHasChanged( this );
2496  } );
2497  return mLineEdit;
2498  }
2499  }
2500  return nullptr;
2501 }
2502 
2503 void QgsProcessingPointWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
2504 {
2506  if ( mPanel && context.mapCanvas() )
2507  mPanel->setMapCanvas( context.mapCanvas() );
2508 }
2509 
2510 void QgsProcessingPointWidgetWrapper::setDialog( QDialog *dialog )
2511 {
2512  mDialog = dialog;
2513  if ( mPanel )
2514  {
2515  connect( mPanel, &QgsProcessingPointPanel::toggleDialogVisibility, mDialog, [ = ]( bool visible )
2516  {
2517  if ( !visible )
2518  mDialog->showMinimized();
2519  else
2520  {
2521  mDialog->showNormal();
2522  mDialog->raise();
2523  mDialog->activateWindow();
2524  }
2525  } );
2526  }
2528 }
2529 
2530 void QgsProcessingPointWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2531 {
2532  if ( mPanel )
2533  {
2534  if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
2535  mPanel->clear();
2536  else
2537  {
2538  QgsPointXY p = QgsProcessingParameters::parameterAsPoint( parameterDefinition(), value, context );
2539  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
2540  mPanel->setValue( p, crs );
2541  }
2542  }
2543  else if ( mLineEdit )
2544  {
2545  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2546  mLineEdit->setText( v );
2547  }
2548 }
2549 
2550 QVariant QgsProcessingPointWidgetWrapper::widgetValue() const
2551 {
2552  if ( mPanel )
2553  {
2554  return mPanel->value();
2555  }
2556  else if ( mLineEdit )
2557  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
2558  else
2559  return QVariant();
2560 }
2561 
2562 QStringList QgsProcessingPointWidgetWrapper::compatibleParameterTypes() const
2563 {
2564  return QStringList()
2567 }
2568 
2569 QStringList QgsProcessingPointWidgetWrapper::compatibleOutputTypes() const
2570 {
2571  return QStringList()
2573 }
2574 
2575 QList<int> QgsProcessingPointWidgetWrapper::compatibleDataTypes() const
2576 {
2577  return QList<int>();
2578 }
2579 
2580 QString QgsProcessingPointWidgetWrapper::modelerExpressionFormatString() const
2581 {
2582  return tr( "string of the format 'x,y' or a geometry value (centroid is used)" );
2583 }
2584 
2585 QString QgsProcessingPointWidgetWrapper::parameterType() const
2586 {
2588 }
2589 
2590 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2591 {
2592  return new QgsProcessingPointWidgetWrapper( parameter, type );
2593 }
2594 
2595 
2596 
2597 
2598 //
2599 // QgsProcessingColorWidgetWrapper
2600 //
2601 
2602 
2603 QgsProcessingColorParameterDefinitionWidget::QgsProcessingColorParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2604  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2605 {
2606  QVBoxLayout *vlayout = new QVBoxLayout();
2607  vlayout->setMargin( 0 );
2608  vlayout->setContentsMargins( 0, 0, 0, 0 );
2609 
2610  vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
2611 
2612  mDefaultColorButton = new QgsColorButton();
2613  mDefaultColorButton->setShowNull( true );
2614  mAllowOpacity = new QCheckBox( tr( "Allow opacity control" ) );
2615 
2616  if ( const QgsProcessingParameterColor *colorParam = dynamic_cast<const QgsProcessingParameterColor *>( definition ) )
2617  {
2618  const QColor c = QgsProcessingParameters::parameterAsColor( colorParam, colorParam->defaultValue(), context );
2619  if ( !c.isValid() )
2620  mDefaultColorButton->setToNull();
2621  else
2622  mDefaultColorButton->setColor( c );
2623  mAllowOpacity->setChecked( colorParam->opacityEnabled() );
2624  }
2625  else
2626  {
2627  mDefaultColorButton->setToNull();
2628  mAllowOpacity->setChecked( true );
2629  }
2630 
2631  vlayout->addWidget( mDefaultColorButton );
2632  vlayout->addWidget( mAllowOpacity );
2633  setLayout( vlayout );
2634 }
2635 
2636 QgsProcessingParameterDefinition *QgsProcessingColorParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
2637 {
2638  auto param = qgis::make_unique< QgsProcessingParameterColor >( name, description, mDefaultColorButton->color(), mAllowOpacity->isChecked() );
2639  param->setFlags( flags );
2640  return param.release();
2641 }
2642 
2643 QgsProcessingColorWidgetWrapper::QgsProcessingColorWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2644  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2645 {
2646 
2647 }
2648 
2649 QWidget *QgsProcessingColorWidgetWrapper::createWidget()
2650 {
2651  const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor *>( parameterDefinition() );
2652  switch ( type() )
2653  {
2657  {
2658  mColorButton = new QgsColorButton( nullptr );
2659  mColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
2660 
2662  mColorButton->setShowNull( true );
2663 
2664  mColorButton->setAllowOpacity( colorParam->opacityEnabled() );
2665  mColorButton->setToolTip( parameterDefinition()->toolTip() );
2666  mColorButton->setColorDialogTitle( parameterDefinition()->description() );
2667  if ( colorParam->defaultValue().value< QColor >().isValid() )
2668  {
2669  mColorButton->setDefaultColor( colorParam->defaultValue().value< QColor >() );
2670  }
2671 
2672  connect( mColorButton, &QgsColorButton::colorChanged, this, [ = ]
2673  {
2674  emit widgetValueHasChanged( this );
2675  } );
2676 
2677  return mColorButton;
2678  }
2679  }
2680  return nullptr;
2681 }
2682 
2683 void QgsProcessingColorWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2684 {
2685  if ( mColorButton )
2686  {
2687  if ( !value.isValid() ||
2688  ( value.type() == QVariant::String && value.toString().isEmpty() )
2689  || ( value.type() == QVariant::Color && !value.value< QColor >().isValid() ) )
2690  mColorButton->setToNull();
2691  else
2692  {
2693  const QColor c = QgsProcessingParameters::parameterAsColor( parameterDefinition(), value, context );
2694  if ( !c.isValid() && mColorButton->showNull() )
2695  mColorButton->setToNull();
2696  else
2697  mColorButton->setColor( c );
2698  }
2699  }
2700 }
2701 
2702 QVariant QgsProcessingColorWidgetWrapper::widgetValue() const
2703 {
2704  if ( mColorButton )
2705  return mColorButton->isNull() ? QVariant() : mColorButton->color();
2706  else
2707  return QVariant();
2708 }
2709 
2710 QStringList QgsProcessingColorWidgetWrapper::compatibleParameterTypes() const
2711 {
2712  return QStringList()
2715 }
2716 
2717 QStringList QgsProcessingColorWidgetWrapper::compatibleOutputTypes() const
2718 {
2719  return QStringList()
2721 }
2722 
2723 QList<int> QgsProcessingColorWidgetWrapper::compatibleDataTypes() const
2724 {
2725  return QList<int>();
2726 }
2727 
2728 QString QgsProcessingColorWidgetWrapper::modelerExpressionFormatString() const
2729 {
2730  return tr( "color style string, e.g. #ff0000 or 255,0,0" );
2731 }
2732 
2733 QString QgsProcessingColorWidgetWrapper::parameterType() const
2734 {
2736 }
2737 
2738 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingColorWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2739 {
2740  return new QgsProcessingColorWidgetWrapper( parameter, type );
2741 }
2742 
2743 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingColorWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2744 {
2745  return new QgsProcessingColorParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2746 }
2747 
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.
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.
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.
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:280
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.
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.
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
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.
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 QString typeName()
Returns the type name for the parameter class.
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.
#define FALLTHROUGH
Definition: qgis.h:681
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...
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
void widgetValueHasChanged(QgsAbstractProcessingParameterWidgetWrapper *wrapper)
Emitted whenever the parameter value (as defined by the wrapped widget) is changed.
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
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...
void setDefaultValue(const QVariant &value)
Sets the default value for the parameter.
static QString typeName()
Returns the type name for the output class.
QStringList options() const
Returns the list of acceptable options for the parameter.
virtual void deactivate()
called when map tool is being deactivated
Definition: qgsmaptool.cpp:99
A print layout item parameter, allowing users to select a particular item from a print layout...
static QString typeName()
Returns the type name for the 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.
Behavior behavior() const
Returns the parameter behavior (e.g.
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 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:328
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the parameter class.
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.
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 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.
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 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.
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.