QGIS API Documentation 3.41.0-Master (45a0abf3bec)
Loading...
Searching...
No Matches
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
20#include "moc_qgsprocessingmodelerparameterwidget.cpp"
26#include "qgsgui.h"
27#include "qgsguiutils.h"
29#include "qgsapplication.h"
30#include "qgsfilterlineedit.h"
31#include <QHBoxLayout>
32#include <QToolButton>
33#include <QStackedWidget>
34#include <QMenu>
35#include <QLabel>
36#include <QComboBox>
37
39 const QString &childId,
41 QWidget *parent )
42 : QWidget( parent )
43 , mModel( model )
44 , mChildId( childId )
45 , mParameterDefinition( parameter )
46 , mContext( context )
47{
48 setFocusPolicy( Qt::StrongFocus );
49
50 // icon size is a bit bigger than text, but minimum size of 24 so that we get pixel-aligned rendering on low-dpi screens
51 const int iconSize = QgsGuiUtils::scaleIconSize( 24 );
52
53 QHBoxLayout *hLayout = new QHBoxLayout();
54
55 {
56 const QVariantList acceptedSourcesMetadata = mParameterDefinition->metadata().value( QStringLiteral( "model_widget" ) ).toMap().value( QStringLiteral( "accepted_sources" ) ).toList();
57 for ( const QVariant &acceptedSource : acceptedSourcesMetadata )
58 {
59 mLimitedSources.append( static_cast< Qgis::ProcessingModelChildParameterSource >( acceptedSource.toInt() ) );
60 }
61 }
62
63 mSourceButton = new QToolButton();
64 mSourceButton->setFocusPolicy( Qt::StrongFocus );
65
66 // button width is 1.25 * icon size, height 1.1 * icon size. But we round to ensure even pixel sizes for equal margins
67 mSourceButton->setFixedSize( 2 * static_cast< int >( 1.25 * iconSize / 2.0 ), 2 * static_cast< int >( iconSize * 1.1 / 2.0 ) );
68 mSourceButton->setIconSize( QSize( iconSize, iconSize ) );
69 mSourceButton->setPopupMode( QToolButton::InstantPopup );
70
71 mSourceMenu = new QMenu( this );
72 connect( mSourceMenu, &QMenu::aboutToShow, this, &QgsProcessingModelerParameterWidget::sourceMenuAboutToShow );
73 connect( mSourceMenu, &QMenu::triggered, this, &QgsProcessingModelerParameterWidget::sourceMenuActionTriggered );
74 mSourceButton->setMenu( mSourceMenu );
75
76 hLayout->addWidget( mSourceButton );
77
78 mStackedWidget = new QStackedWidget();
79
80 mStaticWidgetWrapper.reset( QgsGui::processingGuiRegistry()->createParameterWidgetWrapper( mParameterDefinition, QgsProcessingGui::Modeler ) );
81 if ( mStaticWidgetWrapper )
82 {
83 QWidget *widget = mStaticWidgetWrapper->createWrappedWidget( context );
84 if ( widget )
85 {
86 mHasStaticWrapper = true;
87 mStackedWidget->addWidget( widget );
88 }
89 else
90 mStackedWidget->addWidget( new QWidget() );
91 }
92 else
93 {
94 mStackedWidget->addWidget( new QWidget() );
95 }
96
97 mExpressionWidget = new QgsExpressionLineEdit();
98 mExpressionWidget->registerExpressionContextGenerator( this );
99 mStackedWidget->addWidget( mExpressionWidget );
100
101 mModelInputCombo = new QComboBox();
102 QHBoxLayout *hLayout2 = new QHBoxLayout();
103 hLayout2->setContentsMargins( 0, 0, 0, 0 );
104 hLayout2->addWidget( new QLabel( tr( "Using model input" ) ) );
105 hLayout2->addWidget( mModelInputCombo, 1 );
106 QWidget *hWidget2 = new QWidget();
107 hWidget2->setLayout( hLayout2 );
108 mStackedWidget->addWidget( hWidget2 );
109
110 mChildOutputCombo = new QComboBox();
111 QHBoxLayout *hLayout3 = new QHBoxLayout();
112 hLayout3->setContentsMargins( 0, 0, 0, 0 );
113 hLayout3->addWidget( new QLabel( tr( "Using algorithm output" ) ) );
114 hLayout3->addWidget( mChildOutputCombo, 1 );
115 QWidget *hWidget3 = new QWidget();
116 hWidget3->setLayout( hLayout3 );
117 mStackedWidget->addWidget( hWidget3 );
118
119 if ( mParameterDefinition->isDestination() )
120 {
121 mModelOutputName = new QgsFilterLineEdit();
122 mModelOutputName->setPlaceholderText( tr( "[Enter name if this is a final result]" ) );
123 QHBoxLayout *hLayout4 = new QHBoxLayout();
124 hLayout4->setContentsMargins( 0, 0, 0, 0 );
125 hLayout4->addWidget( mModelOutputName );
126 QWidget *hWidget4 = new QWidget();
127 hWidget4->setLayout( hLayout4 );
128 mStackedWidget->addWidget( hWidget4 );
129 }
130
131 hLayout->setContentsMargins( 0, 0, 0, 0 );
132 hLayout->addWidget( mStackedWidget, 1 );
133
134 setLayout( hLayout );
136}
137
139
141{
142 if ( mStaticWidgetWrapper )
143 mStaticWidgetWrapper->setWidgetContext( context );
144}
145
147{
148 if ( mStaticWidgetWrapper )
149 mStaticWidgetWrapper->registerProcessingContextGenerator( generator );
150}
151
156
158{
159 if ( mStaticWidgetWrapper )
160 return mStaticWidgetWrapper->createWrappedLabel();
161 else
162 return nullptr;
163}
164
165void QgsProcessingModelerParameterWidget::setWidgetValue( const QgsProcessingModelChildParameterSource &value )
166{
167 // we make a copy of all attributes and store locally, so that users can flick between
168 // sources without losing their current value
169 mStaticValue = value.staticValue();
170 mModelInputParameterName = value.parameterName();
171 mOutputChildId = value.outputChildId();
172 mOutputName = value.outputName();
173 mExpression = value.expression();
174
175 updateUi();
176 setSourceType( value.source() );
177}
178
179void QgsProcessingModelerParameterWidget::setWidgetValue( const QList<QgsProcessingModelChildParameterSource> &values )
180{
181 if ( values.size() == 1 )
182 setWidgetValue( values.at( 0 ) );
183 else
184 {
185 QVariantList r;
186 for ( const QgsProcessingModelChildParameterSource &v : values )
187 r << QVariant::fromValue( v );
188 mStaticValue = r;
189 updateUi();
191 }
192}
193
195{
196 if ( mModelOutputName )
197 mModelOutputName->setText( value );
199}
200
202{
203 return currentSourceType() == ModelOutput;
204}
205
207{
208 return mModelOutputName ? mModelOutputName->text().trimmed() : QString();
209}
210
212{
213 switch ( currentSourceType() )
214 {
215 case StaticValue:
216 {
217 const QVariant v = mStaticWidgetWrapper->parameterValue();
218
219 if ( v.userType() == QMetaType::Type::QVariantList )
220 {
221 const QVariantList vList = v.toList();
222 if ( std::all_of( vList.begin(), vList.end(), []( const QVariant & val )
223 {
224 return val.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>();
225 } ) )
226 {
227 return v;
228 }
229 }
230 return QVariant::fromValue( QgsProcessingModelChildParameterSource::fromStaticValue( v ) );
231 }
232
233 case Expression:
234 return QVariant::fromValue( QgsProcessingModelChildParameterSource::fromExpression( mExpressionWidget->expression() ) );
235
236 case ModelParameter:
237 return QVariant::fromValue( QgsProcessingModelChildParameterSource::fromModelParameter( mModelInputCombo->currentData().toString() ) );
238
239 case ChildOutput:
240 {
241 const QStringList parts = mChildOutputCombo->currentData().toStringList();
242 return QVariant::fromValue( QgsProcessingModelChildParameterSource::fromChildOutput( parts.value( 0, QString() ), parts.value( 1, QString() ) ) );
243 }
244
245 case ModelOutput:
246 return mModelOutputName ? ( mModelOutputName->text().trimmed().isEmpty() ? QVariant() : mModelOutputName->text() ) : QVariant();
247 }
248
249 return QVariant::fromValue( QgsProcessingModelChildParameterSource() );
250}
251
253{
254 if ( mStaticWidgetWrapper )
255 mStaticWidgetWrapper->setDialog( dialog );
256}
257
259{
261 if ( mModel )
262 {
263 const QgsProcessingAlgorithm *alg = nullptr;
264 if ( mModel->childAlgorithms().contains( mChildId ) )
265 alg = mModel->childAlgorithm( mChildId ).algorithm();
266 QgsExpressionContextScope *algorithmScope = QgsExpressionContextUtils::processingAlgorithmScope( alg, QVariantMap(), mContext );
267 c << algorithmScope;
268 QgsExpressionContextScope *modelScope = QgsExpressionContextUtils::processingModelAlgorithmScope( mModel, QVariantMap(), mContext );
269 c << modelScope;
270 QgsExpressionContextScope *childScope = mModel->createExpressionContextScopeForChildAlgorithm( mChildId, mContext, QVariantMap(), QVariantMap() );
271 c << childScope;
272
273 QStringList highlightedVariables = childScope->variableNames();
274 QStringList highlightedFunctions = childScope->functionNames();
275 highlightedVariables += algorithmScope->variableNames();
276 highlightedVariables += mModel->variables().keys();
277 highlightedFunctions += algorithmScope->functionNames();
278 c.setHighlightedVariables( highlightedVariables );
279 c.setHighlightedFunctions( highlightedFunctions );
280 }
281
282 return c;
283}
284
285void QgsProcessingModelerParameterWidget::sourceMenuAboutToShow()
286{
287 mSourceMenu->clear();
288
289 const SourceType currentSource = currentSourceType();
290
291 if ( mParameterDefinition->isDestination()
292 && ( mLimitedSources.empty() || mLimitedSources.contains( Qgis::ProcessingModelChildParameterSource::ModelOutput ) ) )
293 {
294 QAction *modelOutputAction = mSourceMenu->addAction( tr( "Model Output" ) );
295 modelOutputAction->setCheckable( currentSource == ModelOutput );
296 modelOutputAction->setChecked( currentSource == ModelOutput );
297 modelOutputAction->setData( QVariant::fromValue( Qgis::ProcessingModelChildParameterSource::ModelOutput ) );
298 }
299
300 if ( mHasStaticWrapper
301 && ( mLimitedSources.empty() || mLimitedSources.contains( Qgis::ProcessingModelChildParameterSource::StaticValue ) ) )
302 {
303 QAction *fixedValueAction = mSourceMenu->addAction( tr( "Value" ) );
304 fixedValueAction->setCheckable( currentSource == StaticValue );
305 fixedValueAction->setChecked( currentSource == StaticValue );
306 fixedValueAction->setData( QVariant::fromValue( Qgis::ProcessingModelChildParameterSource::StaticValue ) );
307 }
308
309 if ( mLimitedSources.empty() || mLimitedSources.contains( Qgis::ProcessingModelChildParameterSource::Expression ) )
310 {
311 QAction *calculatedValueAction = mSourceMenu->addAction( tr( "Pre-calculated Value" ) );
312 calculatedValueAction->setCheckable( currentSource == Expression );
313 calculatedValueAction->setChecked( currentSource == Expression );
314 calculatedValueAction->setData( QVariant::fromValue( Qgis::ProcessingModelChildParameterSource::Expression ) );
315 }
316
317 if ( mLimitedSources.empty() || mLimitedSources.contains( Qgis::ProcessingModelChildParameterSource::ModelParameter ) )
318 {
319 QAction *inputValueAction = mSourceMenu->addAction( tr( "Model Input" ) );
320 inputValueAction->setCheckable( currentSource == ModelParameter );
321 inputValueAction->setChecked( currentSource == ModelParameter );
322 inputValueAction->setData( QVariant::fromValue( Qgis::ProcessingModelChildParameterSource::ModelParameter ) );
323 }
324
325 if ( mLimitedSources.empty() || mLimitedSources.contains( Qgis::ProcessingModelChildParameterSource::ChildOutput ) )
326 {
327 QAction *childOutputValueAction = mSourceMenu->addAction( tr( "Algorithm Output" ) );
328 childOutputValueAction->setCheckable( currentSource == ChildOutput );
329 childOutputValueAction->setChecked( currentSource == ChildOutput );
330 childOutputValueAction->setData( QVariant::fromValue( Qgis::ProcessingModelChildParameterSource::ChildOutput ) );
331 }
332
333 // TODO - expression text item?
334}
335
336void QgsProcessingModelerParameterWidget::sourceMenuActionTriggered( QAction *action )
337{
339 setSourceType( sourceType );
340}
341
342QgsProcessingModelerParameterWidget::SourceType QgsProcessingModelerParameterWidget::currentSourceType() const
343{
344 return static_cast< SourceType >( mStackedWidget->currentIndex() );
345}
346
348{
349 if ( !mLimitedSources.empty() && !mLimitedSources.contains( type ) )
350 {
351 // specified type is not acceptable for this parameter, so override with the first acceptable
352 // type
353 type = mLimitedSources.at( 0 );
354 }
355
356 switch ( type )
357 {
359 mStackedWidget->setCurrentIndex( static_cast< int >( StaticValue ) );
360 mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconFieldInteger.svg" ) ) );
361 mSourceButton->setToolTip( tr( "Value" ) );
362 break;
363
365 mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconExpression.svg" ) ) );
366 mStackedWidget->setCurrentIndex( static_cast< int >( Expression ) );
367 mSourceButton->setToolTip( tr( "Pre-calculated Value" ) );
368 break;
369
371 {
372 mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "processingModel.svg" ) ) );
373 mStackedWidget->setCurrentIndex( static_cast< int >( ModelParameter ) );
374 mSourceButton->setToolTip( tr( "Model Input" ) );
375 break;
376 }
377
379 {
380 mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "processingAlgorithm.svg" ) ) );
381 mStackedWidget->setCurrentIndex( static_cast< int >( ChildOutput ) );
382 mSourceButton->setToolTip( tr( "Algorithm Output" ) );
383 break;
384 }
385
387 {
388 mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconModelOutput.svg" ) ) );
389 mStackedWidget->setCurrentIndex( static_cast< int >( ModelOutput ) );
390 mSourceButton->setToolTip( tr( "Model Output" ) );
391 break;
392 }
393
395 break;
396 }
397}
398
399void QgsProcessingModelerParameterWidget::updateUi()
400{
401 mStaticWidgetWrapper->setParameterValue( mStaticValue, mContext );
402
403 mExpressionWidget->setExpression( mExpression );
404
405 int currentIndex = mModelInputCombo->findData( mModelInputParameterName );
406 if ( currentIndex == -1 && mModelInputCombo->count() > 0 )
407 currentIndex = 0;
408 mModelInputCombo->setCurrentIndex( currentIndex );
409
410 const QStringList parts = QStringList() << mOutputChildId << mOutputName;
411 currentIndex = mChildOutputCombo->findData( parts );
412 if ( currentIndex == -1 && mChildOutputCombo->count() > 0 )
413 currentIndex = 0;
414 mChildOutputCombo->setCurrentIndex( currentIndex );
415}
416
417void QgsProcessingModelerParameterWidget::populateSources( const QStringList &compatibleParameterTypes, const QStringList &compatibleOutputTypes, const QList<int> &compatibleDataTypes )
418{
419 const QList< QgsProcessingModelChildParameterSource > sources = mModel->availableSourcesForChild( mChildId,
420 compatibleParameterTypes, compatibleOutputTypes, compatibleDataTypes );
421
422 for ( const QgsProcessingModelChildParameterSource &source : sources )
423 {
424 switch ( source.source() )
425 {
427 mModelInputCombo->addItem( mModel->parameterDefinition( source.parameterName() )->description(), source.parameterName() );
428 break;
429
431 {
432 if ( !mModel->childAlgorithms().contains( source.outputChildId() ) )
433 continue;
434
435 const QgsProcessingModelChildAlgorithm &alg = mModel->childAlgorithm( source.outputChildId() );
436 if ( !alg.algorithm() )
437 continue;
438 const QString outputDescription = alg.algorithm()->outputDefinition( source.outputName() )->description();
439 const QString childDescription = alg.description();
440
441 mChildOutputCombo->addItem( tr( "“%1” from algorithm “%2”" ).arg( outputDescription, childDescription ), QStringList() << source.outputChildId() << source.outputName() );
442 break;
443 }
444
449 break;
450 }
451
452 }
453}
454
456{
457 mExpressionWidget->setExpectedOutputFormat( text );
458}
ProcessingModelChildParameterSource
Processing model child parameter sources.
Definition qgis.h:3569
@ 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:154
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,...
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