QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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"
17#include "qgsfeaturelistmodel.h"
21#include "qgsapplication.h"
22#include "qgsvectorlayercache.h"
23
24#include <QItemSelection>
25#include <QSettings>
26
28 : QSortFilterProxyModel( parent )
29{
30 setSourceModel( sourceModel );
31}
32
34{
35 if ( mSourceLayer )
36 disconnect( mSourceLayer->conditionalStyles(), &QgsConditionalLayerStyles::changed, this, &QgsFeatureListModel::conditionalStylesChanged );
37
38 QSortFilterProxyModel::setSourceModel( sourceModel );
39 mExpressionContext = sourceModel->layer()->createExpressionContext();
40 mFilterModel = sourceModel;
41
42 mSourceLayer = sourceModel->layer();
43 connect( mSourceLayer->conditionalStyles(), &QgsConditionalLayerStyles::changed, this, &QgsFeatureListModel::conditionalStylesChanged );
44}
45
47{
48 return mFilterModel->layerCache();
49}
50
51QgsFeatureId QgsFeatureListModel::idxToFid( const QModelIndex &index ) const
52{
53 return mFilterModel->masterModel()->rowToId( mapToMaster( index ).row() );
54}
55
56QModelIndex QgsFeatureListModel::fidToIdx( const QgsFeatureId fid ) const
57{
58 return mapFromMaster( mFilterModel->masterModel()->idToIndex( fid ) );
59}
60
61QVariant QgsFeatureListModel::data( const QModelIndex &index, int role ) const
62{
63 if ( mInjectNull && index.row() == 0 )
64 {
65 if ( role == Qt::DisplayRole )
66 {
68 }
69 else
70 {
71 return QVariant( QVariant::Invalid );
72 }
73 }
74
75 if ( role == Qt::DisplayRole || role == Qt::EditRole )
76 {
77 QgsFeature feat;
78
79 mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
80
81 mExpressionContext.setFeature( feat );
82 return mDisplayExpression.evaluate( &mExpressionContext );
83 }
84
85 if ( role == FeatureInfoRole )
86 {
87 FeatureInfo featInfo;
88
89 QgsFeature feat;
90
91 mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
92
93 QgsVectorLayerEditBuffer *editBuffer = mFilterModel->layer()->editBuffer();
94
95 if ( editBuffer )
96 {
97 if ( editBuffer->isFeatureAdded( feat.id() ) )
98 {
99 featInfo.isNew = true;
100 }
101 if ( editBuffer->isFeatureAttributesChanged( feat.id() ) )
102 {
103 featInfo.isEdited = true;
104 }
105 }
106
107 return QVariant::fromValue( featInfo );
108 }
109 else if ( role == FeatureRole )
110 {
111 QgsFeature feat;
112
113 mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
114
115 return QVariant::fromValue( feat );
116 }
117 else if ( role == Qt::TextAlignmentRole )
118 {
119 return static_cast<Qt::Alignment::Int>( Qt::AlignLeft );
120 }
121
122 if ( role == Qt::BackgroundRole
123 || role == Qt::ForegroundRole
124 || role == Qt::DecorationRole
125 || role == Qt::FontRole )
126 {
127 QgsVectorLayer *layer = mFilterModel->layer();
128 QgsFeature feat;
129 const QgsFeatureId fid = idxToFid( index );
130 mFilterModel->layerCache()->featureAtIdWithAllAttributes( fid, feat );
131 mExpressionContext.setFeature( feat );
132 QList<QgsConditionalStyle> styles;
133
134 if ( mRowStylesMap.contains( fid ) )
135 {
136 styles = mRowStylesMap.value( fid );
137 }
138 else
139 {
140 styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
141 mRowStylesMap.insert( fid, styles );
142 }
143
145
146 if ( mDisplayExpression.isField() )
147 {
148 const QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
149 styles = layer->conditionalStyles()->fieldStyles( fieldName );
150 styles = QgsConditionalStyle::matchingConditionalStyles( styles, feat.attribute( fieldName ), mExpressionContext );
151 }
152
153 styles.insert( 0, rowstyle );
154
156
157 if ( style.isValid() )
158 {
159 if ( role == Qt::BackgroundRole && style.validBackgroundColor() )
160 return style.backgroundColor().isValid() ? style.backgroundColor() : QVariant();
161 if ( role == Qt::ForegroundRole && style.validTextColor() )
162 return style.textColor().isValid() ? style.textColor() : QVariant();
163 if ( role == Qt::DecorationRole )
164 return style.icon().isNull() ? QVariant() : style.icon();
165 if ( role == Qt::FontRole )
166 return style.font();
167 }
168
169 return QVariant();
170 }
171
172 return sourceModel()->data( mapToSource( index ), role );
173}
174
175Qt::ItemFlags QgsFeatureListModel::flags( const QModelIndex &index ) const
176{
177 if ( mInjectNull && index.row() == 0 )
178 {
179 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
180 }
181 else
182 {
183 return sourceModel()->flags( mapToSource( index ) ) & ~Qt::ItemIsEditable;
184 }
185}
186
188{
189 if ( mInjectNull == injectNull )
190 return;
191
192 if ( injectNull )
194
195 beginResetModel();
196 mInjectNull = injectNull;
197 endResetModel();
198}
199
201{
202 return mInjectNull;
203}
204
206{
207 return mFilterModel->masterModel();
208}
209
210bool QgsFeatureListModel::setDisplayExpression( const QString &expression )
211{
212 QgsExpression exp = QgsExpression( expression );
213
214 exp.prepare( &mExpressionContext );
215
216 if ( exp.hasParserError() )
217 {
218 mParserErrorString = exp.parserErrorString();
219 return false;
220 }
221
222 mDisplayExpression = exp;
223
224 if ( mSortByDisplayExpression )
225 masterModel()->prefetchSortData( expression, 1 );
226
227 emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );
228
229 invalidate();
230 return true;
231}
232
234{
235 return mParserErrorString;
236}
237
239{
240 return mDisplayExpression.expression();
241}
242
243bool QgsFeatureListModel::featureByIndex( const QModelIndex &index, QgsFeature &feat )
244{
245 return mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
246}
247
248void QgsFeatureListModel::onBeginRemoveRows( const QModelIndex &parent, int first, int last )
249{
250 beginRemoveRows( parent, first, last );
251}
252
253void QgsFeatureListModel::onEndRemoveRows( const QModelIndex &parent, int first, int last )
254{
255 Q_UNUSED( parent )
256 Q_UNUSED( first )
257 Q_UNUSED( last )
258 endRemoveRows();
259}
260
261void QgsFeatureListModel::onBeginInsertRows( const QModelIndex &parent, int first, int last )
262{
263 beginInsertRows( parent, first, last );
264}
265
266void QgsFeatureListModel::onEndInsertRows( const QModelIndex &parent, int first, int last )
267{
268 Q_UNUSED( parent )
269 Q_UNUSED( first )
270 Q_UNUSED( last )
271 endInsertRows();
272}
273
274void QgsFeatureListModel::conditionalStylesChanged()
275{
276 mRowStylesMap.clear();
277 emit dataChanged( index( 0, 0 ), index( rowCount() - 1, columnCount() - 1 ) );
278}
279
281{
282 return mSortByDisplayExpression;
283}
284
285void QgsFeatureListModel::setSortByDisplayExpression( bool sortByDisplayExpression, Qt::SortOrder order )
286{
287 mSortByDisplayExpression = sortByDisplayExpression;
288
289 // If we are sorting by display expression, we do not support injected null
290 if ( mSortByDisplayExpression )
291 setInjectNull( false );
292
293 setSortRole( static_cast< int >( QgsAttributeTableModel::CustomRole::Sort ) + 1 );
294 setDynamicSortFilter( mSortByDisplayExpression );
295 sort( 0, order );
296}
297
298QModelIndex QgsFeatureListModel::mapToMaster( const QModelIndex &proxyIndex ) const
299{
300 QModelIndex masterIndex;
301
302 if ( proxyIndex.isValid() )
303 {
304 if ( mSortByDisplayExpression )
305 {
306 masterIndex = mFilterModel->mapToMaster( mapToSource( proxyIndex ) );
307 }
308 else
309 {
310 const int offset = mInjectNull ? 1 : 0;
311
312 masterIndex = mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
313 }
314 }
315 return masterIndex;
316}
317
318QModelIndex QgsFeatureListModel::mapFromMaster( const QModelIndex &masterIndex ) const
319{
320 QModelIndex proxyIndex;
321
322 if ( masterIndex.isValid() )
323 {
324 if ( mSortByDisplayExpression )
325 {
326 proxyIndex = mapFromSource( mFilterModel->mapFromMaster( masterIndex ) );
327 }
328 else
329 {
330 const int offset = mInjectNull ? 1 : 0;
331
332 return createIndex( mFilterModel->mapFromMaster( masterIndex ).row() + offset, 0 );
333 }
334 }
335
336 return proxyIndex;
337}
338
339QItemSelection QgsFeatureListModel::mapSelectionFromMaster( const QItemSelection &selection ) const
340{
341 return mapSelectionFromSource( mFilterModel->mapSelectionFromSource( selection ) );
342}
343
344QItemSelection QgsFeatureListModel::mapSelectionToMaster( const QItemSelection &selection ) const
345{
346 return mFilterModel->mapSelectionToSource( mapSelectionToSource( selection ) );
347}
348
349// Override some methods from QAbstractProxyModel, not that interesting
350
351QModelIndex QgsFeatureListModel::mapToSource( const QModelIndex &proxyIndex ) const
352{
353 QModelIndex sourceIndex;
354
355 if ( mSortByDisplayExpression )
356 {
357 sourceIndex = QSortFilterProxyModel::mapToSource( proxyIndex );
358 }
359 else
360 {
361 if ( !proxyIndex.isValid() )
362 return QModelIndex();
363
364 const int offset = mInjectNull ? 1 : 0;
365
366 sourceIndex = sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
367 }
368
369 return sourceIndex;
370}
371
372QModelIndex QgsFeatureListModel::mapFromSource( const QModelIndex &sourceIndex ) const
373{
374 QModelIndex proxyIndex;
375
376 if ( mSortByDisplayExpression )
377 {
378 proxyIndex = QSortFilterProxyModel::mapFromSource( sourceIndex );
379 }
380 else
381 {
382 if ( sourceIndex.isValid() )
383 proxyIndex = createIndex( sourceIndex.row(), 0 );
384 }
385
386 return proxyIndex;
387}
388
389QModelIndex QgsFeatureListModel::parent( const QModelIndex &child ) const
390{
391 Q_UNUSED( child )
392 return QModelIndex();
393}
394
395int QgsFeatureListModel::columnCount( const QModelIndex &parent ) const
396{
397 Q_UNUSED( parent )
398 return 1;
399}
400
401int QgsFeatureListModel::rowCount( const QModelIndex &parent ) const
402{
403 Q_UNUSED( parent )
404
405 const int offset = mInjectNull ? 1 : 0;
406
407 return sourceModel()->rowCount() + offset;
408}
409
411{
412 return mapFromMaster( masterModel()->idToIndex( fid ) );
413}
414
416{
417 return QModelIndexList() << fidToIndex( fid );
418}
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
QgsVectorLayerCache * layerCache() const
Returns the layerCache this filter acts on.
QModelIndex mapFromMaster(const QModelIndex &sourceIndex) const
QgsAttributeTableModel * masterModel() const
Returns the table model this filter is using.
QModelIndex mapToMaster(const QModelIndex &proxyIndex) const
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
QModelIndex idToIndex(QgsFeatureId id) const
void prefetchSortData(const QString &expression, unsigned long cacheIndex=0)
Prefetches the entire data for an expression.
QgsFeatureId rowToId(int row) const
Maps row to feature id.
@ Sort
Role used for sorting start here.
void changed()
Emitted when the conditional styles are changed.
QgsConditionalStyles rowStyles() const
Returns a list of row styles associated with the layer.
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName) const
Returns the conditional styles set for the field with matching fieldName.
Conditional styling for a rule.
static QgsConditionalStyle compressStyles(const QList< QgsConditionalStyle > &styles)
Compress a list of styles into a single style.
static QList< QgsConditionalStyle > matchingConditionalStyles(const QList< QgsConditionalStyle > &styles, const QVariant &value, QgsExpressionContext &context)
Find and return the matching styles for the value and feature.
QColor backgroundColor() const
The background color for style.
QColor textColor() const
The text color set for style.
QFont font() const
The font for the style.
bool validTextColor() const
Check if the text color is valid for render.
bool isValid() const
isValid Check if this rule is valid.
QPixmap icon() const
The icon set for style generated from the set symbol.
bool validBackgroundColor() const
Check if the background color is valid for render.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QString expression() const
Returns the original, unmodified expression string.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QString parserErrorString() const
Returns parser error.
bool isField() const
Checks whether an expression consists only of a single field reference.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
QVariant evaluate()
Evaluate the feature and return the result.
QgsFeatureId idxToFid(const QModelIndex &index) const
Returns the feature ID corresponding to an index from the model.
virtual void setSourceModel(QgsAttributeTableFilterModel *sourceModel)
void setInjectNull(bool injectNull)
If true is specified, a NULL value will be injected.
Q_DECL_DEPRECATED void onEndRemoveRows(const QModelIndex &parent, int first, int last)
Does nothing except for calling endRemoveRows()
Q_DECL_DEPRECATED void onBeginInsertRows(const QModelIndex &parent, int first, int last)
Does nothing except for calling beginInsertRows()
Qt::ItemFlags flags(const QModelIndex &index) const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QModelIndexList fidToIndexList(QgsFeatureId fid)
bool featureByIndex(const QModelIndex &index, QgsFeature &feat)
virtual QModelIndex mapToMaster(const QModelIndex &proxyIndex) const
void setSortByDisplayExpression(bool sortByDisplayExpression, Qt::SortOrder order=Qt::AscendingOrder)
Sort this model by its display expression.
QModelIndex fidToIdx(QgsFeatureId fid) const
Returns the model index corresponding to a feature ID.
QString parserErrorString()
Returns a detailed message about errors while parsing a QgsExpression.
Q_DECL_DEPRECATED void onBeginRemoveRows(const QModelIndex &parent, int first, int last)
Does nothing except for calling beginRemoveRows()
QVariant data(const QModelIndex &index, int role) const override
bool injectNull()
Returns the current state of null value injection.
virtual QItemSelection mapSelectionToMaster(const QItemSelection &selection) const
bool sortByDisplayExpression() const
Sort this model by its display expression.
QModelIndex parent(const QModelIndex &child) const override
bool setDisplayExpression(const QString &expression)
virtual QModelIndex mapFromMaster(const QModelIndex &sourceIndex) const
QString displayExpression() const
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
QgsVectorLayerCache * layerCache()
Returns the vector layer cache which is being used to populate the model.
QModelIndex fidToIndex(QgsFeatureId fid) override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
QgsFeatureListModel(QgsAttributeTableFilterModel *sourceModel, QObject *parent=nullptr)
Constructor for QgsFeatureListModel.
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
Q_DECL_DEPRECATED void onEndInsertRows(const QModelIndex &parent, int first, int last)
Does nothing except for calling endInsertRows()
virtual QItemSelection mapSelectionFromMaster(const QItemSelection &selection) const
QgsAttributeTableModel * masterModel()
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:335
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
This class caches features of a given QgsVectorLayer.
bool featureAtIdWithAllAttributes(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id with all attributes, if the cached feature already contains ...
bool isFeatureAdded(QgsFeatureId id) const
Returns true if the specified feature ID has been added but not committed.
bool isFeatureAttributesChanged(QgsFeatureId id) const
Returns true if the specified feature ID has had an attribute changed but not committed.
Represents a vector layer which manages a vector based data sets.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Q_INVOKABLE QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on.
QgsConditionalLayerStyles * conditionalStyles() const
Returns the conditional styles that are set for this layer.
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
bool isEdited
True if feature has been edited.
bool isNew
True if feature is a newly added feature.