QGIS API Documentation 3.43.0-Master (b60ef06885e)
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
6 email : matthias@opengis.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
17#include "moc_qgsfeaturepickermodelbase.cpp"
19
20#include "qgsvectorlayer.h"
21#include "qgsconditionalstyle.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)
35}
36
37
39{
40 if ( mGatherer )
41 connect( mGatherer, &QgsFeatureExpressionValuesGatherer::finished, mGatherer, &QgsFeatureExpressionValuesGatherer::deleteLater );
42}
43
44
46{
47 return mSourceLayer;
48}
49
50
52{
53 if ( mSourceLayer == sourceLayer )
54 return;
55
56 mSourceLayer = sourceLayer;
57 if ( mSourceLayer )
58 mExpressionContext = mSourceLayer->createExpressionContext();
59
60 reload();
61 emit sourceLayerChanged();
62
63 if ( mSourceLayer )
64 setDisplayExpression( mSourceLayer->displayExpression() );
65}
66
67
69{
70 return mDisplayExpression.expression();
71}
72
73
74void QgsFeaturePickerModelBase::setDisplayExpression( const QString &displayExpression )
75{
76 if ( mDisplayExpression.expression() == displayExpression )
77 return;
78
79 mDisplayExpression = QgsExpression( displayExpression );
80 reload();
82}
83
84
86{
87 return mFilterValue;
88}
89
90
91void QgsFeaturePickerModelBase::setFilterValue( const QString &filterValue )
92{
93 if ( mFilterValue == filterValue )
94 return;
95
96 mFilterValue = filterValue;
97 reload();
98 emit filterValueChanged();
99}
100
101
103{
104 return mFilterExpression;
105}
106
107
108void QgsFeaturePickerModelBase::setFilterExpression( const QString &filterExpression )
109{
110 if ( mFilterExpression == filterExpression )
111 return;
112
113 mFilterExpression = filterExpression;
114 reload();
116}
117
119{
120 return mFormFeature;
121}
122
124{
125 if ( mFormFeature == feature )
126 return;
127
128 mFormFeature = feature;
129 if ( !mFilterExpression.isEmpty() && QgsValueRelationFieldFormatter::expressionRequiresFormScope( mFilterExpression ) )
130 {
131 reload();
132 }
133 emit formFeatureChanged();
134}
135
137{
138 return mParentFormFeature;
139}
140
142{
143 if ( mParentFormFeature == feature )
144 return;
145
146 mParentFormFeature = feature;
147 if ( !mFilterExpression.isEmpty() && QgsValueRelationFieldFormatter::expressionRequiresParentFormScope( mFilterExpression ) )
148 {
149 reload();
150 }
152}
153
155{
156 return mGatherer;
157}
158
163
164
165QModelIndex QgsFeaturePickerModelBase::index( int row, int column, const QModelIndex &parent ) const
166{
167 Q_UNUSED( parent )
168 return createIndex( row, column, nullptr );
169}
170
171
172QModelIndex QgsFeaturePickerModelBase::parent( const QModelIndex &child ) const
173{
174 Q_UNUSED( child )
175 return QModelIndex();
176}
177
178
179int QgsFeaturePickerModelBase::rowCount( const QModelIndex &parent ) const
180{
181 Q_UNUSED( parent )
182 return mEntries.size();
183}
184
185
186
187QVariant QgsFeaturePickerModelBase::data( const QModelIndex &index, int role ) const
188{
189 if ( !index.isValid() )
190 return QVariant();
191
192 switch ( role )
193 {
194 case Qt::DisplayRole:
195 case Qt::EditRole:
196 case static_cast< int >( CustomRole::Value ):
197 return mEntries.value( index.row() ).value;
198
199 case static_cast< int >( CustomRole::FeatureId ):
200 return mEntries.value( index.row() ).featureId;
201
202 case static_cast< int >( CustomRole::Feature ):
203 return mEntries.value( index.row() ).feature;
204
205 case static_cast< int >( CustomRole::IdentifierValue ):
206 {
207 const QVariantList values = mEntries.value( index.row() ).identifierFields;
208 return values.value( 0 );
209 }
210
211 case static_cast< int >( CustomRole::IdentifierValues ):
212 return mEntries.value( index.row() ).identifierFields;
213
214 case Qt::BackgroundRole:
215 case Qt::ForegroundRole:
216 case Qt::DecorationRole:
217 case Qt::FontRole:
218 {
219 const bool isNull = identifierIsNull( entryIdentifier( mEntries.value( index.row() ) ) );
220 if ( isNull )
221 {
222 // Representation for NULL value
223 if ( role == Qt::ForegroundRole )
224 {
225 return QBrush( QColor( Qt::gray ) );
226 }
227 if ( role == Qt::FontRole )
228 {
229 QFont font = QFont();
230 if ( index.row() == mExtraValueIndex )
231 font.setBold( true );
232 else
233 font.setItalic( true );
234 return font;
235 }
236 }
237 else
238 {
239 // Respect conditional style
240 const QgsConditionalStyle style = featureStyle( mEntries.value( index.row() ).feature );
241
242 if ( style.isValid() )
243 {
244 if ( role == Qt::BackgroundRole && style.validBackgroundColor() )
245 return style.backgroundColor();
246 if ( role == Qt::ForegroundRole && style.validTextColor() )
247 return style.textColor();
248 if ( role == Qt::DecorationRole )
249 return style.icon();
250 if ( role == Qt::FontRole )
251 return style.font();
252 }
253 }
254 break;
255 }
256 }
257
258 return QVariant();
259}
260
261
262void QgsFeaturePickerModelBase::updateCompleter()
263{
264 emit beginUpdate();
265
266 QgsFeatureExpressionValuesGatherer *gatherer = qobject_cast<QgsFeatureExpressionValuesGatherer *>( sender() );
267 if ( gatherer->wasCanceled() )
268 {
269 delete gatherer;
270 return;
271 }
272
273 QVector<QgsFeatureExpressionValuesGatherer::Entry> entries = mGatherer->entries();
274
275 if ( mExtraValueIndex == -1 )
276 {
278 }
279
280 // Only reloading the current entry?
281 const bool reloadCurrentFeatureOnly = mGatherer->data().toBool();
282 if ( reloadCurrentFeatureOnly )
283 {
284 if ( !entries.isEmpty() )
285 {
286 mEntries.replace( mExtraValueIndex, entries.at( 0 ) );
287 emit dataChanged( index( mExtraValueIndex, 0, QModelIndex() ), index( mExtraValueIndex, 0, QModelIndex() ) );
288 mShouldReloadCurrentFeature = false;
289 setExtraValueDoesNotExist( false );
290 }
291 else
292 {
293 setExtraValueDoesNotExist( true );
294 }
295
296 mKeepCurrentEntry = true;
297 mShouldReloadCurrentFeature = false;
298
299 if ( mFilterValue.isEmpty() )
300 reload();
301 }
302 else
303 {
304 // We got strings for a filter selection
305 std::sort( entries.begin(), entries.end(), []( const QgsFeatureExpressionValuesGatherer::Entry & a, const QgsFeatureExpressionValuesGatherer::Entry & b ) { return a.value.localeAwareCompare( b.value ) < 0; } );
306
307 if ( mAllowNull && mSourceLayer )
308 {
309 entries.prepend( QgsFeatureExpressionValuesGatherer::nullEntry( mSourceLayer ) );
310 }
311
312 const int newEntriesSize = entries.size();
313
314 // fixed entry is either NULL or extra value
315 const int nbFixedEntry = ( mKeepCurrentEntry ? 1 : 0 ) + ( mAllowNull ? 1 : 0 );
316
317 // Find the index of the current entry in the new list
318 int currentEntryInNewList = -1;
319 if ( mExtraValueIndex != -1 && mExtraValueIndex < mEntries.count() )
320 {
321 for ( int i = 0; i < newEntriesSize; ++i )
322 {
323 if ( compareEntries( entries.at( i ), mEntries.at( mExtraValueIndex ) ) )
324 {
325 mEntries.replace( mExtraValueIndex, entries.at( i ) );
326 currentEntryInNewList = i;
327 setExtraValueDoesNotExist( false );
328 break;
329 }
330 }
331 }
332
333 int firstRow = 0;
334
335 // Move current entry to the first position if this is a fixed entry or because
336 // the entry exists in the new list
337 if ( mExtraValueIndex > -1 && ( mExtraValueIndex < nbFixedEntry || currentEntryInNewList != -1 ) )
338 {
339 if ( mExtraValueIndex != 0 )
340 {
341 beginMoveRows( QModelIndex(), mExtraValueIndex, mExtraValueIndex, QModelIndex(), 0 );
342 mEntries.move( mExtraValueIndex, 0 );
343 endMoveRows();
344 }
345 firstRow = 1;
346 }
347
348 // Remove all entries (except for extra entry if existent)
349 beginRemoveRows( QModelIndex(), firstRow, mEntries.size() - firstRow );
350 mEntries.remove( firstRow, mEntries.size() - firstRow );
351
352 // if we remove all rows before endRemoveRows, setExtraIdentifierValuesUnguarded will be called
353 // and a null value will be added to mEntries, so we block setExtraIdentifierValuesUnguarded call
354
355 mIsSettingExtraIdentifierValue = true;
356 endRemoveRows();
357 mIsSettingExtraIdentifierValue = false;
358
359 if ( currentEntryInNewList == -1 )
360 {
361 beginInsertRows( QModelIndex(), firstRow, entries.size() + 1 );
362 mEntries += entries;
363 endInsertRows();
364
365 // if all entries have been cleaned (firstRow == 0)
366 // and there is a value in entries, prefer this value over NULL
367 // else chose the first one (the previous one)
368 setExtraIdentifierValueIndex( firstRow == 0 && mAllowNull && !entries.isEmpty() ? 1 : 0, firstRow == 0 );
369 }
370 else
371 {
372 if ( currentEntryInNewList != 0 )
373 {
374 beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 );
375 mEntries = entries.mid( 0, currentEntryInNewList ) + mEntries;
376 endInsertRows();
377 }
378 else
379 {
380 mEntries.replace( 0, entries.at( 0 ) );
381 }
382
383 // don't notify for a change if it's a fixed entry
384 if ( currentEntryInNewList >= nbFixedEntry )
385 {
386 emit dataChanged( index( currentEntryInNewList, 0, QModelIndex() ), index( currentEntryInNewList, 0, QModelIndex() ) );
387 }
388
389 beginInsertRows( QModelIndex(), currentEntryInNewList + 1, newEntriesSize - currentEntryInNewList - 1 );
390 mEntries += entries.mid( currentEntryInNewList + 1 );
391 endInsertRows();
392 setExtraIdentifierValueIndex( currentEntryInNewList );
393 }
394
395 emit filterJobCompleted();
396
397 mKeepCurrentEntry = false;
398 }
399 emit endUpdate();
400
401 // scheduleReload and updateCompleter lives in the same thread so if the gatherer hasn't been stopped
402 // (checked before), mGatherer still references the current gatherer
403 Q_ASSERT( gatherer == mGatherer );
404 delete mGatherer;
405 mGatherer = nullptr;
406 emit isLoadingChanged();
407}
408
409
410void QgsFeaturePickerModelBase::scheduledReload()
411{
412 if ( !mSourceLayer )
413 return;
414
415 bool wasLoading = false;
416
417 if ( mGatherer )
418 {
419 mGatherer->stop();
420 wasLoading = true;
421 }
422
423 QgsFeatureRequest request;
424
425 if ( mShouldReloadCurrentFeature )
426 {
428 }
429 else
430 {
431 QString filterClause;
432
433 if ( mFilterValue.isEmpty() && !mFilterExpression.isEmpty() )
434 filterClause = mFilterExpression;
435 else if ( mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
436 filterClause = QStringLiteral( "(%1) ILIKE '%%2%'" ).arg( mDisplayExpression, mFilterValue );
437 else if ( !mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
438 filterClause = QStringLiteral( "(%1) AND ((%2) ILIKE '%%3%')" ).arg( mFilterExpression, mDisplayExpression, mFilterValue );
439
440 if ( !filterClause.isEmpty() )
441 {
442 request.setFilterExpression( filterClause );
444
445 if ( !mFilterExpression.isEmpty() )
446 {
447 if ( mFormFeature.isValid() && QgsValueRelationFieldFormatter::expressionRequiresFormScope( mFilterExpression ) )
448 {
450 }
451 if ( mParentFormFeature.isValid() && QgsValueRelationFieldFormatter::expressionRequiresParentFormScope( mFilterExpression ) )
452 {
454 }
455 }
456 }
457 }
458 QSet<QString> attributes = requestedAttributes();
459 if ( !attributes.isEmpty() )
460 {
461 if ( auto *lFilterExpression = request.filterExpression() )
462 attributes += lFilterExpression->referencedColumns();
463 attributes += requestedAttributesForStyle();
464
465 request.setSubsetOfAttributes( attributes, mSourceLayer->fields() );
466 }
467
468 if ( !mFetchGeometry )
470 if ( mFetchLimit > 0 )
471 request.setLimit( mFetchLimit );
472
473 mGatherer = createValuesGatherer( request );
474 mGatherer->setData( mShouldReloadCurrentFeature );
475 connect( mGatherer, &QgsFeatureExpressionValuesGatherer::finished, this, &QgsFeaturePickerModelBase::updateCompleter );
476
477 mGatherer->start();
478 if ( !wasLoading )
479 emit isLoadingChanged();
480}
481
482
483QSet<QString> QgsFeaturePickerModelBase::requestedAttributesForStyle() const
484{
485 QSet<QString> requestedAttrs;
486
487 const auto rowStyles = mSourceLayer->conditionalStyles()->rowStyles();
488
489 for ( const QgsConditionalStyle &style : rowStyles )
490 {
491 const QgsExpression exp( style.rule() );
492 requestedAttrs += exp.referencedColumns();
493 }
494
495 if ( mDisplayExpression.isField() )
496 {
497 const QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
498 const auto constFieldStyles = mSourceLayer->conditionalStyles()->fieldStyles( fieldName );
499 for ( const QgsConditionalStyle &style : constFieldStyles )
500 {
501 const QgsExpression exp( style.rule() );
502 requestedAttrs += exp.referencedColumns();
503 }
504 }
505
506 return requestedAttrs;
507}
508
509
510void QgsFeaturePickerModelBase::setExtraIdentifierValueIndex( int index, bool force )
511{
512 if ( mExtraValueIndex == index && !force )
513 return;
514
517}
518
519
520void QgsFeaturePickerModelBase::reloadCurrentFeature()
521{
522 mShouldReloadCurrentFeature = true;
523 mReloadTimer.start();
524}
525
526
528{
529 const QVector<QgsFeatureExpressionValuesGatherer::Entry> entries = mEntries;
530
531 int index = 0;
532 for ( const QgsFeatureExpressionValuesGatherer::Entry &entry : entries )
533 {
534 if ( compareEntries( entry, createEntry( identifierValue ) ) )
535 {
536 setExtraIdentifierValueIndex( index );
537 break;
538 }
539
540 index++;
541 }
542
543 // Value not found in current entries
544 if ( mExtraValueIndex != index )
545 {
546 const bool isNull = identifierIsNull( identifierValue );
547 if ( !isNull || mAllowNull )
548 {
549 beginInsertRows( QModelIndex(), 0, 0 );
550 if ( !isNull )
551 {
552 mEntries.prepend( createEntry( identifierValue ) );
553 setExtraValueDoesNotExist( true );
554 reloadCurrentFeature();
555 }
556 else
557 {
558 mEntries.prepend( QgsFeatureExpressionValuesGatherer::nullEntry( mSourceLayer ) );
559 setExtraValueDoesNotExist( false );
560 }
561 endInsertRows();
562
563 setExtraIdentifierValueIndex( 0, true );
564 }
565 }
566}
567
568
569QgsConditionalStyle QgsFeaturePickerModelBase::featureStyle( const QgsFeature &feature ) const
570{
571 if ( !mSourceLayer )
572 return QgsConditionalStyle();
573
574 QgsVectorLayer *layer = mSourceLayer;
575 const QgsFeatureId fid = feature.id();
576 mExpressionContext.setFeature( feature );
577
578 auto styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
579
580 if ( mDisplayExpression.referencedColumns().count() == 1 )
581 {
582 // Style specific for this field
583 const QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
584 const auto allStyles = layer->conditionalStyles()->fieldStyles( fieldName );
585 const auto matchingFieldStyles = QgsConditionalStyle::matchingConditionalStyles( allStyles, feature.attribute( fieldName ), mExpressionContext );
586
587 styles += matchingFieldStyles;
588 }
589
591 style = QgsConditionalStyle::compressStyles( styles );
592 mEntryStylesMap.insert( fid, style );
593
594 return style;
595}
596
597
599{
600 return mAllowNull;
601}
602
603
605{
606 if ( mAllowNull == allowNull )
607 return;
608
609 mAllowNull = allowNull;
610 emit allowNullChanged();
611
612 reload();
613}
614
616{
617 return mFetchGeometry;
618}
619
621{
622 if ( mFetchGeometry == fetchGeometry )
623 return;
624
625 mFetchGeometry = fetchGeometry;
626 reload();
627}
628
630{
631 return mFetchLimit;
632}
633
635{
636 if ( fetchLimit == mFetchLimit )
637 return;
638
639 mFetchLimit = fetchLimit;
640 emit fetchLimitChanged();
641
642 reload();
643}
644
645
647{
648 return mExtraValueDoesNotExist;
649}
650
651
652void QgsFeaturePickerModelBase::setExtraValueDoesNotExist( bool extraValueDoesNotExist )
653{
654 if ( mExtraValueDoesNotExist == extraValueDoesNotExist )
655 return;
656
657 mExtraValueDoesNotExist = extraValueDoesNotExist;
658 emit extraValueDoesNotExistChanged( mExtraValueDoesNotExist );
659}
660
661
666
667
668void QgsFeaturePickerModelBase::reload()
669{
670 mReloadTimer.start();
671}
672
673
674void QgsFeaturePickerModelBase::setExtraIdentifierValue( const QVariant &extraIdentifierValue )
675{
677 return;
678
679 if ( mIsSettingExtraIdentifierValue )
680 return;
681
682 mIsSettingExtraIdentifierValue = true;
683
685
687
688 mIsSettingExtraIdentifierValue = false;
689
691}
692
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
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 QgsExpressionContextScope * parentFormScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current parent attribute form/tab...
static QgsExpressionContextScope * formScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current attribute form/table form...
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
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.
Handles 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 setParentFormFeature(const QgsFeature &feature)
Sets a parent attribute form feature to be used with the filter expression.
void parentFormFeatureChanged()
A parent attribute form feature to be used alongside the filter expression.
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...
void extraValueDoesNotExistChanged(bool found)
Notification whether the model has found a feature tied to the extraIdentifierValue or not.
QgsFeature formFeature() const
Returns an attribute form feature to be used with the filter expression.
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.
@ IdentifierValues
Used to retrieve the identifierValues (primary keys) of a feature.
@ FeatureId
Used to retrieve the id of a feature.
@ IdentifierValue
Used to retrieve the identifier value (primary key) of a feature.
@ Feature
Used to retrieve the feature, it might be incomplete if the request doesn't fetch all attributes or g...
@ Value
Used to retrieve the displayExpression of a feature.
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.
void setFormFeature(const QgsFeature &feature)
Sets an attribute form feature to be used with the filter expression.
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.
QgsFeature parentFormFeature() const
Returns a parent attribute form feature to be used with the filter expression.
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.
void formFeatureChanged()
An attribute form feature to be used alongside the filter expression.
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 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.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
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 & 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.
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
bool isValid() const
Returns the validity of this feature.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
static bool expressionRequiresFormScope(const QString &expression)
Check if the expression requires a form scope (i.e.
static bool expressionRequiresParentFormScope(const QString &expression)
Check if the expression requires a parent form scope (i.e.
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...
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