QGIS API Documentation  2.99.0-Master (c558d51)
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  {
76  return QSettings().value( QStringLiteral( "qgis/nullValue" ), "NULL" ).toString();
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  QgsExpressionContext context;
97  << QgsExpressionContextUtils::layerScope( mFilterModel->layer() );
98  context.setFeature( feat );
99  return mExpression->evaluate( &context );
100  }
101 
102  if ( role == FeatureInfoRole )
103  {
104  FeatureInfo featInfo;
105 
106  QgsFeature feat;
107 
108  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
109 
110  QgsVectorLayerEditBuffer* editBuffer = mFilterModel->layer()->editBuffer();
111 
112  if ( editBuffer )
113  {
114  if ( editBuffer->isFeatureAdded( feat.id() ) )
115  {
116  featInfo.isNew = true;
117  }
118  if ( editBuffer->isFeatureAttributesChanged( feat.id() ) )
119  {
120  featInfo.isEdited = true;
121  }
122  }
123 
124  return QVariant::fromValue( featInfo );
125  }
126  else if ( role == FeatureRole )
127  {
128  QgsFeature feat;
129 
130  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
131 
132  return QVariant::fromValue( feat );
133  }
134  else if ( role == Qt::TextAlignmentRole )
135  {
136  return Qt::AlignLeft;
137  }
138 
139  return sourceModel()->data( mapToSource( index ), role );
140 }
141 
142 Qt::ItemFlags QgsFeatureListModel::flags( const QModelIndex &index ) const
143 {
144  if ( mInjectNull && index.row() == 0 )
145  {
146  return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
147  }
148  else
149  {
150  return sourceModel()->flags( mapToSource( index ) ) & ~Qt::ItemIsEditable;
151  }
152 }
153 
155 {
156  if ( mInjectNull != injectNull )
157  {
158  emit beginResetModel();
159  mInjectNull = injectNull;
160  emit endResetModel();
161  }
162 }
163 
165 {
166  return mInjectNull;
167 }
168 
170 {
171  return mFilterModel->masterModel();
172 }
173 
174 bool QgsFeatureListModel::setDisplayExpression( const QString& expression )
175 {
176  QgsExpression* exp = new QgsExpression( expression );
177 
178  QgsExpressionContext context;
181  << QgsExpressionContextUtils::layerScope( mFilterModel->layer() );
182 
183  exp->prepare( &context );
184 
185  if ( exp->hasParserError() )
186  {
187  mParserErrorString = exp->parserErrorString();
188  delete exp;
189  return false;
190  }
191 
192  delete mExpression;
193  mExpression = exp;
194 
195  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );
196  return true;
197 }
198 
200 {
201  return mParserErrorString;
202 }
203 
205 {
206  return mExpression->expression();
207 }
208 
209 bool QgsFeatureListModel::featureByIndex( const QModelIndex &index, QgsFeature &feat )
210 {
211  return mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
212 }
213 
214 void QgsFeatureListModel::onBeginRemoveRows( const QModelIndex& parent, int first, int last )
215 {
216  beginRemoveRows( parent, first, last );
217 }
218 
219 void QgsFeatureListModel::onEndRemoveRows( const QModelIndex& parent, int first, int last )
220 {
221  Q_UNUSED( parent )
222  Q_UNUSED( first )
223  Q_UNUSED( last )
224  endRemoveRows();
225 }
226 
227 void QgsFeatureListModel::onBeginInsertRows( const QModelIndex& parent, int first, int last )
228 {
229  beginInsertRows( parent, first, last );
230 }
231 
232 void QgsFeatureListModel::onEndInsertRows( const QModelIndex& parent, int first, int last )
233 {
234  Q_UNUSED( parent )
235  Q_UNUSED( first )
236  Q_UNUSED( last )
237  endInsertRows();
238 }
239 
240 QModelIndex QgsFeatureListModel::mapToMaster( const QModelIndex &proxyIndex ) const
241 {
242  if ( !proxyIndex.isValid() )
243  return QModelIndex();
244 
245  int offset = mInjectNull ? 1 : 0;
246 
247  return mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
248 }
249 
250 QModelIndex QgsFeatureListModel::mapFromMaster( const QModelIndex &sourceIndex ) const
251 {
252  if ( !sourceIndex.isValid() )
253  return QModelIndex();
254 
255  int offset = mInjectNull ? 1 : 0;
256 
257  return createIndex( mFilterModel->mapFromMaster( sourceIndex ).row() + offset, 0 );
258 }
259 
260 QItemSelection QgsFeatureListModel::mapSelectionFromMaster( const QItemSelection& selection ) const
261 {
262  return mapSelectionFromSource( mFilterModel->mapSelectionFromSource( selection ) );
263 }
264 
265 QItemSelection QgsFeatureListModel::mapSelectionToMaster( const QItemSelection& selection ) const
266 {
267  return mFilterModel->mapSelectionToSource( mapSelectionToSource( selection ) );
268 }
269 
270 // Override some methods from QAbstractProxyModel, not that interesting
271 
272 QModelIndex QgsFeatureListModel::mapToSource( const QModelIndex &proxyIndex ) const
273 {
274  if ( !proxyIndex.isValid() )
275  return QModelIndex();
276 
277  int offset = mInjectNull ? 1 : 0;
278 
279  return sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
280 }
281 
282 QModelIndex QgsFeatureListModel::mapFromSource( const QModelIndex &sourceIndex ) const
283 {
284  if ( !sourceIndex.isValid() )
285  return QModelIndex();
286 
287  return createIndex( sourceIndex.row(), 0 );
288 }
289 
290 QModelIndex QgsFeatureListModel::index( int row, int column, const QModelIndex& parent ) const
291 {
292  Q_UNUSED( parent )
293 
294  return createIndex( row, column );
295 }
296 
297 QModelIndex QgsFeatureListModel::parent( const QModelIndex& child ) const
298 {
299  Q_UNUSED( child )
300  return QModelIndex();
301 }
302 
303 int QgsFeatureListModel::columnCount( const QModelIndex&parent ) const
304 {
305  Q_UNUSED( parent )
306  return 1;
307 }
308 
309 int QgsFeatureListModel::rowCount( const QModelIndex& parent ) const
310 {
311  Q_UNUSED( parent )
312 
313  int offset = mInjectNull ? 1 : 0;
314 
315  return sourceModel()->rowCount() + offset;
316 }
317 
319 {
320  return mapFromMaster( masterModel()->idToIndex( fid ) );
321 }
322 
324 {
325  return QModelIndexList() << fidToIndex( fid );
326 }
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:139
QModelIndex fidToIndex(QgsFeatureId fid) override
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
bool setDisplayExpression(const QString &expression)
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
virtual QModelIndex mapToMaster(const QModelIndex &proxyIndex) const
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)
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:135
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)
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
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QgsVectorLayerCache * layerCache() const
Returns the layerCache this filter acts on.
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
QModelIndex mapToMaster(const QModelIndex &proxyIndex) const
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)
virtual Qt::ItemFlags flags(const QModelIndex &index) const override
QgsAttributeTableModel * masterModel()
void onBeginRemoveRows(const QModelIndex &parent, int first, int last)
This class caches features of a given QgsVectorLayer.
QgsAttributeTableModel * masterModel() const
Returns the table model this filter is using.
QModelIndex mapFromMaster(const QModelIndex &sourceIndex) 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.
QgsFeatureId idxToFid(const QModelIndex &index) const
qint64 QgsFeatureId
Definition: qgsfeature.h:32
void onEndRemoveRows(const QModelIndex &parent, int first, int last)
QString expression() const
Return the original, unmodified expression string.
QgsVectorLayerCache * layerCache()
void setInjectNull(bool injectNull)
If true is specified, a NULL value will be injected.
QgsFeatureId rowToId(int row) const
Maps row to feature id.
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
bool isFeatureAttributesChanged(QgsFeatureId id) const
Returns true if the specified feature ID has had an attribute changed but not committed.
virtual QModelIndex parent(const QModelIndex &child) const override
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
bool isFeatureAdded(QgsFeatureId id) const
Returns true if the specified feature ID has been added but not committed.
QModelIndex fidToIdx(const QgsFeatureId fid) const
QString parserErrorString() const
Returns parser error.
virtual QItemSelection mapSelectionFromMaster(const QItemSelection &selection) const
QgsFeatureListModel(QgsAttributeTableFilterModel *sourceModel, QObject *parent=nullptr)
QString displayExpression() const