QGIS API Documentation  2.99.0-Master (c4aa4d0)
qgsfeaturelistmodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfeaturelistmodel.cpp
3  ---------------------
4  begin : February 2013
5  copyright : (C) 2013 by Matthias Kuhn
6  email : matthias at opengis dot ch
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 #include "qgsexception.h"
16 #include "qgsvectordataprovider.h"
17 #include "qgsfeaturelistmodel.h"
18 #include "qgsattributetablemodel.h"
21 
22 #include <QItemSelection>
23 #include <QSettings>
24 
26  : QAbstractProxyModel( parent )
27  , mInjectNull( false )
28 {
29  setSourceModel( sourceModel );
30 }
31 
33 {
34  QAbstractProxyModel::setSourceModel( sourceModel );
35  mExpressionContext = sourceModel->layer()->createExpressionContext();
36  mFilterModel = sourceModel;
37 
38  if ( mFilterModel )
39  {
40  // rewire (filter-)change events in the source model so this proxy reflects the changes
41  connect( mFilterModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &QgsFeatureListModel::onBeginRemoveRows );
42  connect( mFilterModel, &QAbstractItemModel::rowsRemoved, this, &QgsFeatureListModel::onEndRemoveRows );
43  connect( mFilterModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &QgsFeatureListModel::onBeginInsertRows );
44  connect( mFilterModel, &QAbstractItemModel::rowsInserted, this, &QgsFeatureListModel::onEndInsertRows );
45  // propagate sort order changes from source model to views connected to this model
46  connect( mFilterModel, &QAbstractItemModel::layoutAboutToBeChanged, this, &QAbstractItemModel::layoutAboutToBeChanged );
47  connect( mFilterModel, &QAbstractItemModel::layoutChanged, this, &QAbstractItemModel::layoutChanged );
48  connect( mFilterModel, &QAbstractItemModel::modelAboutToBeReset, this, &QAbstractItemModel::modelAboutToBeReset );
49  connect( mFilterModel, &QAbstractItemModel::modelReset, this, &QAbstractItemModel::modelReset );
50  }
51 }
52 
54 {
55  return mFilterModel->layerCache();
56 }
57 
59 {
60  return mFilterModel->masterModel()->rowToId( mapToMaster( index ).row() );
61 }
62 
63 QModelIndex QgsFeatureListModel::fidToIdx( const QgsFeatureId fid ) const
64 {
65  return mFilterModel->mapFromMaster( mFilterModel->masterModel()->idToIndex( fid ) );
66 }
67 
68 QVariant QgsFeatureListModel::data( const QModelIndex &index, int role ) const
69 {
70  if ( mInjectNull && index.row() == 0 )
71  {
72  if ( role == Qt::DisplayRole )
73  {
75  }
76  else
77  {
78  return QVariant( QVariant::Invalid );
79  }
80  }
81 
82  if ( role == Qt::DisplayRole || role == Qt::EditRole )
83  {
84  QgsFeature feat;
85 
86  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
87 
88  mExpressionContext.setFeature( feat );
89  return mDisplayExpression.evaluate( &mExpressionContext );
90  }
91 
92  if ( role == FeatureInfoRole )
93  {
94  FeatureInfo featInfo;
95 
96  QgsFeature feat;
97 
98  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
99 
100  QgsVectorLayerEditBuffer *editBuffer = mFilterModel->layer()->editBuffer();
101 
102  if ( editBuffer )
103  {
104  if ( editBuffer->isFeatureAdded( feat.id() ) )
105  {
106  featInfo.isNew = true;
107  }
108  if ( editBuffer->isFeatureAttributesChanged( feat.id() ) )
109  {
110  featInfo.isEdited = true;
111  }
112  }
113 
114  return QVariant::fromValue( featInfo );
115  }
116  else if ( role == FeatureRole )
117  {
118  QgsFeature feat;
119 
120  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
121 
122  return QVariant::fromValue( feat );
123  }
124  else if ( role == Qt::TextAlignmentRole )
125  {
126  return Qt::AlignLeft;
127  }
128 
129  if ( role == Qt::BackgroundColorRole
130  || role == Qt::TextColorRole
131  || role == Qt::DecorationRole
132  || role == Qt::FontRole )
133  {
134  QgsVectorLayer *layer = mFilterModel->layer();
135  QgsFeature feat;
136  QgsFeatureId fid = idxToFid( index );
137  mFilterModel->layerCache()->featureAtId( fid, feat );
138  mExpressionContext.setFeature( feat );
139  QList<QgsConditionalStyle> styles;
140 
141  if ( mRowStylesMap.contains( fid ) )
142  {
143  styles = mRowStylesMap.value( fid );
144  }
145  else
146  {
147  styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
148  mRowStylesMap.insert( fid, styles );
149  }
150 
152 
153  if ( mDisplayExpression.isField() )
154  {
155  QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
156  styles = layer->conditionalStyles()->fieldStyles( fieldName );
157  styles = QgsConditionalStyle::matchingConditionalStyles( styles, feat.attribute( fieldName ), mExpressionContext );
158  }
159 
160  styles.insert( 0, rowstyle );
161 
163 
164  if ( style.isValid() )
165  {
166  if ( role == Qt::BackgroundColorRole && style.validBackgroundColor() )
167  return style.backgroundColor();
168  if ( role == Qt::TextColorRole && style.validTextColor() )
169  return style.textColor();
170  if ( role == Qt::DecorationRole )
171  return style.icon();
172  if ( role == Qt::FontRole )
173  return style.font();
174  }
175 
176  return QVariant();
177  }
178 
179  return sourceModel()->data( mapToSource( index ), role );
180 }
181 
182 Qt::ItemFlags QgsFeatureListModel::flags( const QModelIndex &index ) const
183 {
184  if ( mInjectNull && index.row() == 0 )
185  {
186  return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
187  }
188  else
189  {
190  return sourceModel()->flags( mapToSource( index ) ) & ~Qt::ItemIsEditable;
191  }
192 }
193 
195 {
196  if ( mInjectNull != injectNull )
197  {
198  beginResetModel();
199  mInjectNull = injectNull;
200  endResetModel();
201  }
202 }
203 
205 {
206  return mInjectNull;
207 }
208 
210 {
211  return mFilterModel->masterModel();
212 }
213 
214 bool QgsFeatureListModel::setDisplayExpression( const QString &expression )
215 {
216  QgsExpression exp = QgsExpression( expression );
217 
218  exp.prepare( &mExpressionContext );
219 
220  if ( exp.hasParserError() )
221  {
222  mParserErrorString = exp.parserErrorString();
223  return false;
224  }
225 
226  mDisplayExpression = exp;
227 
228  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );
229  return true;
230 }
231 
233 {
234  return mParserErrorString;
235 }
236 
238 {
239  return mDisplayExpression.expression();
240 }
241 
242 bool QgsFeatureListModel::featureByIndex( const QModelIndex &index, QgsFeature &feat )
243 {
244  return mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
245 }
246 
247 void QgsFeatureListModel::onBeginRemoveRows( const QModelIndex &parent, int first, int last )
248 {
249  beginRemoveRows( parent, first, last );
250 }
251 
252 void QgsFeatureListModel::onEndRemoveRows( const QModelIndex &parent, int first, int last )
253 {
254  Q_UNUSED( parent )
255  Q_UNUSED( first )
256  Q_UNUSED( last )
257  endRemoveRows();
258 }
259 
260 void QgsFeatureListModel::onBeginInsertRows( const QModelIndex &parent, int first, int last )
261 {
262  beginInsertRows( parent, first, last );
263 }
264 
265 void QgsFeatureListModel::onEndInsertRows( const QModelIndex &parent, int first, int last )
266 {
267  Q_UNUSED( parent )
268  Q_UNUSED( first )
269  Q_UNUSED( last )
270  endInsertRows();
271 }
272 
273 QModelIndex QgsFeatureListModel::mapToMaster( const QModelIndex &proxyIndex ) const
274 {
275  if ( !proxyIndex.isValid() )
276  return QModelIndex();
277 
278  int offset = mInjectNull ? 1 : 0;
279 
280  return mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
281 }
282 
283 QModelIndex QgsFeatureListModel::mapFromMaster( const QModelIndex &sourceIndex ) const
284 {
285  if ( !sourceIndex.isValid() )
286  return QModelIndex();
287 
288  int offset = mInjectNull ? 1 : 0;
289 
290  return createIndex( mFilterModel->mapFromMaster( sourceIndex ).row() + offset, 0 );
291 }
292 
293 QItemSelection QgsFeatureListModel::mapSelectionFromMaster( const QItemSelection &selection ) const
294 {
295  return mapSelectionFromSource( mFilterModel->mapSelectionFromSource( selection ) );
296 }
297 
298 QItemSelection QgsFeatureListModel::mapSelectionToMaster( const QItemSelection &selection ) const
299 {
300  return mFilterModel->mapSelectionToSource( mapSelectionToSource( selection ) );
301 }
302 
303 // Override some methods from QAbstractProxyModel, not that interesting
304 
305 QModelIndex QgsFeatureListModel::mapToSource( const QModelIndex &proxyIndex ) const
306 {
307  if ( !proxyIndex.isValid() )
308  return QModelIndex();
309 
310  int offset = mInjectNull ? 1 : 0;
311 
312  return sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
313 }
314 
315 QModelIndex QgsFeatureListModel::mapFromSource( const QModelIndex &sourceIndex ) const
316 {
317  if ( !sourceIndex.isValid() )
318  return QModelIndex();
319 
320  return createIndex( sourceIndex.row(), 0 );
321 }
322 
323 QModelIndex QgsFeatureListModel::index( int row, int column, const QModelIndex &parent ) const
324 {
325  Q_UNUSED( parent )
326 
327  return createIndex( row, column );
328 }
329 
330 QModelIndex QgsFeatureListModel::parent( const QModelIndex &child ) const
331 {
332  Q_UNUSED( child )
333  return QModelIndex();
334 }
335 
336 int QgsFeatureListModel::columnCount( const QModelIndex &parent ) const
337 {
338  Q_UNUSED( parent )
339  return 1;
340 }
341 
342 int QgsFeatureListModel::rowCount( const QModelIndex &parent ) const
343 {
344  Q_UNUSED( parent )
345 
346  int offset = mInjectNull ? 1 : 0;
347 
348  return sourceModel()->rowCount() + offset;
349 }
350 
352 {
353  return mapFromMaster( masterModel()->idToIndex( fid ) );
354 }
355 
357 {
358  return QModelIndexList() << fidToIndex( fid );
359 }
bool injectNull()
Returns the current state of null value injection.
QgsFeatureId id
Definition: qgsfeature.h:71
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
QModelIndex fidToIndex(QgsFeatureId fid) override
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
QgsAttributeTableModel * masterModel() const
Returns the table model this filter is using.
QgsFeatureId idxToFid(const QModelIndex &index) const
bool setDisplayExpression(const QString &expression)
QModelIndex mapFromMaster(const QModelIndex &sourceIndex) const
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName)
Returns the conditional styles set for the field UI properties.
void onEndInsertRows(const QModelIndex &parent, int first, int last)
bool featureByIndex(const QModelIndex &index, QgsFeature &feat)
bool validBackgroundColor() const
Check if the background color is valid for render.
QPixmap icon() const
The icon set for style generated from the set symbol.
bool isFeatureAdded(QgsFeatureId id) const
Returns true if the specified feature ID has been added but not committed.
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...
QString parserErrorString()
Returns a detailed message about errors while parsing a QgsExpression.
virtual void setSourceModel(QgsAttributeTableFilterModel *sourceModel)
virtual QModelIndex mapToMaster(const QModelIndex &proxyIndex) const
QModelIndex idToIndex(QgsFeatureId id) const
QgsConditionalLayerStyles * conditionalStyles() const
Return the conditional styles that are set for this layer.
void onBeginInsertRows(const QModelIndex &parent, int first, int last)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QList< QgsConditionalStyle > rowStyles()
QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
Conditional styling for a rule.
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
QVariant data(const QModelIndex &index, int role) const override
bool isValid() const
isValid Check if this rule is valid.
static QList< QgsConditionalStyle > matchingConditionalStyles(const QList< QgsConditionalStyle > &styles, const QVariant &value, QgsExpressionContext &context)
Find and return the matching styles for the value and feature.
QModelIndexList fidToIndexList(QgsFeatureId fid)
QColor backgroundColor() const
The background color for style.
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
QString displayExpression() const
static QgsConditionalStyle compressStyles(const QList< QgsConditionalStyle > &styles)
Compress a list of styles into a single style.
Qt::ItemFlags flags(const QModelIndex &index) const override
bool isFeatureAttributesChanged(QgsFeatureId id) const
Returns true if the specified feature ID has had an attribute changed but not committed.
QgsAttributeTableModel * masterModel()
virtual QModelIndex mapFromMaster(const QModelIndex &sourceIndex) const
void onBeginRemoveRows(const QModelIndex &parent, int first, int last)
This class caches features of a given QgsVectorLayer.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QColor textColor() const
The text color set for style.
virtual QItemSelection mapSelectionToMaster(const QItemSelection &selection) const
bool featureAtId(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id.
QModelIndex fidToIdx(const QgsFeatureId fid) const
bool validTextColor() const
Check if the text color is valid for render.
QgsFeatureId rowToId(int row) const
Maps row to feature id.
qint64 QgsFeatureId
Definition: qgsfeature.h:37
void onEndRemoveRows(const QModelIndex &parent, int first, int last)
virtual QItemSelection mapSelectionFromMaster(const QItemSelection &selection) const
QgsVectorLayerCache * layerCache()
void setInjectNull(bool injectNull)
If true is specified, a NULL value will be injected.
QModelIndex parent(const QModelIndex &child) const override
QFont font() const
The font for the style.
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:255
QgsFeatureListModel(QgsAttributeTableFilterModel *sourceModel, QObject *parent=nullptr)
Constructor for QgsFeatureListModel.
QgsVectorLayerCache * layerCache() const
Returns the layerCache this filter acts on.
QModelIndex mapToMaster(const QModelIndex &proxyIndex) const