QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgsprocessingtininputlayerswidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsprocessingtininputlayerswidget.cpp
3  ---------------------
4  Date : August 2020
5  Copyright : (C) 2020 by Vincent Cloarec
6  Email : vcloarec 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 #include "qgsproject.h"
18 #include "qgsprocessingcontext.h"
19 
21 
22 QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersWidget( QgsProject *project ):
23  mInputLayersModel( project )
24 {
25  setupUi( this );
26  mComboLayers->setFilters( QgsMapLayerProxyModel::VectorLayer );
27 
28  connect( mComboLayers, &QgsMapLayerComboBox::layerChanged, this, &QgsProcessingTinInputLayersWidget::onLayerChanged );
29  connect( mButtonAdd, &QToolButton::clicked, this, &QgsProcessingTinInputLayersWidget::onCurrentLayerAdded );
30  connect( mButtonRemove, &QToolButton::clicked, this, &QgsProcessingTinInputLayersWidget::onLayersRemove );
31  connect( &mInputLayersModel, &QgsProcessingTinInputLayersModel::dataChanged, this, &QgsProcessingTinInputLayersWidget::changed );
32 
33  onLayerChanged( mComboLayers->currentLayer() );
34 
35  mTableView->setModel( &mInputLayersModel );
36  mTableView->setItemDelegateForColumn( 1, new Delegate( mTableView ) );
37 }
38 
39 QVariant QgsProcessingTinInputLayersWidget::value() const
40 {
41  const QList<QgsProcessingParameterTinInputLayers::InputLayer> &layers = mInputLayersModel.layers();
42  QVariantList list;
43 
44  for ( const QgsProcessingParameterTinInputLayers::InputLayer &layer : layers )
45  {
46  QVariantMap layerMap;
47  layerMap[QStringLiteral( "source" )] = layer.source;
48  layerMap[QStringLiteral( "type" )] = layer.type;
49  layerMap[QStringLiteral( "attributeIndex" )] = layer.attributeIndex;
50  list.append( layerMap );
51  }
52 
53  return list;
54 }
55 
56 void QgsProcessingTinInputLayersWidget::setValue( const QVariant &value )
57 {
58  mInputLayersModel.clear();
59  if ( !value.isValid() || value.type() != QVariant::List )
60  return;
61 
62  const QVariantList list = value.toList();
63 
64  for ( const QVariant &layerValue : list )
65  {
66  if ( layerValue.type() != QVariant::Map )
67  continue;
68  const QVariantMap layerMap = layerValue.toMap();
70  layer.source = layerMap.value( QStringLiteral( "source" ) ).toString();
71  layer.type = static_cast<QgsProcessingParameterTinInputLayers::Type>( layerMap.value( QStringLiteral( "type" ) ).toInt() );
72  layer.attributeIndex = layerMap.value( QStringLiteral( "attributeIndex" ) ).toInt();
73  mInputLayersModel.addLayer( layer );
74  }
75 
76  emit changed();
77 }
78 
79 void QgsProcessingTinInputLayersWidget::setProject( QgsProject *project )
80 {
81  mInputLayersModel.setProject( project );
82 }
83 
84 void QgsProcessingTinInputLayersWidget::onLayerChanged( QgsMapLayer *layer )
85 {
86  QgsVectorLayer *newLayer = qobject_cast<QgsVectorLayer *>( layer );
87 
88  if ( !newLayer || !newLayer->isValid() )
89  return;
90 
91  QgsVectorDataProvider *provider = newLayer->dataProvider();
92 
93  if ( !provider )
94  return;
95 
96  mComboFields->setLayer( newLayer );
97  mComboFields->setCurrentIndex( 0 );
98  mCheckBoxUseZCoordinate->setEnabled( QgsWkbTypes::hasZ( provider->wkbType() ) );
99 }
100 
101 void QgsProcessingTinInputLayersWidget::onCurrentLayerAdded()
102 {
103  QgsVectorLayer *currentLayer = qobject_cast<QgsVectorLayer *>( mComboLayers->currentLayer() );
104  if ( !currentLayer )
105  return;
107  layer.source = mComboLayers->currentLayer()->id();
108 
109  switch ( currentLayer->geometryType() )
110  {
113  break;
117  break;
120  return;
121  break;
122  }
123  if ( mCheckBoxUseZCoordinate->isChecked() && mCheckBoxUseZCoordinate->isEnabled() )
124  layer.attributeIndex = -1;
125  else
126  layer.attributeIndex = mComboFields->currentIndex();
127 
128  mInputLayersModel.addLayer( layer );
129 
130  emit changed();
131 }
132 
133 void QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersWidget::onLayersRemove()
134 {
135  mInputLayersModel.removeLayer( mTableView->selectionModel()->currentIndex().row() );
136 
137  emit changed();
138 }
139 
140 QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersModel::QgsProcessingTinInputLayersModel( QgsProject *project ):
141  mProject( project )
142 {}
143 
144 int QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersModel::rowCount( const QModelIndex &parent ) const
145 {
146  Q_UNUSED( parent );
147  return mInputLayers.count();
148 }
149 
150 int QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersModel::columnCount( const QModelIndex &parent ) const
151 {
152  Q_UNUSED( parent );
153  return 3;
154 }
155 
156 QVariant QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersModel::data( const QModelIndex &index, int role ) const
157 {
158  if ( !index.isValid() )
159  return QVariant();
160 
161  if ( index.row() >= mInputLayers.count() )
162  return QVariant();
163 
164  switch ( role )
165  {
166  case Qt::DisplayRole:
167  {
168  QgsVectorLayer *layer = QgsProject::instance()->mapLayer<QgsVectorLayer *>( mInputLayers.at( index.row() ).source );
169  switch ( index.column() )
170  {
171  case 0:
172  if ( layer )
173  return layer->name();
174  else
175  return QVariant();
176  break;
177  case 1:
178  switch ( mInputLayers.at( index.row() ).type )
179  {
181  return tr( "Vertices" );
182  break;
184  return tr( "Break Lines" );
185  break;
186  default:
187  return QString();
188  break;
189  }
190  break;
191  case 2:
192  const int attributeindex = mInputLayers.at( index.row() ).attributeIndex;
193  if ( attributeindex < 0 )
194  return tr( "Z coordinate" );
195  else
196  {
197  if ( attributeindex < layer->fields().count() )
198  return layer->fields().at( attributeindex ).name();
199  else
200  return tr( "Invalid field" );
201  }
202  break;
203  }
204  }
205  break;
206  case Qt::ForegroundRole:
207  if ( index.column() == 2 )
208  {
209  const int attributeindex = mInputLayers.at( index.row() ).attributeIndex;
210  if ( attributeindex < 0 )
211  return QColor( Qt::darkGray );
212  }
213  break;
214  case Qt::FontRole:
215  if ( index.column() == 2 )
216  {
217  const int attributeindex = mInputLayers.at( index.row() ).attributeIndex;
218  if ( attributeindex < 0 )
219  {
220  QFont font;
221  font.setItalic( true );
222  return font;
223  }
224  }
225  break;
226  case Type:
227  if ( index.column() == 1 )
228  return mInputLayers.at( index.row() ).type;
229  break;
230  default:
231  break;
232  }
233  return QVariant();
234 }
235 
236 bool QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersModel::setData( const QModelIndex &index, const QVariant &value, int role )
237 {
238  if ( index.column() == 1 && role == Qt::EditRole )
239  {
240  mInputLayers[index.row()].type = static_cast<QgsProcessingParameterTinInputLayers::Type>( value.toInt() );
241  emit dataChanged( QAbstractTableModel::index( index.row(), 1 ), QAbstractTableModel::index( index.row(), 1 ) );
242  return true;
243  }
244  return false;
245 }
246 
247 Qt::ItemFlags QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersModel::flags( const QModelIndex &index ) const
248 {
249  if ( !index.isValid() )
250  return Qt::NoItemFlags;
251 
252  if ( index.column() == 1 )
253  return QAbstractTableModel::flags( index ) | Qt::ItemIsEditable;
254 
255  return QAbstractTableModel::flags( index );
256 }
257 
258 QVariant QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersModel::headerData( int section, Qt::Orientation orientation, int role ) const
259 {
260  if ( orientation == Qt::Horizontal && role == Qt::DisplayRole )
261  {
262  switch ( section )
263  {
264  case 0:
265  return tr( "Vector Layer" );
266  break;
267  case 1:
268  return tr( "Type" );
269  break;
270  case 2:
271  return tr( "Z Value Attribute" );
272  break;
273  default:
274  return QVariant();
275  break;
276  }
277  }
278 
279  return QVariant();
280 }
281 
282 void QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersModel::addLayer( QgsProcessingParameterTinInputLayers::InputLayer &layer )
283 {
284  beginInsertRows( QModelIndex(), mInputLayers.count() - 1, mInputLayers.count() - 1 );
285  mInputLayers.append( layer );
286  endInsertRows();
287 }
288 
289 void QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersModel::removeLayer( int index )
290 {
291  if ( index < 0 || index >= mInputLayers.count() )
292  return;
293  beginRemoveRows( QModelIndex(), index, index );
294  mInputLayers.removeAt( index );
295  endRemoveRows();
296 }
297 
298 void QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersModel::clear()
299 {
300  mInputLayers.clear();
301 }
302 
303 QList<QgsProcessingParameterTinInputLayers::InputLayer> QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersModel::layers() const
304 {
305  return mInputLayers;
306 }
307 
308 void QgsProcessingTinInputLayersWidget::QgsProcessingTinInputLayersModel::setProject( QgsProject *project )
309 {
310  mProject = project;
311 }
312 
313 QWidget *QgsProcessingTinInputLayersWidget::Delegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
314 {
315  Q_UNUSED( option );
316  Q_UNUSED( index );
317  QComboBox *comboType = new QComboBox( parent );
318  comboType->addItem( tr( "Vertices" ), QgsProcessingParameterTinInputLayers::Vertices );
319  comboType->addItem( tr( "Break Lines" ), QgsProcessingParameterTinInputLayers::BreakLines );
320  return comboType;
321 }
322 
323 void QgsProcessingTinInputLayersWidget::Delegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
324 {
325  QComboBox *comboType = qobject_cast<QComboBox *>( editor );
326  Q_ASSERT( comboType );
328  static_cast<QgsProcessingParameterTinInputLayers::Type>( index.data( QgsProcessingTinInputLayersModel::Type ).toInt() );
329  const int comboIndex = comboType->findData( type );
330  if ( comboIndex >= 0 )
331  comboType->setCurrentIndex( comboIndex );
332  else
333  comboType->setCurrentIndex( 0 );
334 }
335 
336 void QgsProcessingTinInputLayersWidget::Delegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
337 {
338  QComboBox *comboType = qobject_cast<QComboBox *>( editor );
339  Q_ASSERT( comboType );
340  model->setData( index, comboType->currentData(), Qt::EditRole );
341 }
342 
343 QgsProcessingTinInputLayersWidgetWrapper::QgsProcessingTinInputLayersWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent ):
344  QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
345 {}
346 
347 QString QgsProcessingTinInputLayersWidgetWrapper::parameterType() const
348 {
349  return QStringLiteral( "tininputlayers" );
350 }
351 
352 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingTinInputLayersWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
353 {
354  return new QgsProcessingTinInputLayersWidgetWrapper( parameter, type );
355 }
356 
357 QStringList QgsProcessingTinInputLayersWidgetWrapper::compatibleParameterTypes() const
358 {
359  return QStringList()
361 }
362 
363 QStringList QgsProcessingTinInputLayersWidgetWrapper::compatibleOutputTypes() const {return QStringList();}
364 
365 QWidget *QgsProcessingTinInputLayersWidgetWrapper::createWidget()
366 {
367  mWidget = new QgsProcessingTinInputLayersWidget( widgetContext().project() );
368  connect( mWidget, &QgsProcessingTinInputLayersWidget::changed, this, [ = ]
369  {
370  emit widgetValueHasChanged( this );
371  } );
372 
373  return mWidget;
374 }
375 
376 void QgsProcessingTinInputLayersWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
377 {
378  if ( !mWidget )
379  return;
380  mWidget->setValue( value );
381  mWidget->setProject( context.project() );
382 }
383 
384 QVariant QgsProcessingTinInputLayersWidgetWrapper::widgetValue() const
385 {
386  if ( mWidget )
387  return mWidget->value();
388  else
389  return QVariant();
390 }
391 
A widget wrapper for Processing parameter value widgets.
QString name
Definition: qgsfield.h:60
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
void layerChanged(QgsMapLayer *layer)
Emitted whenever the currently selected layer changes.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString name
Definition: qgsmaplayer.h:76
bool isValid
Definition: qgsmaplayer.h:81
Contains information about the context in which a processing algorithm is executed.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
WidgetType
Types of dialogs which Processing widgets can be created for.
Base class for the definition of processing parameters.
@ BreakLines
Input that adds vertices and break lines.
static QString typeName()
Returns the type name for the parameter class.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:101
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:467
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
This is the base class for vector data providers.
QgsWkbTypes::Type wkbType() const override=0
Returns the geometry type which is returned by this layer.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1050
Used to store input layer Id and other associated parameters.