QGIS API Documentation  3.0.2-Girona (307d082)
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 
71  QgsAttributeEditorContext context( masterModel( index.model() )->editorContext(), QgsAttributeEditorContext::Popup );
72  QgsEditorWidgetWrapper *eww = QgsGui::editorWidgetRegistry()->create( vl, fieldIdx, nullptr, parent, context );
73  QWidget *w = eww->widget();
74 
75  w->setAutoFillBackground( true );
76  w->setFocusPolicy( Qt::StrongFocus ); // to make sure QMouseEvents are propagated to the editor widget
77 
78  const int fieldOrigin = vl->fields().fieldOrigin( fieldIdx );
79  bool readOnly = true;
80  if ( fieldOrigin == QgsFields::OriginJoin )
81  {
82  int srcFieldIndex;
83  const QgsVectorLayerJoinInfo *info = vl->joinBuffer()->joinForFieldIndex( fieldIdx, vl->fields(), srcFieldIndex );
84 
85  if ( info && info->isEditable() )
86  readOnly = info->joinLayer()->editFormConfig().readOnly( srcFieldIndex );
87  }
88  else
89  readOnly = vl->editFormConfig().readOnly( fieldIdx );
90 
91  eww->setEnabled( !readOnly );
92 
93  return w;
94 }
95 
96 void QgsAttributeTableDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
97 {
98  QgsVectorLayer *vl = layer( model );
99  if ( !vl )
100  return;
101 
102  int fieldIdx = model->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt();
103  QgsFeatureId fid = model->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong();
104  QVariant oldValue = model->data( index, Qt::EditRole );
105 
106  QVariant newValue;
108  if ( !eww )
109  return;
110 
111  newValue = eww->value();
112 
113  if ( ( oldValue != newValue && newValue.isValid() ) || oldValue.isNull() != newValue.isNull() )
114  {
115  // This fixes https://issues.qgis.org/issues/16492
116  QgsFeatureRequest request( fid );
119  QgsFeature feature;
120  vl->getFeatures( request ).nextFeature( feature );
121  if ( feature.isValid() )
122  {
123  vl->beginEditCommand( tr( "Attribute changed" ) );
124  vl->changeAttributeValue( fid, fieldIdx, newValue, oldValue );
125  vl->endEditCommand();
126  }
127  }
128 }
129 
130 void QgsAttributeTableDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
131 {
133  if ( !eww )
134  return;
135 
136  eww->setValue( index.model()->data( index, Qt::EditRole ) );
137 }
138 
140 {
141  mFeatureSelectionModel = featureSelectionModel;
142 }
143 
144 void QgsAttributeTableDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
145 {
147 
149  {
150  emit actionColumnItemPainted( index );
151  }
152  else
153  {
154  QgsFeatureId fid = index.model()->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong();
155 
156  QStyleOptionViewItem myOpt = option;
157 
158  if ( index.model()->data( index, Qt::EditRole ).isNull() )
159  {
160  myOpt.font.setItalic( true );
161  myOpt.palette.setColor( QPalette::Text, QColor( "gray" ) );
162  }
163 
164  if ( mFeatureSelectionModel && mFeatureSelectionModel->isSelected( fid ) )
165  myOpt.state |= QStyle::State_Selected;
166 
167  QItemDelegate::paint( painter, myOpt, index );
168 
169  if ( option.state & QStyle::State_HasFocus )
170  {
171  QRect r = option.rect.adjusted( 1, 1, -1, -1 );
172  QPen p( QBrush( QColor( 0, 255, 127 ) ), 2 );
173  painter->save();
174  painter->setPen( p );
175  painter->drawRect( r );
176  painter->restore();
177  }
178  }
179 }
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:176
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:50
FieldOrigin fieldOrigin(int fieldIdx) const
Get field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:171
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.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
void actionColumnItemPainted(const QModelIndex &index) const
Is emitted when an action column item is painted.
void setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)
Get the feature id of the feature in this row.
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)
void setEditorData(QWidget *editor, const QModelIndex &index) const override
Sets data from model into the editor.
QgsVectorLayer * joinLayer() const
Returns joined layer (may be null if the reference was set by layer ID and not resolved yet) ...
QgsFields fields() const override
Returns the list of fields of this layer.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories...
Definition: qgsgui.cpp:46
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)...
virtual void setValue(const QVariant &value)=0
Is called, when the value of the widget needs to be changed.
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.
QgsVectorLayerJoinBuffer * joinBuffer()
Accessor to the join buffer object.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Query the layer for features specified in request.
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.
qint64 QgsFeatureId
Definition: qgsfeature.h:37
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 ...
QList< int > QgsAttributeList
Definition: qgsfield.h:27
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer. ...
bool nextFeature(QgsFeature &f)
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.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Set flags that affect how features will be fetched.