QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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  if ( mSourceLayer )
35  disconnect( mSourceLayer->conditionalStyles(), &QgsConditionalLayerStyles::changed, this, &QgsFeatureListModel::conditionalStylesChanged );
36 
37  QSortFilterProxyModel::setSourceModel( sourceModel );
38  mExpressionContext = sourceModel->layer()->createExpressionContext();
39  mFilterModel = sourceModel;
40 
41  mSourceLayer = sourceModel->layer();
42  connect( mSourceLayer->conditionalStyles(), &QgsConditionalLayerStyles::changed, this, &QgsFeatureListModel::conditionalStylesChanged );
43 }
44 
46 {
47  return mFilterModel->layerCache();
48 }
49 
50 QgsFeatureId QgsFeatureListModel::idxToFid( const QModelIndex &index ) const
51 {
52  return mFilterModel->masterModel()->rowToId( mapToMaster( index ).row() );
53 }
54 
55 QModelIndex QgsFeatureListModel::fidToIdx( const QgsFeatureId fid ) const
56 {
57  return mapFromMaster( mFilterModel->masterModel()->idToIndex( fid ) );
58 }
59 
60 QVariant QgsFeatureListModel::data( const QModelIndex &index, int role ) const
61 {
62  if ( mInjectNull && index.row() == 0 )
63  {
64  if ( role == Qt::DisplayRole )
65  {
67  }
68  else
69  {
70  return QVariant( QVariant::Invalid );
71  }
72  }
73 
74  if ( role == Qt::DisplayRole || role == Qt::EditRole )
75  {
76  QgsFeature feat;
77 
78  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
79 
80  mExpressionContext.setFeature( feat );
81  return mDisplayExpression.evaluate( &mExpressionContext );
82  }
83 
84  if ( role == FeatureInfoRole )
85  {
86  FeatureInfo featInfo;
87 
88  QgsFeature feat;
89 
90  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
91 
92  QgsVectorLayerEditBuffer *editBuffer = mFilterModel->layer()->editBuffer();
93 
94  if ( editBuffer )
95  {
96  if ( editBuffer->isFeatureAdded( feat.id() ) )
97  {
98  featInfo.isNew = true;
99  }
100  if ( editBuffer->isFeatureAttributesChanged( feat.id() ) )
101  {
102  featInfo.isEdited = true;
103  }
104  }
105 
106  return QVariant::fromValue( featInfo );
107  }
108  else if ( role == FeatureRole )
109  {
110  QgsFeature feat;
111 
112  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
113 
114  return QVariant::fromValue( feat );
115  }
116  else if ( role == Qt::TextAlignmentRole )
117  {
118  return Qt::AlignLeft;
119  }
120 
121  if ( role == Qt::BackgroundColorRole
122  || role == Qt::TextColorRole
123  || role == Qt::DecorationRole
124  || role == Qt::FontRole )
125  {
126  QgsVectorLayer *layer = mFilterModel->layer();
127  QgsFeature feat;
128  QgsFeatureId fid = idxToFid( index );
129  mFilterModel->layerCache()->featureAtId( fid, feat );
130  mExpressionContext.setFeature( feat );
131  QList<QgsConditionalStyle> styles;
132 
133  if ( mRowStylesMap.contains( fid ) )
134  {
135  styles = mRowStylesMap.value( fid );
136  }
137  else
138  {
139  styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
140  mRowStylesMap.insert( fid, styles );
141  }
142 
144 
145  if ( mDisplayExpression.isField() )
146  {
147  QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
148  styles = layer->conditionalStyles()->fieldStyles( fieldName );
149  styles = QgsConditionalStyle::matchingConditionalStyles( styles, feat.attribute( fieldName ), mExpressionContext );
150  }
151 
152  styles.insert( 0, rowstyle );
153 
155 
156  if ( style.isValid() )
157  {
158  if ( role == Qt::BackgroundColorRole && style.validBackgroundColor() )
159  return style.backgroundColor().isValid() ? style.backgroundColor() : QVariant();
160  if ( role == Qt::TextColorRole && style.validTextColor() )
161  return style.textColor().isValid() ? style.textColor() : QVariant();
162  if ( role == Qt::DecorationRole )
163  return style.icon().isNull() ? QVariant() : style.icon();
164  if ( role == Qt::FontRole )
165  return style.font();
166  }
167 
168  return QVariant();
169  }
170 
171  return sourceModel()->data( mapToSource( index ), role );
172 }
173 
174 Qt::ItemFlags QgsFeatureListModel::flags( const QModelIndex &index ) const
175 {
176  if ( mInjectNull && index.row() == 0 )
177  {
178  return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
179  }
180  else
181  {
182  return sourceModel()->flags( mapToSource( index ) ) & ~Qt::ItemIsEditable;
183  }
184 }
185 
187 {
188  if ( mInjectNull == injectNull )
189  return;
190 
191  if ( injectNull )
193 
194  beginResetModel();
195  mInjectNull = injectNull;
196  endResetModel();
197 }
198 
200 {
201  return mInjectNull;
202 }
203 
205 {
206  return mFilterModel->masterModel();
207 }
208 
209 bool QgsFeatureListModel::setDisplayExpression( const QString &expression )
210 {
211  QgsExpression exp = QgsExpression( expression );
212 
213  exp.prepare( &mExpressionContext );
214 
215  if ( exp.hasParserError() )
216  {
217  mParserErrorString = exp.parserErrorString();
218  return false;
219  }
220 
221  mDisplayExpression = exp;
222 
223  if ( mSortByDisplayExpression )
224  masterModel()->prefetchSortData( expression, 1 );
225 
226  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );
227 
228  invalidate();
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 void QgsFeatureListModel::conditionalStylesChanged()
274 {
275  mRowStylesMap.clear();
276  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, columnCount() - 1 ) );
277 }
278 
280 {
281  return mSortByDisplayExpression;
282 }
283 
285 {
286  mSortByDisplayExpression = sortByDisplayExpression;
287 
288  // If we are sorting by display expression, we do not support injected null
289  if ( sortByDisplayExpression )
290  setInjectNull( false );
291 
292  setSortRole( QgsAttributeTableModel::SortRole + 1 );
293  setDynamicSortFilter( mSortByDisplayExpression );
294  sort( 0 );
295 }
296 
297 QModelIndex QgsFeatureListModel::mapToMaster( const QModelIndex &proxyIndex ) const
298 {
299  QModelIndex masterIndex;
300 
301  if ( proxyIndex.isValid() )
302  {
303  if ( mSortByDisplayExpression )
304  {
305  masterIndex = mFilterModel->mapToMaster( mapToSource( proxyIndex ) );
306  }
307  else
308  {
309  int offset = mInjectNull ? 1 : 0;
310 
311  masterIndex = mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
312  }
313  }
314  return masterIndex;
315 }
316 
317 QModelIndex QgsFeatureListModel::mapFromMaster( const QModelIndex &masterIndex ) const
318 {
319  QModelIndex proxyIndex;
320 
321  if ( masterIndex.isValid() )
322  {
323  if ( mSortByDisplayExpression )
324  {
325  proxyIndex = mapFromSource( mFilterModel->mapFromMaster( masterIndex ) );
326  }
327  else
328  {
329  int offset = mInjectNull ? 1 : 0;
330 
331  return createIndex( mFilterModel->mapFromMaster( masterIndex ).row() + offset, 0 );
332  }
333  }
334 
335  return proxyIndex;
336 }
337 
338 QItemSelection QgsFeatureListModel::mapSelectionFromMaster( const QItemSelection &selection ) const
339 {
340  return mapSelectionFromSource( mFilterModel->mapSelectionFromSource( selection ) );
341 }
342 
343 QItemSelection QgsFeatureListModel::mapSelectionToMaster( const QItemSelection &selection ) const
344 {
345  return mFilterModel->mapSelectionToSource( mapSelectionToSource( selection ) );
346 }
347 
348 // Override some methods from QAbstractProxyModel, not that interesting
349 
350 QModelIndex QgsFeatureListModel::mapToSource( const QModelIndex &proxyIndex ) const
351 {
352  QModelIndex sourceIndex;
353 
354  if ( mSortByDisplayExpression )
355  {
356  sourceIndex = QSortFilterProxyModel::mapToSource( proxyIndex );
357  }
358  else
359  {
360  if ( !proxyIndex.isValid() )
361  return QModelIndex();
362 
363  int offset = mInjectNull ? 1 : 0;
364 
365  sourceIndex = sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
366  }
367 
368  return sourceIndex;
369 }
370 
371 QModelIndex QgsFeatureListModel::mapFromSource( const QModelIndex &sourceIndex ) const
372 {
373  QModelIndex proxyIndex;
374 
375  if ( mSortByDisplayExpression )
376  {
377  proxyIndex = QSortFilterProxyModel::mapFromSource( sourceIndex );
378  }
379  else
380  {
381  if ( sourceIndex.isValid() )
382  proxyIndex = createIndex( sourceIndex.row(), 0 );
383  }
384 
385  return proxyIndex;
386 }
387 
388 QModelIndex QgsFeatureListModel::parent( const QModelIndex &child ) const
389 {
390  Q_UNUSED( child )
391  return QModelIndex();
392 }
393 
394 int QgsFeatureListModel::columnCount( const QModelIndex &parent ) const
395 {
396  Q_UNUSED( parent )
397  return 1;
398 }
399 
400 int QgsFeatureListModel::rowCount( const QModelIndex &parent ) const
401 {
402  Q_UNUSED( parent )
403 
404  int offset = mInjectNull ? 1 : 0;
405 
406  return sourceModel()->rowCount() + offset;
407 }
408 
410 {
411  return mapFromMaster( masterModel()->idToIndex( fid ) );
412 }
413 
415 {
416  return QModelIndexList() << fidToIndex( fid );
417 }
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
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()
Role 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()
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName) const
Returns the conditional styles set for the field with matching fieldName.
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
void changed()
Emitted when the conditional styles are changed.
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.
QgsConditionalStyles rowStyles() const
Returns a list of row styles associated with the layer.
QModelIndex mapToMaster(const QModelIndex &proxyIndex) const