QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 #include "qgsapplication.h"
22 
23 #include <QItemSelection>
24 #include <QSettings>
25 
27  : QSortFilterProxyModel( parent )
28 {
29  setSourceModel( sourceModel );
30 }
31 
33 {
34  QSortFilterProxyModel::setSourceModel( sourceModel );
35  mExpressionContext = sourceModel->layer()->createExpressionContext();
36  mFilterModel = sourceModel;
37 
38 }
39 
41 {
42  return mFilterModel->layerCache();
43 }
44 
45 QgsFeatureId QgsFeatureListModel::idxToFid( const QModelIndex &index ) const
46 {
47  return mFilterModel->masterModel()->rowToId( mapToMaster( index ).row() );
48 }
49 
50 QModelIndex QgsFeatureListModel::fidToIdx( const QgsFeatureId fid ) const
51 {
52  return mapFromMaster( mFilterModel->masterModel()->idToIndex( fid ) );
53 }
54 
55 QVariant QgsFeatureListModel::data( const QModelIndex &index, int role ) const
56 {
57  if ( mInjectNull && index.row() == 0 )
58  {
59  if ( role == Qt::DisplayRole )
60  {
62  }
63  else
64  {
65  return QVariant( QVariant::Invalid );
66  }
67  }
68 
69  if ( role == Qt::DisplayRole || role == Qt::EditRole )
70  {
71  QgsFeature feat;
72 
73  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
74 
75  mExpressionContext.setFeature( feat );
76  return mDisplayExpression.evaluate( &mExpressionContext );
77  }
78 
79  if ( role == FeatureInfoRole )
80  {
81  FeatureInfo featInfo;
82 
83  QgsFeature feat;
84 
85  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
86 
87  QgsVectorLayerEditBuffer *editBuffer = mFilterModel->layer()->editBuffer();
88 
89  if ( editBuffer )
90  {
91  if ( editBuffer->isFeatureAdded( feat.id() ) )
92  {
93  featInfo.isNew = true;
94  }
95  if ( editBuffer->isFeatureAttributesChanged( feat.id() ) )
96  {
97  featInfo.isEdited = true;
98  }
99  }
100 
101  return QVariant::fromValue( featInfo );
102  }
103  else if ( role == FeatureRole )
104  {
105  QgsFeature feat;
106 
107  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
108 
109  return QVariant::fromValue( feat );
110  }
111  else if ( role == Qt::TextAlignmentRole )
112  {
113  return Qt::AlignLeft;
114  }
115 
116  if ( role == Qt::BackgroundColorRole
117  || role == Qt::TextColorRole
118  || role == Qt::DecorationRole
119  || role == Qt::FontRole )
120  {
121  QgsVectorLayer *layer = mFilterModel->layer();
122  QgsFeature feat;
123  QgsFeatureId fid = idxToFid( index );
124  mFilterModel->layerCache()->featureAtId( fid, feat );
125  mExpressionContext.setFeature( feat );
126  QList<QgsConditionalStyle> styles;
127 
128  if ( mRowStylesMap.contains( fid ) )
129  {
130  styles = mRowStylesMap.value( fid );
131  }
132  else
133  {
134  styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
135  mRowStylesMap.insert( fid, styles );
136  }
137 
139 
140  if ( mDisplayExpression.isField() )
141  {
142  QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
143  styles = layer->conditionalStyles()->fieldStyles( fieldName );
144  styles = QgsConditionalStyle::matchingConditionalStyles( styles, feat.attribute( fieldName ), mExpressionContext );
145  }
146 
147  styles.insert( 0, rowstyle );
148 
150 
151  if ( style.isValid() )
152  {
153  if ( role == Qt::BackgroundColorRole && style.validBackgroundColor() )
154  return style.backgroundColor();
155  if ( role == Qt::TextColorRole && style.validTextColor() )
156  return style.textColor();
157  if ( role == Qt::DecorationRole )
158  return style.icon();
159  if ( role == Qt::FontRole )
160  return style.font();
161  }
162 
163  return QVariant();
164  }
165 
166  return sourceModel()->data( mapToSource( index ), role );
167 }
168 
169 Qt::ItemFlags QgsFeatureListModel::flags( const QModelIndex &index ) const
170 {
171  if ( mInjectNull && index.row() == 0 )
172  {
173  return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
174  }
175  else
176  {
177  return sourceModel()->flags( mapToSource( index ) ) & ~Qt::ItemIsEditable;
178  }
179 }
180 
182 {
183  if ( mInjectNull == injectNull )
184  return;
185 
186  if ( injectNull )
188 
189  beginResetModel();
190  mInjectNull = injectNull;
191  endResetModel();
192 }
193 
195 {
196  return mInjectNull;
197 }
198 
200 {
201  return mFilterModel->masterModel();
202 }
203 
204 bool QgsFeatureListModel::setDisplayExpression( const QString &expression )
205 {
206  QgsExpression exp = QgsExpression( expression );
207 
208  exp.prepare( &mExpressionContext );
209 
210  if ( exp.hasParserError() )
211  {
212  mParserErrorString = exp.parserErrorString();
213  return false;
214  }
215 
216  mDisplayExpression = exp;
217 
218  if ( mSortByDisplayExpression )
219  masterModel()->prefetchSortData( expression, 1 );
220 
221  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );
222 
223  invalidate();
224  return true;
225 }
226 
228 {
229  return mParserErrorString;
230 }
231 
233 {
234  return mDisplayExpression.expression();
235 }
236 
237 bool QgsFeatureListModel::featureByIndex( const QModelIndex &index, QgsFeature &feat )
238 {
239  return mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
240 }
241 
242 void QgsFeatureListModel::onBeginRemoveRows( const QModelIndex &parent, int first, int last )
243 {
244  beginRemoveRows( parent, first, last );
245 }
246 
247 void QgsFeatureListModel::onEndRemoveRows( const QModelIndex &parent, int first, int last )
248 {
249  Q_UNUSED( parent )
250  Q_UNUSED( first )
251  Q_UNUSED( last )
252  endRemoveRows();
253 }
254 
255 void QgsFeatureListModel::onBeginInsertRows( const QModelIndex &parent, int first, int last )
256 {
257  beginInsertRows( parent, first, last );
258 }
259 
260 void QgsFeatureListModel::onEndInsertRows( const QModelIndex &parent, int first, int last )
261 {
262  Q_UNUSED( parent )
263  Q_UNUSED( first )
264  Q_UNUSED( last )
265  endInsertRows();
266 }
267 
269 {
270  return mSortByDisplayExpression;
271 }
272 
274 {
275  mSortByDisplayExpression = sortByDisplayExpression;
276 
277  // If we are sorting by display expression, we do not support injected null
278  if ( sortByDisplayExpression )
279  setInjectNull( false );
280 
281  setSortRole( QgsAttributeTableModel::SortRole + 1 );
282  setDynamicSortFilter( mSortByDisplayExpression );
283  sort( 0 );
284 }
285 
286 QModelIndex QgsFeatureListModel::mapToMaster( const QModelIndex &proxyIndex ) const
287 {
288  QModelIndex masterIndex;
289 
290  if ( proxyIndex.isValid() )
291  {
292  if ( mSortByDisplayExpression )
293  {
294  masterIndex = mFilterModel->mapToMaster( mapToSource( proxyIndex ) );
295  }
296  else
297  {
298  int offset = mInjectNull ? 1 : 0;
299 
300  masterIndex = mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
301  }
302  }
303  return masterIndex;
304 }
305 
306 QModelIndex QgsFeatureListModel::mapFromMaster( const QModelIndex &masterIndex ) const
307 {
308  QModelIndex proxyIndex;
309 
310  if ( masterIndex.isValid() )
311  {
312  if ( mSortByDisplayExpression )
313  {
314  proxyIndex = mapFromSource( mFilterModel->mapFromMaster( masterIndex ) );
315  }
316  else
317  {
318  int offset = mInjectNull ? 1 : 0;
319 
320  return createIndex( mFilterModel->mapFromMaster( masterIndex ).row() + offset, 0 );
321  }
322  }
323 
324  return proxyIndex;
325 }
326 
327 QItemSelection QgsFeatureListModel::mapSelectionFromMaster( const QItemSelection &selection ) const
328 {
329  return mapSelectionFromSource( mFilterModel->mapSelectionFromSource( selection ) );
330 }
331 
332 QItemSelection QgsFeatureListModel::mapSelectionToMaster( const QItemSelection &selection ) const
333 {
334  return mFilterModel->mapSelectionToSource( mapSelectionToSource( selection ) );
335 }
336 
337 // Override some methods from QAbstractProxyModel, not that interesting
338 
339 QModelIndex QgsFeatureListModel::mapToSource( const QModelIndex &proxyIndex ) const
340 {
341  QModelIndex sourceIndex;
342 
343  if ( mSortByDisplayExpression )
344  {
345  sourceIndex = QSortFilterProxyModel::mapToSource( proxyIndex );
346  }
347  else
348  {
349  if ( !proxyIndex.isValid() )
350  return QModelIndex();
351 
352  int offset = mInjectNull ? 1 : 0;
353 
354  sourceIndex = sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
355  }
356 
357  return sourceIndex;
358 }
359 
360 QModelIndex QgsFeatureListModel::mapFromSource( const QModelIndex &sourceIndex ) const
361 {
362  QModelIndex proxyIndex;
363 
364  if ( mSortByDisplayExpression )
365  {
366  proxyIndex = QSortFilterProxyModel::mapFromSource( sourceIndex );
367  }
368  else
369  {
370  if ( sourceIndex.isValid() )
371  proxyIndex = createIndex( sourceIndex.row(), 0 );
372  }
373 
374  return proxyIndex;
375 }
376 
377 QModelIndex QgsFeatureListModel::parent( const QModelIndex &child ) const
378 {
379  Q_UNUSED( child )
380  return QModelIndex();
381 }
382 
383 int QgsFeatureListModel::columnCount( const QModelIndex &parent ) const
384 {
385  Q_UNUSED( parent )
386  return 1;
387 }
388 
389 int QgsFeatureListModel::rowCount( const QModelIndex &parent ) const
390 {
391  Q_UNUSED( parent )
392 
393  int offset = mInjectNull ? 1 : 0;
394 
395  return sourceModel()->rowCount() + offset;
396 }
397 
399 {
400  return mapFromMaster( masterModel()->idToIndex( fid ) );
401 }
402 
404 {
405  return QModelIndexList() << fidToIndex( fid );
406 }
bool injectNull()
Returns the current state of null value injection.
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsFeatureId id
Definition: qgsfeature.h:64
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
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
Returns the feature ID corresponding to an index from the model.
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 prefetchSortData(const QString &expression, unsigned long cacheIndex=0)
Prefetches the entire data for an expression.
QVariant evaluate()
Evaluate the feature and return the result.
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
Q_DECL_DEPRECATED void onEndInsertRows(const QModelIndex &parent, int first, int last)
Does nothing except for calling endInsertRows()
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.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
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...
QString parserErrorString() const
Returns parser error.
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
Returns the conditional styles that are set for this layer.
Q_DECL_DEPRECATED void onBeginInsertRows(const QModelIndex &parent, int first, int last)
Does nothing except for calling beginInsertRows()
QList< QgsConditionalStyle > rowStyles()
Roles used for sorting start here.
QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
bool isEdited
True if feature has been edited.
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.
bool isNew
True if feature is a newly added feature.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
bool sortByDisplayExpression() const
Sort this model by its display expression.
QgsAttributeTableModel * masterModel()
virtual QModelIndex mapFromMaster(const QModelIndex &sourceIndex) const
Q_DECL_DEPRECATED void onBeginRemoveRows(const QModelIndex &parent, int first, int last)
Does nothing except for calling beginRemoveRows()
QString expression() const
Returns the original, unmodified expression string.
This class caches features of a given QgsVectorLayer.
QColor textColor() const
The text color set for style.
virtual QItemSelection mapSelectionToMaster(const QItemSelection &selection) const
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
bool featureAtId(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id.
bool validTextColor() const
Check if the text color is valid for render.
bool isField() const
Checks whether an expression consists only of a single field reference.
QgsFeatureId rowToId(int row) const
Maps row to feature id.
Q_DECL_DEPRECATED void onEndRemoveRows(const QModelIndex &parent, int first, int last)
Does nothing except for calling endRemoveRows()
virtual QItemSelection mapSelectionFromMaster(const QItemSelection &selection) const
QgsVectorLayerCache * layerCache()
Returns the vector layer cache which is being used to populate the model.
void setInjectNull(bool injectNull)
If true is specified, a NULL value will be injected.
void setSortByDisplayExpression(bool sortByDisplayExpression)
Sort this model by its display expression.
QModelIndex fidToIdx(QgsFeatureId fid) const
Returns the model index corresponding to a feature ID.
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:262
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