QGIS API Documentation  2.99.0-Master (7705179)
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  }
49 }
50 
52 {
53  return mFilterModel->layerCache();
54 }
55 
57 {
58  return mFilterModel->masterModel()->rowToId( mapToMaster( index ).row() );
59 }
60 
61 QModelIndex QgsFeatureListModel::fidToIdx( const QgsFeatureId fid ) const
62 {
63  return mFilterModel->mapFromMaster( mFilterModel->masterModel()->idToIndex( fid ) );
64 }
65 
66 QVariant QgsFeatureListModel::data( const QModelIndex &index, int role ) const
67 {
68  if ( mInjectNull && index.row() == 0 )
69  {
70  if ( role == Qt::DisplayRole )
71  {
73  }
74  else
75  {
76  return QVariant( QVariant::Invalid );
77  }
78  }
79 
80  if ( role == Qt::DisplayRole || role == Qt::EditRole )
81  {
82  QgsFeature feat;
83 
84  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
85 
86  mExpressionContext.setFeature( feat );
87  return mDisplayExpression.evaluate( &mExpressionContext );
88  }
89 
90  if ( role == FeatureInfoRole )
91  {
92  FeatureInfo featInfo;
93 
94  QgsFeature feat;
95 
96  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
97 
98  QgsVectorLayerEditBuffer *editBuffer = mFilterModel->layer()->editBuffer();
99 
100  if ( editBuffer )
101  {
102  if ( editBuffer->isFeatureAdded( feat.id() ) )
103  {
104  featInfo.isNew = true;
105  }
106  if ( editBuffer->isFeatureAttributesChanged( feat.id() ) )
107  {
108  featInfo.isEdited = true;
109  }
110  }
111 
112  return QVariant::fromValue( featInfo );
113  }
114  else if ( role == FeatureRole )
115  {
116  QgsFeature feat;
117 
118  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
119 
120  return QVariant::fromValue( feat );
121  }
122  else if ( role == Qt::TextAlignmentRole )
123  {
124  return Qt::AlignLeft;
125  }
126 
127  if ( role == Qt::BackgroundColorRole
128  || role == Qt::TextColorRole
129  || role == Qt::DecorationRole
130  || role == Qt::FontRole )
131  {
132  QgsVectorLayer *layer = mFilterModel->layer();
133  QgsFeature feat;
134  QgsFeatureId fid = idxToFid( index );
135  mFilterModel->layerCache()->featureAtId( fid, feat );
136  mExpressionContext.setFeature( feat );
137  QList<QgsConditionalStyle> styles;
138 
139  if ( mRowStylesMap.contains( fid ) )
140  {
141  styles = mRowStylesMap.value( fid );
142  }
143  else
144  {
145  styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
146  mRowStylesMap.insert( fid, styles );
147  }
148 
150 
151  if ( mDisplayExpression.isField() )
152  {
153  QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
154  styles = layer->conditionalStyles()->fieldStyles( fieldName );
155  styles = QgsConditionalStyle::matchingConditionalStyles( styles, feat.attribute( fieldName ), mExpressionContext );
156  }
157 
158  styles.insert( 0, rowstyle );
159 
161 
162  if ( style.isValid() )
163  {
164  if ( role == Qt::BackgroundColorRole && style.validBackgroundColor() )
165  return style.backgroundColor();
166  if ( role == Qt::TextColorRole && style.validTextColor() )
167  return style.textColor();
168  if ( role == Qt::DecorationRole )
169  return style.icon();
170  if ( role == Qt::FontRole )
171  return style.font();
172  }
173 
174  return QVariant();
175  }
176 
177  return sourceModel()->data( mapToSource( index ), role );
178 }
179 
180 Qt::ItemFlags QgsFeatureListModel::flags( const QModelIndex &index ) const
181 {
182  if ( mInjectNull && index.row() == 0 )
183  {
184  return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
185  }
186  else
187  {
188  return sourceModel()->flags( mapToSource( index ) ) & ~Qt::ItemIsEditable;
189  }
190 }
191 
193 {
194  if ( mInjectNull != injectNull )
195  {
196  beginResetModel();
197  mInjectNull = injectNull;
198  endResetModel();
199  }
200 }
201 
203 {
204  return mInjectNull;
205 }
206 
208 {
209  return mFilterModel->masterModel();
210 }
211 
212 bool QgsFeatureListModel::setDisplayExpression( const QString &expression )
213 {
214  QgsExpression exp = QgsExpression( expression );
215 
216  exp.prepare( &mExpressionContext );
217 
218  if ( exp.hasParserError() )
219  {
220  mParserErrorString = exp.parserErrorString();
221  return false;
222  }
223 
224  mDisplayExpression = exp;
225 
226  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );
227  return true;
228 }
229 
231 {
232  return mParserErrorString;
233 }
234 
236 {
237  return mDisplayExpression.expression();
238 }
239 
240 bool QgsFeatureListModel::featureByIndex( const QModelIndex &index, QgsFeature &feat )
241 {
242  return mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
243 }
244 
245 void QgsFeatureListModel::onBeginRemoveRows( const QModelIndex &parent, int first, int last )
246 {
247  beginRemoveRows( parent, first, last );
248 }
249 
250 void QgsFeatureListModel::onEndRemoveRows( const QModelIndex &parent, int first, int last )
251 {
252  Q_UNUSED( parent )
253  Q_UNUSED( first )
254  Q_UNUSED( last )
255  endRemoveRows();
256 }
257 
258 void QgsFeatureListModel::onBeginInsertRows( const QModelIndex &parent, int first, int last )
259 {
260  beginInsertRows( parent, first, last );
261 }
262 
263 void QgsFeatureListModel::onEndInsertRows( const QModelIndex &parent, int first, int last )
264 {
265  Q_UNUSED( parent )
266  Q_UNUSED( first )
267  Q_UNUSED( last )
268  endInsertRows();
269 }
270 
271 QModelIndex QgsFeatureListModel::mapToMaster( const QModelIndex &proxyIndex ) const
272 {
273  if ( !proxyIndex.isValid() )
274  return QModelIndex();
275 
276  int offset = mInjectNull ? 1 : 0;
277 
278  return mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
279 }
280 
281 QModelIndex QgsFeatureListModel::mapFromMaster( const QModelIndex &sourceIndex ) const
282 {
283  if ( !sourceIndex.isValid() )
284  return QModelIndex();
285 
286  int offset = mInjectNull ? 1 : 0;
287 
288  return createIndex( mFilterModel->mapFromMaster( sourceIndex ).row() + offset, 0 );
289 }
290 
291 QItemSelection QgsFeatureListModel::mapSelectionFromMaster( const QItemSelection &selection ) const
292 {
293  return mapSelectionFromSource( mFilterModel->mapSelectionFromSource( selection ) );
294 }
295 
296 QItemSelection QgsFeatureListModel::mapSelectionToMaster( const QItemSelection &selection ) const
297 {
298  return mFilterModel->mapSelectionToSource( mapSelectionToSource( selection ) );
299 }
300 
301 // Override some methods from QAbstractProxyModel, not that interesting
302 
303 QModelIndex QgsFeatureListModel::mapToSource( const QModelIndex &proxyIndex ) const
304 {
305  if ( !proxyIndex.isValid() )
306  return QModelIndex();
307 
308  int offset = mInjectNull ? 1 : 0;
309 
310  return sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
311 }
312 
313 QModelIndex QgsFeatureListModel::mapFromSource( const QModelIndex &sourceIndex ) const
314 {
315  if ( !sourceIndex.isValid() )
316  return QModelIndex();
317 
318  return createIndex( sourceIndex.row(), 0 );
319 }
320 
321 QModelIndex QgsFeatureListModel::index( int row, int column, const QModelIndex &parent ) const
322 {
323  Q_UNUSED( parent )
324 
325  return createIndex( row, column );
326 }
327 
328 QModelIndex QgsFeatureListModel::parent( const QModelIndex &child ) const
329 {
330  Q_UNUSED( child )
331  return QModelIndex();
332 }
333 
334 int QgsFeatureListModel::columnCount( const QModelIndex &parent ) const
335 {
336  Q_UNUSED( parent )
337  return 1;
338 }
339 
340 int QgsFeatureListModel::rowCount( const QModelIndex &parent ) const
341 {
342  Q_UNUSED( parent )
343 
344  int offset = mInjectNull ? 1 : 0;
345 
346  return sourceModel()->rowCount() + offset;
347 }
348 
350 {
351  return mapFromMaster( masterModel()->idToIndex( fid ) );
352 }
353 
355 {
356  return QModelIndexList() << fidToIndex( fid );
357 }
bool injectNull()
Returns the current state of null value injection.
QgsFeatureId id
Definition: qgsfeature.h:70
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
QModelIndex fidToIndex(QgsFeatureId fid) override
virtual 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.
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const override
virtual 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:61
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)
virtual 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.
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
virtual 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.
virtual 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.
virtual 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=0)
QgsVectorLayerCache * layerCache() const
Returns the layerCache this filter acts on.
QModelIndex mapToMaster(const QModelIndex &proxyIndex) const