QGIS API Documentation 4.3.0-Master (b46232e4f9a)
Loading...
Searching...
No Matches
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
17
18#include "qgsactionmanager.h"
25#include "qgsgui.h"
26#include "qgspainting.h"
27#include "qgsrendercontext.h"
31
32#include <QComboBox>
33#include <QItemDelegate>
34#include <QLineEdit>
35#include <QPainter>
36#include <QToolButton>
37
38#include "moc_qgsattributetabledelegate.cpp"
39
40QgsVectorLayer *QgsAttributeTableDelegate::layer( const QAbstractItemModel *model )
41{
42 const QgsAttributeTableModel *tm = qobject_cast<const QgsAttributeTableModel *>( model );
43 if ( tm )
44 return tm->layer();
45
46 const QgsAttributeTableFilterModel *fm = qobject_cast<const QgsAttributeTableFilterModel *>( model );
47 if ( fm )
48 return fm->layer();
49
50 return nullptr;
51}
52
53const QgsAttributeTableModel *QgsAttributeTableDelegate::masterModel( const QAbstractItemModel *model )
54{
55 const QgsAttributeTableModel *tm = qobject_cast<const QgsAttributeTableModel *>( model );
56 if ( tm )
57 return tm;
58
59 const QgsAttributeTableFilterModel *fm = qobject_cast<const QgsAttributeTableFilterModel *>( model );
60 if ( fm )
61 return fm->masterModel();
62
63 return nullptr;
64}
65
66QWidget *QgsAttributeTableDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
67{
68 Q_UNUSED( option )
69 QgsVectorLayer *vl = layer( index.model() );
70 if ( !vl )
71 return nullptr;
72
73 const int fieldIdx = index.model()->data( index, static_cast<int>( QgsAttributeTableModel::CustomRole::FieldIndex ) ).toInt();
74 QgsAttributeEditorContext context( masterModel( index.model() )->editorContext(), QgsAttributeEditorContext::Popup );
75
76 // Update the editor form context with the feature being edited
77 const QgsFeatureId fid( index.model()->data( index, static_cast<int>( QgsAttributeTableModel::CustomRole::FeatureId ) ).toLongLong() );
78 context.setFormFeature( vl->getFeature( fid ) );
79
80 QgsEditorWidgetWrapper *eww = QgsGui::editorWidgetRegistry()->create( vl, fieldIdx, nullptr, parent, context );
81 eww->setFeature( context.formFeature() );
82
83 QWidget *w = eww->widget();
84 w->setAutoFillBackground( true );
85 w->setFocusPolicy( Qt::StrongFocus ); // to make sure QMouseEvents are propagated to the editor widget
86
87 const Qgis::FieldOrigin fieldOrigin = vl->fields().fieldOrigin( fieldIdx );
88 bool readOnly = true;
89 if ( fieldOrigin == Qgis::FieldOrigin::Join )
90 {
91 int srcFieldIndex;
92 const QgsVectorLayerJoinInfo *info = vl->joinBuffer()->joinForFieldIndex( fieldIdx, vl->fields(), srcFieldIndex );
93
94 if ( info && info->isEditable() )
95 readOnly = info->joinLayer()->editFormConfig().readOnly( srcFieldIndex );
96 }
97 else
98 readOnly = vl->editFormConfig().readOnly( fieldIdx );
99
100 eww->setEnabled( !readOnly );
101
102 return w;
103}
104
105void QgsAttributeTableDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
106{
107 QgsVectorLayer *vl = layer( model );
108 if ( !vl )
109 return;
110
111 const int fieldIdx = model->data( index, static_cast<int>( QgsAttributeTableModel::CustomRole::FieldIndex ) ).toInt();
112 const QgsFeatureId fid = model->data( index, static_cast<int>( QgsAttributeTableModel::CustomRole::FeatureId ) ).toLongLong();
113 const QVariant oldValue = model->data( index, Qt::EditRole );
114
116 if ( !eww )
117 return;
118
119 QList<int> indexes = QList<int>() << fieldIdx;
120 QVariantList newValues = QVariantList() << eww->value();
121 const QStringList additionalFields = eww->additionalFields();
122 for ( const QString &fieldName : additionalFields )
123 {
124 indexes << eww->layer()->fields().lookupField( fieldName );
125 }
126 newValues.append( eww->additionalFieldValues() );
127
128 if ( ( oldValue != newValues.at( 0 ) && newValues.at( 0 ).isValid() ) || QgsVariantUtils::isNull( oldValue ) != QgsVariantUtils::isNull( newValues.at( 0 ) ) || newValues.count() > 1 )
129 {
130 // This fixes https://github.com/qgis/QGIS/issues/24398
131 QgsFeatureRequest request( fid );
133 QgsFeature feature;
134 vl->getFeatures( request ).nextFeature( feature );
135 if ( feature.isValid() )
136 {
137 vl->beginEditCommand( tr( "Attribute changed" ) );
138 for ( int i = 0; i < newValues.count(); i++ )
139 vl->changeAttributeValue( fid, indexes.at( i ), newValues.at( i ), feature.attribute( indexes.at( i ) ) );
140 vl->endEditCommand();
141 }
142 }
143}
144
145void QgsAttributeTableDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
146{
148 if ( !eww )
149 return;
150
151 const QVariant value = index.model()->data( index, Qt::EditRole );
152 const QStringList additionalFields = eww->additionalFields();
153
154 if ( !additionalFields.empty() )
155 {
156 const QgsAttributeTableModel *model = masterModel( index.model() );
157 if ( model )
158 {
159 const QgsFeature feat = model->feature( index );
160 QVariantList additionalFieldValues;
161 for ( const QString &fieldName : additionalFields )
162 {
163 additionalFieldValues << feat.attribute( fieldName );
164 }
165 eww->setValues( value, additionalFieldValues );
166 }
167 }
168 else
169 {
170 eww->setValues( value, QVariantList() );
171 }
172}
173
175{
176 mFeatureSelectionModel = featureSelectionModel;
177}
178
179void QgsAttributeTableDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
180{
182 index.model()->data( index, static_cast<int>( QgsAttributeTableFilterModel::CustomRole::Type ) ).toInt()
183 );
184
186 {
187 emit actionColumnItemPainted( index );
188 }
189 else
190 {
191 const QgsFeatureId fid = index.model()->data( index, static_cast<int>( QgsAttributeTableModel::CustomRole::FeatureId ) ).toLongLong();
192
193 QStyleOptionViewItem myOpt = option;
194
195 if ( QgsVariantUtils::isNull( index.model()->data( index, Qt::EditRole ) ) )
196 {
197 myOpt.font.setItalic( true );
198 myOpt.palette.setColor( QPalette::Text, QColor( "gray" ) );
199 }
200
201 if ( mFeatureSelectionModel && mFeatureSelectionModel->isSelected( fid ) )
202 myOpt.state |= QStyle::State_Selected;
203
204 QItemDelegate::paint( painter, myOpt, index );
205
206 if ( option.state & QStyle::State_HasFocus )
207 {
208 const QRect r = option.rect.adjusted( 1, 1, -1, -1 );
209 const QPen p( QBrush( QColor( 0, 255, 127 ) ), 2 );
210 const QgsScopedQPainterState painterState( painter );
211 painter->setPen( p );
212 painter->drawRect( r );
213 }
214 }
215}
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2380
FieldOrigin
Field origin.
Definition qgis.h:1874
@ Join
Field originates from a joined layer.
Definition qgis.h:1877
Contains context information for attribute editor widgets.
void setFormFeature(const QgsFeature &feature)
Set current feature for the currently edited form or table row.
@ Popup
A widget was opened as a popup (e.g. attribute table editor widget).
QgsFeature formFeature() const
Returns current feature from the currently edited form or table row.
void actionColumnItemPainted(const QModelIndex &index) const
Emitted when an action column item is painted.
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
Sets data from editor back to model.
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.
void setEditorData(QWidget *editor, const QModelIndex &index) const override
Sets data from model into the editor.
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Overloads the paint method form the QItemDelegate base class.
void setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)
QgsAttributeTableModel * masterModel() const
Returns the table model this filter is using.
@ ColumnTypeActionButton
This column shows action buttons.
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
QgsFeature feature(const QModelIndex &idx) const
Returns the feature attributes at given model index.
QgsVectorLayer * layer() const
Returns the layer this model uses as backend.
@ FeatureId
Get the feature id of the feature in this row.
@ FieldIndex
Get the field index of this column.
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 ...
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.
Manages an editor widget.
virtual QVariant value() const =0
Will be used to access the widget's value.
virtual QVariantList additionalFieldValues() const
Will be used to access the widget's values for potential additional fields handled by the widget.
void setFeature(const QgsFeature &feature) override
Will be called when the feature changes.
virtual QStringList additionalFields() const
Returns the list of additional fields which the editor handles.
void setEnabled(bool enabled) override
Is used to enable or disable the edit functionality of the managed widget.
void setValues(const QVariant &value, const QVariantList &additionalValues)
Is called when the value of the widget or additional field values needs to be changed.
static QgsEditorWidgetWrapper * fromWidget(QWidget *widget)
Will return a wrapper for a given widget.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
Item selection model for selecting features.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
bool isValid() const
Returns the validity of this feature.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Qgis::FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
Definition qgsgui.cpp:110
Scoped object for saving and restoring a QPainter object's state.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
Defines left outer join from our vector layer to some other vector layer.
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer.
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet).
Represents a vector layer which manages a vector based dataset.
Q_INVOKABLE bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false, QgsVectorLayerToolsContext *context=nullptr)
Changes an attribute value for a feature (but does not immediately commit the changes).
void endEditCommand()
Finish edit command and add it to undo/redo stack.
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
void beginEditCommand(const QString &text)
Create edit command for undo/redo operations.
QgsEditFormConfig editFormConfig
Q_INVOKABLE QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
QWidget * widget()
Access the widget managed by this wrapper.
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features