QGIS API Documentation  2.99.0-Master (0a63d1f)
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  mExpression = new QgsExpression( QLatin1String( "" ) );
31 }
32 
34 {
35  delete mExpression;
36 }
37 
39 {
40  QAbstractProxyModel::setSourceModel( sourceModel );
41  mFilterModel = sourceModel;
42  if ( mFilterModel )
43  {
44  // rewire (filter-)change events in the source model so this proxy reflects the changes
45  connect( mFilterModel, SIGNAL( rowsAboutToBeRemoved( const QModelIndex&, int, int ) ), SLOT( onBeginRemoveRows( const QModelIndex&, int, int ) ) );
46  connect( mFilterModel, SIGNAL( rowsRemoved( const QModelIndex&, int, int ) ), SLOT( onEndRemoveRows( const QModelIndex&, int, int ) ) );
47  connect( mFilterModel, SIGNAL( rowsAboutToBeInserted( const QModelIndex&, int, int ) ), SLOT( onBeginInsertRows( const QModelIndex&, int, int ) ) );
48  connect( mFilterModel, SIGNAL( rowsInserted( const QModelIndex&, int, int ) ), SLOT( onEndInsertRows( const QModelIndex&, int, int ) ) );
49  // propagate sort order changes from source model to views connected to this model
50  connect( mFilterModel, SIGNAL( layoutAboutToBeChanged() ), this, SIGNAL( layoutAboutToBeChanged() ) );
51  connect( mFilterModel, SIGNAL( layoutChanged() ), this, SIGNAL( 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 
95  context.setFeature( feat );
96  return mExpression->evaluate( &context );
97  }
98 
99  if ( role == FeatureInfoRole )
100  {
101  FeatureInfo featInfo;
102 
103  QgsFeature feat;
104 
105  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
106 
107  QgsVectorLayerEditBuffer* editBuffer = mFilterModel->layer()->editBuffer();
108 
109  if ( editBuffer )
110  {
111  if ( editBuffer->isFeatureAdded( feat.id() ) )
112  {
113  featInfo.isNew = true;
114  }
115  if ( editBuffer->isFeatureAttributesChanged( feat.id() ) )
116  {
117  featInfo.isEdited = true;
118  }
119  }
120 
121  return QVariant::fromValue( featInfo );
122  }
123  else if ( role == FeatureRole )
124  {
125  QgsFeature feat;
126 
127  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
128 
129  return QVariant::fromValue( feat );
130  }
131  else if ( role == Qt::TextAlignmentRole )
132  {
133  return Qt::AlignLeft;
134  }
135 
136  return sourceModel()->data( mapToSource( index ), role );
137 }
138 
139 Qt::ItemFlags QgsFeatureListModel::flags( const QModelIndex &index ) const
140 {
141  if ( mInjectNull && index.row() == 0 )
142  {
143  return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
144  }
145  else
146  {
147  return sourceModel()->flags( mapToSource( index ) ) & ~Qt::ItemIsEditable;
148  }
149 }
150 
152 {
153  if ( mInjectNull != injectNull )
154  {
155  emit beginResetModel();
156  mInjectNull = injectNull;
157  emit endResetModel();
158  }
159 }
160 
162 {
163  return mInjectNull;
164 }
165 
167 {
168  return mFilterModel->masterModel();
169 }
170 
171 bool QgsFeatureListModel::setDisplayExpression( const QString& expression )
172 {
173  QgsExpression* exp = new QgsExpression( expression );
174 
176 
177  exp->prepare( &context );
178 
179  if ( exp->hasParserError() )
180  {
181  mParserErrorString = exp->parserErrorString();
182  delete exp;
183  return false;
184  }
185 
186  delete mExpression;
187  mExpression = exp;
188 
189  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );
190  return true;
191 }
192 
194 {
195  return mParserErrorString;
196 }
197 
199 {
200  return mExpression->expression();
201 }
202 
203 bool QgsFeatureListModel::featureByIndex( const QModelIndex &index, QgsFeature &feat )
204 {
205  return mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
206 }
207 
208 void QgsFeatureListModel::onBeginRemoveRows( const QModelIndex& parent, int first, int last )
209 {
210  beginRemoveRows( parent, first, last );
211 }
212 
213 void QgsFeatureListModel::onEndRemoveRows( const QModelIndex& parent, int first, int last )
214 {
215  Q_UNUSED( parent )
216  Q_UNUSED( first )
217  Q_UNUSED( last )
218  endRemoveRows();
219 }
220 
221 void QgsFeatureListModel::onBeginInsertRows( const QModelIndex& parent, int first, int last )
222 {
223  beginInsertRows( parent, first, last );
224 }
225 
226 void QgsFeatureListModel::onEndInsertRows( const QModelIndex& parent, int first, int last )
227 {
228  Q_UNUSED( parent )
229  Q_UNUSED( first )
230  Q_UNUSED( last )
231  endInsertRows();
232 }
233 
234 QModelIndex QgsFeatureListModel::mapToMaster( const QModelIndex &proxyIndex ) const
235 {
236  if ( !proxyIndex.isValid() )
237  return QModelIndex();
238 
239  int offset = mInjectNull ? 1 : 0;
240 
241  return mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
242 }
243 
244 QModelIndex QgsFeatureListModel::mapFromMaster( const QModelIndex &sourceIndex ) const
245 {
246  if ( !sourceIndex.isValid() )
247  return QModelIndex();
248 
249  int offset = mInjectNull ? 1 : 0;
250 
251  return createIndex( mFilterModel->mapFromMaster( sourceIndex ).row() + offset, 0 );
252 }
253 
254 QItemSelection QgsFeatureListModel::mapSelectionFromMaster( const QItemSelection& selection ) const
255 {
256  return mapSelectionFromSource( mFilterModel->mapSelectionFromSource( selection ) );
257 }
258 
259 QItemSelection QgsFeatureListModel::mapSelectionToMaster( const QItemSelection& selection ) const
260 {
261  return mFilterModel->mapSelectionToSource( mapSelectionToSource( selection ) );
262 }
263 
264 // Override some methods from QAbstractProxyModel, not that interesting
265 
266 QModelIndex QgsFeatureListModel::mapToSource( const QModelIndex &proxyIndex ) const
267 {
268  if ( !proxyIndex.isValid() )
269  return QModelIndex();
270 
271  int offset = mInjectNull ? 1 : 0;
272 
273  return sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
274 }
275 
276 QModelIndex QgsFeatureListModel::mapFromSource( const QModelIndex &sourceIndex ) const
277 {
278  if ( !sourceIndex.isValid() )
279  return QModelIndex();
280 
281  return createIndex( sourceIndex.row(), 0 );
282 }
283 
284 QModelIndex QgsFeatureListModel::index( int row, int column, const QModelIndex& parent ) const
285 {
286  Q_UNUSED( parent )
287 
288  return createIndex( row, column );
289 }
290 
291 QModelIndex QgsFeatureListModel::parent( const QModelIndex& child ) const
292 {
293  Q_UNUSED( child )
294  return QModelIndex();
295 }
296 
297 int QgsFeatureListModel::columnCount( const QModelIndex&parent ) const
298 {
299  Q_UNUSED( parent )
300  return 1;
301 }
302 
303 int QgsFeatureListModel::rowCount( const QModelIndex& parent ) const
304 {
305  Q_UNUSED( parent )
306 
307  int offset = mInjectNull ? 1 : 0;
308 
309  return sourceModel()->rowCount() + offset;
310 }
311 
313 {
314  return mapFromMaster( masterModel()->idToIndex( fid ) );
315 }
316 
318 {
319  return QModelIndexList() << fidToIndex( fid );
320 }
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
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 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: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
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
QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
virtual QVariant data(const QModelIndex &index, int role) const override
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QModelIndexList fidToIndexList(QgsFeatureId fid)
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
QString displayExpression() const
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
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.
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
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
QgsFeatureListModel(QgsAttributeTableFilterModel *sourceModel, QObject *parent=nullptr)
QgsVectorLayerCache * layerCache() const
Returns the layerCache this filter acts on.
QModelIndex mapToMaster(const QModelIndex &proxyIndex) const