QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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
191QVariant QgsFeaturePickerModelBase::data( const QModelIndex &index, int role ) const
192{
193 if ( !index.isValid() )
194 return QVariant();
195
196 switch ( role )
197 {
198 case Qt::DisplayRole:
199 case Qt::EditRole:
200 case static_cast< int >( CustomRole::Value ):
201 return mEntries.value( index.row() ).value;
202
203 case static_cast< int >( CustomRole::FeatureId ):
204 return mEntries.value( index.row() ).featureId;
205
206 case static_cast< int >( CustomRole::Feature ):
207 return mEntries.value( index.row() ).feature;
208
209 case static_cast< int >( CustomRole::IdentifierValue ):
210 {
211 const QVariantList values = mEntries.value( index.row() ).identifierFields;
212 return values.value( 0 );
213 }
214
215 case static_cast< int >( CustomRole::IdentifierValues ):
216 return mEntries.value( index.row() ).identifierFields;
217
218 case Qt::BackgroundRole:
219 case Qt::ForegroundRole:
220 case Qt::DecorationRole:
221 case Qt::FontRole:
222 {
223 const bool isNull = identifierIsNull( entryIdentifier( mEntries.value( index.row() ) ) );
224 if ( isNull )
225 {
226 // Representation for NULL value
227 if ( role == Qt::ForegroundRole )
228 {
229 return QBrush( QColor( Qt::gray ) );
230 }
231 if ( role == Qt::FontRole )
232 {
233 QFont font = QFont();
234 if ( index.row() == mExtraValueIndex )
235 font.setBold( true );
236 else
237 font.setItalic( true );
238 return font;
239 }
240 }
241 else
242 {
243 // Respect conditional style
244 const QgsConditionalStyle style = featureStyle( mEntries.value( index.row() ).feature );
245
246 if ( style.isValid() )
247 {
248 if ( role == Qt::BackgroundRole && style.validBackgroundColor() )
249 return style.backgroundColor();
250 if ( role == Qt::ForegroundRole && style.validTextColor() )
251 return style.textColor();
252 if ( role == Qt::DecorationRole )
253 return style.icon();
254 if ( role == Qt::FontRole )
255 return style.font();
256 }
257 }
258 break;
259 }
260 }
261
262 return QVariant();
263}
264
265
266void QgsFeaturePickerModelBase::updateCompleter()
267{
268 emit beginUpdate();
269
270 QgsFeatureExpressionValuesGatherer *gatherer = qobject_cast<QgsFeatureExpressionValuesGatherer *>( sender() );
271 if ( gatherer->wasCanceled() )
272 {
273 delete gatherer;
274 return;
275 }
276
277 QVector<QgsFeatureExpressionValuesGatherer::Entry> entries = mGatherer->entries();
278
279 if ( mExtraValueIndex == -1 )
280 {
282 }
283
284 // Only reloading the current entry?
285 const bool reloadCurrentFeatureOnly = mGatherer->data().toBool();
286 if ( reloadCurrentFeatureOnly )
287 {
288 if ( !entries.isEmpty() )
289 {
290 mEntries.replace( mExtraValueIndex, entries.at( 0 ) );
291 emit dataChanged( index( mExtraValueIndex, 0, QModelIndex() ), index( mExtraValueIndex, 0, QModelIndex() ) );
292 mShouldReloadCurrentFeature = false;
293 setExtraValueDoesNotExist( false );
294 }
295 else
296 {
297 setExtraValueDoesNotExist( true );
298 }
299
300 mKeepCurrentEntry = true;
301 mShouldReloadCurrentFeature = false;
302
303 if ( mFilterValue.isEmpty() )
304 reload();
305 }
306 else
307 {
308 // We got strings for a filter selection
309 std::sort( entries.begin(), entries.end(), [&]( const QgsFeatureExpressionValuesGatherer::Entry &a, const QgsFeatureExpressionValuesGatherer::Entry &b ) {
310 bool ok = false;
311 double aNumericOrderValue = a.orderValue.toDouble( &ok );
312 if ( ok )
313 {
314 double bNumericOrderValue = b.orderValue.toDouble( &ok );
315 if ( ok )
316 {
317 if ( mSortOrder == Qt::DescendingOrder )
318 {
319 return aNumericOrderValue > bNumericOrderValue;
320 }
321 else
322 {
323 return aNumericOrderValue < bNumericOrderValue;
324 }
325 }
326 }
327 if ( mSortOrder == Qt::DescendingOrder )
328 {
329 return a.orderValue.localeAwareCompare( b.orderValue ) > 0;
330 }
331 else
332 {
333 return a.orderValue.localeAwareCompare( b.orderValue ) < 0;
334 }
335 } );
336
337 if ( mAllowNull && mSourceLayer )
338 {
339 entries.prepend( QgsFeatureExpressionValuesGatherer::nullEntry( mSourceLayer ) );
340 }
341
342 const int newEntriesSize = entries.size();
343
344 // fixed entry is either NULL or extra value
345 const int nbFixedEntry = ( mKeepCurrentEntry ? 1 : 0 ) + ( mAllowNull ? 1 : 0 );
346
347 // Find the index of the current entry in the new list
348 int currentEntryInNewList = -1;
349 if ( mExtraValueIndex != -1 && mExtraValueIndex < mEntries.count() )
350 {
351 for ( int i = 0; i < newEntriesSize; ++i )
352 {
353 if ( compareEntries( entries.at( i ), mEntries.at( mExtraValueIndex ) ) )
354 {
355 mEntries.replace( mExtraValueIndex, entries.at( i ) );
356 currentEntryInNewList = i;
357 setExtraValueDoesNotExist( false );
358 break;
359 }
360 }
361 }
362
363 int firstRow = 0;
364
365 // Move current entry to the first position if this is a fixed entry or because
366 // the entry exists in the new list
367 if ( mExtraValueIndex > -1 && ( mExtraValueIndex < nbFixedEntry || currentEntryInNewList != -1 ) )
368 {
369 if ( mExtraValueIndex != 0 )
370 {
371 beginMoveRows( QModelIndex(), mExtraValueIndex, mExtraValueIndex, QModelIndex(), 0 );
372 mEntries.move( mExtraValueIndex, 0 );
373 endMoveRows();
374 }
375 firstRow = 1;
376 }
377
378 // Remove all entries (except for extra entry if existent)
379 beginRemoveRows( QModelIndex(), firstRow, mEntries.size() - firstRow );
380 mEntries.remove( firstRow, mEntries.size() - firstRow );
381
382 // if we remove all rows before endRemoveRows, setExtraIdentifierValuesUnguarded will be called
383 // and a null value will be added to mEntries, so we block setExtraIdentifierValuesUnguarded call
384
385 mIsSettingExtraIdentifierValue = true;
386 endRemoveRows();
387 mIsSettingExtraIdentifierValue = false;
388
389 if ( currentEntryInNewList == -1 )
390 {
391 beginInsertRows( QModelIndex(), firstRow, entries.size() + 1 );
392 mEntries += entries;
393 endInsertRows();
394
395 // if all entries have been cleaned (firstRow == 0)
396 // and there is a value in entries, prefer this value over NULL
397 // else chose the first one (the previous one)
398 setExtraIdentifierValueIndex( firstRow == 0 && mAllowNull && !entries.isEmpty() ? 1 : 0, firstRow == 0 );
399 }
400 else
401 {
402 if ( currentEntryInNewList != 0 )
403 {
404 beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 );
405 mEntries = entries.mid( 0, currentEntryInNewList ) + mEntries;
406 endInsertRows();
407 }
408 else
409 {
410 mEntries.replace( 0, entries.at( 0 ) );
411 }
412
413 // don't notify for a change if it's a fixed entry
414 if ( currentEntryInNewList >= nbFixedEntry )
415 {
416 emit dataChanged( index( currentEntryInNewList, 0, QModelIndex() ), index( currentEntryInNewList, 0, QModelIndex() ) );
417 }
418
419 beginInsertRows( QModelIndex(), currentEntryInNewList + 1, newEntriesSize - currentEntryInNewList - 1 );
420 mEntries += entries.mid( currentEntryInNewList + 1 );
421 endInsertRows();
422 setExtraIdentifierValueIndex( currentEntryInNewList );
423 }
424
425 emit filterJobCompleted();
426
427 mKeepCurrentEntry = false;
428 }
429 emit endUpdate();
430
431 // scheduleReload and updateCompleter lives in the same thread so if the gatherer hasn't been stopped
432 // (checked before), mGatherer still references the current gatherer
433 Q_ASSERT( gatherer == mGatherer );
434 delete mGatherer;
435 mGatherer = nullptr;
436 emit isLoadingChanged();
437}
438
439
440void QgsFeaturePickerModelBase::scheduledReload()
441{
442 if ( !mSourceLayer )
443 return;
444
445 bool wasLoading = false;
446
447 if ( mGatherer )
448 {
449 mGatherer->stop();
450 wasLoading = true;
451 }
452
453 QgsFeatureRequest request;
454
455 if ( mShouldReloadCurrentFeature )
456 {
458 }
459 else
460 {
461 QString filterClause;
462
463 if ( mFilterValue.isEmpty() && !mFilterExpression.isEmpty() )
464 filterClause = mFilterExpression;
465 else if ( mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
466 filterClause = u"(%1) ILIKE '%%2%'"_s.arg( mDisplayExpression, mFilterValue );
467 else if ( !mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
468 filterClause = u"(%1) AND ((%2) ILIKE '%%3%')"_s.arg( mFilterExpression, mDisplayExpression, mFilterValue );
469
470 if ( !filterClause.isEmpty() )
471 {
472 request.setFilterExpression( filterClause );
474
475 if ( !mFilterExpression.isEmpty() )
476 {
477 if ( mFormFeature.isValid() && QgsValueRelationFieldFormatter::expressionRequiresFormScope( mFilterExpression ) )
478 {
480 }
481 if ( mParentFormFeature.isValid() && QgsValueRelationFieldFormatter::expressionRequiresParentFormScope( mFilterExpression ) )
482 {
484 }
485 }
486 }
487 }
488 QSet<QString> attributes = requestedAttributes();
489 if ( !attributes.isEmpty() )
490 {
491 if ( auto *lFilterExpression = request.filterExpression() )
492 attributes += lFilterExpression->referencedColumns();
493 attributes += requestedAttributesForStyle();
494
495 request.setSubsetOfAttributes( attributes, mSourceLayer->fields() );
496 }
497
498 if ( !mFetchGeometry )
500 if ( mFetchLimit > 0 )
501 request.setLimit( mFetchLimit );
502
503 mGatherer = createValuesGatherer( request );
504 mGatherer->setData( mShouldReloadCurrentFeature );
505 connect( mGatherer, &QgsFeatureExpressionValuesGatherer::finished, this, &QgsFeaturePickerModelBase::updateCompleter );
506
507 mGatherer->start();
508 if ( !wasLoading )
509 emit isLoadingChanged();
510}
511
512
513QSet<QString> QgsFeaturePickerModelBase::requestedAttributesForStyle() const
514{
515 QSet<QString> requestedAttrs;
516
517 const auto rowStyles = mSourceLayer->conditionalStyles()->rowStyles();
518
519 for ( const QgsConditionalStyle &style : rowStyles )
520 {
521 const QgsExpression exp( style.rule() );
522 requestedAttrs += exp.referencedColumns();
523 }
524
525 if ( mDisplayExpression.isField() )
526 {
527 const QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
528 const auto constFieldStyles = mSourceLayer->conditionalStyles()->fieldStyles( fieldName );
529 for ( const QgsConditionalStyle &style : constFieldStyles )
530 {
531 const QgsExpression exp( style.rule() );
532 requestedAttrs += exp.referencedColumns();
533 }
534 }
535
536 return requestedAttrs;
537}
538
539
540void QgsFeaturePickerModelBase::setExtraIdentifierValueIndex( int index, bool force )
541{
542 if ( mExtraValueIndex == index && !force )
543 return;
544
547}
548
549
550void QgsFeaturePickerModelBase::reloadCurrentFeature()
551{
552 mShouldReloadCurrentFeature = true;
553 mReloadTimer.start();
554}
555
556
558{
559 const QVector<QgsFeatureExpressionValuesGatherer::Entry> entries = mEntries;
560
561 int index = 0;
562 for ( const QgsFeatureExpressionValuesGatherer::Entry &entry : entries )
563 {
564 if ( compareEntries( entry, createEntry( identifierValue ) ) )
565 {
566 setExtraIdentifierValueIndex( index );
567 break;
568 }
569
570 index++;
571 }
572
573 // Value not found in current entries
574 if ( mExtraValueIndex != index )
575 {
576 const bool isNull = identifierIsNull( identifierValue );
577 if ( !isNull || mAllowNull )
578 {
579 beginInsertRows( QModelIndex(), 0, 0 );
580 if ( !isNull )
581 {
582 mEntries.prepend( createEntry( identifierValue ) );
583 setExtraValueDoesNotExist( true );
584 reloadCurrentFeature();
585 }
586 else
587 {
588 mEntries.prepend( QgsFeatureExpressionValuesGatherer::nullEntry( mSourceLayer ) );
589 setExtraValueDoesNotExist( false );
590 }
591 endInsertRows();
592
593 setExtraIdentifierValueIndex( 0, true );
594 }
595 }
596}
597
598
599QgsConditionalStyle QgsFeaturePickerModelBase::featureStyle( const QgsFeature &feature ) const
600{
601 if ( !mSourceLayer )
602 return QgsConditionalStyle();
603
604 QgsVectorLayer *layer = mSourceLayer;
605 const QgsFeatureId fid = feature.id();
606 mExpressionContext.setFeature( feature );
607
608 auto styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
609
610 if ( mDisplayExpression.referencedColumns().count() == 1 )
611 {
612 // Style specific for this field
613 const QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
614 const auto allStyles = layer->conditionalStyles()->fieldStyles( fieldName );
615 const auto matchingFieldStyles = QgsConditionalStyle::matchingConditionalStyles( allStyles, feature.attribute( fieldName ), mExpressionContext );
616
617 styles += matchingFieldStyles;
618 }
619
620 QgsConditionalStyle style;
621 style = QgsConditionalStyle::compressStyles( styles );
622 mEntryStylesMap.insert( fid, style );
623
624 return style;
625}
626
627
629{
630 return mAllowNull;
631}
632
633
635{
636 if ( mAllowNull == allowNull )
637 return;
638
639 mAllowNull = allowNull;
640 emit allowNullChanged();
641
642 reload();
643}
644
646{
647 return mFetchGeometry;
648}
649
651{
652 if ( mFetchGeometry == fetchGeometry )
653 return;
654
655 mFetchGeometry = fetchGeometry;
656 reload();
657}
658
660{
661 return mFetchLimit;
662}
663
665{
666 if ( fetchLimit == mFetchLimit )
667 return;
668
669 mFetchLimit = fetchLimit;
670 emit fetchLimitChanged();
671
672 reload();
673}
674
675
677{
678 return mExtraValueDoesNotExist;
679}
680
681
682void QgsFeaturePickerModelBase::setExtraValueDoesNotExist( bool extraValueDoesNotExist )
683{
684 if ( mExtraValueDoesNotExist == extraValueDoesNotExist )
685 return;
686
687 mExtraValueDoesNotExist = extraValueDoesNotExist;
688 emit extraValueDoesNotExistChanged( mExtraValueDoesNotExist );
689}
690
691
696
697
698void QgsFeaturePickerModelBase::reload()
699{
700 mReloadTimer.start();
701}
702
703
705{
707 return;
708
709 if ( mIsSettingExtraIdentifierValue )
710 return;
711
712 mIsSettingExtraIdentifierValue = true;
713
715
717
718 mIsSettingExtraIdentifierValue = false;
719
721}
722
723
725{
726 return mOrderExpression.expression();
727}
728
729
731{
732 if ( mOrderExpression.expression() == orderExpression )
733 return;
734
735 mOrderExpression = QgsExpression( orderExpression );
736 reload();
738}
739
740
742{
743 return mSortOrder;
744}
745
746
748{
749 if ( mSortOrder == sortOrder )
750 return;
751
752 mSortOrder = sortOrder;
753 reload();
754 emit sortOrderChanged();
755}
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2276
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