QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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( "" );
31 }
32 
34 {
35  delete mExpression;
36 }
37 
39 {
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 
66 {
67  return mFilterModel->mapFromMaster( mFilterModel->masterModel()->idToIndex( fid ) );
68 }
69 
71 {
72  if ( mInjectNull && index.row() == 0 )
73  {
74  if ( role == Qt::DisplayRole )
75  {
76  return QSettings().value( "qgis/nullValue", "NULL" ).toString();
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  QgsExpressionContext context;
93  << QgsExpressionContextUtils::layerScope( mFilterModel->layer() );
94  context.setFeature( feat );
95  return mExpression->evaluate( &context );
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  const QList<QgsFeatureId> addedFeatures = editBuffer->addedFeatures().keys();
111  const QList<QgsFeatureId> changedFeatures = editBuffer->changedAttributeValues().keys();
112 
113  if ( addedFeatures.contains( feat.id() ) )
114  {
115  featInfo.isNew = true;
116  }
117  if ( changedFeatures.contains( feat.id() ) )
118  {
119  featInfo.isEdited = true;
120  }
121  }
122 
123  return QVariant::fromValue( featInfo );
124  }
125  else if ( role == FeatureRole )
126  {
127  QgsFeature feat;
128 
129  mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
130 
131  return QVariant::fromValue( feat );
132  }
133  else if ( role == Qt::TextAlignmentRole )
134  {
135  return Qt::AlignLeft;
136  }
137 
138  return sourceModel()->data( mapToSource( index ), role );
139 }
140 
142 {
143  if ( mInjectNull && index.row() == 0 )
144  {
145  return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
146  }
147  else
148  {
149  return sourceModel()->flags( mapToSource( index ) ) & ~Qt::ItemIsEditable;
150  }
151 }
152 
154 {
155  if ( mInjectNull != injectNull )
156  {
157  emit beginResetModel();
158  mInjectNull = injectNull;
159  emit endResetModel();
160  }
161 }
162 
164 {
165  return mInjectNull;
166 }
167 
169 {
170  return mFilterModel->masterModel();
171 }
172 
174 {
175  QgsExpression* exp = new QgsExpression( expression );
176 
177  QgsExpressionContext context;
180  << QgsExpressionContextUtils::layerScope( mFilterModel->layer() );
181 
182  exp->prepare( &context );
183 
184  if ( exp->hasParserError() )
185  {
186  mParserErrorString = exp->parserErrorString();
187  delete exp;
188  return false;
189  }
190 
191  delete mExpression;
192  mExpression = exp;
193 
194  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );
195  return true;
196 }
197 
199 {
200  return mParserErrorString;
201 }
202 
204 {
205  return mExpression->expression();
206 }
207 
209 {
210  return mFilterModel->layerCache()->featureAtId( idxToFid( index ), feat );
211 }
212 
213 void QgsFeatureListModel::onBeginRemoveRows( const QModelIndex& parent, int first, int last )
214 {
215  beginRemoveRows( parent, first, last );
216 }
217 
218 void QgsFeatureListModel::onEndRemoveRows( const QModelIndex& parent, int first, int last )
219 {
220  Q_UNUSED( parent )
221  Q_UNUSED( first )
222  Q_UNUSED( last )
223  endRemoveRows();
224 }
225 
226 void QgsFeatureListModel::onBeginInsertRows( const QModelIndex& parent, int first, int last )
227 {
228  beginInsertRows( parent, first, last );
229 }
230 
231 void QgsFeatureListModel::onEndInsertRows( const QModelIndex& parent, int first, int last )
232 {
233  Q_UNUSED( parent )
234  Q_UNUSED( first )
235  Q_UNUSED( last )
236  endInsertRows();
237 }
238 
240 {
241  if ( !proxyIndex.isValid() )
242  return QModelIndex();
243 
244  int offset = mInjectNull ? 1 : 0;
245 
246  return mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
247 }
248 
250 {
251  if ( !sourceIndex.isValid() )
252  return QModelIndex();
253 
254  int offset = mInjectNull ? 1 : 0;
255 
256  return createIndex( mFilterModel->mapFromMaster( sourceIndex ).row() + offset, 0 );
257 }
258 
260 {
261  return mapSelectionFromSource( mFilterModel->mapSelectionFromSource( selection ) );
262 }
263 
265 {
266  return mFilterModel->mapSelectionToSource( mapSelectionToSource( selection ) );
267 }
268 
269 // Override some methods from QAbstractProxyModel, not that interesting
270 
272 {
273  if ( !proxyIndex.isValid() )
274  return QModelIndex();
275 
276  int offset = mInjectNull ? 1 : 0;
277 
278  return sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
279 }
280 
282 {
283  if ( !sourceIndex.isValid() )
284  return QModelIndex();
285 
286  return createIndex( sourceIndex.row(), 0 );
287 }
288 
289 QModelIndex QgsFeatureListModel::index( int row, int column, const QModelIndex& parent ) const
290 {
291  Q_UNUSED( parent )
292 
293  return createIndex( row, column );
294 }
295 
297 {
298  Q_UNUSED( child )
299  return QModelIndex();
300 }
301 
303 {
304  Q_UNUSED( parent )
305  return 1;
306 }
307 
309 {
310  Q_UNUSED( parent )
311 
312  int offset = mInjectNull ? 1 : 0;
313 
314  return sourceModel()->rowCount() + offset;
315 }
316 
318 {
319  return mapFromMaster( masterModel()->idToIndex( fid ) );
320 }
321 
323 {
324  return QModelIndexList() << fidToIndex( fid );
325 }
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
bool injectNull()
Returns the current state of null value injection.
QObject * child(const char *objName, const char *inheritsClass, bool recursiveSearch) const
Class for parsing and evaluation of expressions (formerly called "search strings").
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 int rowCount(const QModelIndex &parent) const=0
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const=0
QgsAttributeTableModel * masterModel() const
Returns the table model this filter is using.
QgsFeatureId idxToFid(const QModelIndex &index) const
Q_DECL_DEPRECATED QVariant evaluate(const QgsFeature *f)
Evaluate the feature and return the result.
bool setDisplayExpression(const QString &expression)
QModelIndex mapFromMaster(const QModelIndex &sourceIndex) const
Q_DECL_DEPRECATED bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
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
const QgsChangedAttributesMap & changedAttributeValues()
Changed attributes values which are not commited.
virtual QItemSelection mapSelectionFromSource(const QItemSelection &sourceSelection) const
void onEndInsertRows(const QModelIndex &parent, int first, int last)
bool featureByIndex(const QModelIndex &index, QgsFeature &feat)
virtual QItemSelection mapSelectionFromSource(const QItemSelection &sourceSelection) const
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
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)
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QList< Key > keys() const
void layoutAboutToBeChanged()
bool isValid() const
QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
virtual QVariant data(const QModelIndex &index, int role) const override
virtual QItemSelection mapSelectionToSource(const QItemSelection &proxySelection) const
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void beginRemoveRows(const QModelIndex &parent, int first, int last)
int row() const
QModelIndexList fidToIndexList(QgsFeatureId fid)
virtual void setSourceModel(QAbstractItemModel *sourceModel)
QString displayExpression() const
virtual QVariant data(const QModelIndex &index, int role) const=0
virtual Qt::ItemFlags flags(const QModelIndex &index) const override
void rowsRemoved(const QModelIndex &parent, int start, int end)
QModelIndex createIndex(int row, int column, void *ptr) const
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
QgsAttributeTableModel * masterModel()
virtual QItemSelection mapSelectionToSource(const QItemSelection &proxySelection) const
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.
bool contains(const T &value) const
QVariant fromValue(const T &value)
void beginInsertRows(const QModelIndex &parent, int first, int last)
const QgsFeatureMap & addedFeatures()
New features which are not commited.
QVariant value(const QString &key, const QVariant &defaultValue) const
QAbstractItemModel * sourceModel() const
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
int column() const
QgsFeatureId rowToId(int row) const
Maps row to feature id.
qint64 QgsFeatureId
Definition: qgsfeature.h:31
void onEndRemoveRows(const QModelIndex &parent, int first, int last)
virtual QItemSelection mapSelectionFromMaster(const QItemSelection &selection) const
QgsVectorLayerCache * layerCache()
virtual Qt::ItemFlags flags(const QModelIndex &index) const
void setInjectNull(bool injectNull)
If true is specified, a NULL value will be injected.
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
void rowsInserted(const QModelIndex &parent, int start, int end)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
QString toString() const
QgsFeatureListModel(QgsAttributeTableFilterModel *sourceModel, QObject *parent=nullptr)
QgsVectorLayerCache * layerCache() const
Returns the layerCache this filter acts on.
QModelIndex mapToMaster(const QModelIndex &proxyIndex) const
typedef ItemFlags