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