QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsfeaturepickermodelbase.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsfeaturepickermodelbase.cpp - QgsFeaturePickerModelBase
3 ---------------------
4 begin : 10.3.2017
5 copyright : (C) 2017 by Matthias Kuhn
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
18
19#include "qgsvectorlayer.h"
20#include "qgsconditionalstyle.h"
21#include "qgsapplication.h"
22#include "qgssettings.h"
24
26 : QAbstractItemModel( parent )
27{
28 mReloadTimer.setInterval( 100 );
29 mReloadTimer.setSingleShot( true );
30 connect( &mReloadTimer, &QTimer::timeout, this, &QgsFeaturePickerModelBase::scheduledReload );
31
32 // The fact that the feature changed is a combination of the 2 signals:
33 // If the extra value is set to a feature currently not fetched, it will go through an intermediate step while the extra value does not exist (as it call reloadFeature)
36}
37
38
40{
41 if ( mGatherer )
42 connect( mGatherer, &QgsFeatureExpressionValuesGatherer::finished, mGatherer, &QgsFeatureExpressionValuesGatherer::deleteLater );
43}
44
45
47{
48 return mSourceLayer;
49}
50
51
53{
54 if ( mSourceLayer == sourceLayer )
55 return;
56
57 mSourceLayer = sourceLayer;
58 if ( mSourceLayer )
59 mExpressionContext = mSourceLayer->createExpressionContext();
60
61 reload();
62 emit sourceLayerChanged();
63
64 if ( mSourceLayer )
65 setDisplayExpression( mSourceLayer->displayExpression() );
66}
67
68
70{
71 return mDisplayExpression.expression();
72}
73
74
75void QgsFeaturePickerModelBase::setDisplayExpression( const QString &displayExpression )
76{
77 if ( mDisplayExpression.expression() == displayExpression )
78 return;
79
80 mDisplayExpression = QgsExpression( displayExpression );
81 reload();
83}
84
85
87{
88 return mFilterValue;
89}
90
91
92void QgsFeaturePickerModelBase::setFilterValue( const QString &filterValue )
93{
94 if ( mFilterValue == filterValue )
95 return;
96
97 mFilterValue = filterValue;
98 reload();
99 emit filterValueChanged();
100}
101
102
104{
105 return mFilterExpression;
106}
107
108
109void QgsFeaturePickerModelBase::setFilterExpression( const QString &filterExpression )
110{
111 if ( mFilterExpression == filterExpression )
112 return;
113
114 mFilterExpression = filterExpression;
115 reload();
117}
118
119
121{
122 return mGatherer;
123}
124
126{
128}
129
130
131QModelIndex QgsFeaturePickerModelBase::index( int row, int column, const QModelIndex &parent ) const
132{
133 Q_UNUSED( parent )
134 return createIndex( row, column, nullptr );
135}
136
137
138QModelIndex QgsFeaturePickerModelBase::parent( const QModelIndex &child ) const
139{
140 Q_UNUSED( child )
141 return QModelIndex();
142}
143
144
145int QgsFeaturePickerModelBase::rowCount( const QModelIndex &parent ) const
146{
147 Q_UNUSED( parent )
148 return mEntries.size();
149}
150
151
152
153QVariant QgsFeaturePickerModelBase::data( const QModelIndex &index, int role ) const
154{
155 if ( !index.isValid() )
156 return QVariant();
157
158 switch ( role )
159 {
160 case Qt::DisplayRole:
161 case Qt::EditRole:
162 case ValueRole:
163 return mEntries.value( index.row() ).value;
164
165 case FeatureIdRole:
166 return mEntries.value( index.row() ).featureId;
167
168 case FeatureRole:
169 return mEntries.value( index.row() ).feature;
170
172 {
173 const QVariantList values = mEntries.value( index.row() ).identifierFields;
174 return values.value( 0 );
175 }
176
178 return mEntries.value( index.row() ).identifierFields;
179
180 case Qt::BackgroundRole:
181 case Qt::ForegroundRole:
182 case Qt::DecorationRole:
183 case Qt::FontRole:
184 {
185 const bool isNull = identifierIsNull( entryIdentifier( mEntries.value( index.row() ) ) );
186 if ( isNull )
187 {
188 // Representation for NULL value
189 if ( role == Qt::ForegroundRole )
190 {
191 return QBrush( QColor( Qt::gray ) );
192 }
193 if ( role == Qt::FontRole )
194 {
195 QFont font = QFont();
196 if ( index.row() == mExtraValueIndex )
197 font.setBold( true );
198 else
199 font.setItalic( true );
200 return font;
201 }
202 }
203 else
204 {
205 // Respect conditional style
206 const QgsConditionalStyle style = featureStyle( mEntries.value( index.row() ).feature );
207
208 if ( style.isValid() )
209 {
210 if ( role == Qt::BackgroundRole && style.validBackgroundColor() )
211 return style.backgroundColor();
212 if ( role == Qt::ForegroundRole && style.validTextColor() )
213 return style.textColor();
214 if ( role == Qt::DecorationRole )
215 return style.icon();
216 if ( role == Qt::FontRole )
217 return style.font();
218 }
219 }
220 break;
221 }
222 }
223
224 return QVariant();
225}
226
227
228void QgsFeaturePickerModelBase::updateCompleter()
229{
230 emit beginUpdate();
231
232 QgsFeatureExpressionValuesGatherer *gatherer = qobject_cast<QgsFeatureExpressionValuesGatherer *>( sender() );
233 if ( gatherer->wasCanceled() )
234 {
235 delete gatherer;
236 return;
237 }
238
239 QVector<QgsFeatureExpressionValuesGatherer::Entry> entries = mGatherer->entries();
240
241 if ( mExtraValueIndex == -1 )
242 {
244 }
245
246 // Only reloading the current entry?
247 const bool reloadCurrentFeatureOnly = mGatherer->data().toBool();
248 if ( reloadCurrentFeatureOnly )
249 {
250 if ( !entries.isEmpty() )
251 {
252 mEntries.replace( mExtraValueIndex, entries.at( 0 ) );
253 emit dataChanged( index( mExtraValueIndex, 0, QModelIndex() ), index( mExtraValueIndex, 0, QModelIndex() ) );
254 mShouldReloadCurrentFeature = false;
255 setExtraValueDoesNotExist( false );
256 }
257 else
258 {
259 setExtraValueDoesNotExist( true );
260 }
261
262 mKeepCurrentEntry = true;
263 mShouldReloadCurrentFeature = false;
264
265 if ( mFilterValue.isEmpty() )
266 reload();
267 }
268 else
269 {
270 // We got strings for a filter selection
271 std::sort( entries.begin(), entries.end(), []( const QgsFeatureExpressionValuesGatherer::Entry & a, const QgsFeatureExpressionValuesGatherer::Entry & b ) { return a.value.localeAwareCompare( b.value ) < 0; } );
272
273 if ( mAllowNull && mSourceLayer )
274 {
275 entries.prepend( QgsFeatureExpressionValuesGatherer::nullEntry( mSourceLayer ) );
276 }
277
278 const int newEntriesSize = entries.size();
279
280 // fixed entry is either NULL or extra value
281 const int nbFixedEntry = ( mKeepCurrentEntry ? 1 : 0 ) + ( mAllowNull ? 1 : 0 );
282
283 // Find the index of the current entry in the new list
284 int currentEntryInNewList = -1;
285 if ( mExtraValueIndex != -1 && mExtraValueIndex < mEntries.count() )
286 {
287 for ( int i = 0; i < newEntriesSize; ++i )
288 {
289 if ( compareEntries( entries.at( i ), mEntries.at( mExtraValueIndex ) ) )
290 {
291 mEntries.replace( mExtraValueIndex, entries.at( i ) );
292 currentEntryInNewList = i;
293 setExtraValueDoesNotExist( false );
294 break;
295 }
296 }
297 }
298
299 int firstRow = 0;
300
301 // Move current entry to the first position if this is a fixed entry or because
302 // the entry exists in the new list
303 if ( mExtraValueIndex > -1 && ( mExtraValueIndex < nbFixedEntry || currentEntryInNewList != -1 ) )
304 {
305 if ( mExtraValueIndex != 0 )
306 {
307 beginMoveRows( QModelIndex(), mExtraValueIndex, mExtraValueIndex, QModelIndex(), 0 );
308 mEntries.move( mExtraValueIndex, 0 );
309 endMoveRows();
310 }
311 firstRow = 1;
312 }
313
314 // Remove all entries (except for extra entry if existent)
315 beginRemoveRows( QModelIndex(), firstRow, mEntries.size() - firstRow );
316 mEntries.remove( firstRow, mEntries.size() - firstRow );
317
318 // if we remove all rows before endRemoveRows, setExtraIdentifierValuesUnguarded will be called
319 // and a null value will be added to mEntries, so we block setExtraIdentifierValuesUnguarded call
320
321 mIsSettingExtraIdentifierValue = true;
322 endRemoveRows();
323 mIsSettingExtraIdentifierValue = false;
324
325 if ( currentEntryInNewList == -1 )
326 {
327 beginInsertRows( QModelIndex(), firstRow, entries.size() + 1 );
328 mEntries += entries;
329 endInsertRows();
330
331 // if all entries have been cleaned (firstRow == 0)
332 // and there is a value in entries, prefer this value over NULL
333 // else chose the first one (the previous one)
334 setExtraIdentifierValueIndex( firstRow == 0 && mAllowNull && !entries.isEmpty() ? 1 : 0, firstRow == 0 );
335 }
336 else
337 {
338 if ( currentEntryInNewList != 0 )
339 {
340 beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 );
341 mEntries = entries.mid( 0, currentEntryInNewList ) + mEntries;
342 endInsertRows();
343 }
344 else
345 {
346 mEntries.replace( 0, entries.at( 0 ) );
347 }
348
349 // don't notify for a change if it's a fixed entry
350 if ( currentEntryInNewList >= nbFixedEntry )
351 {
352 emit dataChanged( index( currentEntryInNewList, 0, QModelIndex() ), index( currentEntryInNewList, 0, QModelIndex() ) );
353 }
354
355 beginInsertRows( QModelIndex(), currentEntryInNewList + 1, newEntriesSize - currentEntryInNewList - 1 );
356 mEntries += entries.mid( currentEntryInNewList + 1 );
357 endInsertRows();
358 setExtraIdentifierValueIndex( currentEntryInNewList );
359 }
360
361 emit filterJobCompleted();
362
363 mKeepCurrentEntry = false;
364 }
365 emit endUpdate();
366
367 // scheduleReload and updateCompleter lives in the same thread so if the gatherer hasn't been stopped
368 // (checked before), mGatherer still references the current gatherer
369 Q_ASSERT( gatherer == mGatherer );
370 delete mGatherer;
371 mGatherer = nullptr;
372 emit isLoadingChanged();
373}
374
375
376void QgsFeaturePickerModelBase::scheduledReload()
377{
378 if ( !mSourceLayer )
379 return;
380
381 bool wasLoading = false;
382
383 if ( mGatherer )
384 {
385 mGatherer->stop();
386 wasLoading = true;
387 }
388
389 QgsFeatureRequest request;
390
391 if ( mShouldReloadCurrentFeature )
392 {
394 }
395 else
396 {
397 QString filterClause;
398
399 if ( mFilterValue.isEmpty() && !mFilterExpression.isEmpty() )
400 filterClause = mFilterExpression;
401 else if ( mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
402 filterClause = QStringLiteral( "(%1) ILIKE '%%2%'" ).arg( mDisplayExpression, mFilterValue );
403 else if ( !mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
404 filterClause = QStringLiteral( "(%1) AND ((%2) ILIKE '%%3%')" ).arg( mFilterExpression, mDisplayExpression, mFilterValue );
405
406 if ( !filterClause.isEmpty() )
407 {
408 request.setFilterExpression( filterClause );
410 }
411 }
412 QSet<QString> attributes = requestedAttributes();
413 if ( !attributes.isEmpty() )
414 {
415 if ( auto *lFilterExpression = request.filterExpression() )
416 attributes += lFilterExpression->referencedColumns();
417 attributes += requestedAttributesForStyle();
418
419 request.setSubsetOfAttributes( attributes, mSourceLayer->fields() );
420 }
421
422 if ( !mFetchGeometry )
424 if ( mFetchLimit > 0 )
425 request.setLimit( mFetchLimit );
426
427 mGatherer = createValuesGatherer( request );
428 mGatherer->setData( mShouldReloadCurrentFeature );
429 connect( mGatherer, &QgsFeatureExpressionValuesGatherer::finished, this, &QgsFeaturePickerModelBase::updateCompleter );
430
431 mGatherer->start();
432 if ( !wasLoading )
433 emit isLoadingChanged();
434}
435
436
437QSet<QString> QgsFeaturePickerModelBase::requestedAttributesForStyle() const
438{
439 QSet<QString> requestedAttrs;
440
441 const auto rowStyles = mSourceLayer->conditionalStyles()->rowStyles();
442
443 for ( const QgsConditionalStyle &style : rowStyles )
444 {
445 const QgsExpression exp( style.rule() );
446 requestedAttrs += exp.referencedColumns();
447 }
448
449 if ( mDisplayExpression.isField() )
450 {
451 const QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
452 const auto constFieldStyles = mSourceLayer->conditionalStyles()->fieldStyles( fieldName );
453 for ( const QgsConditionalStyle &style : constFieldStyles )
454 {
455 const QgsExpression exp( style.rule() );
456 requestedAttrs += exp.referencedColumns();
457 }
458 }
459
460 return requestedAttrs;
461}
462
463
464void QgsFeaturePickerModelBase::setExtraIdentifierValueIndex( int index, bool force )
465{
466 if ( mExtraValueIndex == index && !force )
467 return;
468
471}
472
473
474void QgsFeaturePickerModelBase::reloadCurrentFeature()
475{
476 mShouldReloadCurrentFeature = true;
477 mReloadTimer.start();
478}
479
480
482{
483 const QVector<QgsFeatureExpressionValuesGatherer::Entry> entries = mEntries;
484
485 int index = 0;
486 for ( const QgsFeatureExpressionValuesGatherer::Entry &entry : entries )
487 {
488 if ( compareEntries( entry, createEntry( identifierValue ) ) )
489 {
490 setExtraIdentifierValueIndex( index );
491 break;
492 }
493
494 index++;
495 }
496
497 // Value not found in current entries
498 if ( mExtraValueIndex != index )
499 {
500 const bool isNull = identifierIsNull( identifierValue );
501 if ( !isNull || mAllowNull )
502 {
503 beginInsertRows( QModelIndex(), 0, 0 );
504 if ( !isNull )
505 {
506 mEntries.prepend( createEntry( identifierValue ) );
507 setExtraValueDoesNotExist( true );
508 reloadCurrentFeature();
509 }
510 else
511 {
512 mEntries.prepend( QgsFeatureExpressionValuesGatherer::nullEntry( mSourceLayer ) );
513 setExtraValueDoesNotExist( false );
514 }
515 endInsertRows();
516
517 setExtraIdentifierValueIndex( 0, true );
518 }
519 }
520}
521
522
523QgsConditionalStyle QgsFeaturePickerModelBase::featureStyle( const QgsFeature &feature ) const
524{
525 if ( !mSourceLayer )
526 return QgsConditionalStyle();
527
528 QgsVectorLayer *layer = mSourceLayer;
529 const QgsFeatureId fid = feature.id();
530 mExpressionContext.setFeature( feature );
531
532 auto styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
533
534 if ( mDisplayExpression.referencedColumns().count() == 1 )
535 {
536 // Style specific for this field
537 const QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
538 const auto allStyles = layer->conditionalStyles()->fieldStyles( fieldName );
539 const auto matchingFieldStyles = QgsConditionalStyle::matchingConditionalStyles( allStyles, feature.attribute( fieldName ), mExpressionContext );
540
541 styles += matchingFieldStyles;
542 }
543
545 style = QgsConditionalStyle::compressStyles( styles );
546 mEntryStylesMap.insert( fid, style );
547
548 return style;
549}
550
551
553{
554 return mAllowNull;
555}
556
557
559{
560 if ( mAllowNull == allowNull )
561 return;
562
563 mAllowNull = allowNull;
564 emit allowNullChanged();
565
566 reload();
567}
568
570{
571 return mFetchGeometry;
572}
573
575{
576 if ( mFetchGeometry == fetchGeometry )
577 return;
578
579 mFetchGeometry = fetchGeometry;
580 reload();
581}
582
584{
585 return mFetchLimit;
586}
587
589{
590 if ( fetchLimit == mFetchLimit )
591 return;
592
593 mFetchLimit = fetchLimit;
594 emit fetchLimitChanged();
595}
596
597
599{
600 return mExtraValueDoesNotExist;
601}
602
603
604void QgsFeaturePickerModelBase::setExtraValueDoesNotExist( bool extraValueDoesNotExist )
605{
606 if ( mExtraValueDoesNotExist == extraValueDoesNotExist )
607 return;
608
609 mExtraValueDoesNotExist = extraValueDoesNotExist;
611}
612
613
615{
616 return mExtraValueIndex;
617}
618
619
620void QgsFeaturePickerModelBase::reload()
621{
622 mReloadTimer.start();
623}
624
625
626void QgsFeaturePickerModelBase::setExtraIdentifierValue( const QVariant &extraIdentifierValue )
627{
629 return;
630
631 if ( mIsSettingExtraIdentifierValue )
632 return;
633
634 mIsSettingExtraIdentifierValue = true;
635
637
639
640 mIsSettingExtraIdentifierValue = false;
641
643}
644
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.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
QString expression() const
Returns the original, unmodified expression string.
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.
void extraIdentifierValueIndexChanged(int index)
The index at which the extra identifier value is available within the model.
void beginUpdate()
Notification that the model is about to be changed because a job was completed.
virtual QVariant entryIdentifier(const QgsFeatureExpressionValuesGatherer::Entry &entry) const =0
Returns the identifier of the given entry.
void filterValueChanged()
This value will be used to filter the features available from this model.
void setFilterValue(const QString &filterValue)
This value will be used to filter the features available from this model.
void setExtraIdentifierValue(const QVariant &extraIdentifierValue)
Allows specifying one value that does not need to match the filter criteria but will still be availab...
virtual void requestToReloadCurrentFeature(QgsFeatureRequest &request)=0
Update the request to match the current feature to be reloaded.
void filterExpressionChanged()
An additional filter expression to apply, next to the filterValue.
void setFetchLimit(int fetchLimit)
Defines the feature request fetch limit If set to 0, no limit is applied when fetching.
QVariant extraIdentifierValue() const
Allows specifying one value that does not need to match the filter criteria but will still be availab...
virtual QgsFeatureExpressionValuesGatherer * createValuesGatherer(const QgsFeatureRequest &request) const =0
Creates the value gatherer.
void setFetchGeometry(bool fetchGeometry)
Defines if the geometry will be fetched.
void setExtraIdentifierValueUnguarded(const QVariant &identifierValue)
This will set the identifier value to be set in the model even if it doesn't exist currently in the d...
void extraIdentifierValueChanged()
Allows specifying one value that does not need to match the filter criteria but will still be availab...
virtual QSet< QString > requestedAttributes() const
Returns the attributes to be fetched in the request.
int mExtraValueIndex
The current index.
QModelIndex parent(const QModelIndex &child) const override
void filterJobCompleted()
Indicates that a filter job has been completed and new data may be available.
void setAllowNull(bool allowNull)
Add a NULL entry to the list.
void setDisplayExpression(const QString &displayExpression)
The display expression will be used for.
QVariant mExtraIdentifierValue
The current identifier value.
QgsFeaturePickerModelBase(QObject *parent=nullptr)
Create a new QgsFeaturePickerModelBase, optionally specifying a parent.
virtual QgsFeatureExpressionValuesGatherer::Entry createEntry(const QVariant &identifier) const =0
Creates an entry with just the identifier so the feature can be retrieved in a next iteration.
bool isLoading() const
Indicator if the model is currently performing any feature iteration in the background.
virtual bool identifierIsNull(const QVariant &identifier) const =0
Returns true if the entry is null The identifier can be either the feature ID or the list of identifi...
QVariant data(const QModelIndex &index, int role) const override
QModelIndex index(int row, int column, const QModelIndex &parent) const override
void fetchLimitChanged()
Emitted when the fetching limit for the feature request changes.
void sourceLayerChanged()
The source layer from which features will be fetched.
@ FeatureIdRole
Used to retrieve the id of a feature.
@ IdentifierValuesRole
Used to retrieve the identifierValues (primary keys) of a feature.
@ FeatureRole
Used to retrieve the feature, it might be incomplete if the request doesn't fetch all attributes or g...
@ ValueRole
Used to retrieve the displayExpression of a feature.
void setFilterExpression(const QString &filterExpression)
An additional filter expression to apply, next to the filterValue.
void allowNullChanged()
Add a NULL entry to the list.
int rowCount(const QModelIndex &parent) const override
virtual bool compareEntries(const QgsFeatureExpressionValuesGatherer::Entry &a, const QgsFeatureExpressionValuesGatherer::Entry &b) const =0
Returns true if the 2 entries refers to the same feature.
void currentFeatureChanged()
Emitted when the current feature in the model has changed This emitted both when the extra value chan...
void isLoadingChanged()
Indicator if the model is currently performing any feature iteration in the background.
QVector< QgsFeatureExpressionValuesGatherer::Entry > mEntries
virtual QVariant nullIdentifier() const =0
Returns a null identifier.
void endUpdate()
Notification that the model change is finished.
void displayExpressionChanged()
The display expression will be used for.
void extraValueDoesNotExistChanged()
Flag indicating that the extraIdentifierValue does not exist in the data.
void setSourceLayer(QgsVectorLayer *sourceLayer)
The source layer from which features will be fetched.
bool extraValueDoesNotExist() const
Flag indicating that the extraIdentifierValue does not exist in the data.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setLimit(long long limit)
Set the maximum number of features to request.
QgsExpressionContext * expressionContext()
Returns the expression context used to evaluate filter expressions.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsExpression * filterExpression() const
Returns the filter expression (if set).
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
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:338
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QString displayExpression
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