QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsprocessingconfigurationwidgets.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingconfigurationwidgets.cpp
3 ---------------------
4 begin : April 2018
5 copyright : (C) 2018 by Matthias Kuhn
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
22#include "qgsapplication.h"
23#include "qgsgui.h"
25
26#include <QTableWidget>
27#include <QGridLayout>
28#include <QToolButton>
29#include <QLabel>
30#include <QCheckBox>
31#include <QHeaderView>
32
34
35QgsFilterAlgorithmConfigurationWidget::QgsFilterAlgorithmConfigurationWidget( QWidget *parent )
37{
38 setContentsMargins( 0, 0, 0, 0 );
39
40 mOutputExpressionWidget = new QTableWidget();
41 mOutputExpressionWidget->setColumnCount( 3 );
42 mOutputExpressionWidget->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Output Name" ) ) );
43 mOutputExpressionWidget->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "Filter Expression" ) ) );
44 mOutputExpressionWidget->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Final Output" ) ) );
45 mOutputExpressionWidget->horizontalHeader()->setSectionResizeMode( 1, QHeaderView::Stretch );
46 QGridLayout *layout = new QGridLayout();
47 setLayout( layout );
48
49 layout->addWidget( new QLabel( tr( "Outputs and filters" ) ), 0, 0, 1, 2 );
50 layout->addWidget( mOutputExpressionWidget, 1, 0, 4, 1 );
51 QToolButton *addOutputButton = new QToolButton();
52 addOutputButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddLayer.svg" ) ) );
53 addOutputButton->setText( tr( "Add Output" ) );
54
55 QToolButton *removeOutputButton = new QToolButton();
56 removeOutputButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionRemoveLayer.svg" ) ) );
57 removeOutputButton->setToolTip( tr( "Remove Selected Outputs" ) );
58
59 layout->addWidget( addOutputButton, 2, 1, 1, 1 );
60 layout->addWidget( removeOutputButton, 3, 1, 1, 1 );
61
62 connect( addOutputButton, &QToolButton::clicked, this, &QgsFilterAlgorithmConfigurationWidget::addOutput );
63 connect( removeOutputButton, &QToolButton::clicked, this, &QgsFilterAlgorithmConfigurationWidget::removeSelectedOutputs );
64
65 connect( mOutputExpressionWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, [removeOutputButton, this]
66 {
67 removeOutputButton->setEnabled( !mOutputExpressionWidget->selectionModel()->selectedIndexes().isEmpty() );
68 } );
69}
70
71QVariantMap QgsFilterAlgorithmConfigurationWidget::configuration() const
72{
73 QVariantList outputs;
74
75 for ( int i = 0; i < mOutputExpressionWidget->rowCount(); ++i )
76 {
77 QVariantMap output;
78 output.insert( QStringLiteral( "name" ), mOutputExpressionWidget->item( i, 0 )->text() );
79 output.insert( QStringLiteral( "expression" ), qobject_cast<QgsExpressionLineEdit *>( mOutputExpressionWidget->cellWidget( i, 1 ) )->expression() );
80 output.insert( QStringLiteral( "isModelOutput" ), qobject_cast<QCheckBox *>( mOutputExpressionWidget->cellWidget( i, 2 ) )->isChecked() );
81 outputs.append( output );
82 }
83
84 QVariantMap map;
85 map.insert( "outputs", outputs );
86
87 return map;
88}
89
90
91void QgsFilterAlgorithmConfigurationWidget::setConfiguration( const QVariantMap &configuration )
92{
93 mOutputExpressionWidget->setRowCount( 0 );
94 int currentRow = 0;
95 const QVariantList outputs = configuration.value( "outputs" ).toList();
96
97 for ( const QVariant &outputvar : outputs )
98 {
99 const QVariantMap output = outputvar.toMap();
100 mOutputExpressionWidget->insertRow( currentRow );
101 mOutputExpressionWidget->setItem( currentRow, 0, new QTableWidgetItem( output.value( "name" ).toString() ) );
102 QgsExpressionLineEdit *expressionBuilder = new QgsExpressionLineEdit();
103 expressionBuilder->registerExpressionContextGenerator( this );
104 expressionBuilder->setExpression( output.value( "expression" ).toString() );
105 mOutputExpressionWidget->setCellWidget( currentRow, 1, expressionBuilder );
106 QCheckBox *isModelOutput = new QCheckBox();
107 isModelOutput->setChecked( output.value( "isModelOutput" ).toBool() );
108 mOutputExpressionWidget->setCellWidget( currentRow, 2, isModelOutput );
109
110 currentRow++;
111 }
112
113 if ( outputs.isEmpty() )
114 addOutput();
115}
116
117void QgsFilterAlgorithmConfigurationWidget::removeSelectedOutputs()
118{
119 const QItemSelection selection( mOutputExpressionWidget->selectionModel()->selection() );
120
121 QList<int> rows;
122 const QModelIndexList indexes = selection.indexes();
123 for ( const QModelIndex &index : indexes )
124 {
125 rows.append( index.row() );
126 }
127
128 std::sort( rows.begin(), rows.end() );
129
130 int prev = -1;
131 for ( int i = rows.count() - 1; i >= 0; i -= 1 )
132 {
133 const int current = rows[i];
134 if ( current != prev )
135 {
136 mOutputExpressionWidget->removeRow( current );
137 prev = current;
138 }
139 }
140}
141
142void QgsFilterAlgorithmConfigurationWidget::addOutput()
143{
144 const int rowIndex = mOutputExpressionWidget->rowCount();
145 mOutputExpressionWidget->setRowCount( rowIndex + 1 );
146 QgsExpressionLineEdit *expressionBuilder = new QgsExpressionLineEdit();
147 expressionBuilder->registerExpressionContextGenerator( this );
148 mOutputExpressionWidget->setItem( rowIndex, 0, new QTableWidgetItem( QString() ) );
149 mOutputExpressionWidget->setCellWidget( rowIndex, 1, expressionBuilder );
150 mOutputExpressionWidget->setCellWidget( rowIndex, 2, new QCheckBox() );
151}
152
153QgsProcessingAlgorithmConfigurationWidget *QgsFilterAlgorithmConfigurationWidgetFactory::create( const QgsProcessingAlgorithm *algorithm ) const
154{
155 if ( algorithm->name() == QLatin1String( "filter" ) )
156 return new QgsFilterAlgorithmConfigurationWidget();
157 else
158 return nullptr;
159}
160
161bool QgsFilterAlgorithmConfigurationWidgetFactory::canCreateFor( const QgsProcessingAlgorithm *algorithm ) const
162{
163 return algorithm->name() == QLatin1String( "filter" );
164}
165
166
167//
168// QgsConditionalBranchAlgorithmConfigurationWidget
169//
170
171QgsConditionalBranchAlgorithmConfigurationWidget::QgsConditionalBranchAlgorithmConfigurationWidget( QWidget *parent )
173{
174 setContentsMargins( 0, 0, 0, 0 );
175
176 mConditionExpressionWidget = new QTableWidget();
177 mConditionExpressionWidget->setColumnCount( 2 );
178 mConditionExpressionWidget->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Branch Name" ) ) );
179 mConditionExpressionWidget->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "Condition" ) ) );
180 mConditionExpressionWidget->horizontalHeader()->setSectionResizeMode( 1, QHeaderView::Stretch );
181 QGridLayout *layout = new QGridLayout();
182 setLayout( layout );
183
184 layout->addWidget( new QLabel( tr( "Conditions" ) ), 0, 0, 1, 2 );
185 layout->addWidget( mConditionExpressionWidget, 1, 0, 4, 1 );
186 QToolButton *addConditionButton = new QToolButton();
187 addConditionButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddLayer.svg" ) ) );
188 addConditionButton->setText( tr( "Add Condition" ) );
189
190 QToolButton *removeConditionButton = new QToolButton();
191 removeConditionButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionRemoveLayer.svg" ) ) );
192 removeConditionButton->setToolTip( tr( "Remove Selected Conditions" ) );
193
194 layout->addWidget( addConditionButton, 2, 1, 1, 1 );
195 layout->addWidget( removeConditionButton, 3, 1, 1, 1 );
196
197 connect( addConditionButton, &QToolButton::clicked, this, &QgsConditionalBranchAlgorithmConfigurationWidget::addCondition );
198 connect( removeConditionButton, &QToolButton::clicked, this, &QgsConditionalBranchAlgorithmConfigurationWidget::removeSelectedConditions );
199
200 connect( mConditionExpressionWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, [removeConditionButton, this]
201 {
202 removeConditionButton->setEnabled( !mConditionExpressionWidget->selectionModel()->selectedIndexes().isEmpty() );
203 } );
204}
205
206QVariantMap QgsConditionalBranchAlgorithmConfigurationWidget::configuration() const
207{
208 QVariantList outputs;
209
210 for ( int i = 0; i < mConditionExpressionWidget->rowCount(); ++i )
211 {
212 QVariantMap output;
213 output.insert( QStringLiteral( "name" ), mConditionExpressionWidget->item( i, 0 )->text() );
214 output.insert( QStringLiteral( "expression" ), qobject_cast<QgsExpressionLineEdit *>( mConditionExpressionWidget->cellWidget( i, 1 ) )->expression() );
215 outputs.append( output );
216 }
217
218 QVariantMap map;
219 map.insert( "conditions", outputs );
220
221 return map;
222}
223
224
225void QgsConditionalBranchAlgorithmConfigurationWidget::setConfiguration( const QVariantMap &configuration )
226{
227 mConditionExpressionWidget->setRowCount( 0 );
228 int currentRow = 0;
229 const QVariantList conditions = configuration.value( "conditions" ).toList();
230
231 for ( const QVariant &conditionvar : conditions )
232 {
233 const QVariantMap output = conditionvar.toMap();
234 mConditionExpressionWidget->insertRow( currentRow );
235 mConditionExpressionWidget->setItem( currentRow, 0, new QTableWidgetItem( output.value( "name" ).toString() ) );
236 QgsExpressionLineEdit *expressionBuilder = new QgsExpressionLineEdit();
237 expressionBuilder->registerExpressionContextGenerator( this );
238 expressionBuilder->setExpression( output.value( "expression" ).toString() );
239 mConditionExpressionWidget->setCellWidget( currentRow, 1, expressionBuilder );
240 currentRow++;
241 }
242
243 if ( conditions .isEmpty() )
244 addCondition();
245}
246
247void QgsConditionalBranchAlgorithmConfigurationWidget::removeSelectedConditions()
248{
249 const QItemSelection selection( mConditionExpressionWidget->selectionModel()->selection() );
250
251 QList<int> rows;
252 const QModelIndexList indexes = selection.indexes();
253 for ( const QModelIndex &index : indexes )
254 {
255 rows.append( index.row() );
256 }
257
258 std::sort( rows.begin(), rows.end() );
259
260 int prev = -1;
261 for ( int i = rows.count() - 1; i >= 0; i -= 1 )
262 {
263 const int current = rows[i];
264 if ( current != prev )
265 {
266 mConditionExpressionWidget->removeRow( current );
267 prev = current;
268 }
269 }
270}
271
272void QgsConditionalBranchAlgorithmConfigurationWidget::addCondition()
273{
274 const int rowIndex = mConditionExpressionWidget->rowCount();
275 mConditionExpressionWidget->setRowCount( rowIndex + 1 );
276 QgsExpressionLineEdit *expressionBuilder = new QgsExpressionLineEdit();
277 expressionBuilder->registerExpressionContextGenerator( this );
278 mConditionExpressionWidget->setItem( rowIndex, 0, new QTableWidgetItem( QString() ) );
279 mConditionExpressionWidget->setCellWidget( rowIndex, 1, expressionBuilder );
280}
281
282QgsConditionalBranchAlgorithmConfigurationWidget *QgsConditionalBranchAlgorithmConfigurationWidgetFactory::create( const QgsProcessingAlgorithm *algorithm ) const
283{
284 if ( algorithm->name() == QLatin1String( "condition" ) )
285 return new QgsConditionalBranchAlgorithmConfigurationWidget();
286 else
287 return nullptr;
288}
289
290bool QgsConditionalBranchAlgorithmConfigurationWidgetFactory::canCreateFor( const QgsProcessingAlgorithm *algorithm ) const
291{
292 return algorithm->name() == QLatin1String( "condition" );
293}
294
295
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
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...
void setExpression(const QString &expression)
Sets the current expression to show in the widget.
A configuration widget for processing algorithms allows providing additional configuration options di...
Abstract base class for processing algorithms.
virtual QString name() const =0
Returns the algorithm name, used for identifying the algorithm.
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