QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 #include "qgsrendercontext.h"
36 
37 QgsVectorLayer *QgsAttributeTableDelegate::layer( const QAbstractItemModel *model )
38 {
39  const QgsAttributeTableModel *tm = qobject_cast<const QgsAttributeTableModel *>( model );
40  if ( tm )
41  return tm->layer();
42 
43  const QgsAttributeTableFilterModel *fm = qobject_cast<const QgsAttributeTableFilterModel *>( model );
44  if ( fm )
45  return fm->layer();
46 
47  return nullptr;
48 }
49 
50 const QgsAttributeTableModel *QgsAttributeTableDelegate::masterModel( const QAbstractItemModel *model )
51 {
52  const QgsAttributeTableModel *tm = qobject_cast<const QgsAttributeTableModel *>( model );
53  if ( tm )
54  return tm;
55 
56  const QgsAttributeTableFilterModel *fm = qobject_cast<const QgsAttributeTableFilterModel *>( model );
57  if ( fm )
58  return fm->masterModel();
59 
60  return nullptr;
61 }
62 
63 QWidget *QgsAttributeTableDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
64 {
65  Q_UNUSED( option )
66  QgsVectorLayer *vl = layer( index.model() );
67  if ( !vl )
68  return nullptr;
69 
70  const int fieldIdx = index.model()->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt();
71  QgsAttributeEditorContext context( masterModel( index.model() )->editorContext(), QgsAttributeEditorContext::Popup );
72 
73  // Update the editor form context with the feature being edited
74  const QgsFeatureId fid( index.model()->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong() );
75  context.setFormFeature( vl->getFeature( fid ) );
76 
77  QgsEditorWidgetWrapper *eww = QgsGui::editorWidgetRegistry()->create( vl, fieldIdx, nullptr, parent, context );
78  QWidget *w = eww->widget();
79 
80  w->setAutoFillBackground( true );
81  w->setFocusPolicy( Qt::StrongFocus ); // to make sure QMouseEvents are propagated to the editor widget
82 
83  const int fieldOrigin = vl->fields().fieldOrigin( fieldIdx );
84  bool readOnly = true;
85  if ( fieldOrigin == QgsFields::OriginJoin )
86  {
87  int srcFieldIndex;
88  const QgsVectorLayerJoinInfo *info = vl->joinBuffer()->joinForFieldIndex( fieldIdx, vl->fields(), srcFieldIndex );
89 
90  if ( info && info->isEditable() )
91  readOnly = info->joinLayer()->editFormConfig().readOnly( srcFieldIndex );
92  }
93  else
94  readOnly = vl->editFormConfig().readOnly( fieldIdx );
95 
96  eww->setEnabled( !readOnly );
97 
98  return w;
99 }
100 
101 void QgsAttributeTableDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
102 {
103  QgsVectorLayer *vl = layer( model );
104  if ( !vl )
105  return;
106 
107  const int fieldIdx = model->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt();
108  const QgsFeatureId fid = model->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong();
109  const QVariant oldValue = model->data( index, Qt::EditRole );
110 
112  if ( !eww )
113  return;
114 
115  QList<int> indexes = QList<int>() << fieldIdx;
116  QVariantList newValues = QVariantList() << eww->value();
117  const QStringList additionalFields = eww->additionalFields();
118  for ( const QString &fieldName : additionalFields )
119  {
120  indexes << eww->layer()->fields().lookupField( fieldName );
121  }
122  newValues.append( eww->additionalFieldValues() );
123 
124  if ( ( oldValue != newValues.at( 0 ) && newValues.at( 0 ).isValid() )
125  || oldValue.isNull() != newValues.at( 0 ).isNull()
126  || newValues.count() > 1 )
127  {
128  // This fixes https://github.com/qgis/QGIS/issues/24398
129  QgsFeatureRequest request( fid );
131  QgsFeature feature;
132  vl->getFeatures( request ).nextFeature( feature );
133  if ( feature.isValid() )
134  {
135  vl->beginEditCommand( tr( "Attribute changed" ) );
136  for ( int i = 0; i < newValues.count(); i++ )
137  vl->changeAttributeValue( fid, indexes.at( i ), newValues.at( i ), feature.attribute( indexes.at( i ) ) );
138  vl->endEditCommand();
139  }
140  }
141 }
142 
143 void QgsAttributeTableDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
144 {
146  if ( !eww )
147  return;
148 
149  const QVariant value = index.model()->data( index, Qt::EditRole );
150  const QStringList additionalFields = eww->additionalFields();
151 
152  if ( !additionalFields.empty() )
153  {
154  const QgsAttributeTableModel *model = masterModel( index.model() );
155  if ( model )
156  {
157  const QgsFeature feat = model->feature( index );
158  QVariantList additionalFieldValues;
159  for ( const QString &fieldName : additionalFields )
160  {
161  additionalFieldValues << feat.attribute( fieldName );
162  }
163  eww->setValues( value, additionalFieldValues );
164  }
165  }
166  else
167  {
168  eww->setValues( value, QVariantList() );
169  }
170 }
171 
173 {
174  mFeatureSelectionModel = featureSelectionModel;
175 }
176 
177 void QgsAttributeTableDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
178 {
179  const QgsAttributeTableFilterModel::ColumnType columnType = static_cast<QgsAttributeTableFilterModel::ColumnType>( index.model()->data( index, QgsAttributeTableFilterModel::TypeRole ).toInt() );
180 
182  {
183  emit actionColumnItemPainted( index );
184  }
185  else
186  {
187  const QgsFeatureId fid = index.model()->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong();
188 
189  QStyleOptionViewItem myOpt = option;
190 
191  if ( index.model()->data( index, Qt::EditRole ).isNull() )
192  {
193  myOpt.font.setItalic( true );
194  myOpt.palette.setColor( QPalette::Text, QColor( "gray" ) );
195  }
196 
197  if ( mFeatureSelectionModel && mFeatureSelectionModel->isSelected( fid ) )
198  myOpt.state |= QStyle::State_Selected;
199 
200  QItemDelegate::paint( painter, myOpt, index );
201 
202  if ( option.state & QStyle::State_HasFocus )
203  {
204  const QRect r = option.rect.adjusted( 1, 1, -1, -1 );
205  const QPen p( QBrush( QColor( 0, 255, 127 ) ), 2 );
206  const QgsScopedQPainterState painterState( painter );
207  painter->setPen( p );
208  painter->drawRect( r );
209  }
210  }
211 }
QgsFeatureRequest::NoGeometry
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition: qgsfeaturerequest.h:115
QgsVectorLayer::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Definition: qgsvectorlayer.cpp:1052
QgsGui::editorWidgetRegistry
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
Definition: qgsgui.cpp:85
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:31
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:172
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:63
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:425
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:3852
QgsWidgetWrapper::widget
QWidget * widget()
Access the widget managed by this wrapper.
Definition: qgswidgetwrapper.cpp:47
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:3072
QgsEditorWidgetWrapper
Manages an editor widget Widget and wrapper share the same parent.
Definition: qgseditorwidgetwrapper.h:47
qgsvectorlayerjoininfo.h
QgsAttributeTableDelegate::setEditorData
void setEditorData(QWidget *editor, const QModelIndex &index) const override
Sets data from model into the editor.
Definition: qgsattributetabledelegate.cpp:143
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3436
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:83
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:3868
QgsAttributeTableDelegate::setModelData
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
Sets data from editor back to model.
Definition: qgsattributetabledelegate.cpp:101
QgsWidgetWrapper::layer
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
Definition: qgswidgetwrapper.cpp:92
qgsvectorlayerjoinbuffer.h
qgsactionmanager.h
QgsFeature::isValid
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:216
QgsAttributeTableFilterModel::layer
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
Definition: qgsattributetablefiltermodel.h:160
QgsAttributeTableModel
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
Definition: qgsattributetablemodel.h:49
qgsattributetablefiltermodel.h
QgsFields::fieldOrigin
FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
Definition: qgsfields.cpp:189
qgsrendercontext.h
qgsvectordataprovider.h
QgsAttributeTableFilterModel::masterModel
QgsAttributeTableModel * masterModel() const
Returns the table model this filter is using.
Definition: qgsattributetablefiltermodel.h:174
QgsVectorLayerJoinInfo::isEditable
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer.
Definition: qgsvectorlayerjoininfo.h:108
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:327
qgsattributetablemodel.h
QgsVectorLayerJoinInfo
Defines left outer join from our vector layer to some other vector layer. The join is done based on [...
Definition: qgsvectorlayerjoininfo.h:33
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:1336
QgsAttributeTableFilterModel::TypeRole
@ TypeRole
The type of a given column.
Definition: qgsattributetablefiltermodel.h:72
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:99
qgsfeatureselectionmodel.h
qgseditorwidgetregistry.h
QgsAttributeTableFilterModel::ColumnTypeActionButton
@ ColumnTypeActionButton
This column shows action buttons.
Definition: qgsattributetablefiltermodel.h:61
QgsAttributeTableModel::feature
QgsFeature feature(const QModelIndex &idx) const
Returns the feature attributes at given model index.
Definition: qgsattributetablemodel.cpp:931
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:399
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsVectorLayer::editFormConfig
QgsEditFormConfig editFormConfig
Definition: qgsvectorlayer.h:398
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:177
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:58
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 unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsVectorLayer::getFeature
QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
Definition: qgsvectorlayer.h:1187
qgslogger.h
QgsFields::lookupField
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:349
QgsAttributeEditorContext
This class contains context information for attribute editor widgets. It will be passed to embedded w...
Definition: qgsattributeeditorcontext.h:40
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:222
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:663
QgsFeatureId
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28