QGIS API Documentation 4.3.0-Master (52aa6503bed)
Loading...
Searching...
No Matches
qgsprocessingparameterswidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingparameterswidget.cpp
3 ------------------------------------
4 Date : March 2020
5 Copyright : (C) 2020 Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgsgui.h"
23
24#include <QLabel>
25#include <QString>
26
27#include "moc_qgsprocessingparameterswidget.cpp"
28
29using namespace Qt::StringLiterals;
30
32
33QgsProcessingParametersWidget::QgsProcessingParametersWidget( const QgsProcessingAlgorithm *algorithm, bool inPlace, QgsMapLayer *activeLayer, QgsMessageBar *messageBar, QWidget *parent )
34 : QgsPanelWidget( parent )
35 , mAlgorithm( algorithm )
36 , mInPlace( inPlace )
37 , mActiveLayer( activeLayer )
38 , mMessageBar( messageBar )
39{
40 Q_ASSERT( mAlgorithm );
41
42 setupUi( this );
43
44 grpAdvanced->hide();
45 grpOutputs->hide();
46
47 scrollAreaWidgetContents->setContentsMargins( 4, 4, 4, 4 );
48}
49
50QgsProcessingParametersWidget::~QgsProcessingParametersWidget()
51{
52 qDeleteAll( mWrappers );
53}
54
55const QgsProcessingAlgorithm *QgsProcessingParametersWidget::algorithm() const
56{
57 return mAlgorithm;
58}
59
60QgsProcessingContext *QgsProcessingParametersWidget::processingContext() const
61{
62 return mContextGenerator ? mContextGenerator->processingContext() : nullptr;
63}
64
65QVariantMap QgsProcessingParametersWidget::createProcessingParameters( Flags flags )
66{
67 QList< QgsProcessingParametersGenerator::ParameterValidationResult > validationResults;
68 return createAndValidateParameters( flags, validationResults );
69}
70
71void QgsProcessingParametersWidget::registerProcessingContextGenerator( QgsProcessingContextGenerator *generator )
72{
73 mContextGenerator = generator;
74}
75
76QList<QgsProcessingParametersGenerator::ParameterValidationResult> QgsProcessingParametersWidget::validate() const
77{
78 QList< QgsProcessingParametersGenerator::ParameterValidationResult > validationResults;
79 createAndValidateParameters( QgsProcessingParametersGenerator::Flags(), validationResults );
80 return validationResults;
81}
82
83QVariantMap QgsProcessingParametersWidget::createAndValidateParameters(
84 QgsProcessingParametersGenerator::Flags flags, QList< QgsProcessingParametersGenerator::ParameterValidationResult > &validationResults
85) const
86{
87 QgsProcessingContext *context = processingContext();
88
89 const bool includeDefault = !flags.testFlag( Flag::SkipDefaultValueParameters );
90 const bool validate = !flags.testFlag( Flag::SkipValidation );
91
92 QVariantMap parameters = mExtraParameters;
93 const QgsProcessingParameterDefinitions defs = mAlgorithm->parameterDefinitions();
94 for ( const QgsProcessingParameterDefinition *definition : defs )
95 {
96 if ( definition->flags().testFlag( Qgis::ProcessingParameterFlag::Hidden ) )
97 {
98 continue;
99 }
100
101 if ( !definition->isDestination() )
102 {
103 QgsAbstractProcessingParameterWidgetWrapper *wrapper = mWrappers.value( definition->name() );
104 if ( !wrapper )
105 continue;
106
107 QWidget *widget = wrapper->wrappedWidget();
108
109 if ( !dynamic_cast< QgsProcessingHiddenWidgetWrapper *>( wrapper ) && !widget )
110 {
111 continue;
112 }
113
114 const QVariant value = wrapper->parameterValue();
115 if ( definition->defaultValue() != value || includeDefault )
116 {
117 parameters[definition->name()] = value;
118 }
119
120 if ( validate && !definition->checkValueIsAcceptable( value ) )
121 {
123 result.parameterName = definition->name();
125 validationResults.append( result );
126 }
127 }
128 else
129 {
130 if ( mInPlace && definition->name() == "OUTPUT"_L1 )
131 {
132 parameters[definition->name()] = u"memory:"_s;
133 continue;
134 }
135
136 QgsAbstractProcessingParameterWidgetWrapper *wrapper = mWrappers.value( definition->name() );
137 if ( !wrapper )
138 continue;
139
140 QVariant value = wrapper->parameterValue();
141
142 QgsProject *destinationProject = nullptr;
143 if ( wrapper->customProperties().value( u"OPEN_AFTER_RUNNING"_s ).toBool() )
144 {
145 destinationProject = QgsProject::instance();
146 }
147
148 if ( value.userType() == qMetaTypeId<QgsProcessingOutputLayerDefinition>() )
149 {
151 outputDefinition.destinationProject = destinationProject;
152 value = QVariant::fromValue( outputDefinition );
153 }
154
155 if ( !QgsVariantUtils::isNull( value ) && ( definition->defaultValue() != value || includeDefault ) )
156 {
157 parameters[definition->name()] = value;
158 if ( validate )
159 {
160 auto destinationParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition );
161 if ( destinationParam )
162 {
163 QString error;
164 const bool ok = destinationParam->isSupportedOutputValue( value, *context, error );
165 if ( !ok )
166 {
168 result.parameterName = definition->name();
170 result.message = error;
171 validationResults.append( result );
172 }
173 }
174 }
175 }
176 }
177 }
178
179 return const_cast< QgsProcessingAlgorithm * >( mAlgorithm )->preprocessParameters( parameters );
180}
181
182void QgsProcessingParametersWidget::setParameters( const QVariantMap &parameters )
183{
184 QgsProcessingContext *context = processingContext();
185
186 mExtraParameters.clear();
187 const QgsProcessingParameterDefinitions defs = mAlgorithm->parameterDefinitions();
188 for ( const QgsProcessingParameterDefinition *definition : std::as_const( defs ) )
189 {
190 auto paramIt = parameters.constFind( definition->name() );
191 if ( definition->flags().testFlag( Qgis::ProcessingParameterFlag::Hidden ) )
192 {
193 if ( paramIt != parameters.constEnd() )
194 {
195 mExtraParameters.insert( definition->name(), paramIt.value() );
196 }
197 continue;
198 }
199
200 if ( paramIt == parameters.constEnd() )
201 {
202 continue;
203 }
204
205 const QVariant value = paramIt.value();
206
207 auto wrapperIt = mWrappers.constFind( definition->name() );
208 if ( wrapperIt != mWrappers.constEnd() )
209 {
210 wrapperIt.value()->setParameterValue( value, *context );
211 }
212 }
213}
214
215QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingParametersWidget::wrapper( const QString &name ) const
216{
217 return mWrappers.value( name );
218}
219
220QList<QgsAbstractProcessingParameterWidgetWrapper *> QgsProcessingParametersWidget::wrappers() const
221{
222 return mWrappers.values();
223}
224
225void QgsProcessingParametersWidget::parameterChanged()
226{
227 auto wrapper = qobject_cast< QgsAbstractProcessingParameterWidgetWrapper * >( sender() );
228 if ( !wrapper )
229 return;
230
231 const QVariantMap defaultValues
232 = mAlgorithm->autogenerateParameterValues( createProcessingParameters( QgsProcessingParametersGenerator::Flag::SkipValidation ), wrapper->parameterDefinition()->name(), Qgis::ProcessingMode::Standard );
233
234 if ( !defaultValues.empty() )
235 {
236 setParameters( defaultValues );
237 }
238}
239
240void QgsProcessingParametersWidget::initWidgets()
241{
242 QgsProcessingContext *context = processingContext();
243
244 // if there are advanced parameters - show corresponding groupbox
245 const QgsProcessingParameterDefinitions defs = mAlgorithm->parameterDefinitions();
246 for ( const QgsProcessingParameterDefinition *param : defs )
247 {
248 if ( param->flags() & Qgis::ProcessingParameterFlag::Advanced )
249 {
250 grpAdvanced->show();
251 break;
252 }
253 }
254
255 if ( !algorithm() )
256 {
257 return;
258 }
259
261 widgetContext.setMessageBar( mMessageBar );
262
263 if ( auto modelAlgorithm = dynamic_cast< const QgsProcessingModelAlgorithm * >( mAlgorithm ) )
264 {
265 widgetContext.setModel( const_cast< QgsProcessingModelAlgorithm * >( modelAlgorithm ) );
266 }
267
268 QString inPlaceInputParameterName = u"INPUT"_s;
269 if ( auto featureAlgorithm = dynamic_cast< const QgsProcessingFeatureBasedAlgorithm * >( mAlgorithm ) )
270 {
271 inPlaceInputParameterName = featureAlgorithm->inputParameterName();
272 }
273
274 bool hasNonInputParams = false;
275 for ( const QgsProcessingParameterDefinition *definition : std::as_const( defs ) )
276 {
277 if ( definition->name() != inPlaceInputParameterName && definition->name() != "OUTPUT"_L1 )
278 {
279 hasNonInputParams = true;
280 break;
281 }
282 }
283 // If there are no parameters to show because it's in-place, we add the info label.
284 // Still, it needs the following steps to create the parameter widgets (even when hidden).
285 if ( mInPlace && !hasNonInputParams )
286 {
287 auto widget = new QWidget( this );
288 auto layout = new QVBoxLayout( widget );
289 auto label = new QLabel( widget );
290 label->setWordWrap( true );
291
292 const QString layerName = mActiveLayer ? mActiveLayer->name() : QString();
293 const QString infoText = tr( "<i>No additional parameters are required. This algorithm will activate edit mode and modify the features on layer <b>%1</b> in place.</i>" ).arg( layerName );
294 label->setText( infoText );
295
296 layout->addWidget( label );
297 layout->addStretch();
298 addExtraWidget( widget );
299 }
300
301 // Create widgets and put them in layouts
302 for ( const QgsProcessingParameterDefinition *definition : defs )
303 {
304 if ( definition->flags().testFlag( Qgis::ProcessingParameterFlag::Hidden ) )
305 {
306 continue;
307 }
308
309 if ( definition->isDestination() )
310 {
311 continue;
312 }
313
314 if ( mInPlace && ( definition->name() == inPlaceInputParameterName || definition->name() == "OUTPUT"_L1 ) )
315 {
316 // don't show the input/output parameter widgets in in-place mode
317 // we still need to CREATE them, because other wrappers may need to interact
318 // with them (e.g. those parameters which need the input layer for field
319 // selections/crs properties/etc)
320 auto wrapper = new QgsProcessingHiddenWidgetWrapper( definition, Qgis::ProcessingMode::Standard, this );
321 wrapper->setLinkedVectorLayer( qobject_cast< QgsVectorLayer * >( mActiveLayer.get() ) );
322 mWrappers.insert( definition->name(), wrapper );
323 continue;
324 }
325
327 if ( !wrapper )
328 {
329 continue;
330 }
331
332 wrapper->setDialog( parentWidget() );
333 wrapper->setWidgetContext( widgetContext );
334 wrapper->registerProcessingContextGenerator( this );
336 mWrappers.insert( definition->name(), wrapper );
337
338 QWidget *widget = wrapper->createWrappedWidget( *context );
339 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, &QgsProcessingParametersWidget::parameterChanged );
340
341 if ( widget )
342 {
343 if ( QLabel *label = wrapper->createWrappedLabel() )
344 {
345 addParameterLabel( definition, label );
346 }
347 addParameterWidget( definition, widget, wrapper->stretch() );
348 }
349 }
350
352 for ( const QgsProcessingParameterDefinition *output : destinationDefinitions )
353 {
354 if ( output->flags().testFlag( Qgis::ProcessingParameterFlag::Hidden ) )
355 {
356 continue;
357 }
358
359 if ( mInPlace && ( output->name() == inPlaceInputParameterName || output->name() == "OUTPUT"_L1 ) )
360 {
361 continue;
362 }
363
365 if ( !wrapper )
366 {
367 continue;
368 }
369
370 wrapper->setWidgetContext( widgetContext );
371 wrapper->registerProcessingContextGenerator( this );
373 mWrappers.insert( output->name(), wrapper );
374
375 if ( QLabel *label = wrapper->createWrappedLabel() )
376 {
377 addOutputLabel( label );
378 }
379
380 QWidget *widget = wrapper->createWrappedWidget( *context );
381 addOutputWidget( widget, wrapper->stretch() );
382 }
383
384 const QList< QgsAbstractProcessingParameterWidgetWrapper * > wrapperList = mWrappers.values();
385 for ( auto it = mWrappers.constBegin(); it != mWrappers.constEnd(); ++it )
386 {
387 it.value()->postInitialize( wrapperList );
388 }
389}
390
391void QgsProcessingParametersWidget::addParameterWidget( const QgsProcessingParameterDefinition *parameter, QWidget *widget, int stretch )
392{
394 mAdvancedGroupLayout->addWidget( widget, stretch );
395 else
396 mScrollAreaLayout->insertWidget( mScrollAreaLayout->count() - 3, widget, stretch );
397}
398
399void QgsProcessingParametersWidget::addParameterLabel( const QgsProcessingParameterDefinition *parameter, QWidget *label )
400{
402 mAdvancedGroupLayout->addWidget( label );
403 else
404 mScrollAreaLayout->insertWidget( mScrollAreaLayout->count() - 3, label );
405}
406
407void QgsProcessingParametersWidget::addOutputLabel( QWidget *label )
408{
409 grpOutputs->show();
410 mOutputGroupLayout->addWidget( label );
411}
412
413void QgsProcessingParametersWidget::addOutputWidget( QWidget *widget, int stretch )
414{
415 grpOutputs->show();
416 mOutputGroupLayout->addWidget( widget, stretch );
417}
418
419void QgsProcessingParametersWidget::addExtraWidget( QWidget *widget )
420{
421 mScrollAreaLayout->addWidget( widget );
422}
423
@ Standard
Standard (single-run) algorithm mode.
Definition qgis.h:3911
@ Hidden
Parameter is hidden and should not be shown to users.
Definition qgis.h:4027
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:4026
A widget wrapper for Processing parameter value widgets.
QVariant parameterValue() const
Returns the current value of the parameter.
virtual void setDialog(QWidget *dialog)
Sets the parent dialog (or widget) in which the wrapper is shown.
virtual QVariantMap customProperties() const
Returns any custom properties set by the wrapper.
void registerProcessingParametersGenerator(QgsProcessingParametersGenerator *generator)
Registers a Processing parameters generator class that will be used to retrieve algorithm parameters ...
virtual void registerProcessingContextGenerator(QgsProcessingContextGenerator *generator)
Registers a Processing context generator class that will be used to retrieve a Processing context for...
QLabel * createWrappedLabel()
Creates and returns 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's value.
void widgetValueHasChanged(QgsAbstractProcessingParameterWidgetWrapper *wrapper)
Emitted whenever the parameter value (as defined by the wrapped widget) is changed.
QWidget * wrappedWidget()
Returns the current wrapped widget, if any.
const QgsProcessingParameterDefinition * parameterDefinition() const
Returns the parameter definition associated with this wrapper.
virtual int stretch() const
Returns the Qt layout "stretch" factor to use when adding this widget to a layout.
virtual void setWidgetContext(const QgsProcessingParameterWidgetContext &context)
Sets the context in which the Processing parameter widget is shown, e.g., the parent model algorithm,...
static QgsProcessingGuiRegistry * processingGuiRegistry()
Returns the global processing gui registry, used for registering the GUI behavior of processing algor...
Definition qgsgui.cpp:170
Base class for all map layer types.
Definition qgsmaplayer.h:83
A bar for displaying non-blocking messages to the user.
Base class for any widget that can be shown as an inline panel.
Abstract base class for processing algorithms.
QgsProcessingParameterDefinitions destinationParameterDefinitions() const
Returns a list of destination parameters definitions utilized by the algorithm.
An interface for objects which can create Processing contexts.
Contains information about the context in which a processing algorithm is executed.
Base class for all parameter definitions which represent file or layer destinations,...
An abstract QgsProcessingAlgorithm base class for processing algorithms which operate "feature-by-fea...
QgsAbstractProcessingParameterWidgetWrapper * createParameterWidgetWrapper(const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type)
Creates a new parameter widget wrapper for the given parameter.
QgsProcessingParameterWidgetContext createWidgetContext() override
Register a Processing widget context.
A widget wrapper for hidden widgets.
Encapsulates settings relating to a feature sink or output raster layer for a processing algorithm.
QgsProject * destinationProject
Destination project.
Base class for the definition of processing parameters.
QString name() const
Returns the name of the parameter.
Qgis::ProcessingParameterFlags flags() const
Returns any flags associated with the parameter.
Contains settings which reflect the context in which a Processing parameter widget is shown.
void setMessageBar(QgsMessageBar *bar)
Sets the message bar associated with the widget.
void setModel(QgsProcessingModelAlgorithm *model)
Sets the model which the parameter widget is associated with.
Encapsulates the result of validating parameters shown in the generator.
QgsProcessingParametersGenerator::ValidationResult result
Validation result.
@ InvalidValue
Generic result for invalid parameter values.
@ InvalidOutputExtension
Output parameter extension is invalid.
@ SkipValidation
Skip validation of parameters.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:114
static QgsProject * instance()
Returns the QgsProject singleton instance.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
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
QList< const QgsProcessingParameterDefinition * > QgsProcessingParameterDefinitions
List of processing parameters.