26#include "moc_qgsfeaturepickermodelbase.cpp"
28using namespace Qt::StringLiterals;
31 : QAbstractItemModel(
parent )
33 mReloadTimer.setInterval( 100 );
34 mReloadTimer.setSingleShot(
true );
35 connect( &mReloadTimer, &QTimer::timeout,
this, &QgsFeaturePickerModelBase::scheduledReload );
46 connect( mGatherer, &QgsFeatureExpressionValuesGatherer::finished, mGatherer, &QgsFeatureExpressionValuesGatherer::deleteLater );
63 mExpressionContext = mSourceLayer->createExpressionContext();
75 return mDisplayExpression.expression();
109 return mFilterExpression;
130 if ( mFormFeature == feature )
133 mFormFeature = feature;
143 return mParentFormFeature;
148 if ( mParentFormFeature == feature )
151 mParentFormFeature = feature;
173 return createIndex( row, column,
nullptr );
180 return QModelIndex();
193 if ( !
index.isValid() )
198 case Qt::DisplayRole:
211 const QVariantList values =
mEntries.value(
index.row() ).identifierFields;
212 return values.value( 0 );
218 case Qt::BackgroundRole:
219 case Qt::ForegroundRole:
220 case Qt::DecorationRole:
227 if ( role == Qt::ForegroundRole )
229 return QBrush( QColor( Qt::gray ) );
231 if ( role == Qt::FontRole )
233 QFont font = QFont();
235 font.setBold(
true );
237 font.setItalic(
true );
252 if ( role == Qt::DecorationRole )
254 if ( role == Qt::FontRole )
266void QgsFeaturePickerModelBase::updateCompleter()
270 QgsFeatureExpressionValuesGatherer *gatherer = qobject_cast<QgsFeatureExpressionValuesGatherer *>( sender() );
271 if ( gatherer->wasCanceled() )
277 QVector<QgsFeatureExpressionValuesGatherer::Entry> entries = mGatherer->entries();
285 const bool reloadCurrentFeatureOnly = mGatherer->data().toBool();
286 if ( reloadCurrentFeatureOnly )
288 if ( !entries.isEmpty() )
292 mShouldReloadCurrentFeature =
false;
293 setExtraValueDoesNotExist(
false );
297 setExtraValueDoesNotExist(
true );
300 mKeepCurrentEntry =
true;
301 mShouldReloadCurrentFeature =
false;
303 if ( mFilterValue.isEmpty() )
309 std::sort( entries.begin(), entries.end(), [&](
const QgsFeatureExpressionValuesGatherer::Entry &a,
const QgsFeatureExpressionValuesGatherer::Entry &b ) {
311 double aNumericOrderValue = a.orderValue.toDouble( &ok );
314 double bNumericOrderValue = b.orderValue.toDouble( &ok );
317 if ( mSortOrder == Qt::DescendingOrder )
319 return aNumericOrderValue > bNumericOrderValue;
323 return aNumericOrderValue < bNumericOrderValue;
327 if ( mSortOrder == Qt::DescendingOrder )
329 return a.orderValue.localeAwareCompare( b.orderValue ) > 0;
333 return a.orderValue.localeAwareCompare( b.orderValue ) < 0;
337 if ( mAllowNull && mSourceLayer )
339 entries.prepend( QgsFeatureExpressionValuesGatherer::nullEntry( mSourceLayer ) );
342 const int newEntriesSize = entries.size();
345 const int nbFixedEntry = ( mKeepCurrentEntry ? 1 : 0 ) + ( mAllowNull ? 1 : 0 );
348 int currentEntryInNewList = -1;
351 for (
int i = 0; i < newEntriesSize; ++i )
356 currentEntryInNewList = i;
357 setExtraValueDoesNotExist(
false );
379 beginRemoveRows( QModelIndex(), firstRow,
mEntries.size() - firstRow );
385 mIsSettingExtraIdentifierValue =
true;
387 mIsSettingExtraIdentifierValue =
false;
389 if ( currentEntryInNewList == -1 )
391 beginInsertRows( QModelIndex(), firstRow, entries.size() + 1 );
398 setExtraIdentifierValueIndex( firstRow == 0 && mAllowNull && !entries.isEmpty() ? 1 : 0, firstRow == 0 );
402 if ( currentEntryInNewList != 0 )
404 beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 );
410 mEntries.replace( 0, entries.at( 0 ) );
414 if ( currentEntryInNewList >= nbFixedEntry )
416 emit dataChanged(
index( currentEntryInNewList, 0, QModelIndex() ),
index( currentEntryInNewList, 0, QModelIndex() ) );
419 beginInsertRows( QModelIndex(), currentEntryInNewList + 1, newEntriesSize - currentEntryInNewList - 1 );
420 mEntries += entries.mid( currentEntryInNewList + 1 );
422 setExtraIdentifierValueIndex( currentEntryInNewList );
427 mKeepCurrentEntry =
false;
433 Q_ASSERT( gatherer == mGatherer );
436 emit isLoadingChanged();
440void QgsFeaturePickerModelBase::scheduledReload()
445 bool wasLoading =
false;
453 QgsFeatureRequest request;
455 if ( mShouldReloadCurrentFeature )
461 QString filterClause;
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 );
470 if ( !filterClause.isEmpty() )
475 if ( !mFilterExpression.isEmpty() )
489 if ( !attributes.isEmpty() )
492 attributes += lFilterExpression->referencedColumns();
493 attributes += requestedAttributesForStyle();
498 if ( !mFetchGeometry )
500 if ( mFetchLimit > 0 )
504 mGatherer->setData( mShouldReloadCurrentFeature );
505 connect( mGatherer, &QgsFeatureExpressionValuesGatherer::finished,
this, &QgsFeaturePickerModelBase::updateCompleter );
513QSet<QString> QgsFeaturePickerModelBase::requestedAttributesForStyle()
const
515 QSet<QString> requestedAttrs;
517 const auto rowStyles = mSourceLayer->conditionalStyles()->rowStyles();
519 for (
const QgsConditionalStyle &style : rowStyles )
521 const QgsExpression exp( style.rule() );
522 requestedAttrs += exp.referencedColumns();
525 if ( mDisplayExpression.isField() )
527 const QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
528 const auto constFieldStyles = mSourceLayer->conditionalStyles()->fieldStyles( fieldName );
529 for (
const QgsConditionalStyle &style : constFieldStyles )
531 const QgsExpression exp( style.rule() );
532 requestedAttrs += exp.referencedColumns();
536 return requestedAttrs;
540void QgsFeaturePickerModelBase::setExtraIdentifierValueIndex(
int index,
bool force )
550void QgsFeaturePickerModelBase::reloadCurrentFeature()
552 mShouldReloadCurrentFeature =
true;
553 mReloadTimer.start();
559 const QVector<QgsFeatureExpressionValuesGatherer::Entry> entries =
mEntries;
562 for (
const QgsFeatureExpressionValuesGatherer::Entry &entry : entries )
566 setExtraIdentifierValueIndex(
index );
577 if ( !isNull || mAllowNull )
579 beginInsertRows( QModelIndex(), 0, 0 );
583 setExtraValueDoesNotExist(
true );
584 reloadCurrentFeature();
588 mEntries.prepend( QgsFeatureExpressionValuesGatherer::nullEntry( mSourceLayer ) );
589 setExtraValueDoesNotExist(
false );
593 setExtraIdentifierValueIndex( 0,
true );
617 styles += matchingFieldStyles;
620 QgsConditionalStyle style;
622 mEntryStylesMap.insert( fid, style );
647 return mFetchGeometry;
678 return mExtraValueDoesNotExist;
682void QgsFeaturePickerModelBase::setExtraValueDoesNotExist(
bool extraValueDoesNotExist )
698void QgsFeaturePickerModelBase::reload()
700 mReloadTimer.start();
709 if ( mIsSettingExtraIdentifierValue )
712 mIsSettingExtraIdentifierValue =
true;
718 mIsSettingExtraIdentifierValue =
false;
726 return mOrderExpression.expression();
@ 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").
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.
int mExtraValueIndex
The current index.
@ 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...
QgsVectorLayer * sourceLayer
QVariant data(const QModelIndex &index, int role) const override
QModelIndex index(int row, int column, const QModelIndex &parent) const override
int extraIdentifierValueIndex
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.
~QgsFeaturePickerModelBase() override
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.
QString displayExpression
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...
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
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