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