QGIS API Documentation 3.41.0-Master (092dc69654e)
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 == Qt::TextAlignmentRole )
119 {
120 return static_cast<Qt::Alignment::Int>( Qt::AlignLeft );
121 }
122
123 if ( role == Qt::BackgroundRole
124 || role == Qt::ForegroundRole
125 || role == Qt::DecorationRole
126 || role == Qt::FontRole )
127 {
128 QgsVectorLayer *layer = mFilterModel->layer();
129 QgsFeature feat;
130 const QgsFeatureId fid = idxToFid( index );
131 mFilterModel->layerCache()->featureAtIdWithAllAttributes( fid, feat );
132 mExpressionContext.setFeature( feat );
133 QList<QgsConditionalStyle> styles;
134
135 if ( mRowStylesMap.contains( fid ) )
136 {
137 styles = mRowStylesMap.value( fid );
138 }
139 else
140 {
141 styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
142 mRowStylesMap.insert( fid, styles );
143 }
144
146
147 if ( mDisplayExpression.isField() )
148 {
149 const QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
150 styles = layer->conditionalStyles()->fieldStyles( fieldName );
151 styles = QgsConditionalStyle::matchingConditionalStyles( styles, feat.attribute( fieldName ), mExpressionContext );
152 }
153
154 styles.insert( 0, rowstyle );
155
157
158 if ( style.isValid() )
159 {
160 if ( role == Qt::BackgroundRole && style.validBackgroundColor() )
161 return style.backgroundColor().isValid() ? style.backgroundColor() : QVariant();
162 if ( role == Qt::ForegroundRole && style.validTextColor() )
163 return style.textColor().isValid() ? style.textColor() : QVariant();
164 if ( role == Qt::DecorationRole )
165 return style.icon().isNull() ? QVariant() : style.icon();
166 if ( role == Qt::FontRole )
167 return style.font();
168 }
169
170 return QVariant();
171 }
172
173 return sourceModel()->data( mapToSource( index ), role );
174}
175
176Qt::ItemFlags QgsFeatureListModel::flags( const QModelIndex &index ) const
177{
178 if ( mInjectNull && index.row() == 0 )
179 {
180 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
181 }
182 else
183 {
184 return sourceModel()->flags( mapToSource( index ) ) & ~Qt::ItemIsEditable;
185 }
186}
187
189{
190 if ( mInjectNull == injectNull )
191 return;
192
193 if ( injectNull )
195
196 beginResetModel();
197 mInjectNull = injectNull;
198 endResetModel();
199}
200
202{
203 return mInjectNull;
204}
205
210
211bool QgsFeatureListModel::setDisplayExpression( const QString &expression )
212{
213 QgsExpression exp = QgsExpression( expression );
214
215 exp.prepare( &mExpressionContext );
216
217 if ( exp.hasParserError() )
218 {
219 mParserErrorString = exp.parserErrorString();
220 return false;
221 }
222
223 mDisplayExpression = exp;
224
225 if ( mSortByDisplayExpression )
226 masterModel()->prefetchSortData( expression, 1 );
227
228 emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );
229
230 invalidate();
231 return true;
232}
233
235{
236 return mParserErrorString;
237}
238
240{
241 return mDisplayExpression.expression();
242}
243
244bool QgsFeatureListModel::featureByIndex( const QModelIndex &index, QgsFeature &feat )
245{
246 return mFilterModel->layerCache()->featureAtIdWithAllAttributes( idxToFid( index ), feat );
247}
248
249void QgsFeatureListModel::onBeginRemoveRows( const QModelIndex &parent, int first, int last )
250{
251 beginRemoveRows( parent, first, last );
252}
253
254void QgsFeatureListModel::onEndRemoveRows( const QModelIndex &parent, int first, int last )
255{
256 Q_UNUSED( parent )
257 Q_UNUSED( first )
258 Q_UNUSED( last )
259 endRemoveRows();
260}
261
262void QgsFeatureListModel::onBeginInsertRows( const QModelIndex &parent, int first, int last )
263{
264 beginInsertRows( parent, first, last );
265}
266
267void QgsFeatureListModel::onEndInsertRows( const QModelIndex &parent, int first, int last )
268{
269 Q_UNUSED( parent )
270 Q_UNUSED( first )
271 Q_UNUSED( last )
272 endInsertRows();
273}
274
275void QgsFeatureListModel::conditionalStylesChanged()
276{
277 mRowStylesMap.clear();
278 emit dataChanged( index( 0, 0 ), index( rowCount() - 1, columnCount() - 1 ) );
279}
280
282{
283 return mSortByDisplayExpression;
284}
285
286void QgsFeatureListModel::setSortByDisplayExpression( bool sortByDisplayExpression, Qt::SortOrder order )
287{
288 mSortByDisplayExpression = sortByDisplayExpression;
289
290 // If we are sorting by display expression, we do not support injected null
291 if ( mSortByDisplayExpression )
292 setInjectNull( false );
293
294 setSortRole( static_cast< int >( QgsAttributeTableModel::CustomRole::Sort ) + 1 );
295 setDynamicSortFilter( mSortByDisplayExpression );
296 sort( 0, order );
297}
298
299QModelIndex QgsFeatureListModel::mapToMaster( const QModelIndex &proxyIndex ) const
300{
301 QModelIndex masterIndex;
302
303 if ( proxyIndex.isValid() )
304 {
305 if ( mSortByDisplayExpression )
306 {
307 masterIndex = mFilterModel->mapToMaster( mapToSource( proxyIndex ) );
308 }
309 else
310 {
311 const int offset = mInjectNull ? 1 : 0;
312
313 masterIndex = mFilterModel->mapToMaster( mFilterModel->index( proxyIndex.row() - offset, proxyIndex.column() ) );
314 }
315 }
316 return masterIndex;
317}
318
319QModelIndex QgsFeatureListModel::mapFromMaster( const QModelIndex &masterIndex ) const
320{
321 QModelIndex proxyIndex;
322
323 if ( masterIndex.isValid() )
324 {
325 if ( mSortByDisplayExpression )
326 {
327 proxyIndex = mapFromSource( mFilterModel->mapFromMaster( masterIndex ) );
328 }
329 else
330 {
331 const int offset = mInjectNull ? 1 : 0;
332
333 return createIndex( mFilterModel->mapFromMaster( masterIndex ).row() + offset, 0 );
334 }
335 }
336
337 return proxyIndex;
338}
339
340QItemSelection QgsFeatureListModel::mapSelectionFromMaster( const QItemSelection &selection ) const
341{
342 return mapSelectionFromSource( mFilterModel->mapSelectionFromSource( selection ) );
343}
344
345QItemSelection QgsFeatureListModel::mapSelectionToMaster( const QItemSelection &selection ) const
346{
347 return mFilterModel->mapSelectionToSource( mapSelectionToSource( selection ) );
348}
349
350// Override some methods from QAbstractProxyModel, not that interesting
351
352QModelIndex QgsFeatureListModel::mapToSource( const QModelIndex &proxyIndex ) const
353{
354 QModelIndex sourceIndex;
355
356 if ( mSortByDisplayExpression )
357 {
358 sourceIndex = QSortFilterProxyModel::mapToSource( proxyIndex );
359 }
360 else
361 {
362 if ( !proxyIndex.isValid() )
363 return QModelIndex();
364
365 const int offset = mInjectNull ? 1 : 0;
366
367 sourceIndex = sourceModel()->index( proxyIndex.row() - offset, proxyIndex.column() );
368 }
369
370 return sourceIndex;
371}
372
373QModelIndex QgsFeatureListModel::mapFromSource( const QModelIndex &sourceIndex ) const
374{
375 QModelIndex proxyIndex;
376
377 if ( mSortByDisplayExpression )
378 {
379 proxyIndex = QSortFilterProxyModel::mapFromSource( sourceIndex );
380 }
381 else
382 {
383 if ( sourceIndex.isValid() )
384 proxyIndex = createIndex( sourceIndex.row(), 0 );
385 }
386
387 return proxyIndex;
388}
389
390QModelIndex QgsFeatureListModel::parent( const QModelIndex &child ) const
391{
392 Q_UNUSED( child )
393 return QModelIndex();
394}
395
396int QgsFeatureListModel::columnCount( const QModelIndex &parent ) const
397{
398 Q_UNUSED( parent )
399 return 1;
400}
401
402int QgsFeatureListModel::rowCount( const QModelIndex &parent ) const
403{
404 Q_UNUSED( parent )
405
406 const int offset = mInjectNull ? 1 : 0;
407
408 return sourceModel()->rowCount() + offset;
409}
410
412{
413 return mapFromMaster( masterModel()->idToIndex( fid ) );
414}
415
417{
418 return QModelIndexList() << fidToIndex( fid );
419}
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()
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 ...
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.