QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsattributetabledelegate.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  QgsAttributeTableDelegate.cpp
3  --------------------------------------
4  Date : Feb 2009
5  Copyright : (C) 2009 Vita Cizek
6  Email : weetya (at) gmail.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 
16 #include <QItemDelegate>
17 #include <QLineEdit>
18 #include <QComboBox>
19 #include <QPainter>
20 #include <QToolButton>
21 
24 #include "qgsattributetablemodel.h"
25 #include "qgsattributetableview.h"
27 #include "qgseditorwidgetwrapper.h"
29 #include "qgslogger.h"
30 #include "qgsvectordataprovider.h"
31 #include "qgsactionmanager.h"
32 #include "qgsgui.h"
33 #include "qgsvectorlayerjoininfo.h"
35 
36 QgsVectorLayer *QgsAttributeTableDelegate::layer( const QAbstractItemModel *model )
37 {
38  const QgsAttributeTableModel *tm = qobject_cast<const QgsAttributeTableModel *>( model );
39  if ( tm )
40  return tm->layer();
41 
42  const QgsAttributeTableFilterModel *fm = qobject_cast<const QgsAttributeTableFilterModel *>( model );
43  if ( fm )
44  return fm->layer();
45 
46  return nullptr;
47 }
48 
49 const QgsAttributeTableModel *QgsAttributeTableDelegate::masterModel( const QAbstractItemModel *model )
50 {
51  const QgsAttributeTableModel *tm = qobject_cast<const QgsAttributeTableModel *>( model );
52  if ( tm )
53  return tm;
54 
55  const QgsAttributeTableFilterModel *fm = qobject_cast<const QgsAttributeTableFilterModel *>( model );
56  if ( fm )
57  return fm->masterModel();
58 
59  return nullptr;
60 }
61 
62 QWidget *QgsAttributeTableDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
63 {
64  Q_UNUSED( option )
65  QgsVectorLayer *vl = layer( index.model() );
66  if ( !vl )
67  return nullptr;
68 
69  int fieldIdx = index.model()->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt();
70  QgsAttributeEditorContext context( masterModel( index.model() )->editorContext(), QgsAttributeEditorContext::Popup );
71 
72  // Update the editor form context with the feature being edited
73  QgsFeatureId fid( index.model()->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong() );
74  context.setFormFeature( vl->getFeature( fid ) );
75 
76  QgsEditorWidgetWrapper *eww = QgsGui::editorWidgetRegistry()->create( vl, fieldIdx, nullptr, parent, context );
77  QWidget *w = eww->widget();
78 
79  w->setAutoFillBackground( true );
80  w->setFocusPolicy( Qt::StrongFocus ); // to make sure QMouseEvents are propagated to the editor widget
81 
82  const int fieldOrigin = vl->fields().fieldOrigin( fieldIdx );
83  bool readOnly = true;
84  if ( fieldOrigin == QgsFields::OriginJoin )
85  {
86  int srcFieldIndex;
87  const QgsVectorLayerJoinInfo *info = vl->joinBuffer()->joinForFieldIndex( fieldIdx, vl->fields(), srcFieldIndex );
88 
89  if ( info && info->isEditable() )
90  readOnly = info->joinLayer()->editFormConfig().readOnly( srcFieldIndex );
91  }
92  else
93  readOnly = vl->editFormConfig().readOnly( fieldIdx );
94 
95  eww->setEnabled( !readOnly );
96 
97  return w;
98 }
99 
100 void QgsAttributeTableDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
101 {
102  QgsVectorLayer *vl = layer( model );
103  if ( !vl )
104  return;
105 
106  int fieldIdx = model->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt();
107  QgsFeatureId fid = model->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong();
108  QVariant oldValue = model->data( index, Qt::EditRole );
109 
111  if ( !eww )
112  return;
113 
114  QList<int> indexes = QList<int>() << fieldIdx;
115  QVariantList newValues = QVariantList() << eww->value();
116  const QStringList additionalFields = eww->additionalFields();
117  for ( const QString &fieldName : additionalFields )
118  {
119  indexes << eww->layer()->fields().lookupField( fieldName );
120  }
121  newValues.append( eww->additionalFieldValues() );
122 
123  if ( ( oldValue != newValues.at( 0 ) && newValues.at( 0 ).isValid() )
124  || oldValue.isNull() != newValues.at( 0 ).isNull()
125  || newValues.count() > 1 )
126  {
127  // This fixes https://github.com/qgis/QGIS/issues/24398
128  QgsFeatureRequest request( fid );
130  QgsFeature feature;
131  vl->getFeatures( request ).nextFeature( feature );
132  if ( feature.isValid() )
133  {
134  vl->beginEditCommand( tr( "Attribute changed" ) );
135  for ( int i = 0; i < newValues.count(); i++ )
136  vl->changeAttributeValue( fid, indexes.at( i ), newValues.at( i ), feature.attribute( indexes.at( i ) ) );
137  vl->endEditCommand();
138  }
139  }
140 }
141 
142 void QgsAttributeTableDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
143 {
145  if ( !eww )
146  return;
147 
148  QVariant value = index.model()->data( index, Qt::EditRole );
149  const QStringList additionalFields = eww->additionalFields();
150 
151  if ( !additionalFields.empty() )
152  {
153  const QgsAttributeTableModel *model = masterModel( index.model() );
154  if ( model )
155  {
156  QgsFeature feat = model->feature( index );
157  QVariantList additionalFieldValues;
158  for ( QString fieldName : additionalFields )
159  {
160  additionalFieldValues << feat.attribute( fieldName );
161  }
162  eww->setValues( value, additionalFieldValues );
163  }
164  }
165  else
166  {
167  eww->setValues( value, QVariantList() );
168  }
169 }
170 
172 {
173  mFeatureSelectionModel = featureSelectionModel;
174 }
175 
176 void QgsAttributeTableDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
177 {
179 
181  {
182  emit actionColumnItemPainted( index );
183  }
184  else
185  {
186  QgsFeatureId fid = index.model()->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong();
187 
188  QStyleOptionViewItem myOpt = option;
189 
190  if ( index.model()->data( index, Qt::EditRole ).isNull() )
191  {
192  myOpt.font.setItalic( true );
193  myOpt.palette.setColor( QPalette::Text, QColor( "gray" ) );
194  }
195 
196  if ( mFeatureSelectionModel && mFeatureSelectionModel->isSelected( fid ) )
197  myOpt.state |= QStyle::State_Selected;
198 
199  QItemDelegate::paint( painter, myOpt, index );
200 
201  if ( option.state & QStyle::State_HasFocus )
202  {
203  QRect r = option.rect.adjusted( 1, 1, -1, -1 );
204  QPen p( QBrush( QColor( 0, 255, 127 ) ), 2 );
205  QgsScopedQPainterState painterState( painter );
206  painter->setPen( p );
207  painter->drawRect( r );
208  }
209  }
210 }
QgsFeatureRequest::NoGeometry
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition: qgsfeaturerequest.h:81
QgsVectorLayer::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Definition: qgsvectorlayer.cpp:993
QgsGui::editorWidgetRegistry
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
Definition: qgsgui.cpp:74
qgseditorwidgetwrapper.h
QgsEditorWidgetWrapper::setValues
void setValues(const QVariant &value, const QVariantList &additionalValues)
Is called when the value of the widget or additional field values needs to be changed.
Definition: qgseditorwidgetwrapper.cpp:86
QgsFeatureSelectionModel
Definition: qgsfeatureselectionmodel.h:32
qgsattributetableview.h
qgsgui.h
QgsFeatureSelectionModel::isSelected
virtual bool isSelected(QgsFeatureId fid)
Returns the selection status of a given feature id.
Definition: qgsfeatureselectionmodel.cpp:53
QgsEditorWidgetWrapper::additionalFieldValues
virtual QVariantList additionalFieldValues() const
Will be used to access the widget's values for potential additional fields handled by the widget.
Definition: qgseditorwidgetwrapper.h:100
QgsAttributeTableDelegate::setFeatureSelectionModel
void setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)
Definition: qgsattributetabledelegate.cpp:171
QgsAttributeTableDelegate::createEditor
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Used to create an editor for when the user tries to change the contents of a cell.
Definition: qgsattributetabledelegate.cpp:62
QgsEditorWidgetWrapper::value
virtual QVariant value() const =0
Will be used to access the widget's value.
QgsVectorLayerJoinBuffer::joinForFieldIndex
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
Definition: qgsvectorlayerjoinbuffer.cpp:397
QgsEditorWidgetWrapper::additionalFields
virtual QStringList additionalFields() const
Returns the list of additional fields which the editor handles.
Definition: qgseditorwidgetwrapper.h:92
QgsAttributeTableModel::editorContext
const QgsAttributeEditorContext & editorContext() const
Returns the context in which this table is shown.
Definition: qgsattributetablemodel.h:245
QgsVectorLayer::beginEditCommand
void beginEditCommand(const QString &text)
Create edit command for undo/redo operations.
Definition: qgsvectorlayer.cpp:3667
QgsWidgetWrapper::widget
QWidget * widget()
Access the widget managed by this wrapper.
Definition: qgswidgetwrapper.cpp:46
QgsVectorLayer::changeAttributeValue
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false)
Changes an attribute value for a feature (but does not immediately commit the changes).
Definition: qgsvectorlayer.cpp:2966
QgsEditorWidgetWrapper
Manages an editor widget Widget and wrapper share the same parent.
Definition: qgseditorwidgetwrapper.h:48
qgsvectorlayerjoininfo.h
QgsAttributeTableDelegate::setEditorData
void setEditorData(QWidget *editor, const QModelIndex &index) const override
Sets data from model into the editor.
Definition: qgsattributetabledelegate.cpp:142
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3283
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:76
QgsAttributeTableFilterModel::ColumnType
ColumnType
The type of a column.
Definition: qgsattributetablefiltermodel.h:58
QgsAttributeTableModel::FieldIndexRole
@ FieldIndexRole
Get the field index of this column.
Definition: qgsattributetablemodel.h:57
QgsVectorLayer::endEditCommand
void endEditCommand()
Finish edit command and add it to undo/redo stack.
Definition: qgsvectorlayer.cpp:3683
QgsAttributeTableDelegate::setModelData
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
Sets data from editor back to model.
Definition: qgsattributetabledelegate.cpp:100
QgsWidgetWrapper::layer
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
Definition: qgswidgetwrapper.cpp:91
qgsvectorlayerjoinbuffer.h
qgsactionmanager.h
QgsFeature::isValid
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:185
QgsAttributeTableFilterModel::layer
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
Definition: qgsattributetablefiltermodel.h:150
QgsAttributeTableModel
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
Definition: qgsattributetablemodel.h:50
qgsattributetablefiltermodel.h
QgsFields::fieldOrigin
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field's origin (value from an enumeration)
Definition: qgsfields.cpp:189
qgsvectordataprovider.h
QgsAttributeTableFilterModel::masterModel
QgsAttributeTableModel * masterModel() const
Returns the table model this filter is using.
Definition: qgsattributetablefiltermodel.h:164
QgsVectorLayerJoinInfo::isEditable
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer.
Definition: qgsvectorlayerjoininfo.h:95
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:264
qgsattributetablemodel.h
QgsVectorLayerJoinInfo
Defines left outer join from our vector layer to some other vector layer.
Definition: qgsvectorlayerjoininfo.h:34
QgsAttributeTableModel::layer
QgsVectorLayer * layer() const
Returns the layer this model uses as backend.
Definition: qgsattributetablemodel.h:168
QgsScopedQPainterState
Scoped object for saving and restoring a QPainter object's state.
Definition: qgsrendercontext.h:1120
QgsAttributeTableFilterModel::TypeRole
@ TypeRole
The type of a given column.
Definition: qgsattributetablefiltermodel.h:71
QgsEditFormConfig::readOnly
bool readOnly(int idx) const
This returns true if the field is manually set to read only or if the field does not support editing ...
Definition: qgseditformconfig.cpp:234
QgsAttributeEditorContext::Popup
@ Popup
A widget was opened as a popup (e.g. attribute table editor widget)
Definition: qgsattributeeditorcontext.h:74
QgsAttributeTableModel::FeatureIdRole
@ FeatureIdRole
Get the feature id of the feature in this row.
Definition: qgsattributetablemodel.h:56
QgsAttributeTableFilterModel
Definition: qgsattributetablefiltermodel.h:36
QgsEditorWidgetRegistry::create
QgsEditorWidgetWrapper * create(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *editor, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())
Create an attribute editor widget wrapper of a given type for a given field.
Definition: qgseditorwidgetregistry.cpp:97
qgsfeatureselectionmodel.h
qgseditorwidgetregistry.h
QgsAttributeTableFilterModel::ColumnTypeActionButton
@ ColumnTypeActionButton
This column shows action buttons.
Definition: qgsattributetablefiltermodel.h:60
QgsAttributeTableModel::feature
QgsFeature feature(const QModelIndex &idx) const
Returns the feature attributes at given model index.
Definition: qgsattributetablemodel.cpp:865
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:374
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsVectorLayer::editFormConfig
QgsEditFormConfig editFormConfig
Definition: qgsvectorlayer.h:393
QgsAttributeTableDelegate::paint
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Overloads the paint method form the QItemDelegate base class.
Definition: qgsattributetabledelegate.cpp:176
QgsVectorLayerJoinInfo::joinLayer
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet)
Definition: qgsvectorlayerjoininfo.h:45
QgsEditorWidgetWrapper::setEnabled
void setEnabled(bool enabled) override
Is used to enable or disable the edit functionality of the managed widget.
Definition: qgseditorwidgetwrapper.cpp:60
QgsAttributeTableDelegate::actionColumnItemPainted
void actionColumnItemPainted(const QModelIndex &index) const
Emitted when an action column item is painted.
QgsFeature
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QgsVectorLayer::getFeature
QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
Definition: qgsvectorlayer.h:1194
qgslogger.h
QgsFields::lookupField
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
QgsAttributeEditorContext
This class contains context information for attribute editor widgets.
Definition: qgsattributeeditorcontext.h:41
QgsEditorWidgetWrapper::fromWidget
static QgsEditorWidgetWrapper * fromWidget(QWidget *widget)
Will return a wrapper for a given widget.
Definition: qgseditorwidgetwrapper.cpp:55
QgsFeatureRequest::setFlags
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
Definition: qgsfeaturerequest.cpp:179
QgsFields::OriginJoin
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfields.h:52
qgsattributetabledelegate.h
QgsAttributeEditorContext::setFormFeature
void setFormFeature(const QgsFeature &feature)
Set current feature for the currently edited form or table row.
Definition: qgsattributeeditorcontext.h:244
QgsVectorLayer::joinBuffer
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
Definition: qgsvectorlayer.h:652
QgsFeatureId
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28