QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 
21 #include "qgsexpressionlineedit.h"
23 #include "models/qgsprocessingmodelalgorithm.h"
24 #include "qgsgui.h"
25 #include "qgsguiutils.h"
26 #include "qgsexpressioncontext.h"
27 #include <QHBoxLayout>
28 #include <QToolButton>
29 #include <QStackedWidget>
30 #include <QMenu>
31 #include <QLabel>
32 #include <QComboBox>
33 
35  const QString &childId,
36  const QgsProcessingParameterDefinition *parameter, QgsProcessingContext &context,
37  QWidget *parent )
38  : QWidget( parent )
39  , mModel( model )
40  , mChildId( childId )
41  , mParameterDefinition( parameter )
42  , mContext( context )
43 {
44  setFocusPolicy( Qt::StrongFocus );
45 
46  // icon size is a bit bigger than text, but minimum size of 24 so that we get pixel-aligned rendering on low-dpi screens
47  int iconSize = QgsGuiUtils::scaleIconSize( 24 );
48 
49  QHBoxLayout *hLayout = new QHBoxLayout();
50 
51  mSourceButton = new QToolButton();
52  mSourceButton->setFocusPolicy( Qt::StrongFocus );
53 
54  // button width is 1.25 * icon size, height 1.1 * icon size. But we round to ensure even pixel sizes for equal margins
55  mSourceButton->setFixedSize( 2 * static_cast< int >( 1.25 * iconSize / 2.0 ), 2 * static_cast< int >( iconSize * 1.1 / 2.0 ) );
56  mSourceButton->setIconSize( QSize( iconSize, iconSize ) );
57  mSourceButton->setPopupMode( QToolButton::InstantPopup );
58 
59  mSourceMenu = new QMenu( this );
60  connect( mSourceMenu, &QMenu::aboutToShow, this, &QgsProcessingModelerParameterWidget::sourceMenuAboutToShow );
61  connect( mSourceMenu, &QMenu::triggered, this, &QgsProcessingModelerParameterWidget::sourceMenuActionTriggered );
62  mSourceButton->setMenu( mSourceMenu );
63 
64  hLayout->addWidget( mSourceButton );
65 
66  mStackedWidget = new QStackedWidget();
67 
68  mStaticWidgetWrapper.reset( QgsGui::processingGuiRegistry()->createParameterWidgetWrapper( mParameterDefinition, QgsProcessingGui::Modeler ) );
69  if ( mStaticWidgetWrapper )
70  {
71  QWidget *widget = mStaticWidgetWrapper->createWrappedWidget( context );
72  if ( widget )
73  {
74  mHasStaticWrapper = true;
75  mStackedWidget->addWidget( widget );
76  }
77  else
78  mStackedWidget->addWidget( new QWidget() );
79  }
80  else
81  {
82  mStackedWidget->addWidget( new QWidget() );
83  }
84 
85  mExpressionWidget = new QgsExpressionLineEdit();
86  mExpressionWidget->registerExpressionContextGenerator( this );
87  mStackedWidget->addWidget( mExpressionWidget );
88 
89  mModelInputCombo = new QComboBox();
90  QHBoxLayout *hLayout2 = new QHBoxLayout();
91  hLayout2->setMargin( 0 );
92  hLayout2->setContentsMargins( 0, 0, 0, 0 );
93  hLayout2->addWidget( new QLabel( tr( "Using model input" ) ) );
94  hLayout2->addWidget( mModelInputCombo, 1 );
95  QWidget *hWidget2 = new QWidget();
96  hWidget2->setLayout( hLayout2 );
97  mStackedWidget->addWidget( hWidget2 );
98 
99  mChildOutputCombo = new QComboBox();
100  QHBoxLayout *hLayout3 = new QHBoxLayout();
101  hLayout3->setMargin( 0 );
102  hLayout3->setContentsMargins( 0, 0, 0, 0 );
103  hLayout3->addWidget( new QLabel( tr( "Using algorithm output" ) ) );
104  hLayout3->addWidget( mChildOutputCombo, 1 );
105  QWidget *hWidget3 = new QWidget();
106  hWidget3->setLayout( hLayout3 );
107  mStackedWidget->addWidget( hWidget3 );
108 
109  hLayout->setMargin( 0 );
110  hLayout->setContentsMargins( 0, 0, 0, 0 );
111  hLayout->addWidget( mStackedWidget, 1 );
112 
113  setLayout( hLayout );
114  setSourceType( QgsProcessingModelChildParameterSource::StaticValue );
115 }
116 
118 
120 {
121  if ( mStaticWidgetWrapper )
122  mStaticWidgetWrapper->setWidgetContext( context );
123 }
124 
126 {
127  if ( mStaticWidgetWrapper )
128  mStaticWidgetWrapper->registerProcessingContextGenerator( generator );
129 }
130 
132 {
133  return mParameterDefinition;
134 }
135 
137 {
138  if ( mStaticWidgetWrapper )
139  return mStaticWidgetWrapper->createWrappedLabel();
140  else
141  return nullptr;
142 }
143 
144 void QgsProcessingModelerParameterWidget::setWidgetValue( const QgsProcessingModelChildParameterSource &value )
145 {
146  // we make a copy of all attributes and store locally, so that users can flick between
147  // sources without losing their current value
148  mStaticValue = value.staticValue();
149  mModelInputParameterName = value.parameterName();
150  mOutputChildId = value.outputChildId();
151  mOutputName = value.outputName();
152  mExpression = value.expression();
153 
154  updateUi();
155  setSourceType( value.source() );
156 }
157 
158 QgsProcessingModelChildParameterSource QgsProcessingModelerParameterWidget::value() const
159 {
160  switch ( currentSourceType() )
161  {
162  case StaticValue:
163  return QgsProcessingModelChildParameterSource::fromStaticValue( mStaticWidgetWrapper->parameterValue() );
164 
165  case Expression:
166  return QgsProcessingModelChildParameterSource::fromExpression( mExpressionWidget->expression() );
167 
168  case ModelParameter:
169  return QgsProcessingModelChildParameterSource::fromModelParameter( mModelInputCombo->currentData().toString() );
170 
171  case ChildOutput:
172  {
173  const QStringList parts = mChildOutputCombo->currentData().toStringList();
174  return QgsProcessingModelChildParameterSource::fromChildOutput( parts.value( 0, QString() ), parts.value( 1, QString() ) );
175  }
176  }
177 
178  return QgsProcessingModelChildParameterSource();
179 }
180 
182 {
184  if ( mModel )
185  {
186  const QgsProcessingAlgorithm *alg = nullptr;
187  if ( mModel->childAlgorithms().contains( mChildId ) )
188  alg = mModel->childAlgorithm( mChildId ).algorithm();
189  QgsExpressionContextScope *algorithmScope = QgsExpressionContextUtils::processingAlgorithmScope( alg, QVariantMap(), mContext );
190  c << algorithmScope;
191  QgsExpressionContextScope *childScope = mModel->createExpressionContextScopeForChildAlgorithm( mChildId, mContext, QVariantMap(), QVariantMap() );
192  c << childScope;
193 
194  QStringList highlightedVariables = childScope->variableNames();
195  QStringList highlightedFunctions = childScope->functionNames();
196  highlightedVariables += algorithmScope->variableNames();
197  highlightedFunctions += algorithmScope->functionNames();
198  c.setHighlightedVariables( highlightedVariables );
199  c.setHighlightedFunctions( highlightedFunctions );
200  }
201 
202  return c;
203 }
204 
205 void QgsProcessingModelerParameterWidget::sourceMenuAboutToShow()
206 {
207  mSourceMenu->clear();
208 
209  const SourceType currentSource = currentSourceType();
210 
211  if ( mHasStaticWrapper )
212  {
213  QAction *fixedValueAction = mSourceMenu->addAction( tr( "Value" ) );
214  fixedValueAction->setCheckable( currentSource == StaticValue );
215  fixedValueAction->setChecked( currentSource == StaticValue );
216  fixedValueAction->setData( QgsProcessingModelChildParameterSource::StaticValue );
217  }
218 
219  QAction *calculatedValueAction = mSourceMenu->addAction( tr( "Pre-calculated Value" ) );
220  calculatedValueAction->setCheckable( currentSource == Expression );
221  calculatedValueAction->setChecked( currentSource == Expression );
222  calculatedValueAction->setData( QgsProcessingModelChildParameterSource::Expression );
223 
224  QAction *inputValueAction = mSourceMenu->addAction( tr( "Model Input" ) );
225  inputValueAction->setCheckable( currentSource == ModelParameter );
226  inputValueAction->setChecked( currentSource == ModelParameter );
227  inputValueAction->setData( QgsProcessingModelChildParameterSource::ModelParameter );
228 
229  QAction *childOutputValueAction = mSourceMenu->addAction( tr( "Algorithm Output" ) );
230  childOutputValueAction->setCheckable( currentSource == ChildOutput );
231  childOutputValueAction->setChecked( currentSource == ChildOutput );
232  childOutputValueAction->setData( QgsProcessingModelChildParameterSource::ChildOutput );
233 
234  // TODO - expression text item?
235 }
236 
237 void QgsProcessingModelerParameterWidget::sourceMenuActionTriggered( QAction *action )
238 {
239  QgsProcessingModelChildParameterSource::Source sourceType = static_cast< QgsProcessingModelChildParameterSource::Source >( action->data().toInt() );
240  setSourceType( sourceType );
241 }
242 
243 QgsProcessingModelerParameterWidget::SourceType QgsProcessingModelerParameterWidget::currentSourceType() const
244 {
245  return static_cast< SourceType >( mStackedWidget->currentIndex() );
246 }
247 
248 void QgsProcessingModelerParameterWidget::setSourceType( QgsProcessingModelChildParameterSource::Source type )
249 {
250  switch ( type )
251  {
252  case QgsProcessingModelChildParameterSource::StaticValue:
253  mStackedWidget->setCurrentIndex( static_cast< int >( StaticValue ) );
254  mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconFieldInteger.svg" ) ) );
255  mSourceButton->setToolTip( tr( "Value" ) );
256  break;
257 
258  case QgsProcessingModelChildParameterSource::Expression:
259  mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconExpression.svg" ) ) );
260  mStackedWidget->setCurrentIndex( static_cast< int >( Expression ) );
261  mSourceButton->setToolTip( tr( "Pre-calculated Value" ) );
262  break;
263 
264  case QgsProcessingModelChildParameterSource::ModelParameter:
265  {
266  mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "processingModel.svg" ) ) );
267  mStackedWidget->setCurrentIndex( static_cast< int >( ModelParameter ) );
268  mSourceButton->setToolTip( tr( "Model Input" ) );
269  break;
270  }
271 
272  case QgsProcessingModelChildParameterSource::ChildOutput:
273  {
274  mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "processingAlgorithm.svg" ) ) );
275  mStackedWidget->setCurrentIndex( static_cast< int >( ChildOutput ) );
276  mSourceButton->setToolTip( tr( "Algorithm Output" ) );
277  break;
278  }
279 
280  case QgsProcessingModelChildParameterSource::ExpressionText:
281  break;
282  }
283 }
284 
285 void QgsProcessingModelerParameterWidget::updateUi()
286 {
287  mStaticWidgetWrapper->setParameterValue( mStaticValue, mContext );
288 
289  mExpressionWidget->setExpression( mExpression );
290 
291  int currentIndex = mModelInputCombo->findData( mModelInputParameterName );
292  if ( currentIndex == -1 && mModelInputCombo->count() > 0 )
293  currentIndex = 0;
294  mModelInputCombo->setCurrentIndex( currentIndex );
295 
296  const QStringList parts = QStringList() << mOutputChildId << mOutputName;
297  currentIndex = mChildOutputCombo->findData( parts );
298  if ( currentIndex == -1 && mChildOutputCombo->count() > 0 )
299  currentIndex = 0;
300  mChildOutputCombo->setCurrentIndex( currentIndex );
301 }
302 
303 void QgsProcessingModelerParameterWidget::populateSources( const QStringList &compatibleParameterTypes, const QStringList &compatibleOutputTypes, const QList<int> &compatibleDataTypes )
304 {
305  const QList< QgsProcessingModelChildParameterSource > sources = mModel->availableSourcesForChild( mChildId,
306  compatibleParameterTypes, compatibleOutputTypes, compatibleDataTypes );
307 
308  for ( const QgsProcessingModelChildParameterSource &source : sources )
309  {
310  switch ( source.source() )
311  {
312  case QgsProcessingModelChildParameterSource::ModelParameter:
313  mModelInputCombo->addItem( mModel->parameterDefinition( source.parameterName() )->description(), source.parameterName() );
314  break;
315 
316  case QgsProcessingModelChildParameterSource::ChildOutput:
317  {
318  if ( !mModel->childAlgorithms().contains( source.outputChildId() ) )
319  continue;
320 
321  const QgsProcessingModelChildAlgorithm &alg = mModel->childAlgorithm( source.outputChildId() );
322  if ( !alg.algorithm() )
323  continue;
324  const QString outputDescription = alg.algorithm()->outputDefinition( source.outputName() )->description();
325  const QString childDescription = alg.description();
326 
327  mChildOutputCombo->addItem( tr( "“%1” from algorithm “%2”" ).arg( outputDescription, childDescription ), QStringList() << source.outputChildId() << source.outputName() );
328  break;
329  }
330 
331  case QgsProcessingModelChildParameterSource::StaticValue:
332  case QgsProcessingModelChildParameterSource::Expression:
333  case QgsProcessingModelChildParameterSource::ExpressionText:
334  break;
335  }
336 
337  }
338 }
339 
341 {
342  mExpressionWidget->setExpectedOutputFormat( text );
343 }
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...
static QgsProcessingGuiRegistry * processingGuiRegistry()
Returns the global processing gui registry, used for registering the GUI behavior of processing algor...
Definition: qgsgui.cpp:88
virtual QgsProcessingModelChildParameterSource value() const
Returns the current value of the parameter.
virtual void setWidgetValue(const QgsProcessingModelChildParameterSource &value)
Sets the current value for the parameter.
void setWidgetContext(const QgsProcessingParameterWidgetContext &context)
Sets the context in which the modeler parameter widget is shown, e.g., the parent model algorithm and...
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly...
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Abstract base class for processing algorithms.
QLabel * createLabel()
Creates a label for use identifying the associated parameter.
void setHighlightedFunctions(const QStringList &names)
Sets the list of function names intended to be highlighted to the user.
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
QString expression() const
Returns the current expression shown in the widget.
void setExpression(const QString &expression)
Sets the current expression to show in the widget.
An interface for objects which can create Processing contexts.
void populateSources(const QStringList &compatibleParameterTypes, const QStringList &compatibleOutputTypes, const QList< int > &compatibleDataTypes)
Populates the widget with available sources for the parameter&#39;s value, e.g.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Single scope for storing variables and functions for use within a QgsExpressionContext.
QgsExpressionContext & expressionContext()
Returns the expression context.
Contains settings which reflect the context in which a Processing parameter widget is shown...
The QgsExpressionLineEdit widget includes a line edit for entering expressions together with a button...
void registerExpressionContextGenerator(const QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
QgsProcessingModelerParameterWidget(QgsProcessingModelAlgorithm *model, const QString &childId, const QgsProcessingParameterDefinition *parameter, QgsProcessingContext &context, QWidget *parent=nullptr)
Constructor for QgsProcessingModelerParameterWidget, for the specified parameter definition within th...
Base class for the definition of processing parameters.
void setExpectedOutputFormat(const QString &expected)
Set the expected format string, which is shown in the expression builder dialog for the widget...
void setHighlightedVariables(const QStringList &variableNames)
Sets the list of variable names within the context intended to be highlighted to the user...
const QgsProcessingParameterDefinition * parameterDefinition() const
Returns the parameter definition associated with this wrapper.
void setExpressionHelpText(const QString &text)
Set the expected expression format text, which is shown in the expression builder dialog for the widg...
Contains information about the context in which a processing algorithm is executed.
void registerProcessingContextGenerator(QgsProcessingContextGenerator *generator)
Registers a Processing context generator class that will be used to retrieve a Processing context for...
QStringList variableNames() const
Returns a list of variable names contained within the scope.