QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsfieldmappingwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfieldmappingwidget.cpp - QgsFieldMappingWidget
3 
4  ---------------------
5  begin : 16.3.2020
6  copyright : (C) 2020 by Alessandro Pasotti
7  email : elpaso at itopen dot it
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgsfieldmappingwidget.h"
19 #include "qgsexpression.h"
21 #include "qgsvectorlayer.h"
22 #include "qgsvectordataprovider.h"
23 
24 #include <QTableView>
25 #include <QVBoxLayout>
26 
27 #ifdef ENABLE_MODELTEST
28 #include "modeltest.h"
29 #endif
30 
32  const QgsFields &sourceFields,
33  const QgsFields &destinationFields,
34  const QMap<QString, QString> &expressions )
35  : QgsPanelWidget( parent )
36 {
37  QVBoxLayout *verticalLayout = new QVBoxLayout();
38  verticalLayout->setContentsMargins( 0, 0, 0, 0 );
39  mTableView = new QTableView();
40  verticalLayout->addWidget( mTableView );
41  setLayout( verticalLayout );
42 
43  mModel = new QgsFieldMappingModel( sourceFields, destinationFields, expressions, this );
44 
45 #ifdef ENABLE_MODELTEST
46  new ModelTest( mModel, this );
47 #endif
48 
49  mTableView->setModel( mModel );
50  mTableView->setItemDelegateForColumn( static_cast<int>( QgsFieldMappingModel::ColumnDataIndex::SourceExpression ), new ExpressionDelegate( this ) );
51  mTableView->setItemDelegateForColumn( static_cast<int>( QgsFieldMappingModel::ColumnDataIndex::DestinationType ), new TypeDelegate( mTableView ) );
52  updateColumns();
53  // Make sure columns are updated when rows are added
54  connect( mModel, &QgsFieldMappingModel::rowsInserted, this, [ = ] { updateColumns(); } );
55  connect( mModel, &QgsFieldMappingModel::modelReset, this, [ = ] { updateColumns(); } );
56  connect( mModel, &QgsFieldMappingModel::dataChanged, this, &QgsFieldMappingWidget::changed );
57  connect( mModel, &QgsFieldMappingModel::rowsInserted, this, &QgsFieldMappingWidget::changed );
58  connect( mModel, &QgsFieldMappingModel::rowsRemoved, this, &QgsFieldMappingWidget::changed );
59  connect( mModel, &QgsFieldMappingModel::modelReset, this, &QgsFieldMappingWidget::changed );
60 }
61 
63 {
64  qobject_cast<QgsFieldMappingModel *>( mModel )->setDestinationEditable( editable );
65  updateColumns();
66 }
67 
69 {
70  return qobject_cast<QgsFieldMappingModel *>( mModel )->destinationEditable();
71 }
72 
74 {
75  return qobject_cast<QgsFieldMappingModel *>( mModel );
76 }
77 
78 QList<QgsFieldMappingModel::Field> QgsFieldMappingWidget::mapping() const
79 {
80  return model()->mapping();
81 }
82 
83 QMap<QString, QgsProperty> QgsFieldMappingWidget::fieldPropertyMap() const
84 {
85  return model()->fieldPropertyMap();
86 }
87 
88 void QgsFieldMappingWidget::setFieldPropertyMap( const QMap<QString, QgsProperty> &map )
89 {
90  model()->setFieldPropertyMap( map );
91 }
92 
94 {
95  return mTableView->selectionModel();
96 }
97 
99 {
101 }
102 
104 {
105  mSourceLayer = layer;
106 }
107 
109 {
110  return mSourceLayer;
111 }
112 
113 void QgsFieldMappingWidget::setDestinationFields( const QgsFields &destinationFields, const QMap<QString, QString> &expressions )
114 {
115  model()->setDestinationFields( destinationFields, expressions );
116 }
117 
118 void QgsFieldMappingWidget::scrollTo( const QModelIndex &index ) const
119 {
120  mTableView->scrollTo( index );
121 }
122 
124 {
126 }
127 
128 void QgsFieldMappingWidget::appendField( const QgsField &field, const QString &expression )
129 {
130  model()->appendField( field, expression );
131 }
132 
134 {
135  if ( ! mTableView->selectionModel()->hasSelection() )
136  return false;
137 
138  std::list<int> rowsToRemove { selectedRows() };
139  rowsToRemove.reverse();
140  for ( const int row : rowsToRemove )
141  {
142  if ( ! model()->removeField( model()->index( row, 0, QModelIndex() ) ) )
143  {
144  return false;
145  }
146  }
147  return true;
148 }
149 
151 {
152  if ( ! mTableView->selectionModel()->hasSelection() )
153  return false;
154 
155  const std::list<int> rowsToMoveUp { selectedRows() };
156  for ( const int row : rowsToMoveUp )
157  {
158  if ( ! model()->moveUp( model()->index( row, 0, QModelIndex() ) ) )
159  {
160  return false;
161  }
162  }
163  return true;
164 }
165 
167 {
168  if ( ! mTableView->selectionModel()->hasSelection() )
169  return false;
170 
171  std::list<int> rowsToMoveDown { selectedRows() };
172  rowsToMoveDown.reverse();
173  for ( const int row : rowsToMoveDown )
174  {
175  if ( ! model()->moveDown( model()->index( row, 0, QModelIndex() ) ) )
176  {
177  return false;
178  }
179  }
180  return true;
181 }
182 
183 void QgsFieldMappingWidget::updateColumns()
184 {
185  for ( int i = 0; i < mModel->rowCount(); ++i )
186  {
187  mTableView->openPersistentEditor( mModel->index( i, static_cast<int>( QgsFieldMappingModel::ColumnDataIndex::SourceExpression ) ) );
188  mTableView->openPersistentEditor( mModel->index( i, static_cast<int>( QgsFieldMappingModel::ColumnDataIndex::DestinationType ) ) );
189  }
190 
191  for ( int i = 0; i < mModel->columnCount(); ++i )
192  {
193  mTableView->resizeColumnToContents( i );
194  }
195 }
196 
197 std::list<int> QgsFieldMappingWidget::selectedRows()
198 {
199  std::list<int> rows;
200  if ( mTableView->selectionModel()->hasSelection() )
201  {
202  const QModelIndexList constSelection { mTableView->selectionModel()->selectedIndexes() };
203  for ( const QModelIndex &index : constSelection )
204  {
205  rows.push_back( index.row() );
206  }
207  rows.sort();
208  rows.unique();
209  }
210  return rows;
211 }
212 
213 //
214 // ExpressionDelegate
215 //
216 
217 QgsFieldMappingWidget::ExpressionDelegate::ExpressionDelegate( QObject *parent )
218  : QStyledItemDelegate( parent )
219 {
220 }
221 
222 void QgsFieldMappingWidget::ExpressionDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
223 {
224  QgsFieldExpressionWidget *editorWidget { qobject_cast<QgsFieldExpressionWidget *>( editor ) };
225  if ( ! editorWidget )
226  return;
227 
228  bool isExpression;
229  bool isValid;
230  const QString currentValue { editorWidget->currentField( &isExpression, &isValid ) };
231  if ( isExpression )
232  {
233  model->setData( index, currentValue, Qt::EditRole );
234  }
235  else
236  {
237  model->setData( index, QgsExpression::quotedColumnRef( currentValue ), Qt::EditRole );
238  }
239 }
240 
241 void QgsFieldMappingWidget::ExpressionDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
242 {
243  QgsFieldExpressionWidget *editorWidget { qobject_cast<QgsFieldExpressionWidget *>( editor ) };
244  if ( ! editorWidget )
245  return;
246 
247  const QVariant value = index.model()->data( index, Qt::EditRole );
248  editorWidget->setField( value.toString() );
249 }
250 
251 QWidget *QgsFieldMappingWidget::ExpressionDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
252 {
253  Q_UNUSED( option )
254  QgsFieldExpressionWidget *editor = new QgsFieldExpressionWidget( parent );
255  editor->setAutoFillBackground( true );
256  editor->setAllowEvalErrors( false );
257  if ( const QgsFieldMappingModel *model = qobject_cast<const QgsFieldMappingModel *>( index.model() ) )
258  {
259  editor->registerExpressionContextGenerator( model->contextGenerator() );
260  editor->setFields( model->sourceFields() );
261  }
262  else if ( const QgsAggregateMappingModel *model = qobject_cast<const QgsAggregateMappingModel *>( index.model() ) )
263  {
264  editor->registerExpressionContextGenerator( model->contextGenerator() );
265  editor->setFields( model->sourceFields() );
266  }
267  else
268  {
269  Q_ASSERT( false );
270  }
271 
272  if ( QgsFieldMappingWidget *mappingWidget = qobject_cast< QgsFieldMappingWidget *>( ExpressionDelegate::parent() ) )
273  {
274  if ( mappingWidget->sourceLayer() )
275  editor->setLayer( mappingWidget->sourceLayer() );
276  }
277  else if ( QgsAggregateMappingWidget *aggregateWidget = qobject_cast< QgsAggregateMappingWidget *>( ExpressionDelegate::parent() ) )
278  {
279  if ( aggregateWidget->sourceLayer() )
280  editor->setLayer( aggregateWidget->sourceLayer() );
281  }
282 
283  editor->setField( index.model()->data( index, Qt::DisplayRole ).toString() );
284  connect( editor,
285  qOverload<const QString &, bool >( &QgsFieldExpressionWidget::fieldChanged ),
286  this,
287  [ = ]( const QString & fieldName, bool isValid )
288  {
289  Q_UNUSED( fieldName )
290  Q_UNUSED( isValid )
291  const_cast< QgsFieldMappingWidget::ExpressionDelegate *>( this )->emit commitData( editor );
292  } );
293  return editor;
294 }
295 
296 
297 //
298 // TypeDelegate
299 //
300 
301 QgsFieldMappingWidget::TypeDelegate::TypeDelegate( QObject *parent )
302  : QStyledItemDelegate( parent )
303 {
304 }
305 
306 QWidget *QgsFieldMappingWidget::TypeDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
307 {
308  Q_UNUSED( option )
309  QComboBox *editor = new QComboBox( parent );
310 
311  const QList<QgsVectorDataProvider::NativeType> typeList = QgsFieldMappingModel::supportedDataTypes();
312  for ( int i = 0; i < typeList.size(); i++ )
313  {
314  editor->addItem( QgsFields::iconForFieldType( typeList[i].mType, typeList[i].mSubType ), typeList[i].mTypeDesc );
315  editor->setItemData( i, typeList[i].mTypeName, Qt::UserRole );
316  }
317 
318  const QgsFieldMappingModel *model { qobject_cast<const QgsFieldMappingModel *>( index.model() ) };
319 
320  if ( model && !model->destinationEditable() )
321  {
322  editor->setEnabled( false );
323  }
324  else
325  {
326  connect( editor,
327  qOverload<int >( &QComboBox::currentIndexChanged ),
328  this,
329  [ = ]( int currentIndex )
330  {
331  Q_UNUSED( currentIndex )
332  const_cast< QgsFieldMappingWidget::TypeDelegate *>( this )->emit commitData( editor );
333  } );
334  }
335  return editor;
336 }
337 
338 void QgsFieldMappingWidget::TypeDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
339 {
340  QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
341  if ( ! editorWidget )
342  return;
343 
344  const QVariant value = index.model()->data( index, Qt::EditRole );
345  editorWidget->setCurrentIndex( editorWidget->findData( value ) );
346 }
347 
348 void QgsFieldMappingWidget::TypeDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
349 {
350  QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
351  if ( ! editorWidget )
352  return;
353 
354  const QVariant currentValue = editorWidget->currentData( );
355  model->setData( index, currentValue, Qt::EditRole );
356 }
QgsFieldMappingModel::setDestinationFields
void setDestinationFields(const QgsFields &destinationFields, const QMap< QString, QString > &expressions=QMap< QString, QString >())
Set destination fields to destinationFields, initial values for the expressions can be optionally spe...
Definition: qgsfieldmappingmodel.cpp:347
qgsexpression.h
QgsFieldExpressionWidget::currentField
QString currentField(bool *isExpression=nullptr, bool *isValid=nullptr) const
currentField returns the currently selected field or expression if allowed
Definition: qgsfieldexpressionwidget.cpp:144
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:44
QgsFieldMappingWidget::appendField
void appendField(const QgsField &field, const QString &expression=QString())
Appends a new field to the model, with an optional expression.
Definition: qgsfieldmappingwidget.cpp:128
QgsFieldMappingWidget::fieldPropertyMap
QMap< QString, QgsProperty > fieldPropertyMap() const
Returns a map of destination field name to QgsProperty definition for field value,...
Definition: qgsfieldmappingwidget.cpp:83
QgsFieldMappingWidget::destinationEditable
bool destinationEditable() const
Returns true if the destination fields are editable in the model.
Definition: qgsfieldmappingwidget.cpp:68
field
const QgsField & field
Definition: qgsfield.h:463
QgsAggregateMappingModel::moveUp
bool moveUp(const QModelIndex &index)
Moves down the field at index.
Definition: qgsprocessingaggregatewidgets.cpp:341
QgsAggregateMappingWidget
The QgsAggregateMappingWidget class creates a mapping for defining sets of aggregates of fields from ...
Definition: qgsprocessingaggregatewidgets.h:149
QgsFieldMappingModel::supportedDataTypes
static const QList< QgsVectorDataProvider::NativeType > supportedDataTypes()
Returns a static list of supported data types.
Definition: qgsfieldmappingmodel.cpp:409
QgsFieldExpressionWidget::registerExpressionContextGenerator
void registerExpressionContextGenerator(const QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
Definition: qgsfieldexpressionwidget.cpp:165
QgsFieldMappingWidget::setDestinationFields
void setDestinationFields(const QgsFields &destinationFields, const QMap< QString, QString > &expressions=QMap< QString, QString >())
Set destination fields to destinationFields in the underlying model, initial values for the expressio...
Definition: qgsfieldmappingwidget.cpp:113
QgsFieldMappingModel
The QgsFieldMappingModel holds mapping information for mapping from one set of QgsFields to another,...
Definition: qgsfieldmappingmodel.h:40
QgsFieldMappingModel::mapping
QList< QgsFieldMappingModel::Field > mapping() const
Returns a list of Field objects representing the current status of the model.
Definition: qgsfieldmappingmodel.cpp:456
QgsFieldMappingModel::appendField
void appendField(const QgsField &field, const QString &expression=QString())
Appends a new field to the model, with an optional expression.
Definition: qgsfieldmappingmodel.cpp:511
QgsFieldMappingModel::setBaseExpressionContextGenerator
void setBaseExpressionContextGenerator(const QgsExpressionContextGenerator *generator)
Sets the base expression context generator, which will generate the expression contexts for expressio...
Definition: qgsfieldmappingmodel.cpp:342
QgsAggregateMappingModel::sourceFields
QgsFields sourceFields() const
Returns a list of source fields.
Definition: qgsprocessingaggregatewidgets.cpp:92
QgsPanelWidget
Base class for any widget that can be shown as a inline panel.
Definition: qgspanelwidget.h:29
QgsFieldMappingWidget::scrollTo
void scrollTo(const QModelIndex &index) const
Scroll the fields view to index.
Definition: qgsfieldmappingwidget.cpp:118
QgsFieldMappingWidget::setFieldPropertyMap
void setFieldPropertyMap(const QMap< QString, QgsProperty > &map)
Sets a map of destination field name to QgsProperty definition for field value.
Definition: qgsfieldmappingwidget.cpp:88
QgsFieldMappingWidget::selectionModel
QItemSelectionModel * selectionModel()
Returns the selection model.
Definition: qgsfieldmappingwidget.cpp:93
QgsFieldMappingWidget::setSourceLayer
void setSourceLayer(QgsVectorLayer *layer)
Sets a source layer to use when generating expression previews in the widget.
Definition: qgsfieldmappingwidget.cpp:103
QgsFieldMappingWidget::mapping
QList< QgsFieldMappingModel::Field > mapping() const
Returns a list of Field objects representing the current status of the underlying mapping model.
Definition: qgsfieldmappingwidget.cpp:78
QgsFieldExpressionWidget::fieldChanged
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
QgsFieldMappingWidget::QgsFieldMappingWidget
QgsFieldMappingWidget(QWidget *parent=nullptr, const QgsFields &sourceFields=QgsFields(), const QgsFields &destinationFields=QgsFields(), const QMap< QString, QString > &expressions=QMap< QString, QString >())
Constructs a QgsFieldMappingWidget from a set of sourceFields and destinationFields,...
Definition: qgsfieldmappingwidget.cpp:31
QgsFieldMappingWidget::sourceLayer
QgsVectorLayer * sourceLayer()
Returns the source layer for use when generating expression previews.
Definition: qgsfieldmappingwidget.cpp:108
qgsvectordataprovider.h
QgsAggregateMappingModel::removeField
bool removeField(const QModelIndex &index)
Removes the field at index from the model, returns true on success.
Definition: qgsprocessingaggregatewidgets.cpp:326
qgsfieldmappingwidget.h
QgsFieldMappingModel::setFieldPropertyMap
void setFieldPropertyMap(const QMap< QString, QgsProperty > &map)
Sets a map of destination field name to QgsProperty definition for field value.
Definition: qgsfieldmappingmodel.cpp:475
QgsFieldMappingWidget::setDestinationEditable
void setDestinationEditable(bool editable)
Sets the destination fields editable state to editable.
Definition: qgsfieldmappingwidget.cpp:62
QgsFieldMappingWidget::setSourceFields
void setSourceFields(const QgsFields &sourceFields)
Set source fields of the underlying mapping model to sourceFields.
Definition: qgsfieldmappingwidget.cpp:98
QgsFieldExpressionWidget::setField
void setField(const QString &fieldName)
sets the current field or expression in the widget
Definition: qgsfieldexpressionwidget.cpp:188
QgsAggregateMappingModel::moveDown
bool moveDown(const QModelIndex &index)
Moves up the field at index.
Definition: qgsprocessingaggregatewidgets.cpp:346
QgsFields::iconForFieldType
static QIcon iconForFieldType(QVariant::Type type, QVariant::Type subType=QVariant::Type::Invalid)
Returns an icon corresponding to a field type.
Definition: qgsfields.cpp:294
QgsFieldExpressionWidget::setFields
void setFields(const QgsFields &fields)
Sets the fields used in the widget to fields, this allows the widget to work without a layer.
Definition: qgsfieldexpressionwidget.cpp:221
qgsprocessingaggregatewidgets.h
qgsvectorlayer.h
QgsFieldMappingWidget::registerExpressionContextGenerator
void registerExpressionContextGenerator(const QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
Definition: qgsfieldmappingwidget.cpp:123
QgsFieldMappingModel::ColumnDataIndex::SourceExpression
@ SourceExpression
Expression.
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsFieldMappingWidget::removeSelectedFields
bool removeSelectedFields()
Removes the currently selected field from the model.
Definition: qgsfieldmappingwidget.cpp:133
QgsFieldMappingWidget::model
QgsFieldMappingModel * model() const
Returns the underlying mapping model.
Definition: qgsfieldmappingwidget.cpp:73
QgsFieldMappingModel::data
QVariant data(const QModelIndex &index, int role) const override
Definition: qgsfieldmappingmodel.cpp:98
QgsExpression::quotedColumnRef
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Definition: qgsexpression.cpp:68
QgsAggregateMappingModel
The QgsAggregateMappingModel holds mapping information for defining sets of aggregates of fields from...
Definition: qgsprocessingaggregatewidgets.h:41
qgsfieldexpressionwidget.h
QgsFieldMappingModel::fieldPropertyMap
QMap< QString, QgsProperty > fieldPropertyMap() const
Returns a map of destination field name to QgsProperty definition for field value,...
Definition: qgsfieldmappingmodel.cpp:461
QgsFieldExpressionWidget::setAllowEvalErrors
void setAllowEvalErrors(bool allowEvalErrors)
Allow accepting expressions with evaluation errors.
Definition: qgsfieldexpressionwidget.cpp:316
QgsFieldMappingModel::setSourceFields
void setSourceFields(const QgsFields &sourceFields)
Set source fields to sourceFields.
Definition: qgsfieldmappingmodel.cpp:311
QgsFieldMappingWidget::moveSelectedFieldsDown
bool moveSelectedFieldsDown()
Moves down the currently selected field.
Definition: qgsfieldmappingwidget.cpp:166
QgsFieldMappingWidget::changed
void changed()
Emitted when the fields defined in the widget are changed.
QgsFieldMappingWidget::moveSelectedFieldsUp
bool moveSelectedFieldsUp()
Moves up currently selected field.
Definition: qgsfieldmappingwidget.cpp:150
QgsFieldExpressionWidget
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
Definition: qgsfieldexpressionwidget.h:46
QgsExpressionContextGenerator
Abstract interface for generating an expression context.
Definition: qgsexpressioncontextgenerator.h:36
QgsFieldExpressionWidget::setLayer
void setLayer(QgsMapLayer *layer)
Sets the layer used to display the fields and expression.
Definition: qgsfieldexpressionwidget.cpp:170
QgsFieldMappingWidget
The QgsFieldMappingWidget class creates a mapping from one set of QgsFields to another,...
Definition: qgsfieldmappingwidget.h:39
QgsFieldMappingModel::ColumnDataIndex::DestinationType
@ DestinationType
Destination field type string.
QgsField
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:50