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