QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
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
17
18#include "qgsconditionalstyle.h"
22#include "qgsvectorlayer.h"
23
24#include <QString>
25
26#include "moc_qgsfeaturepickermodelbase.cpp"
27
28using namespace Qt::StringLiterals;
29
31 : QAbstractItemModel( parent )
32{
33 mReloadTimer.setInterval( 100 );
34 mReloadTimer.setSingleShot( true );
35 connect( &mReloadTimer, &QTimer::timeout, this, &QgsFeaturePickerModelBase::scheduledReload );
36
37 // The fact that the feature changed is a combination of the 2 signals:
38 // 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)
40}
41
42
44{
45 if ( mGatherer )
46 connect( mGatherer, &QgsFeatureExpressionValuesGatherer::finished, mGatherer, &QgsFeatureExpressionValuesGatherer::deleteLater );
47}
48
49
51{
52 return mSourceLayer;
53}
54
55
57{
58 if ( mSourceLayer == sourceLayer )
59 return;
60
61 mSourceLayer = sourceLayer;
62 if ( mSourceLayer )
63 mExpressionContext = mSourceLayer->createExpressionContext();
64
65 reload();
66 emit sourceLayerChanged();
67
68 if ( mSourceLayer )
69 setDisplayExpression( mSourceLayer->displayExpression() );
70}
71
72
74{
75 return mDisplayExpression.expression();
76}
77
78
80{
81 if ( mDisplayExpression.expression() == displayExpression )
82 return;
83
84 mDisplayExpression = QgsExpression( displayExpression );
85 reload();
87}
88
89
91{
92 return mFilterValue;
93}
94
95
97{
98 if ( mFilterValue == filterValue )
99 return;
100
101 mFilterValue = filterValue;
102 reload();
103 emit filterValueChanged();
104}
105
106
108{
109 return mFilterExpression;
110}
111
112
114{
115 if ( mFilterExpression == filterExpression )
116 return;
117
118 mFilterExpression = filterExpression;
119 reload();
121}
122
124{
125 return mFormFeature;
126}
127
129{
130 if ( mFormFeature == feature )
131 return;
132
133 mFormFeature = feature;
134 if ( !mFilterExpression.isEmpty() && QgsValueRelationFieldFormatter::expressionRequiresFormScope( mFilterExpression ) )
135 {
136 reload();
137 }
138 emit formFeatureChanged();
139}
140
142{
143 return mParentFormFeature;
144}
145
147{
148 if ( mParentFormFeature == feature )
149 return;
150
151 mParentFormFeature = feature;
152 if ( !mFilterExpression.isEmpty() && QgsValueRelationFieldFormatter::expressionRequiresParentFormScope( mFilterExpression ) )
153 {
154 reload();
155 }
157}
158
160{
161 return mGatherer;
162}
163
168
169
170QModelIndex QgsFeaturePickerModelBase::index( int row, int column, const QModelIndex &parent ) const
171{
172 Q_UNUSED( parent )
173 return createIndex( row, column, nullptr );
174}
175
176
177QModelIndex QgsFeaturePickerModelBase::parent( const QModelIndex &child ) const
178{
179 Q_UNUSED( child )
180 return QModelIndex();
181}
182
183
184int QgsFeaturePickerModelBase::rowCount( const QModelIndex &parent ) const
185{
186 Q_UNUSED( parent )
187 return mEntries.size();
188}
189
190
191
192QVariant QgsFeaturePickerModelBase::data( const QModelIndex &index, int role ) const
193{
194 if ( !index.isValid() )
195 return QVariant();
196
197 switch ( role )
198 {
199 case Qt::DisplayRole:
200 case Qt::EditRole:
201 case static_cast< int >( CustomRole::Value ):
202 return mEntries.value( index.row() ).value;
203
204 case static_cast< int >( CustomRole::FeatureId ):
205 return mEntries.value( index.row() ).featureId;
206
207 case static_cast< int >( CustomRole::Feature ):
208 return mEntries.value( index.row() ).feature;
209
210 case static_cast< int >( CustomRole::IdentifierValue ):
211 {
212 const QVariantList values = mEntries.value( index.row() ).identifierFields;
213 return values.value( 0 );
214 }
215
216 case static_cast< int >( CustomRole::IdentifierValues ):
217 return mEntries.value( index.row() ).identifierFields;
218
219 case Qt::BackgroundRole:
220 case Qt::ForegroundRole:
221 case Qt::DecorationRole:
222 case Qt::FontRole:
223 {
224 const bool isNull = identifierIsNull( entryIdentifier( mEntries.value( index.row() ) ) );
225 if ( isNull )
226 {
227 // Representation for NULL value
228 if ( role == Qt::ForegroundRole )
229 {
230 return QBrush( QColor( Qt::gray ) );
231 }
232 if ( role == Qt::FontRole )
233 {
234 QFont font = QFont();
235 if ( index.row() == mExtraValueIndex )
236 font.setBold( true );
237 else
238 font.setItalic( true );
239 return font;
240 }
241 }
242 else
243 {
244 // Respect conditional style
245 const QgsConditionalStyle style = featureStyle( mEntries.value( index.row() ).feature );
246
247 if ( style.isValid() )
248 {
249 if ( role == Qt::BackgroundRole && style.validBackgroundColor() )
250 return style.backgroundColor();
251 if ( role == Qt::ForegroundRole && style.validTextColor() )
252 return style.textColor();
253 if ( role == Qt::DecorationRole )
254 return style.icon();
255 if ( role == Qt::FontRole )
256 return style.font();
257 }
258 }
259 break;
260 }
261 }
262
263 return QVariant();
264}
265
266
267void QgsFeaturePickerModelBase::updateCompleter()
268{
269 emit beginUpdate();
270
271 QgsFeatureExpressionValuesGatherer *gatherer = qobject_cast<QgsFeatureExpressionValuesGatherer *>( sender() );
272 if ( gatherer->wasCanceled() )
273 {
274 delete gatherer;
275 return;
276 }
277
278 QVector<QgsFeatureExpressionValuesGatherer::Entry> entries = mGatherer->entries();
279
280 if ( mExtraValueIndex == -1 )
281 {
283 }
284
285 // Only reloading the current entry?
286 const bool reloadCurrentFeatureOnly = mGatherer->data().toBool();
287 if ( reloadCurrentFeatureOnly )
288 {
289 if ( !entries.isEmpty() )
290 {
291 mEntries.replace( mExtraValueIndex, entries.at( 0 ) );
292 emit dataChanged( index( mExtraValueIndex, 0, QModelIndex() ), index( mExtraValueIndex, 0, QModelIndex() ) );
293 mShouldReloadCurrentFeature = false;
294 setExtraValueDoesNotExist( false );
295 }
296 else
297 {
298 setExtraValueDoesNotExist( true );
299 }
300
301 mKeepCurrentEntry = true;
302 mShouldReloadCurrentFeature = false;
303
304 if ( mFilterValue.isEmpty() )
305 reload();
306 }
307 else
308 {
309 // We got strings for a filter selection
310 std::sort( entries.begin(), entries.end(), [&]( const QgsFeatureExpressionValuesGatherer::Entry & a, const QgsFeatureExpressionValuesGatherer::Entry & b )
311 {
312 bool ok = false;
313 double aNumericOrderValue = a.orderValue.toDouble( &ok );
314 if ( ok )
315 {
316 double bNumericOrderValue = b.orderValue.toDouble( &ok );
317 if ( ok )
318 {
319 if ( mSortOrder == Qt::DescendingOrder )
320 {
321 return aNumericOrderValue > bNumericOrderValue;
322 }
323 else
324 {
325 return aNumericOrderValue < bNumericOrderValue;
326 }
327 }
328 }
329 if ( mSortOrder == Qt::DescendingOrder )
330 {
331 return a.orderValue.localeAwareCompare( b.orderValue ) > 0;
332 }
333 else
334 {
335 return a.orderValue.localeAwareCompare( b.orderValue ) < 0;
336 }
337
338 } );
339
340 if ( mAllowNull && mSourceLayer )
341 {
342 entries.prepend( QgsFeatureExpressionValuesGatherer::nullEntry( mSourceLayer ) );
343 }
344
345 const int newEntriesSize = entries.size();
346
347 // fixed entry is either NULL or extra value
348 const int nbFixedEntry = ( mKeepCurrentEntry ? 1 : 0 ) + ( mAllowNull ? 1 : 0 );
349
350 // Find the index of the current entry in the new list
351 int currentEntryInNewList = -1;
352 if ( mExtraValueIndex != -1 && mExtraValueIndex < mEntries.count() )
353 {
354 for ( int i = 0; i < newEntriesSize; ++i )
355 {
356 if ( compareEntries( entries.at( i ), mEntries.at( mExtraValueIndex ) ) )
357 {
358 mEntries.replace( mExtraValueIndex, entries.at( i ) );
359 currentEntryInNewList = i;
360 setExtraValueDoesNotExist( false );
361 break;
362 }
363 }
364 }
365
366 int firstRow = 0;
367
368 // Move current entry to the first position if this is a fixed entry or because
369 // the entry exists in the new list
370 if ( mExtraValueIndex > -1 && ( mExtraValueIndex < nbFixedEntry || currentEntryInNewList != -1 ) )
371 {
372 if ( mExtraValueIndex != 0 )
373 {
374 beginMoveRows( QModelIndex(), mExtraValueIndex, mExtraValueIndex, QModelIndex(), 0 );
375 mEntries.move( mExtraValueIndex, 0 );
376 endMoveRows();
377 }
378 firstRow = 1;
379 }
380
381 // Remove all entries (except for extra entry if existent)
382 beginRemoveRows( QModelIndex(), firstRow, mEntries.size() - firstRow );
383 mEntries.remove( firstRow, mEntries.size() - firstRow );
384
385 // if we remove all rows before endRemoveRows, setExtraIdentifierValuesUnguarded will be called
386 // and a null value will be added to mEntries, so we block setExtraIdentifierValuesUnguarded call
387
388 mIsSettingExtraIdentifierValue = true;
389 endRemoveRows();
390 mIsSettingExtraIdentifierValue = false;
391
392 if ( currentEntryInNewList == -1 )
393 {
394 beginInsertRows( QModelIndex(), firstRow, entries.size() + 1 );
395 mEntries += entries;
396 endInsertRows();
397
398 // if all entries have been cleaned (firstRow == 0)
399 // and there is a value in entries, prefer this value over NULL
400 // else chose the first one (the previous one)
401 setExtraIdentifierValueIndex( firstRow == 0 && mAllowNull && !entries.isEmpty() ? 1 : 0, firstRow == 0 );
402 }
403 else
404 {
405 if ( currentEntryInNewList != 0 )
406 {
407 beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 );
408 mEntries = entries.mid( 0, currentEntryInNewList ) + mEntries;
409 endInsertRows();
410 }
411 else
412 {
413 mEntries.replace( 0, entries.at( 0 ) );
414 }
415
416 // don't notify for a change if it's a fixed entry
417 if ( currentEntryInNewList >= nbFixedEntry )
418 {
419 emit dataChanged( index( currentEntryInNewList, 0, QModelIndex() ), index( currentEntryInNewList, 0, QModelIndex() ) );
420 }
421
422 beginInsertRows( QModelIndex(), currentEntryInNewList + 1, newEntriesSize - currentEntryInNewList - 1 );
423 mEntries += entries.mid( currentEntryInNewList + 1 );
424 endInsertRows();
425 setExtraIdentifierValueIndex( currentEntryInNewList );
426 }
427
428 emit filterJobCompleted();
429
430 mKeepCurrentEntry = false;
431 }
432 emit endUpdate();
433
434 // scheduleReload and updateCompleter lives in the same thread so if the gatherer hasn't been stopped
435 // (checked before), mGatherer still references the current gatherer
436 Q_ASSERT( gatherer == mGatherer );
437 delete mGatherer;
438 mGatherer = nullptr;
439 emit isLoadingChanged();
440}
441
442
443void QgsFeaturePickerModelBase::scheduledReload()
444{
445 if ( !mSourceLayer )
446 return;
447
448 bool wasLoading = false;
449
450 if ( mGatherer )
451 {
452 mGatherer->stop();
453 wasLoading = true;
454 }
455
456 QgsFeatureRequest request;
457
458 if ( mShouldReloadCurrentFeature )
459 {
461 }
462 else
463 {
464 QString filterClause;
465
466 if ( mFilterValue.isEmpty() && !mFilterExpression.isEmpty() )
467 filterClause = mFilterExpression;
468 else if ( mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
469 filterClause = u"(%1) ILIKE '%%2%'"_s.arg( mDisplayExpression, mFilterValue );
470 else if ( !mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
471 filterClause = u"(%1) AND ((%2) ILIKE '%%3%')"_s.arg( mFilterExpression, mDisplayExpression, mFilterValue );
472
473 if ( !filterClause.isEmpty() )
474 {
475 request.setFilterExpression( filterClause );
477
478 if ( !mFilterExpression.isEmpty() )
479 {
480 if ( mFormFeature.isValid() && QgsValueRelationFieldFormatter::expressionRequiresFormScope( mFilterExpression ) )
481 {
483 }
484 if ( mParentFormFeature.isValid() && QgsValueRelationFieldFormatter::expressionRequiresParentFormScope( mFilterExpression ) )
485 {
487 }
488 }
489 }
490 }
491 QSet<QString> attributes = requestedAttributes();
492 if ( !attributes.isEmpty() )
493 {
494 if ( auto *lFilterExpression = request.filterExpression() )
495 attributes += lFilterExpression->referencedColumns();
496 attributes += requestedAttributesForStyle();
497
498 request.setSubsetOfAttributes( attributes, mSourceLayer->fields() );
499 }
500
501 if ( !mFetchGeometry )
503 if ( mFetchLimit > 0 )
504 request.setLimit( mFetchLimit );
505
506 mGatherer = createValuesGatherer( request );
507 mGatherer->setData( mShouldReloadCurrentFeature );
508 connect( mGatherer, &QgsFeatureExpressionValuesGatherer::finished, this, &QgsFeaturePickerModelBase::updateCompleter );
509
510 mGatherer->start();
511 if ( !wasLoading )
512 emit isLoadingChanged();
513}
514
515
516QSet<QString> QgsFeaturePickerModelBase::requestedAttributesForStyle() const
517{
518 QSet<QString> requestedAttrs;
519
520 const auto rowStyles = mSourceLayer->conditionalStyles()->rowStyles();
521
522 for ( const QgsConditionalStyle &style : rowStyles )
523 {
524 const QgsExpression exp( style.rule() );
525 requestedAttrs += exp.referencedColumns();
526 }
527
528 if ( mDisplayExpression.isField() )
529 {
530 const QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
531 const auto constFieldStyles = mSourceLayer->conditionalStyles()->fieldStyles( fieldName );
532 for ( const QgsConditionalStyle &style : constFieldStyles )
533 {
534 const QgsExpression exp( style.rule() );
535 requestedAttrs += exp.referencedColumns();
536 }
537 }
538
539 return requestedAttrs;
540}
541
542
543void QgsFeaturePickerModelBase::setExtraIdentifierValueIndex( int index, bool force )
544{
545 if ( mExtraValueIndex == index && !force )
546 return;
547
550}
551
552
553void QgsFeaturePickerModelBase::reloadCurrentFeature()
554{
555 mShouldReloadCurrentFeature = true;
556 mReloadTimer.start();
557}
558
559
561{
562 const QVector<QgsFeatureExpressionValuesGatherer::Entry> entries = mEntries;
563
564 int index = 0;
565 for ( const QgsFeatureExpressionValuesGatherer::Entry &entry : entries )
566 {
567 if ( compareEntries( entry, createEntry( identifierValue ) ) )
568 {
569 setExtraIdentifierValueIndex( index );
570 break;
571 }
572
573 index++;
574 }
575
576 // Value not found in current entries
577 if ( mExtraValueIndex != index )
578 {
579 const bool isNull = identifierIsNull( identifierValue );
580 if ( !isNull || mAllowNull )
581 {
582 beginInsertRows( QModelIndex(), 0, 0 );
583 if ( !isNull )
584 {
585 mEntries.prepend( createEntry( identifierValue ) );
586 setExtraValueDoesNotExist( true );
587 reloadCurrentFeature();
588 }
589 else
590 {
591 mEntries.prepend( QgsFeatureExpressionValuesGatherer::nullEntry( mSourceLayer ) );
592 setExtraValueDoesNotExist( false );
593 }
594 endInsertRows();
595
596 setExtraIdentifierValueIndex( 0, true );
597 }
598 }
599}
600
601
602QgsConditionalStyle QgsFeaturePickerModelBase::featureStyle( const QgsFeature &feature ) const
603{
604 if ( !mSourceLayer )
605 return QgsConditionalStyle();
606
607 QgsVectorLayer *layer = mSourceLayer;
608 const QgsFeatureId fid = feature.id();
609 mExpressionContext.setFeature( feature );
610
611 auto styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
612
613 if ( mDisplayExpression.referencedColumns().count() == 1 )
614 {
615 // Style specific for this field
616 const QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
617 const auto allStyles = layer->conditionalStyles()->fieldStyles( fieldName );
618 const auto matchingFieldStyles = QgsConditionalStyle::matchingConditionalStyles( allStyles, feature.attribute( fieldName ), mExpressionContext );
619
620 styles += matchingFieldStyles;
621 }
622
623 QgsConditionalStyle style;
624 style = QgsConditionalStyle::compressStyles( styles );
625 mEntryStylesMap.insert( fid, style );
626
627 return style;
628}
629
630
632{
633 return mAllowNull;
634}
635
636
638{
639 if ( mAllowNull == allowNull )
640 return;
641
642 mAllowNull = allowNull;
643 emit allowNullChanged();
644
645 reload();
646}
647
649{
650 return mFetchGeometry;
651}
652
654{
655 if ( mFetchGeometry == fetchGeometry )
656 return;
657
658 mFetchGeometry = fetchGeometry;
659 reload();
660}
661
663{
664 return mFetchLimit;
665}
666
668{
669 if ( fetchLimit == mFetchLimit )
670 return;
671
672 mFetchLimit = fetchLimit;
673 emit fetchLimitChanged();
674
675 reload();
676}
677
678
680{
681 return mExtraValueDoesNotExist;
682}
683
684
685void QgsFeaturePickerModelBase::setExtraValueDoesNotExist( bool extraValueDoesNotExist )
686{
687 if ( mExtraValueDoesNotExist == extraValueDoesNotExist )
688 return;
689
690 mExtraValueDoesNotExist = extraValueDoesNotExist;
691 emit extraValueDoesNotExistChanged( mExtraValueDoesNotExist );
692}
693
694
699
700
701void QgsFeaturePickerModelBase::reload()
702{
703 mReloadTimer.start();
704}
705
706
708{
710 return;
711
712 if ( mIsSettingExtraIdentifierValue )
713 return;
714
715 mIsSettingExtraIdentifierValue = true;
716
718
720
721 mIsSettingExtraIdentifierValue = false;
722
724}
725
726
728{
729 return mOrderExpression.expression();
730}
731
732
734{
735 if ( mOrderExpression.expression() == orderExpression )
736 return;
737
738 mOrderExpression = QgsExpression( orderExpression );
739 reload();
741}
742
743
745{
746 return mSortOrder;
747}
748
749
751{
752 if ( mSortOrder == sortOrder )
753 return;
754
755 mSortOrder = sortOrder;
756 reload();
757 emit sortOrderChanged();
758}
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2254
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").
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 setSortOrder(const Qt::SortOrder sortOrder)
The order direction will be used for sort values in the combobox.
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...
void setOrderExpression(const QString &orderExpression)
The order expression will be used for sort values in the combobox.
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 orderExpressionChanged()
An expression for generating values for sorting.
void sortOrderChanged()
The direction used for sorting.
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 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.
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:60
QgsFeatureId id
Definition qgsfeature.h:68
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.
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