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