QGIS API Documentation 3.99.0-Master (26c88405ac0)
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 "qgsfeaturelistmodel.h"
16
17#include "qgsapplication.h"
20#include "qgsexception.h"
22#include "qgsvectorlayercache.h"
24
25#include <QItemSelection>
26#include <QSettings>
27
28#include "moc_qgsfeaturelistmodel.cpp"
29
31 : QSortFilterProxyModel( parent )
32{
33 setSourceModel( sourceModel );
34}
35
37{
38 if ( mSourceLayer )
39 disconnect( mSourceLayer->conditionalStyles(), &QgsConditionalLayerStyles::changed, this, &QgsFeatureListModel::conditionalStylesChanged );
40
41 QSortFilterProxyModel::setSourceModel( sourceModel );
42 mExpressionContext = sourceModel->layer()->createExpressionContext();
43 mFilterModel = sourceModel;
44
45 mSourceLayer = sourceModel->layer();
46 connect( mSourceLayer->conditionalStyles(), &QgsConditionalLayerStyles::changed, this, &QgsFeatureListModel::conditionalStylesChanged );
47}
48
50{
51 return mFilterModel->layerCache();
52}
53
54QgsFeatureId QgsFeatureListModel::idxToFid( const QModelIndex &index ) const
55{
56 return mFilterModel->masterModel()->rowToId( mapToMaster( index ).row() );
57}
58
59QModelIndex QgsFeatureListModel::fidToIdx( const QgsFeatureId fid ) const
60{
61 return mapFromMaster( mFilterModel->masterModel()->idToIndex( fid ) );
62}
63
64QVariant QgsFeatureListModel::data( const QModelIndex &index, int role ) const
65{
66 if ( mInjectNull && index.row() == 0 )
67 {
68 if ( role == Qt::DisplayRole )
69 {
71 }
72 else
73 {
74 return QgsVariantUtils::createNullVariant( QMetaType::Type::UnknownType );
75 }
76 }
77
78 if ( role == Qt::DisplayRole || role == Qt::EditRole )
79 {
80 QgsFeature feat;
81
82 mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
83
84 mExpressionContext.setFeature( feat );
85 return mDisplayExpression.evaluate( &mExpressionContext );
86 }
87
88 if ( role == FeatureInfoRole )
89 {
90 FeatureInfo featInfo;
91
92 QgsFeature feat;
93
94 mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
95
96 QgsVectorLayerEditBuffer *editBuffer = mFilterModel->layer()->editBuffer();
97
98 if ( editBuffer )
99 {
100 if ( editBuffer->isFeatureAdded( feat.id() ) )
101 {
102 featInfo.isNew = true;
103 }
104 if ( editBuffer->isFeatureAttributesChanged( feat.id() ) )
105 {
106 featInfo.isEdited = true;
107 }
108 }
109
110 return QVariant::fromValue( featInfo );
111 }
112 else if ( role == FeatureRole )
113 {
114 QgsFeature feat;
115
116 mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
117
118 return QVariant::fromValue( feat );
119 }
120 else if ( role == FeatureWithGeometryRole )
121 {
122 QgsFeature feat;
123
124 mFilterModel->layerCache()->completeFeatureAtId( idxToFid( index ), feat );
125
126 return QVariant::fromValue( feat );
127 }
128 else if ( role == Qt::TextAlignmentRole )
129 {
130 return static_cast<Qt::Alignment::Int>( Qt::AlignLeft );
131 }
132
133 if ( role == Qt::BackgroundRole
134 || role == Qt::ForegroundRole
135 || role == Qt::DecorationRole
136 || role == Qt::FontRole )
137 {
138 QgsVectorLayer *layer = mFilterModel->layer();
139 QgsFeature feat;
140 const QgsFeatureId fid = idxToFid( index );
141 mFilterModel->layerCache()->featureAtIdWithAllAttributes( fid, feat );
142 mExpressionContext.setFeature( feat );
143 QList<QgsConditionalStyle> styles;
144
145 if ( mRowStylesMap.contains( fid ) )
146 {
147 styles = mRowStylesMap.value( fid );
148 }
149 else
150 {
151 styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
152 mRowStylesMap.insert( fid, styles );
153 }
154
156
157 if ( mDisplayExpression.isField() )
158 {
159 const QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
160 styles = layer->conditionalStyles()->fieldStyles( fieldName );
161 styles = QgsConditionalStyle::matchingConditionalStyles( styles, feat.attribute( fieldName ), mExpressionContext );
162 }
163
164 styles.insert( 0, rowstyle );
165
167
168 if ( style.isValid() )
169 {
170 if ( role == Qt::BackgroundRole && style.validBackgroundColor() )
171 return style.backgroundColor().isValid() ? style.backgroundColor() : QVariant();
172 if ( role == Qt::ForegroundRole && style.validTextColor() )
173 return style.textColor().isValid() ? style.textColor() : QVariant();
174 if ( role == Qt::DecorationRole )
175 return style.icon().isNull() ? QVariant() : style.icon();
176 if ( role == Qt::FontRole )
177 return style.font();
178 }
179
180 return QVariant();
181 }
182
183 return sourceModel()->data( mapToSource( index ), role );
184}
185
186Qt::ItemFlags QgsFeatureListModel::flags( const QModelIndex &index ) const
187{
188 if ( mInjectNull && index.row() == 0 )
189 {
190 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
191 }
192 else
193 {
194 return sourceModel()->flags( mapToSource( index ) ) & ~Qt::ItemIsEditable;
195 }
196}
197
199{
200 if ( mInjectNull == injectNull )
201 return;
202
203 if ( injectNull )
205
206 beginResetModel();
207 mInjectNull = injectNull;
208 endResetModel();
209}
210
212{
213 return mInjectNull;
214}
215
217{
218 return mFilterModel->masterModel();
219}
220
221bool QgsFeatureListModel::setDisplayExpression( const QString &expression )
222{
223 QgsExpression exp = QgsExpression( expression );
224
225 exp.prepare( &mExpressionContext );
226
227 if ( exp.hasParserError() )
228 {
229 mParserErrorString = exp.parserErrorString();
230 return false;
231 }
232
233 mDisplayExpression = exp;
234
235 if ( mSortByDisplayExpression )
236 {
238 }
239
240 emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );
241
242 invalidate();
243 return true;
244}
245
247{
248 return mParserErrorString;
249}
250
252{
253 return mDisplayExpression.expression();
254}
255
256bool QgsFeatureListModel::featureByIndex( const QModelIndex &index, QgsFeature &feat )
257{
258 return mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
259}
260
261void QgsFeatureListModel::onBeginRemoveRows( const QModelIndex &parent, int first, int last )
262{
263 beginRemoveRows( parent, first, last );
264}
265
266void QgsFeatureListModel::onEndRemoveRows( const QModelIndex &parent, int first, int last )
267{
268 Q_UNUSED( parent )
269 Q_UNUSED( first )
270 Q_UNUSED( last )
271 endRemoveRows();
272}
273
274void QgsFeatureListModel::onBeginInsertRows( const QModelIndex &parent, int first, int last )
275{
276 beginInsertRows( parent, first, last );
277}
278
279void QgsFeatureListModel::onEndInsertRows( const QModelIndex &parent, int first, int last )
280{
281 Q_UNUSED( parent )
282 Q_UNUSED( first )
283 Q_UNUSED( last )
284 endInsertRows();
285}
286
287void QgsFeatureListModel::conditionalStylesChanged()
288{
289 mRowStylesMap.clear();
290 emit dataChanged( index( 0, 0 ), index( rowCount() - 1, columnCount() - 1 ) );
291}
292
294{
295 return mSortByDisplayExpression;
296}
297
299{
300 if ( !mSortByDisplayExpression && sortByDisplayExpression )
301 {
302 masterModel()->prefetchSortData( mDisplayExpression.expression(), QGSFEATURELISTMODEL_CACHE_INDEX );
303 }
304
305 mSortByDisplayExpression = sortByDisplayExpression;
306
307 // If we are sorting by display expression, we do not support injected null
308 if ( mSortByDisplayExpression )
309 {
310 setInjectNull( false );
311 }
312
313 setSortRole( static_cast<int>( QgsAttributeTableModel::CustomRole::Sort ) + 1 );
314 setDynamicSortFilter( mSortByDisplayExpression );
315 sort( 0, order );
316}
317
318QModelIndex QgsFeatureListModel::mapToMaster( const QModelIndex &proxyIndex ) const
319{
320 QModelIndex masterIndex;
321
322 if ( proxyIndex.isValid() )
323 {
324 if ( mSortByDisplayExpression )
325 {
326 masterIndex = mFilterModel->mapToMaster( mapToSource( proxyIndex ) );
327 }
328 else
329 {
330 const int offset = mInjectNull ? 1 : 0;
331
332 masterIndex = mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
333 }
334 }
335 return masterIndex;
336}
337
338QModelIndex QgsFeatureListModel::mapFromMaster( const QModelIndex &masterIndex ) const
339{
340 QModelIndex proxyIndex;
341
342 if ( masterIndex.isValid() )
343 {
344 if ( mSortByDisplayExpression )
345 {
346 proxyIndex = mapFromSource( mFilterModel->mapFromMaster( masterIndex ) );
347 }
348 else
349 {
350 const int offset = mInjectNull ? 1 : 0;
351
352 return createIndex( mFilterModel->mapFromMaster( masterIndex ).row() + offset, 0 );
353 }
354 }
355
356 return proxyIndex;
357}
358
359QItemSelection QgsFeatureListModel::mapSelectionFromMaster( const QItemSelection &selection ) const
360{
361 return mapSelectionFromSource( mFilterModel->mapSelectionFromSource( selection ) );
362}
363
364QItemSelection QgsFeatureListModel::mapSelectionToMaster( const QItemSelection &selection ) const
365{
366 return mFilterModel->mapSelectionToSource( mapSelectionToSource( selection ) );
367}
368
369// Override some methods from QAbstractProxyModel, not that interesting
370
371QModelIndex QgsFeatureListModel::mapToSource( const QModelIndex &proxyIndex ) const
372{
373 QModelIndex sourceIndex;
374
375 if ( mSortByDisplayExpression )
376 {
377 sourceIndex = QSortFilterProxyModel::mapToSource( proxyIndex );
378 }
379 else
380 {
381 if ( !proxyIndex.isValid() )
382 return QModelIndex();
383
384 const int offset = mInjectNull ? 1 : 0;
385
386 sourceIndex = sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
387 }
388
389 return sourceIndex;
390}
391
392QModelIndex QgsFeatureListModel::mapFromSource( const QModelIndex &sourceIndex ) const
393{
394 QModelIndex proxyIndex;
395
396 if ( mSortByDisplayExpression )
397 {
398 proxyIndex = QSortFilterProxyModel::mapFromSource( sourceIndex );
399 }
400 else
401 {
402 if ( sourceIndex.isValid() )
403 proxyIndex = createIndex( sourceIndex.row(), 0 );
404 }
405
406 return proxyIndex;
407}
408
409QModelIndex QgsFeatureListModel::parent( const QModelIndex &child ) const
410{
411 Q_UNUSED( child )
412 return QModelIndex();
413}
414
415int QgsFeatureListModel::columnCount( const QModelIndex &parent ) const
416{
417 Q_UNUSED( parent )
418 return 1;
419}
420
421int QgsFeatureListModel::rowCount( const QModelIndex &parent ) const
422{
423 Q_UNUSED( parent )
424
425 const int offset = mInjectNull ? 1 : 0;
426
427 return sourceModel()->rowCount() + offset;
428}
429
431{
432 return mapFromMaster( masterModel()->idToIndex( fid ) );
433}
434
436{
437 return QModelIndexList() << fidToIndex( fid );
438}
static QString nullRepresentation()
Returns the string used to represent the value NULL throughout QGIS.
A proxy model for filtering an attribute table model.
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...
void prefetchSortData(const QString &expression, unsigned long cacheIndex=0)
Prefetches the entire data for an expression.
@ 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.
Handles parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QString parserErrorString() const
Returns parser error.
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)
Sets the display 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.
Caches features for a given QgsVectorLayer.
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 dataset.
QgsExpressionContext createExpressionContext() const final
This method needs to be reimplemented in all classes which implement this interface and return an exp...
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
#define QGSFEATURELISTMODEL_CACHE_INDEX
bool isEdited
True if feature has been edited.
bool isNew
True if feature is a newly added feature.