QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 <QLabel>
27 #include <QHBoxLayout>
28 #include <QCheckBox>
29 #include <QComboBox>
30 #include <QLineEdit>
31 #include <QPlainTextEdit>
32 
34 
35 //
36 // QgsProcessingBooleanWidgetWrapper
37 //
38 
39 QgsProcessingBooleanWidgetWrapper::QgsProcessingBooleanWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
40  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
41 {
42 
43 }
44 
45 QWidget *QgsProcessingBooleanWidgetWrapper::createWidget()
46 {
47  switch ( type() )
48  {
50  {
51  QString description = parameterDefinition()->description();
52  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
53  description = QObject::tr( "%1 [optional]" ).arg( description );
54 
55  mCheckBox = new QCheckBox( description );
56  mCheckBox->setToolTip( parameterDefinition()->toolTip() );
57 
58  connect( mCheckBox, &QCheckBox::toggled, this, [ = ]
59  {
60  emit widgetValueHasChanged( this );
61  } );
62  return mCheckBox;
63  };
64 
67  {
68  mComboBox = new QComboBox();
69  mComboBox->addItem( tr( "Yes" ), true );
70  mComboBox->addItem( tr( "No" ), false );
71  mComboBox->setToolTip( parameterDefinition()->toolTip() );
72 
73  connect( mComboBox, qgis::overload< int>::of( &QComboBox::currentIndexChanged ), this, [ = ]
74  {
75  emit widgetValueHasChanged( this );
76  } );
77 
78  return mComboBox;
79  }
80  }
81  return nullptr;
82 }
83 
84 QLabel *QgsProcessingBooleanWidgetWrapper::createLabel()
85 {
86  // avoid creating labels in standard dialogs
87  if ( type() == QgsProcessingGui::Standard )
88  return nullptr;
89  else
91 }
92 
93 void QgsProcessingBooleanWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
94 {
95  switch ( type() )
96  {
98  {
99  const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
100  mCheckBox->setChecked( v );
101  break;
102  }
103 
106  {
107  const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
108  mComboBox->setCurrentIndex( mComboBox->findData( v ) );
109  break;
110  }
111  }
112 }
113 
114 QVariant QgsProcessingBooleanWidgetWrapper::widgetValue() const
115 {
116  switch ( type() )
117  {
119  return mCheckBox->isChecked();
120 
123  return mComboBox->currentData();
124  }
125  return QVariant();
126 }
127 
128 QStringList QgsProcessingBooleanWidgetWrapper::compatibleParameterTypes() const
129 {
130  //pretty much everything is compatible here and can be converted to a bool!
131  return QStringList() << QgsProcessingParameterBoolean::typeName()
142 }
143 
144 QStringList QgsProcessingBooleanWidgetWrapper::compatibleOutputTypes() const
145 {
146  return QStringList() << QgsProcessingOutputNumber::typeName()
152 }
153 
154 QList<int> QgsProcessingBooleanWidgetWrapper::compatibleDataTypes() const
155 {
156  return QList< int >();
157 }
158 
159 QString QgsProcessingBooleanWidgetWrapper::parameterType() const
160 {
162 }
163 
164 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBooleanWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
165 {
166  return new QgsProcessingBooleanWidgetWrapper( parameter, type );
167 }
168 
169 
170 //
171 // QgsProcessingCrsWidgetWrapper
172 //
173 
174 QgsProcessingCrsWidgetWrapper::QgsProcessingCrsWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
175  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
176 {
177 
178 }
179 
180 QWidget *QgsProcessingCrsWidgetWrapper::createWidget()
181 {
182  mProjectionSelectionWidget = new QgsProjectionSelectionWidget();
183  mProjectionSelectionWidget->setToolTip( parameterDefinition()->toolTip() );
184 
185  if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
186  mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
187  else
188  mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, false );
189 
190  connect( mProjectionSelectionWidget, &QgsProjectionSelectionWidget::crsChanged, this, [ = ]
191  {
192  emit widgetValueHasChanged( this );
193  } );
194 
195  switch ( type() )
196  {
199  {
200  return mProjectionSelectionWidget;
201  };
202 
204  {
205  QWidget *w = new QWidget();
206  w->setToolTip( parameterDefinition()->toolTip() );
207 
208  QVBoxLayout *vl = new QVBoxLayout();
209  vl->setMargin( 0 );
210  vl->setContentsMargins( 0, 0, 0, 0 );
211  w->setLayout( vl );
212 
213  mUseProjectCrsCheckBox = new QCheckBox( tr( "Use project CRS" ) );
214  mUseProjectCrsCheckBox->setToolTip( tr( "Always use the current project CRS when running the model" ) );
215  vl->addWidget( mUseProjectCrsCheckBox );
216  connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, mProjectionSelectionWidget, &QgsProjectionSelectionWidget::setDisabled );
217  connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, this, [ = ]
218  {
219  emit widgetValueHasChanged( this );
220  } );
221 
222  vl->addWidget( mProjectionSelectionWidget );
223 
224  return w;
225  }
226  }
227  return nullptr;
228 }
229 
230 void QgsProcessingCrsWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
231 {
232  if ( mUseProjectCrsCheckBox )
233  {
234  if ( value.toString().compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
235  {
236  mUseProjectCrsCheckBox->setChecked( true );
237  return;
238  }
239  else
240  {
241  mUseProjectCrsCheckBox->setChecked( false );
242  }
243  }
244 
245  const QgsCoordinateReferenceSystem v = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, context );
246  if ( mProjectionSelectionWidget )
247  mProjectionSelectionWidget->setCrs( v );
248 }
249 
250 QVariant QgsProcessingCrsWidgetWrapper::widgetValue() const
251 {
252  if ( mUseProjectCrsCheckBox && mUseProjectCrsCheckBox->isChecked() )
253  return QStringLiteral( "ProjectCrs" );
254  else if ( mProjectionSelectionWidget )
255  return mProjectionSelectionWidget->crs().isValid() ? mProjectionSelectionWidget->crs() : QVariant();
256  else
257  return QVariant();
258 }
259 
260 QStringList QgsProcessingCrsWidgetWrapper::compatibleParameterTypes() const
261 {
262  return QStringList()
269 }
270 
271 QStringList QgsProcessingCrsWidgetWrapper::compatibleOutputTypes() const
272 {
273  return QStringList() << QgsProcessingOutputVectorLayer::typeName()
277 }
278 
279 QList<int> QgsProcessingCrsWidgetWrapper::compatibleDataTypes() const
280 {
281  return QList< int >();
282 }
283 
284 QString QgsProcessingCrsWidgetWrapper::modelerExpressionFormatString() const
285 {
286  return tr( "string as EPSG code, WKT or PROJ format, or a string identifying a map layer" );
287 }
288 
289 QString QgsProcessingCrsWidgetWrapper::parameterType() const
290 {
292 }
293 
294 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCrsWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
295 {
296  return new QgsProcessingCrsWidgetWrapper( parameter, type );
297 }
298 
299 
300 
301 //
302 // QgsProcessingStringWidgetWrapper
303 //
304 
305 QgsProcessingStringWidgetWrapper::QgsProcessingStringWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
306  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
307 {
308 
309 }
310 
311 QWidget *QgsProcessingStringWidgetWrapper::createWidget()
312 {
313  switch ( type() )
314  {
317  {
318  if ( static_cast< const QgsProcessingParameterString * >( parameterDefinition() )->multiLine() )
319  {
320  mPlainTextEdit = new QPlainTextEdit();
321  mPlainTextEdit->setToolTip( parameterDefinition()->toolTip() );
322 
323  connect( mPlainTextEdit, &QPlainTextEdit::textChanged, this, [ = ]
324  {
325  emit widgetValueHasChanged( this );
326  } );
327  return mPlainTextEdit;
328  }
329  else
330  {
331  mLineEdit = new QLineEdit();
332  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
333 
334  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
335  {
336  emit widgetValueHasChanged( this );
337  } );
338  return mLineEdit;
339  }
340  };
341 
343  {
344  mLineEdit = new QLineEdit();
345  mLineEdit->setToolTip( parameterDefinition()->toolTip() );
346 
347  connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
348  {
349  emit widgetValueHasChanged( this );
350  } );
351  return mLineEdit;
352  }
353  }
354  return nullptr;
355 }
356 
357 void QgsProcessingStringWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
358 {
359  const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
360  if ( mLineEdit )
361  mLineEdit->setText( v );
362  if ( mPlainTextEdit )
363  mPlainTextEdit->setPlainText( v );
364 }
365 
366 QVariant QgsProcessingStringWidgetWrapper::widgetValue() const
367 {
368  if ( mLineEdit )
369  return mLineEdit->text();
370  else if ( mPlainTextEdit )
371  return mPlainTextEdit->toPlainText();
372  else
373  return QVariant();
374 }
375 
376 QStringList QgsProcessingStringWidgetWrapper::compatibleParameterTypes() const
377 {
378  return QStringList()
385 }
386 
387 QStringList QgsProcessingStringWidgetWrapper::compatibleOutputTypes() const
388 {
389  return QStringList() << QgsProcessingOutputNumber::typeName()
392 }
393 
394 QList<int> QgsProcessingStringWidgetWrapper::compatibleDataTypes() const
395 {
396  return QList< int >();
397 }
398 
399 QString QgsProcessingStringWidgetWrapper::parameterType() const
400 {
402 }
403 
404 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingStringWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
405 {
406  return new QgsProcessingStringWidgetWrapper( parameter, type );
407 }
408 
409 
410 
411 //
412 // QgsProcessingNumericWidgetWrapper
413 //
414 
415 QgsProcessingNumericWidgetWrapper::QgsProcessingNumericWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
416  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
417 {
418 
419 }
420 
421 QWidget *QgsProcessingNumericWidgetWrapper::createWidget()
422 {
423  const QgsProcessingParameterNumber *numberDef = static_cast< const QgsProcessingParameterNumber * >( parameterDefinition() );
424  const QVariantMap metadata = numberDef->metadata();
425  const int decimals = metadata.value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "decimals" ), 6 ).toInt();
426  switch ( type() )
427  {
431  {
432  // lots of duplicate code here -- but there's no common interface between QSpinBox/QDoubleSpinBox which would allow us to avoid this
433  QAbstractSpinBox *spinBox = nullptr;
434  switch ( numberDef->dataType() )
435  {
437  mDoubleSpinBox = new QgsDoubleSpinBox();
438  mDoubleSpinBox->setExpressionsEnabled( true );
439  mDoubleSpinBox->setDecimals( decimals );
440 
441  // guess reasonable step value for double spin boxes
442  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) &&
443  !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() + 1 ) )
444  {
445  double singleStep = calculateStep( numberDef->minimum(), numberDef->maximum() );
446  singleStep = std::max( singleStep, std::pow( 10, -decimals ) );
447  mDoubleSpinBox->setSingleStep( singleStep );
448  }
449 
450  spinBox = mDoubleSpinBox;
451  break;
452 
454  mSpinBox = new QgsSpinBox();
455  mSpinBox->setExpressionsEnabled( true );
456  spinBox = mSpinBox;
457  break;
458  }
459  spinBox->setToolTip( parameterDefinition()->toolTip() );
460 
461  double max = 999999999;
462  if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) )
463  {
464  max = numberDef->maximum();
465  }
466  double min = -999999999;
467  if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
468  {
469  min = numberDef->minimum();
470  }
471  if ( mDoubleSpinBox )
472  {
473  mDoubleSpinBox->setMinimum( min );
474  mDoubleSpinBox->setMaximum( max );
475  }
476  else
477  {
478  mSpinBox->setMinimum( static_cast< int >( min ) );
479  mSpinBox->setMaximum( static_cast< int >( max ) );
480  }
481 
483  {
484  mAllowingNull = true;
485  if ( mDoubleSpinBox )
486  {
487  mDoubleSpinBox->setShowClearButton( true );
488  const double min = mDoubleSpinBox->minimum() - 1;
489  mDoubleSpinBox->setMinimum( min );
490  mDoubleSpinBox->setValue( min );
491  }
492  else
493  {
494  mSpinBox->setShowClearButton( true );
495  const int min = mSpinBox->minimum() - 1;
496  mSpinBox->setMinimum( min );
497  mSpinBox->setValue( min );
498  }
499  spinBox->setSpecialValueText( tr( "Not set" ) );
500  }
501  else
502  {
503  if ( numberDef->defaultValue().isValid() )
504  {
505  // if default value for parameter, we clear to that
506  bool ok = false;
507  if ( mDoubleSpinBox )
508  {
509  double defaultVal = numberDef->defaultValue().toDouble( &ok );
510  if ( ok )
511  mDoubleSpinBox->setClearValue( defaultVal );
512  }
513  else
514  {
515  int intVal = numberDef->defaultValue().toInt( &ok );
516  if ( ok )
517  mSpinBox->setClearValue( intVal );
518  }
519  }
520  else if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
521  {
522  // otherwise we clear to the minimum, if it's set
523  if ( mDoubleSpinBox )
524  mDoubleSpinBox->setClearValue( numberDef->minimum() );
525  else
526  mSpinBox->setClearValue( static_cast< int >( numberDef->minimum() ) );
527  }
528  else
529  {
530  // last resort, we clear to 0
531  if ( mDoubleSpinBox )
532  {
533  mDoubleSpinBox->setValue( 0 );
534  mDoubleSpinBox->setClearValue( 0 );
535  }
536  else
537  {
538  mSpinBox->setValue( 0 );
539  mSpinBox->setClearValue( 0 );
540  }
541  }
542  }
543 
544  if ( mDoubleSpinBox )
545  connect( mDoubleSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
546  else if ( mSpinBox )
547  connect( mSpinBox, qgis::overload<int>::of( &QgsSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
548 
549  return spinBox;
550  };
551  }
552  return nullptr;
553 }
554 
555 void QgsProcessingNumericWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
556 {
557  if ( mDoubleSpinBox )
558  {
559  if ( mAllowingNull && !value.isValid() )
560  mDoubleSpinBox->clear();
561  else
562  {
563  const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
564  mDoubleSpinBox->setValue( v );
565  }
566  }
567  else if ( mSpinBox )
568  {
569  if ( mAllowingNull && !value.isValid() )
570  mSpinBox->clear();
571  else
572  {
573  const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
574  mSpinBox->setValue( v );
575  }
576  }
577 }
578 
579 QVariant QgsProcessingNumericWidgetWrapper::widgetValue() const
580 {
581  if ( mDoubleSpinBox )
582  {
583  if ( mAllowingNull && qgsDoubleNear( mDoubleSpinBox->value(), mDoubleSpinBox->minimum() ) )
584  return QVariant();
585  else
586  return mDoubleSpinBox->value();
587  }
588  else if ( mSpinBox )
589  {
590  if ( mAllowingNull && mSpinBox->value() == mSpinBox->minimum() )
591  return QVariant();
592  else
593  return mSpinBox->value();
594  }
595  else
596  return QVariant();
597 }
598 
599 QStringList QgsProcessingNumericWidgetWrapper::compatibleParameterTypes() const
600 {
601  return QStringList()
605 }
606 
607 QStringList QgsProcessingNumericWidgetWrapper::compatibleOutputTypes() const
608 {
609  return QStringList() << QgsProcessingOutputNumber::typeName()
611 }
612 
613 QList<int> QgsProcessingNumericWidgetWrapper::compatibleDataTypes() const
614 {
615  return QList< int >();
616 }
617 
618 double QgsProcessingNumericWidgetWrapper::calculateStep( const double minimum, const double maximum )
619 {
620  const double valueRange = maximum - minimum;
621  if ( valueRange <= 1.0 )
622  {
623  const double step = valueRange / 10.0;
624  // round to 1 significant figure
625  return qgsRound( step, -std::floor( std::log( step ) ) );
626  }
627  else
628  {
629  return 1.0;
630  }
631 }
632 
633 QString QgsProcessingNumericWidgetWrapper::parameterType() const
634 {
636 }
637 
638 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingNumericWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
639 {
640  return new QgsProcessingNumericWidgetWrapper( parameter, type );
641 }
642 
643 //
644 // QgsProcessingDistanceWidgetWrapper
645 //
646 
647 QgsProcessingDistanceWidgetWrapper::QgsProcessingDistanceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
648  : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
649 {
650 
651 }
652 
653 QString QgsProcessingDistanceWidgetWrapper::parameterType() const
654 {
656 }
657 
658 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDistanceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
659 {
660  return new QgsProcessingDistanceWidgetWrapper( parameter, type );
661 }
662 
663 QWidget *QgsProcessingDistanceWidgetWrapper::createWidget()
664 {
665  const QgsProcessingParameterDistance *distanceDef = static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() );
666 
667  QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
668  switch ( type() )
669  {
671  {
672  mLabel = new QLabel();
673  mUnitsCombo = new QComboBox();
674 
680 
681  const int labelMargin = static_cast< int >( std::round( mUnitsCombo->fontMetrics().width( 'X' ) ) );
682  QHBoxLayout *layout = new QHBoxLayout();
683  layout->addWidget( spin, 1 );
684  layout->insertSpacing( 1, labelMargin / 2 );
685  layout->insertWidget( 2, mLabel );
686  layout->insertWidget( 3, mUnitsCombo );
687 
688  // bit of fiddlyness here -- we want the initial spacing to only be visible
689  // when the warning label is shown, so it's embedded inside mWarningLabel
690  // instead of outside it
691  mWarningLabel = new QWidget();
692  QHBoxLayout *warningLayout = new QHBoxLayout();
693  warningLayout->setMargin( 0 );
694  warningLayout->setContentsMargins( 0, 0, 0, 0 );
695  QLabel *warning = new QLabel();
696  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
697  const int size = static_cast< int >( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
698  warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
699  warning->setToolTip( tr( "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
700  warningLayout->insertSpacing( 0, labelMargin / 2 );
701  warningLayout->insertWidget( 1, warning );
702  mWarningLabel->setLayout( warningLayout );
703  layout->insertWidget( 4, mWarningLabel );
704 
705  setUnits( distanceDef->defaultUnit() );
706 
707  QWidget *w = new QWidget();
708  layout->setMargin( 0 );
709  layout->setContentsMargins( 0, 0, 0, 0 );
710  w->setLayout( layout );
711  return w;
712  }
713 
716  return spin;
717 
718  }
719  return nullptr;
720 }
721 
722 void QgsProcessingDistanceWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
723 {
724  QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
725  switch ( type() )
726  {
728  {
729  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
730  {
731  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDistance * >( parameterDefinition() )->parentParameterName() )
732  {
733  setUnitParameterValue( wrapper->parameterValue() );
735  {
736  setUnitParameterValue( wrapper->parameterValue() );
737  } );
738  break;
739  }
740  }
741  break;
742  }
743 
746  break;
747  }
748 }
749 
750 void QgsProcessingDistanceWidgetWrapper::setUnitParameterValue( const QVariant &value )
751 {
753 
754  // evaluate value to layer
755  QgsProcessingContext *context = nullptr;
756  std::unique_ptr< QgsProcessingContext > tmpContext;
757  if ( mProcessingContextGenerator )
758  context = mProcessingContextGenerator->processingContext();
759 
760  if ( !context )
761  {
762  tmpContext = qgis::make_unique< QgsProcessingContext >();
763  context = tmpContext.get();
764  }
765 
766  QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, *context );
767  if ( crs.isValid() )
768  {
769  units = crs.mapUnits();
770  }
771 
772  setUnits( units );
773 }
774 
775 void QgsProcessingDistanceWidgetWrapper::setUnits( const QgsUnitTypes::DistanceUnit units )
776 {
777  mLabel->setText( QgsUnitTypes::toString( units ) );
779  {
780  mUnitsCombo->hide();
781  mLabel->show();
782  }
783  else
784  {
785  mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( units ) );
786  mUnitsCombo->show();
787  mLabel->hide();
788  }
789  mWarningLabel->setVisible( units == QgsUnitTypes::DistanceDegrees );
790  mBaseUnit = units;
791 }
792 
793 QVariant QgsProcessingDistanceWidgetWrapper::widgetValue() const
794 {
795  const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
796  if ( val.type() == QVariant::Double && mUnitsCombo && mUnitsCombo->isVisible() )
797  {
798  QgsUnitTypes::DistanceUnit displayUnit = static_cast<QgsUnitTypes::DistanceUnit >( mUnitsCombo->currentData().toInt() );
799  return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
800  }
801  else
802  {
803  return val;
804  }
805 }
806 
807 
808 //
809 // QgsProcessingRangeWidgetWrapper
810 //
811 
812 QgsProcessingRangeWidgetWrapper::QgsProcessingRangeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
813  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
814 {
815 
816 }
817 
818 QWidget *QgsProcessingRangeWidgetWrapper::createWidget()
819 {
820  const QgsProcessingParameterRange *rangeDef = static_cast< const QgsProcessingParameterRange * >( parameterDefinition() );
821  switch ( type() )
822  {
826  {
827  QHBoxLayout *layout = new QHBoxLayout();
828 
829  mMinSpinBox = new QgsDoubleSpinBox();
830  mMaxSpinBox = new QgsDoubleSpinBox();
831 
832  mMinSpinBox->setExpressionsEnabled( true );
833  mMinSpinBox->setShowClearButton( false );
834  mMaxSpinBox->setExpressionsEnabled( true );
835  mMaxSpinBox->setShowClearButton( false );
836 
837  QLabel *minLabel = new QLabel( tr( "Min" ) );
838  layout->addWidget( minLabel );
839  layout->addWidget( mMinSpinBox, 1 );
840 
841  QLabel *maxLabel = new QLabel( tr( "Max" ) );
842  layout->addWidget( maxLabel );
843  layout->addWidget( mMaxSpinBox, 1 );
844 
845  QWidget *w = new QWidget();
846  layout->setMargin( 0 );
847  layout->setContentsMargins( 0, 0, 0, 0 );
848  w->setLayout( layout );
849 
850  if ( rangeDef->dataType() == QgsProcessingParameterNumber::Double )
851  {
852  mMinSpinBox->setDecimals( 6 );
853  mMaxSpinBox->setDecimals( 6 );
854  }
855  else
856  {
857  mMinSpinBox->setDecimals( 0 );
858  mMaxSpinBox->setDecimals( 0 );
859  }
860 
861  mMinSpinBox->setMinimum( -99999999.999999 );
862  mMaxSpinBox->setMinimum( -99999999.999999 );
863  mMinSpinBox->setMaximum( 99999999.999999 );
864  mMaxSpinBox->setMaximum( 99999999.999999 );
865 
866  w->setToolTip( parameterDefinition()->toolTip() );
867 
868  connect( mMinSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
869  {
870  mBlockChangedSignal++;
871  if ( v > mMaxSpinBox->value() )
872  mMaxSpinBox->setValue( v );
873  mBlockChangedSignal--;
874 
875  if ( !mBlockChangedSignal )
876  emit widgetValueHasChanged( this );
877  } );
878  connect( mMaxSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( const double v )
879  {
880  mBlockChangedSignal++;
881  if ( v < mMinSpinBox->value() )
882  mMinSpinBox->setValue( v );
883  mBlockChangedSignal--;
884 
885  if ( !mBlockChangedSignal )
886  emit widgetValueHasChanged( this );
887  } );
888 
889  return w;
890  };
891  }
892  return nullptr;
893 }
894 
895 void QgsProcessingRangeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
896 {
897  const QList< double > v = QgsProcessingParameters::parameterAsRange( parameterDefinition(), value, context );
898  if ( v.empty() )
899  return;
900 
901  mBlockChangedSignal++;
902  mMinSpinBox->setValue( v.at( 0 ) );
903  if ( v.count() >= 2 )
904  mMaxSpinBox->setValue( v.at( 1 ) );
905  mBlockChangedSignal--;
906 
907  if ( !mBlockChangedSignal )
908  emit widgetValueHasChanged( this );
909 }
910 
911 QVariant QgsProcessingRangeWidgetWrapper::widgetValue() const
912 {
913  return QStringLiteral( "%1,%2" ).arg( mMinSpinBox->value() ).arg( mMaxSpinBox->value() );
914 }
915 
916 QStringList QgsProcessingRangeWidgetWrapper::compatibleParameterTypes() const
917 {
918  return QStringList()
921 }
922 
923 QStringList QgsProcessingRangeWidgetWrapper::compatibleOutputTypes() const
924 {
925  return QStringList() << QgsProcessingOutputString::typeName();
926 }
927 
928 QList<int> QgsProcessingRangeWidgetWrapper::compatibleDataTypes() const
929 {
930  return QList< int >();
931 }
932 
933 QString QgsProcessingRangeWidgetWrapper::modelerExpressionFormatString() const
934 {
935  return tr( "string as two comma delimited floats, e.g. '1,10'" );
936 }
937 
938 QString QgsProcessingRangeWidgetWrapper::parameterType() const
939 {
941 }
942 
943 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRangeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
944 {
945  return new QgsProcessingRangeWidgetWrapper( parameter, type );
946 }
947 
948 
949 
950 //
951 // QgsProcessingMatrixWidgetWrapper
952 //
953 
954 QgsProcessingMatrixWidgetWrapper::QgsProcessingMatrixWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
955  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
956 {
957 
958 }
959 
960 QWidget *QgsProcessingMatrixWidgetWrapper::createWidget()
961 {
962  mMatrixWidget = new QgsProcessingMatrixParameterPanel( nullptr, dynamic_cast< const QgsProcessingParameterMatrix *>( parameterDefinition() ) );
963  mMatrixWidget->setToolTip( parameterDefinition()->toolTip() );
964 
965  connect( mMatrixWidget, &QgsProcessingMatrixParameterPanel::changed, this, [ = ]
966  {
967  emit widgetValueHasChanged( this );
968  } );
969 
970  switch ( type() )
971  {
975  {
976  return mMatrixWidget;
977  };
978  }
979  return nullptr;
980 }
981 
982 void QgsProcessingMatrixWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
983 {
984  const QVariantList v = QgsProcessingParameters::parameterAsMatrix( parameterDefinition(), value, context );
985  if ( mMatrixWidget )
986  mMatrixWidget->setValue( v );
987 }
988 
989 QVariant QgsProcessingMatrixWidgetWrapper::widgetValue() const
990 {
991  if ( mMatrixWidget )
992  return mMatrixWidget->value().isEmpty() ? QVariant() : mMatrixWidget->value();
993  else
994  return QVariant();
995 }
996 
997 QStringList QgsProcessingMatrixWidgetWrapper::compatibleParameterTypes() const
998 {
999  return QStringList()
1001 }
1002 
1003 QStringList QgsProcessingMatrixWidgetWrapper::compatibleOutputTypes() const
1004 {
1005  return QStringList();
1006 }
1007 
1008 QList<int> QgsProcessingMatrixWidgetWrapper::compatibleDataTypes() const
1009 {
1010  return QList< int >();
1011 }
1012 
1013 QString QgsProcessingMatrixWidgetWrapper::modelerExpressionFormatString() const
1014 {
1015  return tr( "comma delimited string of values, or an array of values" );
1016 }
1017 
1018 QString QgsProcessingMatrixWidgetWrapper::parameterType() const
1019 {
1021 }
1022 
1023 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMatrixWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1024 {
1025  return new QgsProcessingMatrixWidgetWrapper( parameter, type );
1026 }
1027 
1028 
1030 
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...
static QString typeName()
Returns the type name for the parameter class.
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.
static QString typeName()
Returns the type name for the parameter class.
double maximum() const
Returns the maximum value acceptable by the parameter.
static QVariantList parameterAsMatrix(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a matrix/table of values.
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.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
WidgetType
Types of dialogs which Processing widgets can be created for.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:278
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.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
virtual QLabel * createLabel()
Creates a new label to accompany widgets created by the wrapper.
static QString typeName()
Returns the type name for the parameter class.
Type dataType() const
Returns the acceptable data type for the parameter.
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.
QgsProcessingParameterNumber::Type dataType() const
Returns the acceptable data type for the range.
double minimum() const
Returns the minimum value acceptable by the parameter.
A numeric range 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.
static QString typeName()
Returns the type name for the parameter class.
void widgetValueHasChanged(QgsAbstractProcessingParameterWidgetWrapper *wrapper)
Emitted whenever the parameter value (as defined by the wrapped widget) is changed.
Flags flags() const
Returns any flags associated with the parameter.
A double numeric parameter for distance values.
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:61
static QString typeName()
Returns the type name for the output class.
QgsUnitTypes::DistanceUnit defaultUnit() const
Returns the default distance unit for the parameter.
static QString typeName()
Returns the type name for the output class.
A numeric parameter for processing algorithms.
QVariantMap metadata() const
Returns the parameter&#39;s freeform metadata.
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:53
A widget for selecting a projection.
static Q_INVOKABLE DistanceUnitType unitType(QgsUnitTypes::DistanceUnit unit)
Returns the type for a distance unit.
Unknown distance unit.
Definition: qgsunittypes.h:64
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places...
Definition: qgis.h:317
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the parameter class.
This class represents a coordinate reference system (CRS).
Base class for the definition of processing parameters.
static double parameterAsDouble(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static double value.
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.
QVariant defaultValue() const
Returns the default value for the parameter.
Terrestrial miles.
Definition: qgsunittypes.h:60
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
Contains information about the context in which a processing algorithm is executed.
static QString typeName()
Returns the type name for the output class.
Unit is a standard measurement unit.
Definition: qgsunittypes.h:73
Standard algorithm dialog.
Batch processing dialog.