QGIS API Documentation  3.17.0-Master (a035f434f4)
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 }
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:344
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:185
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
QgsVectorLayer * layer() const
Returns the layer this model uses as backend.
virtual bool isSelected(QgsFeatureId fid)
Returns the selection status of a given feature id.
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfields.h:52
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:189
QgsAttributeTableModel * masterModel() const
Returns the table model this filter is using.
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Overloads the paint method form the QItemDelegate base class.
Get the field index of this column.
void beginEditCommand(const QString &text)
Create edit command for undo/redo operations.
This class contains context information for attribute editor widgets.
Manages an editor widget Widget and wrapper share the same parent.
QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features ...
Definition: qgsfeatureid.h:28
void setEnabled(bool enabled) override
Is used to enable or disable the edit functionality of the managed widget.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
void actionColumnItemPainted(const QModelIndex &index) const
Emitted when an action column item is painted.
void setFormFeature(const QgsFeature &feature)
Set current feature for the currently edited form or table row.
void setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)
Get the feature id of the feature in this row.
QgsFeature feature(const QModelIndex &idx) const
Returns the feature attributes at given model index.
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.
A widget was opened as a popup (e.g. attribute table editor widget)
Scoped object for saving and restoring a QPainter object&#39;s state.
void setEditorData(QWidget *editor, const QModelIndex &index) const override
Sets data from model into the editor.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet) ...
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories...
Definition: qgsgui.cpp:74
static QgsEditorWidgetWrapper * fromWidget(QWidget *widget)
Will return a wrapper for a given widget.
Defines left outer join from our vector layer to some other vector layer.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QgsEditFormConfig editFormConfig
void endEditCommand()
Finish edit command and add it to undo/redo stack.
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.
void setValues(const QVariant &value, const QVariantList &additionalValues)
Is called when the value of the widget or additional field values needs to be changed.
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
virtual QVariantList additionalFieldValues() const
Will be used to access the widget&#39;s values for potential additional fields handled by the widget...
virtual QStringList additionalFields() const
Returns the list of additional fields which the editor handles.
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
Sets data from editor back to model.
virtual QVariant value() const =0
Will be used to access the widget&#39;s value.
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
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).
QWidget * widget()
Access the widget managed by this wrapper.
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 ...
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer. ...
bool nextFeature(QgsFeature &f)
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Represents a vector layer which manages a vector based data sets.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:264
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.