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