QGIS API Documentation  3.20.0-Odense (decaadbb31)
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
6  email : [email protected]
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 #include "qgsprocessingalgorithm.h"
21 #include "qgsexpressionlineedit.h"
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 
35 QgsFilterAlgorithmConfigurationWidget::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 
71 QVariantMap 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 
91 void 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 
117 void QgsFilterAlgorithmConfigurationWidget::removeSelectedOutputs()
118 {
119  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  int current = rows[i];
134  if ( current != prev )
135  {
136  mOutputExpressionWidget->removeRow( current );
137  prev = current;
138  }
139  }
140 }
141 
142 void QgsFilterAlgorithmConfigurationWidget::addOutput()
143 {
144  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 
153 QgsProcessingAlgorithmConfigurationWidget *QgsFilterAlgorithmConfigurationWidgetFactory::create( const QgsProcessingAlgorithm *algorithm ) const
154 {
155  if ( algorithm->name() == QLatin1String( "filter" ) )
156  return new QgsFilterAlgorithmConfigurationWidget();
157  else
158  return nullptr;
159 }
160 
161 bool QgsFilterAlgorithmConfigurationWidgetFactory::canCreateFor( const QgsProcessingAlgorithm *algorithm ) const
162 {
163  return algorithm->name() == QLatin1String( "filter" );
164 }
165 
166 
167 //
168 // QgsConditionalBranchAlgorithmConfigurationWidget
169 //
170 
171 QgsConditionalBranchAlgorithmConfigurationWidget::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 
206 QVariantMap 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 
225 void 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 
247 void QgsConditionalBranchAlgorithmConfigurationWidget::removeSelectedConditions()
248 {
249  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  int current = rows[i];
264  if ( current != prev )
265  {
266  mConditionExpressionWidget->removeRow( current );
267  prev = current;
268  }
269  }
270 }
271 
272 void QgsConditionalBranchAlgorithmConfigurationWidget::addCondition()
273 {
274  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 
282 QgsConditionalBranchAlgorithmConfigurationWidget *QgsConditionalBranchAlgorithmConfigurationWidgetFactory::create( const QgsProcessingAlgorithm *algorithm ) const
283 {
284  if ( algorithm->name() == QLatin1String( "condition" ) )
285  return new QgsConditionalBranchAlgorithmConfigurationWidget();
286  else
287  return nullptr;
288 }
289 
290 bool 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