QGIS API Documentation 4.3.0-Master (0cfde48c85b)
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 scrollAreaWidgetContents->setContentsMargins( 4, 4, 4, 4 );
46}
47
48QgsProcessingParametersWidget::~QgsProcessingParametersWidget()
49{
50 qDeleteAll( mWrappers );
51}
52
53const QgsProcessingAlgorithm *QgsProcessingParametersWidget::algorithm() const
54{
55 return mAlgorithm;
56}
57
58QgsProcessingContext *QgsProcessingParametersWidget::processingContext() const
59{
60 return mContextGenerator ? mContextGenerator->processingContext() : nullptr;
61}
62
63QVariantMap QgsProcessingParametersWidget::createProcessingParameters( Flags flags )
64{
65 QList< QgsProcessingParametersGenerator::ParameterValidationResult > validationResults;
66 return createAndValidateParameters( flags, validationResults );
67}
68
69void QgsProcessingParametersWidget::registerProcessingContextGenerator( QgsProcessingContextGenerator *generator )
70{
71 mContextGenerator = generator;
72}
73
74QList<QgsProcessingParametersGenerator::ParameterValidationResult> QgsProcessingParametersWidget::validate() const
75{
76 QList< QgsProcessingParametersGenerator::ParameterValidationResult > validationResults;
77 createAndValidateParameters( QgsProcessingParametersGenerator::Flags(), validationResults );
78 return validationResults;
79}
80
81QVariantMap QgsProcessingParametersWidget::createAndValidateParameters(
82 QgsProcessingParametersGenerator::Flags flags, QList< QgsProcessingParametersGenerator::ParameterValidationResult > &validationResults
83) const
84{
85 QgsProcessingContext *context = processingContext();
86
87 const bool includeDefault = !flags.testFlag( Flag::SkipDefaultValueParameters );
88 const bool validate = !flags.testFlag( Flag::SkipValidation );
89
90 QVariantMap parameters = mExtraParameters;
91 const QgsProcessingParameterDefinitions defs = mAlgorithm->parameterDefinitions();
92 for ( const QgsProcessingParameterDefinition *definition : defs )
93 {
94 if ( definition->flags().testFlag( Qgis::ProcessingParameterFlag::Hidden ) )
95 {
96 continue;
97 }
98
99 if ( !definition->isDestination() )
100 {
101 QgsAbstractProcessingParameterWidgetWrapper *wrapper = mWrappers.value( definition->name() );
102 if ( !wrapper )
103 continue;
104
105 QWidget *widget = wrapper->wrappedWidget();
106
107 if ( !dynamic_cast< QgsProcessingHiddenWidgetWrapper *>( wrapper ) && !widget )
108 {
109 continue;
110 }
111
112 const QVariant value = wrapper->parameterValue();
113 if ( definition->defaultValue() != value || includeDefault )
114 {
115 parameters[definition->name()] = value;
116 }
117
118 if ( validate && !definition->checkValueIsAcceptable( value ) )
119 {
121 result.parameterName = definition->name();
123 validationResults.append( result );
124 }
125 }
126 else
127 {
128 if ( mInPlace && definition->name() == "OUTPUT"_L1 )
129 {
130 parameters[definition->name()] = u"memory:"_s;
131 continue;
132 }
133
134 QgsAbstractProcessingParameterWidgetWrapper *wrapper = mWrappers.value( definition->name() );
135 if ( !wrapper )
136 continue;
137
138 QVariant value = wrapper->parameterValue();
139
140 QgsProject *destinationProject = nullptr;
141 if ( wrapper->customProperties().value( u"OPEN_AFTER_RUNNING"_s ).toBool() )
142 {
143 destinationProject = QgsProject::instance();
144 }
145
146 if ( value.userType() == qMetaTypeId<QgsProcessingOutputLayerDefinition>() )
147 {
149 outputDefinition.destinationProject = destinationProject;
150 value = QVariant::fromValue( outputDefinition );
151 }
152
153 if ( !QgsVariantUtils::isNull( value ) && ( definition->defaultValue() != value || includeDefault ) )
154 {
155 parameters[definition->name()] = value;
156 if ( validate )
157 {
158 auto destinationParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition );
159 if ( destinationParam )
160 {
161 QString error;
162 const bool ok = destinationParam->isSupportedOutputValue( value, *context, error );
163 if ( !ok )
164 {
166 result.parameterName = definition->name();
168 result.message = error;
169 validationResults.append( result );
170 }
171 }
172 }
173 }
174 }
175 }
176
177 return const_cast< QgsProcessingAlgorithm * >( mAlgorithm )->preprocessParameters( parameters );
178}
179
180void QgsProcessingParametersWidget::setParameters( const QVariantMap &parameters )
181{
182 QgsProcessingContext *context = processingContext();
183
184 mExtraParameters.clear();
185 const QgsProcessingParameterDefinitions defs = mAlgorithm->parameterDefinitions();
186 for ( const QgsProcessingParameterDefinition *definition : std::as_const( defs ) )
187 {
188 auto paramIt = parameters.constFind( definition->name() );
189 if ( definition->flags().testFlag( Qgis::ProcessingParameterFlag::Hidden ) )
190 {
191 if ( paramIt != parameters.constEnd() )
192 {
193 mExtraParameters.insert( definition->name(), paramIt.value() );
194 }
195 continue;
196 }
197
198 if ( paramIt == parameters.constEnd() )
199 {
200 continue;
201 }
202
203 const QVariant value = paramIt.value();
204
205 auto wrapperIt = mWrappers.constFind( definition->name() );
206 if ( wrapperIt != mWrappers.constEnd() )
207 {
208 wrapperIt.value()->setParameterValue( value, *context );
209 }
210 }
211}
212
213QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingParametersWidget::wrapper( const QString &name ) const
214{
215 return mWrappers.value( name );
216}
217
218QList<QgsAbstractProcessingParameterWidgetWrapper *> QgsProcessingParametersWidget::wrappers() const
219{
220 return mWrappers.values();
221}
222
223void QgsProcessingParametersWidget::parameterChanged()
224{
225 auto wrapper = qobject_cast< QgsAbstractProcessingParameterWidgetWrapper * >( sender() );
226 if ( !wrapper )
227 return;
228
229 const QVariantMap defaultValues
230 = mAlgorithm->autogenerateParameterValues( createProcessingParameters( QgsProcessingParametersGenerator::Flag::SkipValidation ), wrapper->parameterDefinition()->name(), Qgis::ProcessingMode::Standard );
231
232 if ( !defaultValues.empty() )
233 {
234 setParameters( defaultValues );
235 }
236}
237
238void QgsProcessingParametersWidget::initWidgets()
239{
240 QgsProcessingContext *context = processingContext();
241
242 // if there are advanced parameters - show corresponding groupbox
243 const QgsProcessingParameterDefinitions defs = mAlgorithm->parameterDefinitions();
244 for ( const QgsProcessingParameterDefinition *param : defs )
245 {
246 if ( param->flags() & Qgis::ProcessingParameterFlag::Advanced )
247 {
248 grpAdvanced->show();
249 break;
250 }
251 }
252
253 if ( !algorithm() )
254 {
255 return;
256 }
257
259 widgetContext.setMessageBar( mMessageBar );
260
261 if ( auto modelAlgorithm = dynamic_cast< const QgsProcessingModelAlgorithm * >( mAlgorithm ) )
262 {
263 widgetContext.setModel( const_cast< QgsProcessingModelAlgorithm * >( modelAlgorithm ) );
264 }
265
266 QString inPlaceInputParameterName = u"INPUT"_s;
267 if ( auto featureAlgorithm = dynamic_cast< const QgsProcessingFeatureBasedAlgorithm * >( mAlgorithm ) )
268 {
269 inPlaceInputParameterName = featureAlgorithm->inputParameterName();
270 }
271
272 bool hasNonInputParams = false;
273 for ( const QgsProcessingParameterDefinition *definition : std::as_const( defs ) )
274 {
275 if ( definition->name() != inPlaceInputParameterName && definition->name() != "OUTPUT"_L1 )
276 {
277 hasNonInputParams = true;
278 break;
279 }
280 }
281 // If there are no parameters to show because it's in-place, we add the info label.
282 // Still, it needs the following steps to create the parameter widgets (even when hidden).
283 if ( mInPlace && !hasNonInputParams )
284 {
285 auto widget = new QWidget( this );
286 auto layout = new QVBoxLayout( widget );
287 auto label = new QLabel( widget );
288 label->setWordWrap( true );
289
290 const QString layerName = mActiveLayer ? mActiveLayer->name() : QString();
291 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 );
292 label->setText( infoText );
293
294 layout->addWidget( label );
295 layout->addStretch();
296 addExtraWidget( widget );
297 }
298
299 // Create widgets and put them in layouts
300 for ( const QgsProcessingParameterDefinition *definition : defs )
301 {
302 if ( definition->flags().testFlag( Qgis::ProcessingParameterFlag::Hidden ) )
303 {
304 continue;
305 }
306
307 if ( definition->isDestination() )
308 {
309 continue;
310 }
311
312 if ( mInPlace && ( definition->name() == inPlaceInputParameterName || definition->name() == "OUTPUT"_L1 ) )
313 {
314 // don't show the input/output parameter widgets in in-place mode
315 // we still need to CREATE them, because other wrappers may need to interact
316 // with them (e.g. those parameters which need the input layer for field
317 // selections/crs properties/etc)
318 auto wrapper = new QgsProcessingHiddenWidgetWrapper( definition, Qgis::ProcessingMode::Standard, this );
319 wrapper->setLinkedVectorLayer( qobject_cast< QgsVectorLayer * >( mActiveLayer.get() ) );
320 mWrappers.insert( definition->name(), wrapper );
321 continue;
322 }
323
325 if ( !wrapper )
326 {
327 continue;
328 }
329
330 wrapper->setDialog( parentWidget() );
331 wrapper->setWidgetContext( widgetContext );
332 wrapper->registerProcessingContextGenerator( this );
334 mWrappers.insert( definition->name(), wrapper );
335
336 QWidget *widget = wrapper->createWrappedWidget( *context );
337 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, &QgsProcessingParametersWidget::parameterChanged );
338
339 if ( widget )
340 {
341 if ( QLabel *label = wrapper->createWrappedLabel() )
342 {
343 addParameterLabel( definition, label );
344 }
345 addParameterWidget( definition, widget, wrapper->stretch() );
346 }
347 }
348
350 for ( const QgsProcessingParameterDefinition *output : destinationDefinitions )
351 {
352 if ( output->flags().testFlag( Qgis::ProcessingParameterFlag::Hidden ) )
353 {
354 continue;
355 }
356
357 if ( mInPlace && ( output->name() == inPlaceInputParameterName || output->name() == "OUTPUT"_L1 ) )
358 {
359 continue;
360 }
361
363 if ( !wrapper )
364 {
365 continue;
366 }
367
368 wrapper->setWidgetContext( widgetContext );
369 wrapper->registerProcessingContextGenerator( this );
371 mWrappers.insert( output->name(), wrapper );
372
373 if ( QLabel *label = wrapper->createWrappedLabel() )
374 {
375 addOutputLabel( label );
376 }
377
378 QWidget *widget = wrapper->createWrappedWidget( *context );
379 addOutputWidget( widget, wrapper->stretch() );
380 }
381
382 const QList< QgsAbstractProcessingParameterWidgetWrapper * > wrapperList = mWrappers.values();
383 for ( auto it = mWrappers.constBegin(); it != mWrappers.constEnd(); ++it )
384 {
385 it.value()->postInitialize( wrapperList );
386 }
387}
388
389void QgsProcessingParametersWidget::addParameterWidget( const QgsProcessingParameterDefinition *parameter, QWidget *widget, int stretch )
390{
392 mAdvancedGroupLayout->addWidget( widget, stretch );
393 else
394 mScrollAreaLayout->insertWidget( mScrollAreaLayout->count() - 2, widget, stretch );
395}
396
397void QgsProcessingParametersWidget::addParameterLabel( const QgsProcessingParameterDefinition *parameter, QWidget *label )
398{
400 mAdvancedGroupLayout->addWidget( label );
401 else
402 mScrollAreaLayout->insertWidget( mScrollAreaLayout->count() - 2, label );
403}
404
405void QgsProcessingParametersWidget::addOutputLabel( QWidget *label )
406{
407 mScrollAreaLayout->insertWidget( mScrollAreaLayout->count() - 1, label );
408}
409
410void QgsProcessingParametersWidget::addOutputWidget( QWidget *widget, int stretch )
411{
412 mScrollAreaLayout->insertWidget( mScrollAreaLayout->count() - 1, widget, stretch );
413}
414
415void QgsProcessingParametersWidget::addExtraWidget( QWidget *widget )
416{
417 mScrollAreaLayout->addWidget( widget );
418}
419
@ 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.