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