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