QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsprocessingmodelerparameterwidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingmodelerparameterwidget.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
25#include "qgsgui.h"
26#include "qgsguiutils.h"
28#include "qgsapplication.h"
29#include "qgsfilterlineedit.h"
30#include <QHBoxLayout>
31#include <QToolButton>
32#include <QStackedWidget>
33#include <QMenu>
34#include <QLabel>
35#include <QComboBox>
36
38 const QString &childId,
40 QWidget *parent )
41 : QWidget( parent )
42 , mModel( model )
43 , mChildId( childId )
44 , mParameterDefinition( parameter )
45 , mContext( context )
46{
47 setFocusPolicy( Qt::StrongFocus );
48
49 // icon size is a bit bigger than text, but minimum size of 24 so that we get pixel-aligned rendering on low-dpi screens
50 const int iconSize = QgsGuiUtils::scaleIconSize( 24 );
51
52 QHBoxLayout *hLayout = new QHBoxLayout();
53
54 {
55 const QVariantList acceptedSourcesMetadata = mParameterDefinition->metadata().value( QStringLiteral( "model_widget" ) ).toMap().value( QStringLiteral( "accepted_sources" ) ).toList();
56 for ( const QVariant &acceptedSource : acceptedSourcesMetadata )
57 {
58 mLimitedSources.append( static_cast< Qgis::ProcessingModelChildParameterSource >( acceptedSource.toInt() ) );
59 }
60 }
61
62 mSourceButton = new QToolButton();
63 mSourceButton->setFocusPolicy( Qt::StrongFocus );
64
65 // button width is 1.25 * icon size, height 1.1 * icon size. But we round to ensure even pixel sizes for equal margins
66 mSourceButton->setFixedSize( 2 * static_cast< int >( 1.25 * iconSize / 2.0 ), 2 * static_cast< int >( iconSize * 1.1 / 2.0 ) );
67 mSourceButton->setIconSize( QSize( iconSize, iconSize ) );
68 mSourceButton->setPopupMode( QToolButton::InstantPopup );
69
70 mSourceMenu = new QMenu( this );
71 connect( mSourceMenu, &QMenu::aboutToShow, this, &QgsProcessingModelerParameterWidget::sourceMenuAboutToShow );
72 connect( mSourceMenu, &QMenu::triggered, this, &QgsProcessingModelerParameterWidget::sourceMenuActionTriggered );
73 mSourceButton->setMenu( mSourceMenu );
74
75 hLayout->addWidget( mSourceButton );
76
77 mStackedWidget = new QStackedWidget();
78
79 mStaticWidgetWrapper.reset( QgsGui::processingGuiRegistry()->createParameterWidgetWrapper( mParameterDefinition, QgsProcessingGui::Modeler ) );
80 if ( mStaticWidgetWrapper )
81 {
82 QWidget *widget = mStaticWidgetWrapper->createWrappedWidget( context );
83 if ( widget )
84 {
85 mHasStaticWrapper = true;
86 mStackedWidget->addWidget( widget );
87 }
88 else
89 mStackedWidget->addWidget( new QWidget() );
90 }
91 else
92 {
93 mStackedWidget->addWidget( new QWidget() );
94 }
95
96 mExpressionWidget = new QgsExpressionLineEdit();
97 mExpressionWidget->registerExpressionContextGenerator( this );
98 mStackedWidget->addWidget( mExpressionWidget );
99
100 mModelInputCombo = new QComboBox();
101 QHBoxLayout *hLayout2 = new QHBoxLayout();
102 hLayout2->setContentsMargins( 0, 0, 0, 0 );
103 hLayout2->addWidget( new QLabel( tr( "Using model input" ) ) );
104 hLayout2->addWidget( mModelInputCombo, 1 );
105 QWidget *hWidget2 = new QWidget();
106 hWidget2->setLayout( hLayout2 );
107 mStackedWidget->addWidget( hWidget2 );
108
109 mChildOutputCombo = new QComboBox();
110 QHBoxLayout *hLayout3 = new QHBoxLayout();
111 hLayout3->setContentsMargins( 0, 0, 0, 0 );
112 hLayout3->addWidget( new QLabel( tr( "Using algorithm output" ) ) );
113 hLayout3->addWidget( mChildOutputCombo, 1 );
114 QWidget *hWidget3 = new QWidget();
115 hWidget3->setLayout( hLayout3 );
116 mStackedWidget->addWidget( hWidget3 );
117
118 if ( mParameterDefinition->isDestination() )
119 {
120 mModelOutputName = new QgsFilterLineEdit();
121 mModelOutputName->setPlaceholderText( tr( "[Enter name if this is a final result]" ) );
122 QHBoxLayout *hLayout4 = new QHBoxLayout();
123 hLayout4->setContentsMargins( 0, 0, 0, 0 );
124 hLayout4->addWidget( mModelOutputName );
125 QWidget *hWidget4 = new QWidget();
126 hWidget4->setLayout( hLayout4 );
127 mStackedWidget->addWidget( hWidget4 );
128 }
129
130 hLayout->setContentsMargins( 0, 0, 0, 0 );
131 hLayout->addWidget( mStackedWidget, 1 );
132
133 setLayout( hLayout );
135}
136
138
140{
141 if ( mStaticWidgetWrapper )
142 mStaticWidgetWrapper->setWidgetContext( context );
143}
144
146{
147 if ( mStaticWidgetWrapper )
148 mStaticWidgetWrapper->registerProcessingContextGenerator( generator );
149}
150
152{
153 return mParameterDefinition;
154}
155
157{
158 if ( mStaticWidgetWrapper )
159 return mStaticWidgetWrapper->createWrappedLabel();
160 else
161 return nullptr;
162}
163
164void QgsProcessingModelerParameterWidget::setWidgetValue( const QgsProcessingModelChildParameterSource &value )
165{
166 // we make a copy of all attributes and store locally, so that users can flick between
167 // sources without losing their current value
168 mStaticValue = value.staticValue();
169 mModelInputParameterName = value.parameterName();
170 mOutputChildId = value.outputChildId();
171 mOutputName = value.outputName();
172 mExpression = value.expression();
173
174 updateUi();
175 setSourceType( value.source() );
176}
177
178void QgsProcessingModelerParameterWidget::setWidgetValue( const QList<QgsProcessingModelChildParameterSource> &values )
179{
180 if ( values.size() == 1 )
181 setWidgetValue( values.at( 0 ) );
182 else
183 {
184 QVariantList r;
185 for ( const QgsProcessingModelChildParameterSource &v : values )
186 r << QVariant::fromValue( v );
187 mStaticValue = r;
188 updateUi();
190 }
191}
192
194{
195 if ( mModelOutputName )
196 mModelOutputName->setText( value );
198}
199
201{
202 return currentSourceType() == ModelOutput;
203}
204
206{
207 return mModelOutputName ? mModelOutputName->text().trimmed() : QString();
208}
209
211{
212 switch ( currentSourceType() )
213 {
214 case StaticValue:
215 {
216 const QVariant v = mStaticWidgetWrapper->parameterValue();
217
218 if ( v.type() == QVariant::List )
219 {
220 const QVariantList vList = v.toList();
221 if ( std::all_of( vList.begin(), vList.end(), []( const QVariant & val )
222 {
223 return val.userType() == QMetaType::type( "QgsProcessingModelChildParameterSource" );
224 } ) )
225 {
226 return v;
227 }
228 }
229 return QVariant::fromValue( QgsProcessingModelChildParameterSource::fromStaticValue( v ) );
230 }
231
232 case Expression:
233 return QVariant::fromValue( QgsProcessingModelChildParameterSource::fromExpression( mExpressionWidget->expression() ) );
234
235 case ModelParameter:
236 return QVariant::fromValue( QgsProcessingModelChildParameterSource::fromModelParameter( mModelInputCombo->currentData().toString() ) );
237
238 case ChildOutput:
239 {
240 const QStringList parts = mChildOutputCombo->currentData().toStringList();
241 return QVariant::fromValue( QgsProcessingModelChildParameterSource::fromChildOutput( parts.value( 0, QString() ), parts.value( 1, QString() ) ) );
242 }
243
244 case ModelOutput:
245 return mModelOutputName ? ( mModelOutputName->text().trimmed().isEmpty() ? QVariant() : mModelOutputName->text() ) : QVariant();
246 }
247
248 return QVariant::fromValue( QgsProcessingModelChildParameterSource() );
249}
250
252{
253 if ( mStaticWidgetWrapper )
254 mStaticWidgetWrapper->setDialog( dialog );
255}
256
258{
260 if ( mModel )
261 {
262 const QgsProcessingAlgorithm *alg = nullptr;
263 if ( mModel->childAlgorithms().contains( mChildId ) )
264 alg = mModel->childAlgorithm( mChildId ).algorithm();
265 QgsExpressionContextScope *algorithmScope = QgsExpressionContextUtils::processingAlgorithmScope( alg, QVariantMap(), mContext );
266 c << algorithmScope;
267 QgsExpressionContextScope *modelScope = QgsExpressionContextUtils::processingModelAlgorithmScope( mModel, QVariantMap(), mContext );
268 c << modelScope;
269 QgsExpressionContextScope *childScope = mModel->createExpressionContextScopeForChildAlgorithm( mChildId, mContext, QVariantMap(), QVariantMap() );
270 c << childScope;
271
272 QStringList highlightedVariables = childScope->variableNames();
273 QStringList highlightedFunctions = childScope->functionNames();
274 highlightedVariables += algorithmScope->variableNames();
275 highlightedVariables += mModel->variables().keys();
276 highlightedFunctions += algorithmScope->functionNames();
277 c.setHighlightedVariables( highlightedVariables );
278 c.setHighlightedFunctions( highlightedFunctions );
279 }
280
281 return c;
282}
283
284void QgsProcessingModelerParameterWidget::sourceMenuAboutToShow()
285{
286 mSourceMenu->clear();
287
288 const SourceType currentSource = currentSourceType();
289
290 if ( mParameterDefinition->isDestination()
291 && ( mLimitedSources.empty() || mLimitedSources.contains( Qgis::ProcessingModelChildParameterSource::ModelOutput ) ) )
292 {
293 QAction *modelOutputAction = mSourceMenu->addAction( tr( "Model Output" ) );
294 modelOutputAction->setCheckable( currentSource == ModelOutput );
295 modelOutputAction->setChecked( currentSource == ModelOutput );
296 modelOutputAction->setData( QVariant::fromValue( Qgis::ProcessingModelChildParameterSource::ModelOutput ) );
297 }
298
299 if ( mHasStaticWrapper
300 && ( mLimitedSources.empty() || mLimitedSources.contains( Qgis::ProcessingModelChildParameterSource::StaticValue ) ) )
301 {
302 QAction *fixedValueAction = mSourceMenu->addAction( tr( "Value" ) );
303 fixedValueAction->setCheckable( currentSource == StaticValue );
304 fixedValueAction->setChecked( currentSource == StaticValue );
305 fixedValueAction->setData( QVariant::fromValue( Qgis::ProcessingModelChildParameterSource::StaticValue ) );
306 }
307
308 if ( mLimitedSources.empty() || mLimitedSources.contains( Qgis::ProcessingModelChildParameterSource::Expression ) )
309 {
310 QAction *calculatedValueAction = mSourceMenu->addAction( tr( "Pre-calculated Value" ) );
311 calculatedValueAction->setCheckable( currentSource == Expression );
312 calculatedValueAction->setChecked( currentSource == Expression );
313 calculatedValueAction->setData( QVariant::fromValue( Qgis::ProcessingModelChildParameterSource::Expression ) );
314 }
315
316 if ( mLimitedSources.empty() || mLimitedSources.contains( Qgis::ProcessingModelChildParameterSource::ModelParameter ) )
317 {
318 QAction *inputValueAction = mSourceMenu->addAction( tr( "Model Input" ) );
319 inputValueAction->setCheckable( currentSource == ModelParameter );
320 inputValueAction->setChecked( currentSource == ModelParameter );
321 inputValueAction->setData( QVariant::fromValue( Qgis::ProcessingModelChildParameterSource::ModelParameter ) );
322 }
323
324 if ( mLimitedSources.empty() || mLimitedSources.contains( Qgis::ProcessingModelChildParameterSource::ChildOutput ) )
325 {
326 QAction *childOutputValueAction = mSourceMenu->addAction( tr( "Algorithm Output" ) );
327 childOutputValueAction->setCheckable( currentSource == ChildOutput );
328 childOutputValueAction->setChecked( currentSource == ChildOutput );
329 childOutputValueAction->setData( QVariant::fromValue( Qgis::ProcessingModelChildParameterSource::ChildOutput ) );
330 }
331
332 // TODO - expression text item?
333}
334
335void QgsProcessingModelerParameterWidget::sourceMenuActionTriggered( QAction *action )
336{
338 setSourceType( sourceType );
339}
340
341QgsProcessingModelerParameterWidget::SourceType QgsProcessingModelerParameterWidget::currentSourceType() const
342{
343 return static_cast< SourceType >( mStackedWidget->currentIndex() );
344}
345
347{
348 if ( !mLimitedSources.empty() && !mLimitedSources.contains( type ) )
349 {
350 // specified type is not acceptable for this parameter, so override with the first acceptable
351 // type
352 type = mLimitedSources.at( 0 );
353 }
354
355 switch ( type )
356 {
358 mStackedWidget->setCurrentIndex( static_cast< int >( StaticValue ) );
359 mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconFieldInteger.svg" ) ) );
360 mSourceButton->setToolTip( tr( "Value" ) );
361 break;
362
364 mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconExpression.svg" ) ) );
365 mStackedWidget->setCurrentIndex( static_cast< int >( Expression ) );
366 mSourceButton->setToolTip( tr( "Pre-calculated Value" ) );
367 break;
368
370 {
371 mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "processingModel.svg" ) ) );
372 mStackedWidget->setCurrentIndex( static_cast< int >( ModelParameter ) );
373 mSourceButton->setToolTip( tr( "Model Input" ) );
374 break;
375 }
376
378 {
379 mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "processingAlgorithm.svg" ) ) );
380 mStackedWidget->setCurrentIndex( static_cast< int >( ChildOutput ) );
381 mSourceButton->setToolTip( tr( "Algorithm Output" ) );
382 break;
383 }
384
386 {
387 mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconModelOutput.svg" ) ) );
388 mStackedWidget->setCurrentIndex( static_cast< int >( ModelOutput ) );
389 mSourceButton->setToolTip( tr( "Model Output" ) );
390 break;
391 }
392
394 break;
395 }
396}
397
398void QgsProcessingModelerParameterWidget::updateUi()
399{
400 mStaticWidgetWrapper->setParameterValue( mStaticValue, mContext );
401
402 mExpressionWidget->setExpression( mExpression );
403
404 int currentIndex = mModelInputCombo->findData( mModelInputParameterName );
405 if ( currentIndex == -1 && mModelInputCombo->count() > 0 )
406 currentIndex = 0;
407 mModelInputCombo->setCurrentIndex( currentIndex );
408
409 const QStringList parts = QStringList() << mOutputChildId << mOutputName;
410 currentIndex = mChildOutputCombo->findData( parts );
411 if ( currentIndex == -1 && mChildOutputCombo->count() > 0 )
412 currentIndex = 0;
413 mChildOutputCombo->setCurrentIndex( currentIndex );
414}
415
416void QgsProcessingModelerParameterWidget::populateSources( const QStringList &compatibleParameterTypes, const QStringList &compatibleOutputTypes, const QList<int> &compatibleDataTypes )
417{
418 const QList< QgsProcessingModelChildParameterSource > sources = mModel->availableSourcesForChild( mChildId,
419 compatibleParameterTypes, compatibleOutputTypes, compatibleDataTypes );
420
421 for ( const QgsProcessingModelChildParameterSource &source : sources )
422 {
423 switch ( source.source() )
424 {
426 mModelInputCombo->addItem( mModel->parameterDefinition( source.parameterName() )->description(), source.parameterName() );
427 break;
428
430 {
431 if ( !mModel->childAlgorithms().contains( source.outputChildId() ) )
432 continue;
433
434 const QgsProcessingModelChildAlgorithm &alg = mModel->childAlgorithm( source.outputChildId() );
435 if ( !alg.algorithm() )
436 continue;
437 const QString outputDescription = alg.algorithm()->outputDefinition( source.outputName() )->description();
438 const QString childDescription = alg.description();
439
440 mChildOutputCombo->addItem( tr( "“%1” from algorithm “%2”" ).arg( outputDescription, childDescription ), QStringList() << source.outputChildId() << source.outputName() );
441 break;
442 }
443
448 break;
449 }
450
451 }
452}
453
455{
456 mExpressionWidget->setExpectedOutputFormat( text );
457}
ProcessingModelChildParameterSource
Processing model child parameter sources.
Definition: qgis.h:3136
@ ExpressionText
Parameter value is taken from a text with expressions, evaluated just before the algorithm runs.
@ ModelOutput
Parameter value is linked to an output parameter for the model.
@ ChildOutput
Parameter value is taken from an output generated by a child algorithm.
@ ModelParameter
Parameter value is taken from a parent model parameter.
@ StaticValue
Parameter value is a static value.
@ Expression
Parameter value is taken from an expression, evaluated just before the algorithm runs.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Single scope for storing variables and functions for use within a QgsExpressionContext.
QStringList functionNames() const
Retrieves a list of names of functions contained in the scope.
QStringList variableNames() const
Returns a list of variable names contained within the scope.
static QgsExpressionContextScope * processingModelAlgorithmScope(const QgsProcessingModelAlgorithm *model, const QVariantMap &parameters, QgsProcessingContext &context)
Creates a new scope which contains variables and functions relating to a processing model algorithm,...
static QgsExpressionContextScope * processingAlgorithmScope(const QgsProcessingAlgorithm *algorithm, const QVariantMap &parameters, QgsProcessingContext &context)
Creates a new scope which contains variables and functions relating to a processing algorithm,...
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
The QgsExpressionLineEdit widget includes a line edit for entering expressions together with a button...
QString expression() const
Returns the current expression shown in the widget.
void registerExpressionContextGenerator(const QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
void setExpectedOutputFormat(const QString &expected)
Set the expected format string, which is shown in the expression builder dialog for the widget.
void setExpression(const QString &expression)
Sets the current expression to show in the widget.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
static QgsProcessingGuiRegistry * processingGuiRegistry()
Returns the global processing gui registry, used for registering the GUI behavior of processing algor...
Definition: qgsgui.cpp:144
Abstract base class for processing algorithms.
An interface for objects which can create Processing contexts.
Contains information about the context in which a processing algorithm is executed.
QgsExpressionContext & expressionContext()
Returns the expression context.
@ Modeler
Modeler dialog.
QgsProcessingModelerParameterWidget(QgsProcessingModelAlgorithm *model, const QString &childId, const QgsProcessingParameterDefinition *parameter, QgsProcessingContext &context, QWidget *parent=nullptr)
Constructor for QgsProcessingModelerParameterWidget, for the specified parameter definition within th...
bool isModelOutput() const
Returns true if the widget is set to the model output mode.
QString modelOutputName() const
Returns the model output name, if isModelOutput() is true.
QLabel * createLabel()
Creates a label for use identifying the associated parameter.
virtual void setWidgetValue(const QgsProcessingModelChildParameterSource &value)
Sets the current value for the parameter.
void setSourceType(Qgis::ProcessingModelChildParameterSource type)
Sets the current source type for the parameter.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
virtual QVariant value() const
Returns the current value of the parameter.
void setDialog(QDialog *dialog)
Sets the parent dialog in which the widget is shown.
void setExpressionHelpText(const QString &text)
Set the expected expression format text, which is shown in the expression builder dialog for the widg...
void setWidgetContext(const QgsProcessingParameterWidgetContext &context)
Sets the context in which the modeler parameter widget is shown, e.g., the parent model algorithm and...
void registerProcessingContextGenerator(QgsProcessingContextGenerator *generator)
Registers a Processing context generator class that will be used to retrieve a Processing context for...
void populateSources(const QStringList &compatibleParameterTypes, const QStringList &compatibleOutputTypes, const QList< int > &compatibleDataTypes)
Populates the widget with available sources for the parameter's value, e.g.
void setToModelOutput(const QString &value)
Sets the widget to a model output, for destination parameters only.
const QgsProcessingParameterDefinition * parameterDefinition() const
Returns the parameter definition associated with this wrapper.
Base class for the definition of processing parameters.
QVariantMap metadata() const
Returns the parameter's freeform metadata.
virtual bool isDestination() const
Returns true if this parameter represents a file or layer destination, e.g.
Contains settings which reflect the context in which a Processing parameter widget is shown,...
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c