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