QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 "qgsprocessingoutputs.h"
23 #include "qgsspinbox.h"
24 #include "qgsdoublespinbox.h"
25 #include "qgsprocessingcontext.h"
26 #include "qgsauthconfigselect.h"
27 #include "qgsapplication.h"
28 #include "qgsfilewidget.h"
29 #include "qgssettings.h"
30 #include "qgsexpressionlineedit.h"
33 #include "qgslayoutmanager.h"
34 #include "qgsproject.h"
35 #include "qgslayoutcombobox.h"
36 #include "qgslayoutitemcombobox.h"
37 #include "qgsprintlayout.h"
38 #include "qgsscalewidget.h"
39 #include "qgssnapindicator.h"
40 #include "qgsmapmouseevent.h"
41 #include "qgsfilterlineedit.h"
42 #include "qgsmapcanvas.h"
43 #include <QToolButton>
44 #include <QLabel>
45 #include <QHBoxLayout>
46 #include <QCheckBox>
47 #include <QComboBox>
48 #include <QLineEdit>
49 #include <QPlainTextEdit>
50 #include <QRadioButton>
51 #include <QButtonGroup>
52 #include <QMenu>
53 
55 
56 //
57 // QgsProcessingBooleanWidgetWrapper
58 //
59 
60 QgsProcessingBooleanWidgetWrapper::QgsProcessingBooleanWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
61  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
62 {
63 
64 }
65 
66 QWidget *QgsProcessingBooleanWidgetWrapper::createWidget()
67 {
68  switch ( type() )
69  {
71  {
72  QString description = parameterDefinition()->description();
73  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
74  description = QObject::tr( "%1 [optional]" ).arg( description );
75 
76  mCheckBox = new QCheckBox( description );
77  mCheckBox->setToolTip( parameterDefinition()->toolTip() );
78 
79  connect( mCheckBox, &QCheckBox::toggled, this, [ = ]
80  {
81  emit widgetValueHasChanged( this );
82  } );
83  return mCheckBox;
84  };
85 
88  {
89  mComboBox = new QComboBox();
90  mComboBox->addItem( tr( "Yes" ), true );
91  mComboBox->addItem( tr( "No" ), false );
92  mComboBox->setToolTip( parameterDefinition()->toolTip() );
93 
94  connect( mComboBox, qgis::overload< int>::of( &QComboBox::currentIndexChanged ), this, [ = ]
95  {
96  emit widgetValueHasChanged( this );
97  } );
98 
99  return mComboBox;
100  }
101  }
102  return nullptr;
103 }
104 
105 QLabel *QgsProcessingBooleanWidgetWrapper::createLabel()
106 {
107  // avoid creating labels in standard dialogs
108  if ( type() == QgsProcessingGui::Standard )
109  return nullptr;
110  else
112 }
113 
114 void QgsProcessingBooleanWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
115 {
116  switch ( type() )
117  {
119  {
120  const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
121  mCheckBox->setChecked( v );
122  break;
123  }
124 
127  {
128  const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
129  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
130  break;
131  }
132  }
133 }
134 
135 QVariant QgsProcessingBooleanWidgetWrapper::widgetValue() const
136 {
137  switch ( type() )
138  {
140  return mCheckBox->isChecked();
141 
144  return mComboBox->currentData();
145  }
146  return QVariant();
147 }
148 
149 QStringList QgsProcessingBooleanWidgetWrapper::compatibleParameterTypes() const
150 {
151  //pretty much everything is compatible here and can be converted to a bool!
152  return QStringList() << QgsProcessingParameterBoolean::typeName()
165 }
166 
167 QStringList QgsProcessingBooleanWidgetWrapper::compatibleOutputTypes() const
168 {
169  return QStringList() << QgsProcessingOutputNumber::typeName()
176 }
177 
178 QList<int> QgsProcessingBooleanWidgetWrapper::compatibleDataTypes() const
179 {
180  return QList< int >();
181 }
182 
183 QString QgsProcessingBooleanWidgetWrapper::parameterType() const
184 {
186 }
187 
188 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBooleanWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
189 {
190  return new QgsProcessingBooleanWidgetWrapper( parameter, type );
191 }
192 
193 
194 //
195 // QgsProcessingCrsWidgetWrapper
196 //
197 
198 QgsProcessingCrsWidgetWrapper::QgsProcessingCrsWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
199  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
200 {
201 
202 }
203 
204 QWidget *QgsProcessingCrsWidgetWrapper::createWidget()
205 {
206  mProjectionSelectionWidget = new QgsProjectionSelectionWidget();
207  mProjectionSelectionWidget->setToolTip( parameterDefinition()->toolTip() );
208 
209  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
210  mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
211  else
212  mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, false );
213 
214  connect( mProjectionSelectionWidget, &QgsProjectionSelectionWidget::crsChanged, this, [ = ]
215  {
216  emit widgetValueHasChanged( this );
217  } );
218 
219  switch ( type() )
220  {
223  {
224  return mProjectionSelectionWidget;
225  };
226 
228  {
229  QWidget *w = new QWidget();
230  w->setToolTip( parameterDefinition()->toolTip() );
231 
232  QVBoxLayout *vl = new QVBoxLayout();
233  vl->setMargin( 0 );
234  vl->setContentsMargins( 0, 0, 0, 0 );
235  w->setLayout( vl );
236 
237  mUseProjectCrsCheckBox = new QCheckBox( tr( "Use project CRS" ) );
238  mUseProjectCrsCheckBox->setToolTip( tr( "Always use the current project CRS when running the model" ) );
239  vl->addWidget( mUseProjectCrsCheckBox );
240  connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, mProjectionSelectionWidget, &QgsProjectionSelectionWidget::setDisabled );
241  connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, this, [ = ]
242  {
243  emit widgetValueHasChanged( this );
244  } );
245 
246  vl->addWidget( mProjectionSelectionWidget );
247 
248  return w;
249  }
250  }
251  return nullptr;
252 }
253 
254 void QgsProcessingCrsWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
255 {
256  if ( mUseProjectCrsCheckBox )
257  {
258  if ( value.toString().compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
259  {
260  mUseProjectCrsCheckBox->setChecked( true );
261  return;
262  }
263  else
264  {
265  mUseProjectCrsCheckBox->setChecked( false );
266  }
267  }
268 
269  const QgsCoordinateReferenceSystem v = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, context );
270  if ( mProjectionSelectionWidget )
271  mProjectionSelectionWidget->setCrs( v );
272 }
273 
274 QVariant QgsProcessingCrsWidgetWrapper::widgetValue() const
275 {
276  if ( mUseProjectCrsCheckBox && mUseProjectCrsCheckBox->isChecked() )
277  return QStringLiteral( "ProjectCrs" );
278  else if ( mProjectionSelectionWidget )
279  return mProjectionSelectionWidget->crs().isValid() ? mProjectionSelectionWidget->crs() : QVariant();
280  else
281  return QVariant();
282 }
283 
284 QStringList QgsProcessingCrsWidgetWrapper::compatibleParameterTypes() const
285 {
286  return QStringList()
294 }
295 
296 QStringList QgsProcessingCrsWidgetWrapper::compatibleOutputTypes() const
297 {
298  return QStringList() << QgsProcessingOutputVectorLayer::typeName()
302 }
303 
304 QList<int> QgsProcessingCrsWidgetWrapper::compatibleDataTypes() const
305 {
306  return QList< int >();
307 }
308 
309 QString QgsProcessingCrsWidgetWrapper::modelerExpressionFormatString() const
310 {
311  return tr( "string as EPSG code, WKT or PROJ format, or a string identifying a map layer" );
312 }
313 
314 QString QgsProcessingCrsWidgetWrapper::parameterType() const
315 {
317 }
318 
319 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCrsWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
320 {
321  return new QgsProcessingCrsWidgetWrapper( parameter, type );
322 }
323 
324 
325 
326 //
327 // QgsProcessingStringWidgetWrapper
328 //
329 
330 QgsProcessingStringWidgetWrapper::QgsProcessingStringWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
331  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
332 {
333 
334 }
335 
336 QWidget *QgsProcessingStringWidgetWrapper::createWidget()
337 {
338  switch ( type() )
339  {
342  {
343  if ( static_cast< const QgsProcessingParameterString * >( parameterDefinition() )->multiLine() )
344  {
345  mPlainTextEdit = new QPlainTextEdit();
346  mPlainTextEdit->setToolTip( parameterDefinition()->toolTip() );
347 
348  connect( mPlainTextEdit, &QPlainTextEdit::textChanged, this, [ = ]
349  {
350  emit widgetValueHasChanged( this );
351  } );
352  return mPlainTextEdit;
353  }
354  else
355  {
356  mLineEdit = new QLineEdit();
357  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
358 
359  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
360  {
361  emit widgetValueHasChanged( this );
362  } );
363  return mLineEdit;
364  }
365  };
366 
368  {
369  mLineEdit = new QLineEdit();
370  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
371 
372  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
373  {
374  emit widgetValueHasChanged( this );
375  } );
376  return mLineEdit;
377  }
378  }
379  return nullptr;
380 }
381 
382 void QgsProcessingStringWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
383 {
384  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
385  if ( mLineEdit )
386  mLineEdit->setText( v );
387  if ( mPlainTextEdit )
388  mPlainTextEdit->setPlainText( v );
389 }
390 
391 QVariant QgsProcessingStringWidgetWrapper::widgetValue() const
392 {
393  if ( mLineEdit )
394  return mLineEdit->text();
395  else if ( mPlainTextEdit )
396  return mPlainTextEdit->toPlainText();
397  else
398  return QVariant();
399 }
400 
401 QStringList QgsProcessingStringWidgetWrapper::compatibleParameterTypes() const
402 {
403  return QStringList()
412 }
413 
414 QStringList QgsProcessingStringWidgetWrapper::compatibleOutputTypes() const
415 {
416  return QStringList() << QgsProcessingOutputNumber::typeName()
419 }
420 
421 QList<int> QgsProcessingStringWidgetWrapper::compatibleDataTypes() const
422 {
423  return QList< int >();
424 }
425 
426 QString QgsProcessingStringWidgetWrapper::parameterType() const
427 {
429 }
430 
431 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingStringWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
432 {
433  return new QgsProcessingStringWidgetWrapper( parameter, type );
434 }
435 
436 
437 
438 //
439 // QgsProcessingAuthConfigWidgetWrapper
440 //
441 
442 QgsProcessingAuthConfigWidgetWrapper::QgsProcessingAuthConfigWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
443  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
444 {
445 
446 }
447 
448 QWidget *QgsProcessingAuthConfigWidgetWrapper::createWidget()
449 {
450  switch ( type() )
451  {
455  {
456  mAuthConfigSelect = new QgsAuthConfigSelect();
457  mAuthConfigSelect->setToolTip( parameterDefinition()->toolTip() );
458 
459  connect( mAuthConfigSelect, &QgsAuthConfigSelect::selectedConfigIdChanged, this, [ = ]
460  {
461  emit widgetValueHasChanged( this );
462  } );
463  return mAuthConfigSelect;
464  };
465  }
466  return nullptr;
467 }
468 
469 void QgsProcessingAuthConfigWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
470 {
471  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
472  if ( mAuthConfigSelect )
473  mAuthConfigSelect->setConfigId( v );
474 }
475 
476 QVariant QgsProcessingAuthConfigWidgetWrapper::widgetValue() const
477 {
478  if ( mAuthConfigSelect )
479  return mAuthConfigSelect->configId();
480  else
481  return QVariant();
482 }
483 
484 QStringList QgsProcessingAuthConfigWidgetWrapper::compatibleParameterTypes() const
485 {
486  return QStringList()
490 }
491 
492 QStringList QgsProcessingAuthConfigWidgetWrapper::compatibleOutputTypes() const
493 {
494  return QStringList() << QgsProcessingOutputString::typeName();
495 }
496 
497 QList<int> QgsProcessingAuthConfigWidgetWrapper::compatibleDataTypes() const
498 {
499  return QList< int >();
500 }
501 
502 QString QgsProcessingAuthConfigWidgetWrapper::parameterType() const
503 {
505 }
506 
507 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAuthConfigWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
508 {
509  return new QgsProcessingAuthConfigWidgetWrapper( parameter, type );
510 }
511 
512 //
513 // QgsProcessingNumericWidgetWrapper
514 //
515 
516 QgsProcessingNumericWidgetWrapper::QgsProcessingNumericWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
517  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
518 {
519 
520 }
521 
522 QWidget *QgsProcessingNumericWidgetWrapper::createWidget()
523 {
524  const QgsProcessingParameterNumber *numberDef = static_cast< const QgsProcessingParameterNumber * >( parameterDefinition() );
525  const QVariantMap metadata = numberDef->metadata();
526  const int decimals = metadata.value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "decimals" ), 6 ).toInt();
527  switch ( type() )
528  {
532  {
533  // lots of duplicate code here -- but there's no common interface between QSpinBox/QDoubleSpinBox which would allow us to avoid this
534  QAbstractSpinBox *spinBox = nullptr;
535  switch ( numberDef->dataType() )
536  {
538  mDoubleSpinBox = new QgsDoubleSpinBox();
539  mDoubleSpinBox->setExpressionsEnabled( true );
540  mDoubleSpinBox->setDecimals( decimals );
541 
542  // guess reasonable step value for double spin boxes
543  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) &&
544  !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() + 1 ) )
545  {
546  double singleStep = calculateStep( numberDef->minimum(), numberDef->maximum() );
547  singleStep = std::max( singleStep, std::pow( 10, -decimals ) );
548  mDoubleSpinBox->setSingleStep( singleStep );
549  }
550 
551  spinBox = mDoubleSpinBox;
552  break;
553 
555  mSpinBox = new QgsSpinBox();
556  mSpinBox->setExpressionsEnabled( true );
557  spinBox = mSpinBox;
558  break;
559  }
560  spinBox->setToolTip( parameterDefinition()->toolTip() );
561 
562  double max = 999999999;
563  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) )
564  {
565  max = numberDef->maximum();
566  }
567  double min = -999999999;
568  if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
569  {
570  min = numberDef->minimum();
571  }
572  if ( mDoubleSpinBox )
573  {
574  mDoubleSpinBox->setMinimum( min );
575  mDoubleSpinBox->setMaximum( max );
576  }
577  else
578  {
579  mSpinBox->setMinimum( static_cast< int >( min ) );
580  mSpinBox->setMaximum( static_cast< int >( max ) );
581  }
582 
584  {
585  mAllowingNull = true;
586  if ( mDoubleSpinBox )
587  {
588  mDoubleSpinBox->setShowClearButton( true );
589  const double min = mDoubleSpinBox->minimum() - 1;
590  mDoubleSpinBox->setMinimum( min );
591  mDoubleSpinBox->setValue( min );
592  }
593  else
594  {
595  mSpinBox->setShowClearButton( true );
596  const int min = mSpinBox->minimum() - 1;
597  mSpinBox->setMinimum( min );
598  mSpinBox->setValue( min );
599  }
600  spinBox->setSpecialValueText( tr( "Not set" ) );
601  }
602  else
603  {
604  if ( numberDef->defaultValue().isValid() )
605  {
606  // if default value for parameter, we clear to that
607  bool ok = false;
608  if ( mDoubleSpinBox )
609  {
610  double defaultVal = numberDef->defaultValue().toDouble( &ok );
611  if ( ok )
612  mDoubleSpinBox->setClearValue( defaultVal );
613  }
614  else
615  {
616  int intVal = numberDef->defaultValue().toInt( &ok );
617  if ( ok )
618  mSpinBox->setClearValue( intVal );
619  }
620  }
621  else if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
622  {
623  // otherwise we clear to the minimum, if it's set
624  if ( mDoubleSpinBox )
625  mDoubleSpinBox->setClearValue( numberDef->minimum() );
626  else
627  mSpinBox->setClearValue( static_cast< int >( numberDef->minimum() ) );
628  }
629  else
630  {
631  // last resort, we clear to 0
632  if ( mDoubleSpinBox )
633  {
634  mDoubleSpinBox->setValue( 0 );
635  mDoubleSpinBox->setClearValue( 0 );
636  }
637  else
638  {
639  mSpinBox->setValue( 0 );
640  mSpinBox->setClearValue( 0 );
641  }
642  }
643  }
644 
645  if ( mDoubleSpinBox )
646  connect( mDoubleSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
647  else if ( mSpinBox )
648  connect( mSpinBox, qgis::overload<int>::of( &QgsSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
649 
650  return spinBox;
651  };
652  }
653  return nullptr;
654 }
655 
656 void QgsProcessingNumericWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
657 {
658  if ( mDoubleSpinBox )
659  {
660  if ( mAllowingNull && !value.isValid() )
661  mDoubleSpinBox->clear();
662  else
663  {
664  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
665  mDoubleSpinBox->setValue( v );
666  }
667  }
668  else if ( mSpinBox )
669  {
670  if ( mAllowingNull && !value.isValid() )
671  mSpinBox->clear();
672  else
673  {
674  const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
675  mSpinBox->setValue( v );
676  }
677  }
678 }
679 
680 QVariant QgsProcessingNumericWidgetWrapper::widgetValue() const
681 {
682  if ( mDoubleSpinBox )
683  {
684  if ( mAllowingNull && qgsDoubleNear( mDoubleSpinBox->value(), mDoubleSpinBox->minimum() ) )
685  return QVariant();
686  else
687  return mDoubleSpinBox->value();
688  }
689  else if ( mSpinBox )
690  {
691  if ( mAllowingNull && mSpinBox->value() == mSpinBox->minimum() )
692  return QVariant();
693  else
694  return mSpinBox->value();
695  }
696  else
697  return QVariant();
698 }
699 
700 QStringList QgsProcessingNumericWidgetWrapper::compatibleParameterTypes() const
701 {
702  return QStringList()
707 }
708 
709 QStringList QgsProcessingNumericWidgetWrapper::compatibleOutputTypes() const
710 {
711  return QStringList() << QgsProcessingOutputNumber::typeName()
713 }
714 
715 QList<int> QgsProcessingNumericWidgetWrapper::compatibleDataTypes() const
716 {
717  return QList< int >();
718 }
719 
720 double QgsProcessingNumericWidgetWrapper::calculateStep( const double minimum, const double maximum )
721 {
722  const double valueRange = maximum - minimum;
723  if ( valueRange <= 1.0 )
724  {
725  const double step = valueRange / 10.0;
726  // round to 1 significant figure
727  return qgsRound( step, -std::floor( std::log( step ) ) );
728  }
729  else
730  {
731  return 1.0;
732  }
733 }
734 
735 QString QgsProcessingNumericWidgetWrapper::parameterType() const
736 {
738 }
739 
740 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingNumericWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
741 {
742  return new QgsProcessingNumericWidgetWrapper( parameter, type );
743 }
744 
745 //
746 // QgsProcessingDistanceWidgetWrapper
747 //
748 
749 QgsProcessingDistanceWidgetWrapper::QgsProcessingDistanceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
750  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
751 {
752 
753 }
754 
755 QString QgsProcessingDistanceWidgetWrapper::parameterType() const
756 {
758 }
759 
760 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDistanceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
761 {
762  return new QgsProcessingDistanceWidgetWrapper( parameter, type );
763 }
764 
765 QWidget *QgsProcessingDistanceWidgetWrapper::createWidget()
766 {
767  const QgsProcessingParameterDistance *distanceDef = static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() );
768 
769  QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
770  switch ( type() )
771  {
773  {
774  mLabel = new QLabel();
775  mUnitsCombo = new QComboBox();
776 
782 
783  const int labelMargin = static_cast< int >( std::round( mUnitsCombo->fontMetrics().width( 'X' ) ) );
784  QHBoxLayout *layout = new QHBoxLayout();
785  layout->addWidget( spin, 1 );
786  layout->insertSpacing( 1, labelMargin / 2 );
787  layout->insertWidget( 2, mLabel );
788  layout->insertWidget( 3, mUnitsCombo );
789 
790  // bit of fiddlyness here -- we want the initial spacing to only be visible
791  // when the warning label is shown, so it's embedded inside mWarningLabel
792  // instead of outside it
793  mWarningLabel = new QWidget();
794  QHBoxLayout *warningLayout = new QHBoxLayout();
795  warningLayout->setMargin( 0 );
796  warningLayout->setContentsMargins( 0, 0, 0, 0 );
797  QLabel *warning = new QLabel();
798  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
799  const int size = static_cast< int >( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
800  warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
801  warning->setToolTip( tr( "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
802  warningLayout->insertSpacing( 0, labelMargin / 2 );
803  warningLayout->insertWidget( 1, warning );
804  mWarningLabel->setLayout( warningLayout );
805  layout->insertWidget( 4, mWarningLabel );
806 
807  setUnits( distanceDef->defaultUnit() );
808 
809  QWidget *w = new QWidget();
810  layout->setMargin( 0 );
811  layout->setContentsMargins( 0, 0, 0, 0 );
812  w->setLayout( layout );
813  return w;
814  }
815 
818  return spin;
819 
820  }
821  return nullptr;
822 }
823 
824 void QgsProcessingDistanceWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
825 {
826  QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
827  switch ( type() )
828  {
830  {
831  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
832  {
833  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() )->parentParameterName() )
834  {
835  setUnitParameterValue( wrapper->parameterValue() );
837  {
838  setUnitParameterValue( wrapper->parameterValue() );
839  } );
840  break;
841  }
842  }
843  break;
844  }
845 
848  break;
849  }
850 }
851 
852 void QgsProcessingDistanceWidgetWrapper::setUnitParameterValue( const QVariant &value )
853 {
855 
856  // evaluate value to layer
857  QgsProcessingContext *context = nullptr;
858  std::unique_ptr< QgsProcessingContext > tmpContext;
859  if ( mProcessingContextGenerator )
860  context = mProcessingContextGenerator->processingContext();
861 
862  if ( !context )
863  {
864  tmpContext = qgis::make_unique< QgsProcessingContext >();
865  context = tmpContext.get();
866  }
867 
868  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, *context );
869  if ( crs.isValid() )
870  {
871  units = crs.mapUnits();
872  }
873 
874  setUnits( units );
875 }
876 
877 void QgsProcessingDistanceWidgetWrapper::setUnits( const QgsUnitTypes::DistanceUnit units )
878 {
879  mLabel->setText( QgsUnitTypes::toString( units ) );
881  {
882  mUnitsCombo->hide();
883  mLabel->show();
884  }
885  else
886  {
887  mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( units ) );
888  mUnitsCombo->show();
889  mLabel->hide();
890  }
891  mWarningLabel->setVisible( units == QgsUnitTypes::DistanceDegrees );
892  mBaseUnit = units;
893 }
894 
895 QVariant QgsProcessingDistanceWidgetWrapper::widgetValue() const
896 {
897  const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
898  if ( val.type() == QVariant::Double && mUnitsCombo && mUnitsCombo->isVisible() )
899  {
900  QgsUnitTypes::DistanceUnit displayUnit = static_cast<QgsUnitTypes::DistanceUnit >( mUnitsCombo->currentData().toInt() );
901  return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
902  }
903  else
904  {
905  return val;
906  }
907 }
908 
909 //
910 // QgsProcessingScaleWidgetWrapper
911 //
912 
913 QgsProcessingScaleWidgetWrapper::QgsProcessingScaleWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
914  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
915 {
916 
917 }
918 
919 QString QgsProcessingScaleWidgetWrapper::parameterType() const
920 {
922 }
923 
924 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingScaleWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
925 {
926  return new QgsProcessingScaleWidgetWrapper( parameter, type );
927 }
928 
929 QWidget *QgsProcessingScaleWidgetWrapper::createWidget()
930 {
931  const QgsProcessingParameterScale *scaleDef = static_cast< const QgsProcessingParameterScale * >( parameterDefinition() );
932 
933  switch ( type() )
934  {
938  {
939  mScaleWidget = new QgsScaleWidget( nullptr );
941  mScaleWidget->setAllowNull( true );
942 
943  mScaleWidget->setMapCanvas( widgetContext().mapCanvas() );
944  mScaleWidget->setShowCurrentScaleButton( true );
945 
946  mScaleWidget->setToolTip( parameterDefinition()->toolTip() );
947  connect( mScaleWidget, &QgsScaleWidget::scaleChanged, this, [ = ]( double )
948  {
949  emit widgetValueHasChanged( this );
950  } );
951  return mScaleWidget;
952  }
953  }
954  return nullptr;
955 }
956 
957 void QgsProcessingScaleWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
958 {
959  if ( mScaleWidget )
960  mScaleWidget->setMapCanvas( context.mapCanvas() );
962 }
963 
964 
965 QVariant QgsProcessingScaleWidgetWrapper::widgetValue() const
966 {
967  return mScaleWidget && !mScaleWidget->isNull() ? QVariant( mScaleWidget->scale() ) : QVariant();
968 }
969 
970 void QgsProcessingScaleWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
971 {
972  if ( mScaleWidget )
973  {
974  if ( mScaleWidget->allowNull() && !value.isValid() )
975  mScaleWidget->setNull();
976  else
977  {
978  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
979  mScaleWidget->setScale( v );
980  }
981  }
982 }
983 
984 
985 //
986 // QgsProcessingRangeWidgetWrapper
987 //
988 
989 QgsProcessingRangeWidgetWrapper::QgsProcessingRangeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
990  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
991 {
992 
993 }
994 
995 QWidget *QgsProcessingRangeWidgetWrapper::createWidget()
996 {
997  const QgsProcessingParameterRange *rangeDef = static_cast< const QgsProcessingParameterRange * >( parameterDefinition() );
998  switch ( type() )
999  {
1003  {
1004  QHBoxLayout *layout = new QHBoxLayout();
1005 
1006  mMinSpinBox = new QgsDoubleSpinBox();
1007  mMaxSpinBox = new QgsDoubleSpinBox();
1008 
1009  mMinSpinBox->setExpressionsEnabled( true );
1010  mMinSpinBox->setShowClearButton( false );
1011  mMaxSpinBox->setExpressionsEnabled( true );
1012  mMaxSpinBox->setShowClearButton( false );
1013 
1014  QLabel *minLabel = new QLabel( tr( "Min" ) );
1015  layout->addWidget( minLabel );
1016  layout->addWidget( mMinSpinBox, 1 );
1017 
1018  QLabel *maxLabel = new QLabel( tr( "Max" ) );
1019  layout->addWidget( maxLabel );
1020  layout->addWidget( mMaxSpinBox, 1 );
1021 
1022  QWidget *w = new QWidget();
1023  layout->setMargin( 0 );
1024  layout->setContentsMargins( 0, 0, 0, 0 );
1025  w->setLayout( layout );
1026 
1027  if ( rangeDef->dataType() == QgsProcessingParameterNumber::Double )
1028  {
1029  mMinSpinBox->setDecimals( 6 );
1030  mMaxSpinBox->setDecimals( 6 );
1031  }
1032  else
1033  {
1034  mMinSpinBox->setDecimals( 0 );
1035  mMaxSpinBox->setDecimals( 0 );
1036  }
1037 
1038  mMinSpinBox->setMinimum( -99999999.999999 );
1039  mMaxSpinBox->setMinimum( -99999999.999999 );
1040  mMinSpinBox->setMaximum( 99999999.999999 );
1041  mMaxSpinBox->setMaximum( 99999999.999999 );
1042 
1043  w->setToolTip( parameterDefinition()->toolTip() );
1044 
1045  connect( mMinSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
1046  {
1047  mBlockChangedSignal++;
1048  if ( v > mMaxSpinBox->value() )
1049  mMaxSpinBox->setValue( v );
1050  mBlockChangedSignal--;
1051 
1052  if ( !mBlockChangedSignal )
1053  emit widgetValueHasChanged( this );
1054  } );
1055  connect( mMaxSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
1056  {
1057  mBlockChangedSignal++;
1058  if ( v < mMinSpinBox->value() )
1059  mMinSpinBox->setValue( v );
1060  mBlockChangedSignal--;
1061 
1062  if ( !mBlockChangedSignal )
1063  emit widgetValueHasChanged( this );
1064  } );
1065 
1066  return w;
1067  };
1068  }
1069  return nullptr;
1070 }
1071 
1072 void QgsProcessingRangeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1073 {
1074  const QList< double > v = QgsProcessingParameters::parameterAsRange( parameterDefinition(), value, context );
1075  if ( v.empty() )
1076  return;
1077 
1078  mBlockChangedSignal++;
1079  mMinSpinBox->setValue( v.at( 0 ) );
1080  if ( v.count() >= 2 )
1081  mMaxSpinBox->setValue( v.at( 1 ) );
1082  mBlockChangedSignal--;
1083 
1084  if ( !mBlockChangedSignal )
1085  emit widgetValueHasChanged( this );
1086 }
1087 
1088 QVariant QgsProcessingRangeWidgetWrapper::widgetValue() const
1089 {
1090  return QStringLiteral( "%1,%2" ).arg( mMinSpinBox->value() ).arg( mMaxSpinBox->value() );
1091 }
1092 
1093 QStringList QgsProcessingRangeWidgetWrapper::compatibleParameterTypes() const
1094 {
1095  return QStringList()
1098 }
1099 
1100 QStringList QgsProcessingRangeWidgetWrapper::compatibleOutputTypes() const
1101 {
1102  return QStringList() << QgsProcessingOutputString::typeName();
1103 }
1104 
1105 QList<int> QgsProcessingRangeWidgetWrapper::compatibleDataTypes() const
1106 {
1107  return QList< int >();
1108 }
1109 
1110 QString QgsProcessingRangeWidgetWrapper::modelerExpressionFormatString() const
1111 {
1112  return tr( "string as two comma delimited floats, e.g. '1,10'" );
1113 }
1114 
1115 QString QgsProcessingRangeWidgetWrapper::parameterType() const
1116 {
1118 }
1119 
1120 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRangeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1121 {
1122  return new QgsProcessingRangeWidgetWrapper( parameter, type );
1123 }
1124 
1125 
1126 
1127 //
1128 // QgsProcessingMatrixWidgetWrapper
1129 //
1130 
1131 QgsProcessingMatrixWidgetWrapper::QgsProcessingMatrixWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1132  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1133 {
1134 
1135 }
1136 
1137 QWidget *QgsProcessingMatrixWidgetWrapper::createWidget()
1138 {
1139  mMatrixWidget = new QgsProcessingMatrixParameterPanel( nullptr, dynamic_cast< const QgsProcessingParameterMatrix *>( parameterDefinition() ) );
1140  mMatrixWidget->setToolTip( parameterDefinition()->toolTip() );
1141 
1142  connect( mMatrixWidget, &QgsProcessingMatrixParameterPanel::changed, this, [ = ]
1143  {
1144  emit widgetValueHasChanged( this );
1145  } );
1146 
1147  switch ( type() )
1148  {
1152  {
1153  return mMatrixWidget;
1154  };
1155  }
1156  return nullptr;
1157 }
1158 
1159 void QgsProcessingMatrixWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1160 {
1161  const QVariantList v = QgsProcessingParameters::parameterAsMatrix( parameterDefinition(), value, context );
1162  if ( mMatrixWidget )
1163  mMatrixWidget->setValue( v );
1164 }
1165 
1166 QVariant QgsProcessingMatrixWidgetWrapper::widgetValue() const
1167 {
1168  if ( mMatrixWidget )
1169  return mMatrixWidget->value().isEmpty() ? QVariant() : mMatrixWidget->value();
1170  else
1171  return QVariant();
1172 }
1173 
1174 QStringList QgsProcessingMatrixWidgetWrapper::compatibleParameterTypes() const
1175 {
1176  return QStringList()
1178 }
1179 
1180 QStringList QgsProcessingMatrixWidgetWrapper::compatibleOutputTypes() const
1181 {
1182  return QStringList();
1183 }
1184 
1185 QList<int> QgsProcessingMatrixWidgetWrapper::compatibleDataTypes() const
1186 {
1187  return QList< int >();
1188 }
1189 
1190 QString QgsProcessingMatrixWidgetWrapper::modelerExpressionFormatString() const
1191 {
1192  return tr( "comma delimited string of values, or an array of values" );
1193 }
1194 
1195 QString QgsProcessingMatrixWidgetWrapper::parameterType() const
1196 {
1198 }
1199 
1200 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMatrixWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1201 {
1202  return new QgsProcessingMatrixWidgetWrapper( parameter, type );
1203 }
1204 
1205 
1206 
1207 
1208 //
1209 // QgsProcessingFileWidgetWrapper
1210 //
1211 
1212 QgsProcessingFileWidgetWrapper::QgsProcessingFileWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1213  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1214 {
1215 
1216 }
1217 
1218 QWidget *QgsProcessingFileWidgetWrapper::createWidget()
1219 {
1220  const QgsProcessingParameterFile *fileParam = dynamic_cast< const QgsProcessingParameterFile *>( parameterDefinition() );
1221  switch ( type() )
1222  {
1226  {
1227  mFileWidget = new QgsFileWidget();
1228  mFileWidget->setToolTip( parameterDefinition()->toolTip() );
1229  mFileWidget->setDialogTitle( parameterDefinition()->description() );
1230 
1231  mFileWidget->setDefaultRoot( QgsSettings().value( QStringLiteral( "/Processing/LastInputPath" ), QDir::homePath() ).toString() );
1232 
1233  switch ( fileParam->behavior() )
1234  {
1236  mFileWidget->setStorageMode( QgsFileWidget::GetFile );
1237  if ( !fileParam->extension().isEmpty() )
1238  mFileWidget->setFilter( tr( "%1 files" ).arg( fileParam->extension().toUpper() ) + QStringLiteral( " (*." ) + fileParam->extension().toLower() + ')' );
1239  break;
1240 
1242  mFileWidget->setStorageMode( QgsFileWidget::GetDirectory );
1243  break;
1244  }
1245 
1246  connect( mFileWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & path )
1247  {
1248  QgsSettings().setValue( QStringLiteral( "/Processing/LastInputPath" ), QFileInfo( path ).canonicalPath() );
1249  emit widgetValueHasChanged( this );
1250  } );
1251  return mFileWidget;
1252  };
1253  }
1254  return nullptr;
1255 }
1256 
1257 void QgsProcessingFileWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1258 {
1259  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
1260  if ( mFileWidget )
1261  mFileWidget->setFilePath( v );
1262 }
1263 
1264 QVariant QgsProcessingFileWidgetWrapper::widgetValue() const
1265 {
1266  if ( mFileWidget )
1267  return mFileWidget->filePath();
1268  else
1269  return QVariant();
1270 }
1271 
1272 QStringList QgsProcessingFileWidgetWrapper::compatibleParameterTypes() const
1273 {
1274  return QStringList()
1277 }
1278 
1279 QStringList QgsProcessingFileWidgetWrapper::compatibleOutputTypes() const
1280 {
1281  return QStringList() << QgsProcessingOutputFile::typeName()
1286 }
1287 
1288 QList<int> QgsProcessingFileWidgetWrapper::compatibleDataTypes() const
1289 {
1290  return QList< int >();
1291 }
1292 
1293 QString QgsProcessingFileWidgetWrapper::modelerExpressionFormatString() const
1294 {
1295  return tr( "string representing a path to a file or folder" );
1296 }
1297 
1298 QString QgsProcessingFileWidgetWrapper::parameterType() const
1299 {
1301 }
1302 
1303 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1304 {
1305  return new QgsProcessingFileWidgetWrapper( parameter, type );
1306 }
1307 
1308 
1309 
1310 
1311 //
1312 // QgsProcessingExpressionWidgetWrapper
1313 //
1314 
1315 QgsProcessingExpressionWidgetWrapper::QgsProcessingExpressionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1316  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1317 {
1318 
1319 }
1320 
1321 QWidget *QgsProcessingExpressionWidgetWrapper::createWidget()
1322 {
1323  const QgsProcessingParameterExpression *expParam = dynamic_cast< const QgsProcessingParameterExpression *>( parameterDefinition() );
1324  switch ( type() )
1325  {
1329  {
1330  if ( expParam->parentLayerParameterName().isEmpty() )
1331  {
1332  mExpLineEdit = new QgsExpressionLineEdit();
1333  mExpLineEdit->setToolTip( parameterDefinition()->toolTip() );
1334  mExpLineEdit->setExpressionDialogTitle( parameterDefinition()->description() );
1335  mExpLineEdit->registerExpressionContextGenerator( this );
1336  connect( mExpLineEdit, &QgsExpressionLineEdit::expressionChanged, this, [ = ]( const QString & )
1337  {
1338  emit widgetValueHasChanged( this );
1339  } );
1340  return mExpLineEdit;
1341  }
1342  else
1343  {
1344  mFieldExpWidget = new QgsFieldExpressionWidget();
1345  mFieldExpWidget->setToolTip( parameterDefinition()->toolTip() );
1346  mFieldExpWidget->setExpressionDialogTitle( parameterDefinition()->description() );
1347  mFieldExpWidget->registerExpressionContextGenerator( this );
1348  connect( mFieldExpWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString & ) >( &QgsFieldExpressionWidget::fieldChanged ), this, [ = ]( const QString & )
1349  {
1350  emit widgetValueHasChanged( this );
1351  } );
1352  return mFieldExpWidget;
1353  }
1354  };
1355  }
1356  return nullptr;
1357 }
1358 
1359 void QgsProcessingExpressionWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1360 {
1362  switch ( type() )
1363  {
1366  {
1367  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1368  {
1369  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterExpression * >( parameterDefinition() )->parentLayerParameterName() )
1370  {
1371  setParentLayerWrapperValue( wrapper );
1373  {
1374  setParentLayerWrapperValue( wrapper );
1375  } );
1376  break;
1377  }
1378  }
1379  break;
1380  }
1381 
1383  break;
1384  }
1385 }
1386 
1387 void QgsProcessingExpressionWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
1388 {
1389  // evaluate value to layer
1390  QgsProcessingContext *context = nullptr;
1391  std::unique_ptr< QgsProcessingContext > tmpContext;
1392  if ( mProcessingContextGenerator )
1393  context = mProcessingContextGenerator->processingContext();
1394 
1395  if ( !context )
1396  {
1397  tmpContext = qgis::make_unique< QgsProcessingContext >();
1398  context = tmpContext.get();
1399  }
1400 
1401  QgsVectorLayer *layer = QgsProcessingParameters::parameterAsVectorLayer( parentWrapper->parameterDefinition(), parentWrapper->parameterValue(), *context );
1402  if ( !layer )
1403  {
1404  if ( mFieldExpWidget )
1405  mFieldExpWidget->setLayer( nullptr );
1406  else if ( mExpLineEdit )
1407  mExpLineEdit->setLayer( nullptr );
1408  return;
1409  }
1410 
1411  // need to grab ownership of layer if required - otherwise layer may be deleted when context
1412  // goes out of scope
1413  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
1414  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::VectorLayer )
1415  {
1416  mParentLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
1417  layer = mParentLayer.get();
1418  }
1419  else
1420  {
1421  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
1422  }
1423 
1424  if ( mFieldExpWidget )
1425  mFieldExpWidget->setLayer( layer );
1426  else if ( mExpLineEdit )
1427  mExpLineEdit->setLayer( layer );
1428 }
1429 
1430 void QgsProcessingExpressionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1431 {
1432  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
1433  if ( mFieldExpWidget )
1434  mFieldExpWidget->setExpression( v );
1435  else if ( mExpLineEdit )
1436  mExpLineEdit->setExpression( v );
1437 }
1438 
1439 QVariant QgsProcessingExpressionWidgetWrapper::widgetValue() const
1440 {
1441  if ( mFieldExpWidget )
1442  return mFieldExpWidget->expression();
1443  else if ( mExpLineEdit )
1444  return mExpLineEdit->expression();
1445  else
1446  return QVariant();
1447 }
1448 
1449 QStringList QgsProcessingExpressionWidgetWrapper::compatibleParameterTypes() const
1450 {
1451  return QStringList()
1457 }
1458 
1459 QStringList QgsProcessingExpressionWidgetWrapper::compatibleOutputTypes() const
1460 {
1461  return QStringList()
1464 }
1465 
1466 QList<int> QgsProcessingExpressionWidgetWrapper::compatibleDataTypes() const
1467 {
1468  return QList< int >();
1469 }
1470 
1471 QString QgsProcessingExpressionWidgetWrapper::modelerExpressionFormatString() const
1472 {
1473  return tr( "string representation of an expression" );
1474 }
1475 
1476 const QgsVectorLayer *QgsProcessingExpressionWidgetWrapper::linkedVectorLayer() const
1477 {
1478  if ( mFieldExpWidget && mFieldExpWidget->layer() )
1479  return mFieldExpWidget->layer();
1480 
1482 }
1483 
1484 QString QgsProcessingExpressionWidgetWrapper::parameterType() const
1485 {
1487 }
1488 
1489 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExpressionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1490 {
1491  return new QgsProcessingExpressionWidgetWrapper( parameter, type );
1492 }
1493 
1494 
1495 
1496 //
1497 // QgsProcessingEnumPanelWidget
1498 //
1499 
1500 QgsProcessingEnumPanelWidget::QgsProcessingEnumPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param )
1501  : QWidget( parent )
1502  , mParam( param )
1503 {
1504  QHBoxLayout *hl = new QHBoxLayout();
1505  hl->setMargin( 0 );
1506  hl->setContentsMargins( 0, 0, 0, 0 );
1507 
1508  mLineEdit = new QLineEdit();
1509  mLineEdit->setEnabled( false );
1510  hl->addWidget( mLineEdit, 1 );
1511 
1512  mToolButton = new QToolButton();
1513  mToolButton->setText( tr( "…" ) );
1514  hl->addWidget( mToolButton );
1515 
1516  setLayout( hl );
1517 
1518  if ( mParam )
1519  {
1520  mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
1521  }
1522 
1523  connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingEnumPanelWidget::showDialog );
1524 }
1525 
1526 void QgsProcessingEnumPanelWidget::setValue( const QVariant &value )
1527 {
1528  if ( value.isValid() )
1529  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
1530  else
1531  mValue.clear();
1532 
1533  updateSummaryText();
1534  emit changed();
1535 }
1536 
1537 void QgsProcessingEnumPanelWidget::showDialog()
1538 {
1539  QVariantList availableOptions;
1540  if ( mParam )
1541  {
1542  availableOptions.reserve( mParam->options().size() );
1543  for ( int i = 0; i < mParam->options().count(); ++i )
1544  availableOptions << i;
1545  }
1546 
1547  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, nullptr );
1548  const QStringList options = mParam ? mParam->options() : QStringList();
1549  dlg.setValueFormatter( [options]( const QVariant & v ) -> QString
1550  {
1551  const int i = v.toInt();
1552  return options.size() > i ? options.at( i ) : QString();
1553  } );
1554  if ( dlg.exec() )
1555  {
1556  setValue( dlg.selectedOptions() );
1557  }
1558 }
1559 
1560 void QgsProcessingEnumPanelWidget::updateSummaryText()
1561 {
1562  if ( mParam )
1563  mLineEdit->setText( tr( "%1 options selected" ).arg( mValue.count() ) );
1564 }
1565 
1566 
1567 //
1568 // QgsProcessingEnumCheckboxPanelWidget
1569 //
1570 QgsProcessingEnumCheckboxPanelWidget::QgsProcessingEnumCheckboxPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param, int columns )
1571  : QWidget( parent )
1572  , mParam( param )
1573  , mButtonGroup( new QButtonGroup( this ) )
1574  , mColumns( columns )
1575 {
1576  mButtonGroup->setExclusive( !mParam->allowMultiple() );
1577 
1578  QGridLayout *l = new QGridLayout();
1579  l->setContentsMargins( 0, 0, 0, 0 );
1580  l->setMargin( 0 );
1581 
1582  int rows = static_cast< int >( std::ceil( mParam->options().count() / static_cast< double >( mColumns ) ) );
1583  for ( int i = 0; i < mParam->options().count(); ++i )
1584  {
1585  QAbstractButton *button = nullptr;
1586  if ( mParam->allowMultiple() )
1587  button = new QCheckBox( mParam->options().at( i ) );
1588  else
1589  button = new QRadioButton( mParam->options().at( i ) );
1590 
1591  connect( button, &QAbstractButton::toggled, this, [ = ]
1592  {
1593  if ( !mBlockChangedSignal )
1594  emit changed();
1595  } );
1596 
1597  mButtons.insert( i, button );
1598  mButtonGroup->addButton( button, i );
1599  l->addWidget( button, i % rows, i / rows );
1600  }
1601  l->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ), 0, mColumns );
1602  setLayout( l );
1603 
1604  if ( mParam->allowMultiple() )
1605  {
1606  setContextMenuPolicy( Qt::CustomContextMenu );
1607  connect( this, &QWidget::customContextMenuRequested, this, &QgsProcessingEnumCheckboxPanelWidget::showPopupMenu );
1608  }
1609 }
1610 
1611 QVariant QgsProcessingEnumCheckboxPanelWidget::value() const
1612 {
1613  if ( mParam->allowMultiple() )
1614  {
1615  QVariantList value;
1616  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
1617  {
1618  if ( it.value()->isChecked() )
1619  value.append( it.key() );
1620  }
1621  return value;
1622  }
1623  else
1624  {
1625  return mButtonGroup->checkedId() >= 0 ? mButtonGroup->checkedId() : QVariant();
1626  }
1627 }
1628 
1629 void QgsProcessingEnumCheckboxPanelWidget::setValue( const QVariant &value )
1630 {
1631  mBlockChangedSignal = true;
1632  if ( mParam->allowMultiple() )
1633  {
1634  QVariantList selected;
1635  if ( value.isValid() )
1636  selected = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
1637  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
1638  {
1639  it.value()->setChecked( selected.contains( it.key() ) );
1640  }
1641  }
1642  else
1643  {
1644  QVariant v = value;
1645  if ( v.type() == QVariant::List )
1646  v = v.toList().value( 0 );
1647  if ( mButtons.contains( v ) )
1648  mButtons.value( v )->setChecked( true );
1649  }
1650  mBlockChangedSignal = false;
1651  emit changed();
1652 }
1653 
1654 void QgsProcessingEnumCheckboxPanelWidget::showPopupMenu()
1655 {
1656  QMenu popupMenu;
1657  QAction *selectAllAction = new QAction( tr( "Select All" ), &popupMenu );
1658  connect( selectAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::selectAll );
1659  QAction *clearAllAction = new QAction( tr( "Clear Selection" ), &popupMenu );
1660  connect( clearAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::deselectAll );
1661  popupMenu.addAction( selectAllAction );
1662  popupMenu.addAction( clearAllAction );
1663  popupMenu.exec( QCursor::pos() );
1664 }
1665 
1666 void QgsProcessingEnumCheckboxPanelWidget::selectAll()
1667 {
1668  mBlockChangedSignal = true;
1669  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
1670  it.value()->setChecked( true );
1671  mBlockChangedSignal = false;
1672  emit changed();
1673 }
1674 
1675 void QgsProcessingEnumCheckboxPanelWidget::deselectAll()
1676 {
1677  mBlockChangedSignal = true;
1678  for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
1679  it.value()->setChecked( false );
1680  mBlockChangedSignal = false;
1681  emit changed();
1682 }
1683 
1684 
1685 //
1686 // QgsProcessingEnumWidgetWrapper
1687 //
1688 
1689 QgsProcessingEnumWidgetWrapper::QgsProcessingEnumWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1690  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1691 {
1692 
1693 }
1694 
1695 QWidget *QgsProcessingEnumWidgetWrapper::createWidget()
1696 {
1697  const QgsProcessingParameterEnum *expParam = dynamic_cast< const QgsProcessingParameterEnum *>( parameterDefinition() );
1698  switch ( type() )
1699  {
1701  {
1702  // checkbox panel only for use outside in standard gui!
1703  if ( expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "useCheckBoxes" ), false ).toBool() )
1704  {
1705  const int columns = expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "columns" ), 2 ).toInt();
1706  mCheckboxPanel = new QgsProcessingEnumCheckboxPanelWidget( nullptr, expParam, columns );
1707  mCheckboxPanel->setToolTip( parameterDefinition()->toolTip() );
1708  connect( mCheckboxPanel, &QgsProcessingEnumCheckboxPanelWidget::changed, this, [ = ]
1709  {
1710  emit widgetValueHasChanged( this );
1711  } );
1712  return mCheckboxPanel;
1713  }
1714  }
1715  FALLTHROUGH
1718  {
1719  if ( expParam->allowMultiple() )
1720  {
1721  mPanel = new QgsProcessingEnumPanelWidget( nullptr, expParam );
1722  mPanel->setToolTip( parameterDefinition()->toolTip() );
1723  connect( mPanel, &QgsProcessingEnumPanelWidget::changed, this, [ = ]
1724  {
1725  emit widgetValueHasChanged( this );
1726  } );
1727  return mPanel;
1728  }
1729  else
1730  {
1731  mComboBox = new QComboBox();
1732 
1734  mComboBox->addItem( tr( "[Not selected]" ), QVariant() );
1735  const QStringList options = expParam->options();
1736  for ( int i = 0; i < options.count(); ++i )
1737  mComboBox->addItem( options.at( i ), i );
1738 
1739  mComboBox->setToolTip( parameterDefinition()->toolTip() );
1740  connect( mComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, [ = ]( int )
1741  {
1742  emit widgetValueHasChanged( this );
1743  } );
1744  return mComboBox;
1745  }
1746  };
1747  }
1748  return nullptr;
1749 }
1750 
1751 void QgsProcessingEnumWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1752 {
1753  if ( mComboBox )
1754  {
1755  if ( !value.isValid() )
1756  mComboBox->setCurrentIndex( mComboBox->findData( QVariant() ) );
1757  else
1758  {
1759  const int v = QgsProcessingParameters::parameterAsEnum( parameterDefinition(), value, context );
1760  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
1761  }
1762  }
1763  else if ( mPanel || mCheckboxPanel )
1764  {
1765  QVariantList opts;
1766  if ( value.isValid() )
1767  {
1768  const QList< int > v = QgsProcessingParameters::parameterAsEnums( parameterDefinition(), value, context );
1769  opts.reserve( v.size() );
1770  for ( int i : v )
1771  opts << i;
1772  }
1773  if ( mPanel )
1774  mPanel->setValue( opts );
1775  else if ( mCheckboxPanel )
1776  mCheckboxPanel->setValue( opts );
1777  }
1778 }
1779 
1780 QVariant QgsProcessingEnumWidgetWrapper::widgetValue() const
1781 {
1782  if ( mComboBox )
1783  return mComboBox->currentData();
1784  else if ( mPanel )
1785  return mPanel->value();
1786  else if ( mCheckboxPanel )
1787  return mCheckboxPanel->value();
1788  else
1789  return QVariant();
1790 }
1791 
1792 QStringList QgsProcessingEnumWidgetWrapper::compatibleParameterTypes() const
1793 {
1794  return QStringList()
1798 }
1799 
1800 QStringList QgsProcessingEnumWidgetWrapper::compatibleOutputTypes() const
1801 {
1802  return QStringList()
1805 }
1806 
1807 QList<int> QgsProcessingEnumWidgetWrapper::compatibleDataTypes() const
1808 {
1809  return QList<int>();
1810 }
1811 
1812 QString QgsProcessingEnumWidgetWrapper::modelerExpressionFormatString() const
1813 {
1814  return tr( "selected option index (starting from 0), array of indices, or comma separated string of options (e.g. '1,3')" );
1815 }
1816 
1817 QString QgsProcessingEnumWidgetWrapper::parameterType() const
1818 {
1820 }
1821 
1822 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingEnumWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1823 {
1824  return new QgsProcessingEnumWidgetWrapper( parameter, type );
1825 }
1826 
1827 
1828 
1829 //
1830 // QgsProcessingLayoutWidgetWrapper
1831 //
1832 
1833 QgsProcessingLayoutWidgetWrapper::QgsProcessingLayoutWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1834  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1835 {
1836 
1837 }
1838 
1839 QWidget *QgsProcessingLayoutWidgetWrapper::createWidget()
1840 {
1841  const QgsProcessingParameterLayout *layoutParam = dynamic_cast< const QgsProcessingParameterLayout *>( parameterDefinition() );
1842  switch ( type() )
1843  {
1846  {
1847  // combobox only for use outside modeler!
1848  mComboBox = new QgsLayoutComboBox( nullptr, widgetContext().project() ? widgetContext().project()->layoutManager() : nullptr );
1850  mComboBox->setAllowEmptyLayout( true );
1851  mComboBox->setFilters( QgsLayoutManagerProxyModel::FilterPrintLayouts );
1852 
1853  mComboBox->setToolTip( parameterDefinition()->toolTip() );
1854  connect( mComboBox, &QgsLayoutComboBox::layoutChanged, this, [ = ]( QgsMasterLayoutInterface * )
1855  {
1856  emit widgetValueHasChanged( this );
1857  } );
1858  return mComboBox;
1859  }
1860 
1862  {
1863  mLineEdit = new QLineEdit();
1864  mLineEdit->setToolTip( tr( "Name of an existing print layout" ) );
1865  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
1866  {
1867  emit widgetValueHasChanged( this );
1868  } );
1869  return mLineEdit;
1870  }
1871  }
1872  return nullptr;
1873 }
1874 
1875 void QgsProcessingLayoutWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1876 {
1877  if ( mComboBox )
1878  {
1879  if ( !value.isValid() )
1880  mComboBox->setCurrentLayout( nullptr );
1881  else
1882  {
1883  if ( QgsPrintLayout *l = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, context ) )
1884  mComboBox->setCurrentLayout( l );
1885  else
1886  mComboBox->setCurrentLayout( nullptr );
1887  }
1888  }
1889  else if ( mLineEdit )
1890  {
1891  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
1892  mLineEdit->setText( v );
1893  }
1894 }
1895 
1896 QVariant QgsProcessingLayoutWidgetWrapper::widgetValue() const
1897 {
1898  if ( mComboBox )
1899  {
1900  const QgsMasterLayoutInterface *l = mComboBox->currentLayout();
1901  return l ? l->name() : QVariant();
1902  }
1903  else if ( mLineEdit )
1904  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
1905  else
1906  return QVariant();
1907 }
1908 
1909 QStringList QgsProcessingLayoutWidgetWrapper::compatibleParameterTypes() const
1910 {
1911  return QStringList()
1914 }
1915 
1916 QStringList QgsProcessingLayoutWidgetWrapper::compatibleOutputTypes() const
1917 {
1918  return QStringList()
1920 }
1921 
1922 QList<int> QgsProcessingLayoutWidgetWrapper::compatibleDataTypes() const
1923 {
1924  return QList<int>();
1925 }
1926 
1927 QString QgsProcessingLayoutWidgetWrapper::modelerExpressionFormatString() const
1928 {
1929  return tr( "string representing the name of an existing print layout" );
1930 }
1931 
1932 QString QgsProcessingLayoutWidgetWrapper::parameterType() const
1933 {
1935 }
1936 
1937 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1938 {
1939  return new QgsProcessingLayoutWidgetWrapper( parameter, type );
1940 }
1941 
1942 
1943 
1944 
1945 //
1946 // QgsProcessingLayoutItemWidgetWrapper
1947 //
1948 
1949 QgsProcessingLayoutItemWidgetWrapper::QgsProcessingLayoutItemWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1950  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
1951 {
1952 
1953 }
1954 
1955 QWidget *QgsProcessingLayoutItemWidgetWrapper::createWidget()
1956 {
1957  const QgsProcessingParameterLayoutItem *layoutParam = dynamic_cast< const QgsProcessingParameterLayoutItem *>( parameterDefinition() );
1958  switch ( type() )
1959  {
1962  {
1963  // combobox only for use outside modeler!
1964  mComboBox = new QgsLayoutItemComboBox( nullptr, nullptr );
1966  mComboBox->setAllowEmptyItem( true );
1967  if ( layoutParam->itemType() >= 0 )
1968  mComboBox->setItemType( static_cast< QgsLayoutItemRegistry::ItemType >( layoutParam->itemType() ) );
1969 
1970  mComboBox->setToolTip( parameterDefinition()->toolTip() );
1971  connect( mComboBox, &QgsLayoutItemComboBox::itemChanged, this, [ = ]( QgsLayoutItem * )
1972  {
1973  emit widgetValueHasChanged( this );
1974  } );
1975  return mComboBox;
1976  }
1977 
1979  {
1980  mLineEdit = new QLineEdit();
1981  mLineEdit->setToolTip( tr( "UUID or ID of an existing print layout item" ) );
1982  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
1983  {
1984  emit widgetValueHasChanged( this );
1985  } );
1986  return mLineEdit;
1987  }
1988  }
1989  return nullptr;
1990 }
1991 
1992 void QgsProcessingLayoutItemWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1993 {
1994  switch ( type() )
1995  {
1998  {
1999  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
2000  {
2001  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterLayoutItem * >( parameterDefinition() )->parentLayoutParameterName() )
2002  {
2003  setLayoutParameterValue( wrapper->parameterValue() );
2005  {
2006  setLayoutParameterValue( wrapper->parameterValue() );
2007  } );
2008  break;
2009  }
2010  }
2011  break;
2012  }
2013 
2015  break;
2016  }
2017 }
2018 
2019 void QgsProcessingLayoutItemWidgetWrapper::setLayoutParameterValue( const QVariant &value )
2020 {
2021  QgsPrintLayout *layout = nullptr;
2022 
2023  // evaluate value to layout
2024  QgsProcessingContext *context = nullptr;
2025  std::unique_ptr< QgsProcessingContext > tmpContext;
2026  if ( mProcessingContextGenerator )
2027  context = mProcessingContextGenerator->processingContext();
2028 
2029  if ( !context )
2030  {
2031  tmpContext = qgis::make_unique< QgsProcessingContext >();
2032  context = tmpContext.get();
2033  }
2034 
2035  layout = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, *context );
2036  setLayout( layout );
2037 }
2038 
2039 void QgsProcessingLayoutItemWidgetWrapper::setLayout( QgsPrintLayout *layout )
2040 {
2041  if ( mComboBox )
2042  mComboBox->setCurrentLayout( layout );
2043 }
2044 
2045 void QgsProcessingLayoutItemWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2046 {
2047  if ( mComboBox )
2048  {
2049  if ( !value.isValid() )
2050  mComboBox->setItem( nullptr );
2051  else
2052  {
2053  QgsLayoutItem *item = QgsProcessingParameters::parameterAsLayoutItem( parameterDefinition(), value, context, qobject_cast< QgsPrintLayout * >( mComboBox->currentLayout() ) );
2054  mComboBox->setItem( item );
2055  }
2056  }
2057  else if ( mLineEdit )
2058  {
2059  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2060  mLineEdit->setText( v );
2061  }
2062 }
2063 
2064 QVariant QgsProcessingLayoutItemWidgetWrapper::widgetValue() const
2065 {
2066  if ( mComboBox )
2067  {
2068  const QgsLayoutItem *i = mComboBox->currentItem();
2069  return i ? i->uuid() : QVariant();
2070  }
2071  else if ( mLineEdit )
2072  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
2073  else
2074  return QVariant();
2075 }
2076 
2077 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleParameterTypes() const
2078 {
2079  return QStringList()
2082 }
2083 
2084 QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleOutputTypes() const
2085 {
2086  return QStringList()
2088 }
2089 
2090 QList<int> QgsProcessingLayoutItemWidgetWrapper::compatibleDataTypes() const
2091 {
2092  return QList<int>();
2093 }
2094 
2095 QString QgsProcessingLayoutItemWidgetWrapper::modelerExpressionFormatString() const
2096 {
2097  return tr( "string representing the UUID or ID of an existing print layout item" );
2098 }
2099 
2100 QString QgsProcessingLayoutItemWidgetWrapper::parameterType() const
2101 {
2103 }
2104 
2105 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutItemWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2106 {
2107  return new QgsProcessingLayoutItemWidgetWrapper( parameter, type );
2108 }
2109 
2110 //
2111 // QgsProcessingPointMapTool
2112 //
2113 
2114 QgsProcessingPointMapTool::QgsProcessingPointMapTool( QgsMapCanvas *canvas )
2115  : QgsMapTool( canvas )
2116 {
2117  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::CapturePoint ) );
2118  mSnapIndicator.reset( new QgsSnapIndicator( canvas ) );
2119 }
2120 
2121 QgsProcessingPointMapTool::~QgsProcessingPointMapTool() = default;
2122 
2123 void QgsProcessingPointMapTool::deactivate()
2124 {
2125  mSnapIndicator->setMatch( QgsPointLocator::Match() );
2127 }
2128 
2129 void QgsProcessingPointMapTool::canvasMoveEvent( QgsMapMouseEvent *e )
2130 {
2131  e->snapPoint();
2132  mSnapIndicator->setMatch( e->mapPointMatch() );
2133 }
2134 
2135 void QgsProcessingPointMapTool::canvasPressEvent( QgsMapMouseEvent *e )
2136 {
2137  if ( e->button() == Qt::LeftButton )
2138  {
2139  QgsPointXY point = e->snapPoint();
2140  emit clicked( point );
2141  emit complete();
2142  }
2143 }
2144 
2145 void QgsProcessingPointMapTool::keyPressEvent( QKeyEvent *e )
2146 {
2147  if ( e->key() == Qt::Key_Escape )
2148  {
2149 
2150  // Override default shortcut management in MapCanvas
2151  e->ignore();
2152  emit complete();
2153  }
2154 }
2155 
2156 
2157 
2158 //
2159 // QgsProcessingPointPanel
2160 //
2161 
2162 QgsProcessingPointPanel::QgsProcessingPointPanel( QWidget *parent )
2163  : QWidget( parent )
2164 {
2165  QHBoxLayout *l = new QHBoxLayout();
2166  l->setContentsMargins( 0, 0, 0, 0 );
2167  l->setMargin( 0 );
2168  mLineEdit = new QgsFilterLineEdit( );
2169  mLineEdit->setShowClearButton( false );
2170  l->addWidget( mLineEdit, 1 );
2171  mButton = new QToolButton();
2172  mButton->setText( QStringLiteral( "…" ) );
2173  l->addWidget( mButton );
2174  setLayout( l );
2175 
2176  connect( mLineEdit, &QLineEdit::textChanged, this, &QgsProcessingPointPanel::changed );
2177  connect( mButton, &QToolButton::clicked, this, &QgsProcessingPointPanel::selectOnCanvas );
2178  mButton->setVisible( false );
2179 }
2180 
2181 void QgsProcessingPointPanel::setMapCanvas( QgsMapCanvas *canvas )
2182 {
2183  mCanvas = canvas;
2184  mButton->setVisible( true );
2185 
2186  mCrs = canvas->mapSettings().destinationCrs();
2187  mTool = qgis::make_unique< QgsProcessingPointMapTool >( mCanvas );
2188  connect( mTool.get(), &QgsProcessingPointMapTool::clicked, this, &QgsProcessingPointPanel::updatePoint );
2189  connect( mTool.get(), &QgsProcessingPointMapTool::complete, this, &QgsProcessingPointPanel::pointPicked );
2190 }
2191 
2192 void QgsProcessingPointPanel::setAllowNull( bool allowNull )
2193 {
2194  mLineEdit->setShowClearButton( allowNull );
2195 }
2196 
2197 QVariant QgsProcessingPointPanel::value() const
2198 {
2199  return mLineEdit->showClearButton() && mLineEdit->text().trimmed().isEmpty() ? QVariant() : QVariant( mLineEdit->text() );
2200 }
2201 
2202 void QgsProcessingPointPanel::clear()
2203 {
2204  mLineEdit->clear();
2205 }
2206 
2207 void QgsProcessingPointPanel::setValue( const QgsPointXY &point, const QgsCoordinateReferenceSystem &crs )
2208 {
2209  QString newText = QStringLiteral( "%1,%2" )
2210  .arg( QString::number( point.x(), 'f' ) )
2211  .arg( QString::number( point.y(), 'f' ) );
2212 
2213  mCrs = crs;
2214  if ( mCrs.isValid() )
2215  {
2216  newText += QStringLiteral( " [%1]" ).arg( mCrs.authid() );
2217  }
2218  mLineEdit->setText( newText );
2219 }
2220 
2221 void QgsProcessingPointPanel::selectOnCanvas()
2222 {
2223  if ( !mCanvas )
2224  return;
2225 
2226  mPrevTool = mCanvas->mapTool();
2227  mCanvas->setMapTool( mTool.get() );
2228 
2229  emit toggleDialogVisibility( false );
2230 }
2231 
2232 void QgsProcessingPointPanel::updatePoint( const QgsPointXY &point )
2233 {
2234  setValue( point, mCanvas->mapSettings().destinationCrs() );
2235 }
2236 
2237 void QgsProcessingPointPanel::pointPicked()
2238 {
2239  if ( !mCanvas )
2240  return;
2241 
2242  mCanvas->setMapTool( mPrevTool );
2243 
2244  emit toggleDialogVisibility( true );
2245 }
2246 
2247 
2248 
2249 
2250 //
2251 // QgsProcessingPointWidgetWrapper
2252 //
2253 
2254 QgsProcessingPointWidgetWrapper::QgsProcessingPointWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2255  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2256 {
2257 
2258 }
2259 
2260 QWidget *QgsProcessingPointWidgetWrapper::createWidget()
2261 {
2262  const QgsProcessingParameterPoint *pointParam = dynamic_cast< const QgsProcessingParameterPoint *>( parameterDefinition() );
2263  switch ( type() )
2264  {
2267  {
2268  mPanel = new QgsProcessingPointPanel( nullptr );
2269  if ( widgetContext().mapCanvas() )
2270  mPanel->setMapCanvas( widgetContext().mapCanvas() );
2271 
2273  mPanel->setAllowNull( true );
2274 
2275  mPanel->setToolTip( parameterDefinition()->toolTip() );
2276 
2277  connect( mPanel, &QgsProcessingPointPanel::changed, this, [ = ]
2278  {
2279  emit widgetValueHasChanged( this );
2280  } );
2281 
2282  if ( mDialog )
2283  setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
2284  return mPanel;
2285  }
2286 
2288  {
2289  mLineEdit = new QLineEdit();
2290  mLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
2291  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & )
2292  {
2293  emit widgetValueHasChanged( this );
2294  } );
2295  return mLineEdit;
2296  }
2297  }
2298  return nullptr;
2299 }
2300 
2301 void QgsProcessingPointWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
2302 {
2304  if ( mPanel && context.mapCanvas() )
2305  mPanel->setMapCanvas( context.mapCanvas() );
2306 }
2307 
2308 void QgsProcessingPointWidgetWrapper::setDialog( QDialog *dialog )
2309 {
2310  mDialog = dialog;
2311  if ( mPanel )
2312  {
2313  connect( mPanel, &QgsProcessingPointPanel::toggleDialogVisibility, mDialog, [ = ]( bool visible )
2314  {
2315  if ( !visible )
2316  mDialog->showMinimized();
2317  else
2318  {
2319  mDialog->showNormal();
2320  mDialog->raise();
2321  mDialog->activateWindow();
2322  }
2323  } );
2324  }
2326 }
2327 
2328 void QgsProcessingPointWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2329 {
2330  if ( mPanel )
2331  {
2332  if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
2333  mPanel->clear();
2334  else
2335  {
2336  QgsPointXY p = QgsProcessingParameters::parameterAsPoint( parameterDefinition(), value, context );
2337  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
2338  mPanel->setValue( p, crs );
2339  }
2340  }
2341  else if ( mLineEdit )
2342  {
2343  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2344  mLineEdit->setText( v );
2345  }
2346 }
2347 
2348 QVariant QgsProcessingPointWidgetWrapper::widgetValue() const
2349 {
2350  if ( mPanel )
2351  {
2352  return mPanel->value();
2353  }
2354  else if ( mLineEdit )
2355  return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
2356  else
2357  return QVariant();
2358 }
2359 
2360 QStringList QgsProcessingPointWidgetWrapper::compatibleParameterTypes() const
2361 {
2362  return QStringList()
2365 }
2366 
2367 QStringList QgsProcessingPointWidgetWrapper::compatibleOutputTypes() const
2368 {
2369  return QStringList()
2371 }
2372 
2373 QList<int> QgsProcessingPointWidgetWrapper::compatibleDataTypes() const
2374 {
2375  return QList<int>();
2376 }
2377 
2378 QString QgsProcessingPointWidgetWrapper::modelerExpressionFormatString() const
2379 {
2380  return tr( "string of the format 'x,y' or a geometry value (centroid is used)" );
2381 }
2382 
2383 QString QgsProcessingPointWidgetWrapper::parameterType() const
2384 {
2386 }
2387 
2388 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2389 {
2390  return new QgsProcessingPointWidgetWrapper( parameter, type );
2391 }
2392 
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...
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.
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
void fileChanged(const QString &)
emitted as soon as the current file or directory is changed
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
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:265
An expression parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
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.
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.
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:73
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.
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...
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:656
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.
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.
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:62
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...
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.
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.
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:54
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
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:65
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:304
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:61
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.
The QgsLayoutComboBox class is a combo box which displays available layouts from a QgsLayoutManager...
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:74
double maximum() const
Returns the maximum value acceptable by the parameter.
Selector widget for authentication configs.
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.