QGIS API Documentation 3.43.0-Master (ebb4087afc0)
Loading...
Searching...
No Matches
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"
18#include "moc_qgsfeaturelistmodel.cpp"
22#include "qgsapplication.h"
23#include "qgsvectorlayercache.h"
24
25#include <QItemSelection>
26#include <QSettings>
27
29 : QSortFilterProxyModel( parent )
30{
31 setSourceModel( sourceModel );
32}
33
35{
36 if ( mSourceLayer )
37 disconnect( mSourceLayer->conditionalStyles(), &QgsConditionalLayerStyles::changed, this, &QgsFeatureListModel::conditionalStylesChanged );
38
39 QSortFilterProxyModel::setSourceModel( sourceModel );
40 mExpressionContext = sourceModel->layer()->createExpressionContext();
41 mFilterModel = sourceModel;
42
43 mSourceLayer = sourceModel->layer();
44 connect( mSourceLayer->conditionalStyles(), &QgsConditionalLayerStyles::changed, this, &QgsFeatureListModel::conditionalStylesChanged );
45}
46
51
52QgsFeatureId QgsFeatureListModel::idxToFid( const QModelIndex &index ) const
53{
54 return mFilterModel->masterModel()->rowToId( mapToMaster( index ).row() );
55}
56
57QModelIndex QgsFeatureListModel::fidToIdx( const QgsFeatureId fid ) const
58{
59 return mapFromMaster( mFilterModel->masterModel()->idToIndex( fid ) );
60}
61
62QVariant QgsFeatureListModel::data( const QModelIndex &index, int role ) const
63{
64 if ( mInjectNull && index.row() == 0 )
65 {
66 if ( role == Qt::DisplayRole )
67 {
69 }
70 else
71 {
72 return QgsVariantUtils::createNullVariant( QMetaType::Type::UnknownType );
73 }
74 }
75
76 if ( role == Qt::DisplayRole || role == Qt::EditRole )
77 {
78 QgsFeature feat;
79
80 mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
81
82 mExpressionContext.setFeature( feat );
83 return mDisplayExpression.evaluate( &mExpressionContext );
84 }
85
86 if ( role == FeatureInfoRole )
87 {
88 FeatureInfo featInfo;
89
90 QgsFeature feat;
91
92 mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
93
94 QgsVectorLayerEditBuffer *editBuffer = mFilterModel->layer()->editBuffer();
95
96 if ( editBuffer )
97 {
98 if ( editBuffer->isFeatureAdded( feat.id() ) )
99 {
100 featInfo.isNew = true;
101 }
102 if ( editBuffer->isFeatureAttributesChanged( feat.id() ) )
103 {
104 featInfo.isEdited = true;
105 }
106 }
107
108 return QVariant::fromValue( featInfo );
109 }
110 else if ( role == FeatureRole )
111 {
112 QgsFeature feat;
113
114 mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
115
116 return QVariant::fromValue( feat );
117 }
118 else if ( role == FeatureWithGeometryRole )
119 {
120 QgsFeature feat;
121
122 mFilterModel->layerCache()->completeFeatureAtId( idxToFid( index ), feat );
123
124 return QVariant::fromValue( feat );
125 }
126 else if ( role == Qt::TextAlignmentRole )
127 {
128 return static_cast<Qt::Alignment::Int>( Qt::AlignLeft );
129 }
130
131 if ( role == Qt::BackgroundRole
132 || role == Qt::ForegroundRole
133 || role == Qt::DecorationRole
134 || role == Qt::FontRole )
135 {
136 QgsVectorLayer *layer = mFilterModel->layer();
137 QgsFeature feat;
138 const QgsFeatureId fid = idxToFid( index );
139 mFilterModel->layerCache()->featureAtIdWithAllAttributes( 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 const 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::BackgroundRole && style.validBackgroundColor() )
169 return style.backgroundColor().isValid() ? style.backgroundColor() : QVariant();
170 if ( role == Qt::ForegroundRole && style.validTextColor() )
171 return style.textColor().isValid() ? style.textColor() : QVariant();
172 if ( role == Qt::DecorationRole )
173 return style.icon().isNull() ? QVariant() : 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
184Qt::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 return;
200
201 if ( injectNull )
203
204 beginResetModel();
205 mInjectNull = injectNull;
206 endResetModel();
207}
208
210{
211 return mInjectNull;
212}
213
218
219bool QgsFeatureListModel::setDisplayExpression( const QString &expression )
220{
221 QgsExpression exp = QgsExpression( expression );
222
223 exp.prepare( &mExpressionContext );
224
225 if ( exp.hasParserError() )
226 {
227 mParserErrorString = exp.parserErrorString();
228 return false;
229 }
230
231 mDisplayExpression = exp;
232
233 if ( mSortByDisplayExpression )
234 masterModel()->prefetchSortData( expression, 1 );
235
236 emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );
237
238 invalidate();
239 return true;
240}
241
243{
244 return mParserErrorString;
245}
246
248{
249 return mDisplayExpression.expression();
250}
251
252bool QgsFeatureListModel::featureByIndex( const QModelIndex &index, QgsFeature &feat )
253{
254 return mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
255}
256
257void QgsFeatureListModel::onBeginRemoveRows( const QModelIndex &parent, int first, int last )
258{
259 beginRemoveRows( parent, first, last );
260}
261
262void QgsFeatureListModel::onEndRemoveRows( const QModelIndex &parent, int first, int last )
263{
264 Q_UNUSED( parent )
265 Q_UNUSED( first )
266 Q_UNUSED( last )
267 endRemoveRows();
268}
269
270void QgsFeatureListModel::onBeginInsertRows( const QModelIndex &parent, int first, int last )
271{
272 beginInsertRows( parent, first, last );
273}
274
275void QgsFeatureListModel::onEndInsertRows( const QModelIndex &parent, int first, int last )
276{
277 Q_UNUSED( parent )
278 Q_UNUSED( first )
279 Q_UNUSED( last )
280 endInsertRows();
281}
282
283void QgsFeatureListModel::conditionalStylesChanged()
284{
285 mRowStylesMap.clear();
286 emit dataChanged( index( 0, 0 ), index( rowCount() - 1, columnCount() - 1 ) );
287}
288
290{
291 return mSortByDisplayExpression;
292}
293
294void QgsFeatureListModel::setSortByDisplayExpression( bool sortByDisplayExpression, Qt::SortOrder order )
295{
296 mSortByDisplayExpression = sortByDisplayExpression;
297
298 // If we are sorting by display expression, we do not support injected null
299 if ( mSortByDisplayExpression )
300 setInjectNull( false );
301
302 setSortRole( static_cast<int>( QgsAttributeTableModel::CustomRole::Sort ) + 1 );
303 setDynamicSortFilter( mSortByDisplayExpression );
304 sort( 0, order );
305}
306
307QModelIndex QgsFeatureListModel::mapToMaster( const QModelIndex &proxyIndex ) const
308{
309 QModelIndex masterIndex;
310
311 if ( proxyIndex.isValid() )
312 {
313 if ( mSortByDisplayExpression )
314 {
315 masterIndex = mFilterModel->mapToMaster( mapToSource( proxyIndex ) );
316 }
317 else
318 {
319 const int offset = mInjectNull ? 1 : 0;
320
321 masterIndex = mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
322 }
323 }
324 return masterIndex;
325}
326
327QModelIndex QgsFeatureListModel::mapFromMaster( const QModelIndex &masterIndex ) const
328{
329 QModelIndex proxyIndex;
330
331 if ( masterIndex.isValid() )
332 {
333 if ( mSortByDisplayExpression )
334 {
335 proxyIndex = mapFromSource( mFilterModel->mapFromMaster( masterIndex ) );
336 }
337 else
338 {
339 const int offset = mInjectNull ? 1 : 0;
340
341 return createIndex( mFilterModel->mapFromMaster( masterIndex ).row() + offset, 0 );
342 }
343 }
344
345 return proxyIndex;
346}
347
348QItemSelection QgsFeatureListModel::mapSelectionFromMaster( const QItemSelection &selection ) const
349{
350 return mapSelectionFromSource( mFilterModel->mapSelectionFromSource( selection ) );
351}
352
353QItemSelection QgsFeatureListModel::mapSelectionToMaster( const QItemSelection &selection ) const
354{
355 return mFilterModel->mapSelectionToSource( mapSelectionToSource( selection ) );
356}
357
358// Override some methods from QAbstractProxyModel, not that interesting
359
360QModelIndex QgsFeatureListModel::mapToSource( const QModelIndex &proxyIndex ) const
361{
362 QModelIndex sourceIndex;
363
364 if ( mSortByDisplayExpression )
365 {
366 sourceIndex = QSortFilterProxyModel::mapToSource( proxyIndex );
367 }
368 else
369 {
370 if ( !proxyIndex.isValid() )
371 return QModelIndex();
372
373 const int offset = mInjectNull ? 1 : 0;
374
375 sourceIndex = sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
376 }
377
378 return sourceIndex;
379}
380
381QModelIndex QgsFeatureListModel::mapFromSource( const QModelIndex &sourceIndex ) const
382{
383 QModelIndex proxyIndex;
384
385 if ( mSortByDisplayExpression )
386 {
387 proxyIndex = QSortFilterProxyModel::mapFromSource( sourceIndex );
388 }
389 else
390 {
391 if ( sourceIndex.isValid() )
392 proxyIndex = createIndex( sourceIndex.row(), 0 );
393 }
394
395 return proxyIndex;
396}
397
398QModelIndex QgsFeatureListModel::parent( const QModelIndex &child ) const
399{
400 Q_UNUSED( child )
401 return QModelIndex();
402}
403
404int QgsFeatureListModel::columnCount( const QModelIndex &parent ) const
405{
406 Q_UNUSED( parent )
407 return 1;
408}
409
410int QgsFeatureListModel::rowCount( const QModelIndex &parent ) const
411{
412 Q_UNUSED( parent )
413
414 const int offset = mInjectNull ? 1 : 0;
415
416 return sourceModel()->rowCount() + offset;
417}
418
420{
421 return mapFromMaster( masterModel()->idToIndex( fid ) );
422}
423
425{
426 return QModelIndexList() << fidToIndex( fid );
427}
static QString nullRepresentation()
Returns the string 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()
@ FeatureWithGeometryRole
Feature with all attributes and geometry,.
@ FeatureRole
Feature with all attributes and no geometry.
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:58
QgsFeatureId id
Definition qgsfeature.h:66
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
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 completeFeatureAtId(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id with all attributes and geometry, if the cached feature alre...
Stores queued vector layer edit operations prior to committing changes to the layer's data provider.
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
bool isEdited
True if feature has been edited.
bool isNew
True if feature is a newly added feature.