QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsprocessingwidgetwrapper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsprocessingwidgetwrapper.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 
23 #include "qgsexpressioncontext.h"
24 #include "models/qgsprocessingmodelalgorithm.h"
26 
27 #include <QLabel>
28 #include <QHBoxLayout>
29 
30 //
31 // QgsProcessingParameterWidgetContext
32 //
33 
35 {
36  mMapCanvas = canvas;
37 }
38 
40 {
41  return mMapCanvas;
42 }
43 
45 {
46  mProject = project;
47 }
48 
50 {
51  return mProject;
52 }
53 
55 {
56  return mModelChildAlgorithmId;
57 }
58 
60 {
61  mModelChildAlgorithmId = modelChildAlgorithmId;
62 }
63 
64 QgsProcessingModelAlgorithm *QgsProcessingParameterWidgetContext::model() const
65 {
66  return mModel;
67 }
68 
69 void QgsProcessingParameterWidgetContext::setModel( QgsProcessingModelAlgorithm *model )
70 {
71  mModel = model;
72 }
73 
74 
75 //
76 // QgsAbstractProcessingParameterWidgetWrapper
77 //
78 
80  : QObject( parent )
81  , mType( type )
82  , mParameterDefinition( parameter )
83 {
84 }
85 
87 {
88  return mType;
89 }
90 
92 {
93  mWidgetContext = context;
94 }
95 
97 {
98  return mWidgetContext;
99 }
100 
102 {
103  if ( mWidget )
104  return mWidget;
105 
106  mWidget = createWidget();
107  QWidget *wrappedWidget = mWidget;
108  if ( mType != QgsProcessingGui::Batch && mParameterDefinition->isDynamic() )
109  {
110  QHBoxLayout *hLayout = new QHBoxLayout();
111  hLayout->setMargin( 0 );
112  hLayout->setContentsMargins( 0, 0, 0, 0 );
113  hLayout->addWidget( mWidget, 1 );
114  mPropertyButton = new QgsPropertyOverrideButton();
115  hLayout->addWidget( mPropertyButton );
116  mPropertyButton->init( 0, QgsProperty(), mParameterDefinition->dynamicPropertyDefinition() );
117  mPropertyButton->registerEnabledWidget( mWidget, false );
118  mPropertyButton->registerExpressionContextGenerator( this );
119 
120  wrappedWidget = new QWidget();
121  wrappedWidget->setLayout( hLayout );
122  }
123 
124  setWidgetValue( mParameterDefinition->defaultValue(), context );
125 
126  return wrappedWidget;
127 }
128 
130 {
131  if ( mLabel )
132  return mLabel;
133 
134  mLabel = createLabel();
135  return mLabel;
136 }
137 
139 {
140  return mWidget;
141 }
142 
144 {
145  return mLabel;
146 }
147 
149 {
150  return mParameterDefinition;
151 }
152 
154 {
155  if ( mPropertyButton && value.canConvert< QgsProperty >() )
156  {
157  mPropertyButton->setToProperty( value.value< QgsProperty >() );
158  }
159  else
160  {
161  if ( mPropertyButton )
162  mPropertyButton->setToProperty( QgsProperty() );
163 
164  setWidgetValue( value, context );
165  }
166 }
167 
169 {
170  if ( mPropertyButton && mPropertyButton->isActive() )
171  return mPropertyButton->toProperty();
172  else
173  return widgetValue();
174 }
175 
177 {
178  mProcessingContextGenerator = generator;
179 }
180 
182 {
183  switch ( mType )
184  {
186  return nullptr;
187 
190  {
191  QString description = mParameterDefinition->description();
193  description = QObject::tr( "%1 [optional]" ).arg( description );
194  std::unique_ptr< QLabel > label = qgis::make_unique< QLabel >( description );
195  label->setToolTip( mParameterDefinition->toolTip() );
196  return label.release();
197  }
198  }
199  return nullptr;
200 }
201 
203 {
204  if ( mPropertyButton )
205  return mPropertyButton->vectorLayer();
206  return nullptr;
207 }
208 
209 void QgsAbstractProcessingParameterWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
210 {
211  switch ( mType )
212  {
215  {
216  if ( parameterDefinition()->isDynamic() )
217  {
218  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
219  {
220  if ( wrapper->parameterDefinition()->name() == parameterDefinition()->dynamicLayerParameterName() )
221  {
222  setDynamicParentLayerParameter( wrapper );
223  connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, &QgsAbstractProcessingParameterWidgetWrapper::parentLayerChanged );
224  break;
225  }
226  }
227  }
228  break;
229  }
230 
232  break;
233  }
234 }
235 
237 {
238  QgsExpressionContext context = QgsProcessingGuiUtils::createExpressionContext( mProcessingContextGenerator, mWidgetContext, mParameterDefinition ? mParameterDefinition->algorithm() : nullptr, linkedVectorLayer() );
239  if ( mParameterDefinition && !mParameterDefinition->additionalExpressionContextVariables().isEmpty() )
240  {
241  std::unique_ptr< QgsExpressionContextScope > paramScope = qgis::make_unique< QgsExpressionContextScope >();
242  const QStringList additional = mParameterDefinition->additionalExpressionContextVariables();
243  for ( const QString &var : additional )
244  {
245  paramScope->setVariable( var, QVariant() );
246  }
247  context.appendScope( paramScope.release() );
248 
249  // we always highlight additional variables for visibility
250  QStringList highlighted = context.highlightedVariables();
251  highlighted.append( additional );
252  context.setHighlightedVariables( highlighted );
253  }
254  return context;
255 }
256 
258 {
259 
260 }
261 
262 void QgsAbstractProcessingParameterWidgetWrapper::parentLayerChanged( QgsAbstractProcessingParameterWidgetWrapper *wrapper )
263 {
264  if ( wrapper )
265  {
266  setDynamicParentLayerParameter( wrapper );
267  }
268 }
269 
270 void QgsAbstractProcessingParameterWidgetWrapper::setDynamicParentLayerParameter( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
271 {
272  if ( mPropertyButton )
273  {
274  // evaluate value to layer
275  QgsProcessingContext *context = nullptr;
276  std::unique_ptr< QgsProcessingContext > tmpContext;
279 
280  if ( !context )
281  {
282  tmpContext = qgis::make_unique< QgsProcessingContext >();
283  context = tmpContext.get();
284  }
285 
286  QgsVectorLayer *layer = QgsProcessingParameters::parameterAsVectorLayer( parentWrapper->parameterDefinition(), parentWrapper->parameterValue(), *context );
287  if ( !layer )
288  {
289  mPropertyButton->setVectorLayer( nullptr );
290  return;
291  }
292 
293  // need to grab ownership of layer if required - otherwise layer may be deleted when context
294  // goes out of scope
295  std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
296  if ( ownedLayer && ownedLayer->type() == QgsMapLayerType::VectorLayer )
297  {
298  mDynamicLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
299  layer = mDynamicLayer.get();
300  }
301  else
302  {
303  // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
304  }
305 
306  mPropertyButton->setVectorLayer( layer );
307  }
308 }
309 
311 {
312  std::unique_ptr< QgsProcessingModelerParameterWidget > widget = qgis::make_unique< QgsProcessingModelerParameterWidget >( model, childId, parameter, context );
313  widget->populateSources( compatibleParameterTypes(), compatibleOutputTypes(), compatibleDataTypes() );
314  widget->setExpressionHelpText( modelerExpressionFormatString() );
315  return widget.release();
316 }
317 
319 {
320  return QString();
321 }
322 
323 //
324 // QgsProcessingGuiUtils
325 //
326 
328 QgsExpressionContext QgsProcessingGuiUtils::createExpressionContext( QgsProcessingContextGenerator *processingContextGenerator, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingAlgorithm *algorithm, const QgsVectorLayer *linkedLayer )
329 {
330  // Get a processing context to start with
331  QgsProcessingContext *context = nullptr;
332  std::unique_ptr< QgsProcessingContext > tmpContext;
333  if ( processingContextGenerator )
334  context = processingContextGenerator->processingContext();
335 
336  if ( !context )
337  {
338  tmpContext = qgis::make_unique< QgsProcessingContext >();
339  context = tmpContext.get();
340  }
341 
343 
344  if ( widgetContext.model() )
345  {
346  c << QgsExpressionContextUtils::processingModelAlgorithmScope( widgetContext.model(), QVariantMap(), *context );
347 
348  const QgsProcessingAlgorithm *alg = nullptr;
349  if ( widgetContext.model()->childAlgorithms().contains( widgetContext.modelChildAlgorithmId() ) )
350  alg = widgetContext.model()->childAlgorithm( widgetContext.modelChildAlgorithmId() ).algorithm();
351 
352  QgsExpressionContextScope *algorithmScope = QgsExpressionContextUtils::processingAlgorithmScope( alg ? alg : algorithm, QVariantMap(), *context );
353  c << algorithmScope;
354  QgsExpressionContextScope *childScope = widgetContext.model()->createExpressionContextScopeForChildAlgorithm( widgetContext.modelChildAlgorithmId(), *context, QVariantMap(), QVariantMap() );
355  c << childScope;
356 
357  QStringList highlightedVariables = childScope->variableNames();
358  QStringList highlightedFunctions = childScope->functionNames();
359  highlightedVariables += algorithmScope->variableNames();
360  highlightedVariables += widgetContext.model()->variables().keys();
361  highlightedFunctions += algorithmScope->functionNames();
362  c.setHighlightedVariables( highlightedVariables );
363  c.setHighlightedFunctions( highlightedFunctions );
364  }
365  else
366  {
367  if ( algorithm )
368  c << QgsExpressionContextUtils::processingAlgorithmScope( algorithm, QVariantMap(), *context );
369  }
370 
371  if ( linkedLayer )
372  c << QgsExpressionContextUtils::layerScope( linkedLayer );
373 
374  return c;
375 }
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...
QgsPropertyDefinition dynamicPropertyDefinition() const
Returns the property definition for dynamic properties.
QgsAbstractProcessingParameterWidgetWrapper(const QgsProcessingParameterDefinition *parameter=nullptr, QgsProcessingGui::WidgetType type=QgsProcessingGui::Standard, QObject *parent=nullptr)
Constructor for QgsAbstractProcessingParameterWidgetWrapper, for the specified parameter definition a...
A widget wrapper for Processing parameter value widgets.
virtual void setWidgetContext(const QgsProcessingParameterWidgetContext &context)
Sets the context in which the Processing parameter widget is shown, e.g., the parent model algorithm...
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
void setParameterValue(const QVariant &value, QgsProcessingContext &context)
Sets the current value for the parameter.
void setModel(QgsProcessingModelAlgorithm *model)
Sets the model which the parameter widget is associated with.
WidgetType
Types of dialogs which Processing widgets can be created for.
QStringList variableNames() const
Returns a list of variable names contained within the scope.
QgsMapLayer * takeResultLayer(const QString &id)
Takes the result map layer with matching id from the context and transfers ownership of it back to th...
A widget for customising the value of Processing algorithm parameter inside a Processing model...
virtual QLabel * createLabel()
Creates a new label to accompany widgets created by the wrapper.
QWidget * createWrappedWidget(QgsProcessingContext &context)
Creates and return a new wrapped widget which allows customization of the parameter&#39;s value...
static QgsVectorLayer * parameterAsVectorLayer(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a vector layer.
Abstract base class for processing algorithms.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:73
QgsProcessingContextGenerator * mProcessingContextGenerator
virtual void setDialog(QDialog *dialog)
Sets the parent dialog in which the wrapper is shown.
void setHighlightedFunctions(const QStringList &names)
Sets the list of function names intended to be highlighted to the user.
QString modelChildAlgorithmId() const
Returns the child algorithm ID within the model which the parameter widget is associated with...
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
virtual const QgsVectorLayer * linkedVectorLayer() const
Returns the optional vector layer associated with this widget wrapper, or nullptr if no vector layer ...
virtual QString toolTip() const
Returns a formatted tooltip for use with the parameter, which gives helpful information like paramete...
A button for controlling property overrides which may apply to a widget.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
QVariant parameterValue() const
Returns the current value of the parameter.
QVariant defaultValue() const
Returns the default value for the parameter.
void widgetValueHasChanged(QgsAbstractProcessingParameterWidgetWrapper *wrapper)
Emitted whenever the parameter value (as defined by the wrapped widget) is changed.
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...
virtual void postInitialize(const QList< QgsAbstractProcessingParameterWidgetWrapper * > &wrappers)
Called after all wrappers have been created within a particular dialog or context, allowing the wrapper to connect to the wrappers of other, related parameters.
virtual void setWidgetValue(const QVariant &value, QgsProcessingContext &context)=0
Sets the current value for the parameter to show in the widget.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
QgsProcessingAlgorithm * algorithm() const
Returns a pointer to the algorithm which owns this parameter.
virtual QString modelerExpressionFormatString() const
Returns the expected expression format string for expression results for the parameter within model c...
const QgsProcessingParameterDefinition * parameterDefinition() const
Returns the parameter definition associated with this wrapper.
Reads and writes project states.
Definition: qgsproject.h:89
void registerProcessingContextGenerator(QgsProcessingContextGenerator *generator)
Registers a Processing context generator class that will be used to retrieve a Processing context for...
QgsProject * project() const
Returns the project associated with the widget.
Single scope for storing variables and functions for use within a QgsExpressionContext.
A store for object properties.
Definition: qgsproperty.h:229
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 allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
QgsProcessingParameterWidgetContext mWidgetContext
QString dynamicLayerParameterName() const
Returns the name of the parameter for a layer linked to a dynamic parameter, or an empty string if th...
QgsExpressionContext & expressionContext()
Returns the expression context.
QStringList highlightedVariables() const
Returns the current list of variables highlighted within the context.
QLabel * wrappedLabel()
Returns the current wrapped label, if any.
virtual QVariant widgetValue() const =0
Returns the current value of the parameter.
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...
QgsProcessingModelAlgorithm * model() const
Returns the model which the parameter widget is associated with.
bool isDynamic() const
Returns true if the parameter supports is dynamic, and can support data-defined values (i...
QgsProcessingGui::WidgetType type() const
Returns the dialog type for which widgets and labels will be created by this wrapper.
virtual QgsProcessingContext * processingContext()=0
This method needs to be reimplemented in all classes which implement this interface and return a Proc...
Contains settings which reflect the context in which a Processing parameter widget is shown...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Base class for the definition of processing parameters.
QStringList additionalExpressionContextVariables() const
Returns a list of additional expression context variables which are available for use when evaluating...
virtual QgsProcessingModelerParameterWidget * createModelerWidgetWrapper(QgsProcessingModelAlgorithm *model, const QString &childId, const QgsProcessingParameterDefinition *parameter, QgsProcessingContext &context)
Creates a new modeler parameter widget for the given parameter.
const QgsProcessingParameterWidgetContext & widgetContext() const
Returns the context in which the Processing parameter widget is shown, e.g., the parent model algorit...
virtual QWidget * createWidget()=0
Creates a new widget which allows customization of the parameter&#39;s value.
void setHighlightedVariables(const QStringList &variableNames)
Sets the list of variable names within the context intended to be highlighted to the user...
QLabel * createWrappedLabel()
Creates and returns a new label to accompany widgets created by the wrapper.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
void setProject(QgsProject *project)
Sets the project associated with the widget.
Represents a vector layer which manages a vector based data sets.
QWidget * wrappedWidget()
Returns the current wrapped widget, if any.
Contains information about the context in which a processing algorithm is executed.
void setModelChildAlgorithmId(const QString &id)
Sets the child algorithm id within the model which the parameter widget is associated with...
QString description() const
Returns the description for the parameter.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Standard algorithm dialog.
Batch processing dialog.