22 : QAbstractItemModel( parent )
24 mReloadTimer.setInterval( 100 );
25 mReloadTimer.setSingleShot(
true );
26 connect( &mReloadTimer, &QTimer::timeout,
this, &QgsFeatureFilterModel::scheduledReload );
27 setExtraIdentifierValueUnguarded( QVariant() );
33 connect( mGatherer, &QgsFieldExpressionValuesGatherer::finished, mGatherer, &QgsFieldExpressionValuesGatherer::deleteLater );
43 if ( mSourceLayer == sourceLayer )
54 return mDisplayExpression.expression();
62 mDisplayExpression = QgsExpression( displayExpression );
74 if ( mFilterValue == filterValue )
84 return mFilterExpression;
89 if ( mFilterExpression == filterExpression )
105 return createIndex( row, column,
nullptr );
111 return QModelIndex();
118 return mEntries.size();
129 if ( !index.isValid() )
134 case Qt::DisplayRole:
137 return mEntries.value( index.row() ).value;
140 return mEntries.value( index.row() ).identifierValue;
142 case Qt::BackgroundColorRole:
143 case Qt::TextColorRole:
144 case Qt::DecorationRole:
147 if ( mEntries.value( index.row() ).identifierValue.isNull() )
150 if ( role == Qt::TextColorRole )
152 return QBrush( QColor( Qt::gray ) );
154 else if ( role == Qt::FontRole )
156 QFont font = QFont();
157 if ( index.row() == mExtraIdentifierValueIndex )
158 font.setBold(
true );
160 if ( mEntries.value( index.row() ).identifierValue.isNull() )
162 font.setItalic(
true );
178 if ( role == Qt::DecorationRole )
180 if ( role == Qt::FontRole )
191 void QgsFeatureFilterModel::updateCompleter()
194 QVector<Entry> entries = mGatherer->entries();
196 if ( mExtraIdentifierValueIndex == -1 )
197 setExtraIdentifierValueUnguarded( QVariant() );
200 if ( mGatherer->data().toBool() )
202 if ( !entries.isEmpty() )
204 mEntries.replace( mExtraIdentifierValueIndex, entries.at( 0 ) );
205 emit dataChanged(
index( mExtraIdentifierValueIndex, 0, QModelIndex() ),
index( mExtraIdentifierValueIndex, 0, QModelIndex() ) );
206 mShouldReloadCurrentFeature =
false;
207 setExtraValueDoesNotExist(
false );
211 setExtraValueDoesNotExist(
true );
214 mShouldReloadCurrentFeature =
false;
216 if ( mFilterValue.isEmpty() )
222 std::sort( entries.begin(), entries.end(), [](
const Entry & a,
const Entry & b ) {
return a.value.localeAwareCompare( b.value ) < 0; } );
225 entries.prepend( Entry( QVariant( QVariant::Int ), tr(
"NULL" ),
QgsFeature() ) );
227 const int newEntriesSize = entries.size();
230 int currentEntryInNewList = -1;
231 if ( mExtraIdentifierValueIndex != -1 )
233 for (
int i = 0; i < newEntriesSize; ++i )
235 if ( entries.at( i ).identifierValue == mExtraIdentifierValue )
237 currentEntryInNewList = i;
238 mEntries.replace( mExtraIdentifierValueIndex, entries.at( i ) );
239 emit dataChanged(
index( mExtraIdentifierValueIndex, 0, QModelIndex() ),
index( mExtraIdentifierValueIndex, 0, QModelIndex() ) );
240 setExtraValueDoesNotExist(
false );
247 Q_ASSERT_X(
false,
"QgsFeatureFilterModel::updateCompleter",
"No extra identifier value generated. Should not get here." );
253 if ( mExtraIdentifierValueIndex != -1 )
255 if ( mExtraIdentifierValueIndex != 0 )
257 beginMoveRows( QModelIndex(), mExtraIdentifierValueIndex, mExtraIdentifierValueIndex, QModelIndex(), 0 );
258 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0) 259 Entry extraEntry = mEntries.takeAt( mExtraIdentifierValueIndex );
260 mEntries.prepend( extraEntry );
262 mEntries.move( mExtraIdentifierValueIndex, 0 );
270 beginRemoveRows( QModelIndex(), firstRow, mEntries.size() - firstRow );
271 mEntries.remove( firstRow, mEntries.size() - firstRow );
274 if ( currentEntryInNewList == -1 )
276 beginInsertRows( QModelIndex(), 1, entries.size() + 1 );
279 setExtraIdentifierValueIndex( 0 );
283 if ( currentEntryInNewList != 0 )
285 beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 );
286 mEntries = entries.mid( 0, currentEntryInNewList ) + mEntries;
291 mEntries.replace( 0, entries.at( 0 ) );
294 emit dataChanged(
index( currentEntryInNewList, 0, QModelIndex() ),
index( currentEntryInNewList, 0, QModelIndex() ) );
296 beginInsertRows( QModelIndex(), currentEntryInNewList + 1, newEntriesSize - currentEntryInNewList - 1 );
297 mEntries += entries.mid( currentEntryInNewList + 1 );
299 setExtraIdentifierValueIndex( currentEntryInNewList );
307 void QgsFeatureFilterModel::gathererThreadFinished()
314 void QgsFeatureFilterModel::scheduledReload()
319 bool wasLoading =
false;
325 disconnect( mGatherer, &QgsFieldExpressionValuesGatherer::collectedValues,
this, &QgsFeatureFilterModel::updateCompleter );
326 disconnect( mGatherer, &QgsFieldExpressionValuesGatherer::finished,
this, &QgsFeatureFilterModel::gathererThreadFinished );
327 connect( mGatherer, &QgsFieldExpressionValuesGatherer::finished, mGatherer, &QgsFieldExpressionValuesGatherer::deleteLater );
334 if ( mShouldReloadCurrentFeature )
336 request.
setFilterExpression( QStringLiteral(
"%1 = %2" ).arg( QgsExpression::quotedColumnRef( mIdentifierField ), QgsExpression::quotedValue( mExtraIdentifierValue ) ) );
340 QString filterClause;
342 if ( mFilterValue.isEmpty() && !mFilterExpression.isEmpty() )
343 filterClause = mFilterExpression;
344 else if ( mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
345 filterClause = QStringLiteral(
"(%1) ILIKE '%%2%'" ).arg( mDisplayExpression, mFilterValue );
346 else if ( !mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
347 filterClause = QStringLiteral(
"(%1) AND ((%2) ILIKE '%%3%')" ).arg( mFilterExpression, mDisplayExpression, mFilterValue );
349 if ( !filterClause.isEmpty() )
352 QSet<QString> attributes;
355 attributes << mIdentifierField;
362 mGatherer->setData( mShouldReloadCurrentFeature );
364 connect( mGatherer, &QgsFieldExpressionValuesGatherer::collectedValues,
this, &QgsFeatureFilterModel::updateCompleter );
365 connect( mGatherer, &QgsFieldExpressionValuesGatherer::finished,
this, &QgsFeatureFilterModel::gathererThreadFinished );
372 QSet<QString> QgsFeatureFilterModel::requestedAttributes()
const 374 QSet<QString> requestedAttrs;
380 QgsExpression exp( style.rule() );
381 requestedAttrs += exp.referencedColumns();
384 if ( mDisplayExpression.isField() )
386 QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
389 QgsExpression exp( style.
rule() );
390 requestedAttrs += exp.referencedColumns();
394 return requestedAttrs;
397 void QgsFeatureFilterModel::setExtraIdentifierValueIndex(
int index )
399 if ( mExtraIdentifierValueIndex == index )
402 mExtraIdentifierValueIndex =
index;
406 void QgsFeatureFilterModel::reloadCurrentFeature()
408 mShouldReloadCurrentFeature =
true;
409 mReloadTimer.start();
412 void QgsFeatureFilterModel::setExtraIdentifierValueUnguarded(
const QVariant &
extraIdentifierValue )
414 const QVector<Entry> entries = mEntries;
417 for (
const Entry &entry : entries )
419 if ( entry.identifierValue == extraIdentifierValue && entry.identifierValue.isNull() == extraIdentifierValue.isNull() && entry.identifierValue.isValid() == extraIdentifierValue.isValid() )
421 setExtraIdentifierValueIndex( index );
429 if ( mExtraIdentifierValueIndex != index )
431 beginInsertRows( QModelIndex(), 0, 0 );
432 if ( extraIdentifierValue.isNull() )
433 mEntries.prepend( Entry( QVariant( QVariant::Int ), QStringLiteral(
"%1" ).arg( tr(
"NULL" ) ),
QgsFeature() ) );
435 mEntries.prepend( Entry( extraIdentifierValue, QStringLiteral(
"(%1)" ).arg( extraIdentifierValue.toString() ),
QgsFeature() ) );
437 setExtraIdentifierValueIndex( 0 );
439 reloadCurrentFeature();
454 if ( mDisplayExpression.referencedColumns().count() == 1 )
457 QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
461 styles += matchingFieldStyles;
466 mEntryStylesMap.insert( fid, style );
478 if ( mAllowNull == allowNull )
489 return mExtraValueDoesNotExist;
494 if ( mExtraValueDoesNotExist == extraValueDoesNotExist )
503 return mExtraIdentifierValueIndex;
508 return mIdentifierField;
513 if ( mIdentifierField == identifierField )
520 void QgsFeatureFilterModel::reload()
522 mReloadTimer.start();
527 return mExtraIdentifierValue;
532 if ( extraIdentifierValue == mExtraIdentifierValue && extraIdentifierValue.isNull() == mExtraIdentifierValue.isNull() && mExtraIdentifierValue.isValid() )
535 setExtraIdentifierValueUnguarded( extraIdentifierValue );
void filterValueChanged()
This value will be used to filter the features available from this model.
bool allowNull() const
Add a NULL entry to the list.
void beginUpdate()
Notification that the model is about to be changed because a job was completed.
int rowCount(const QModelIndex &parent) const override
Used to retrieve the displayExpression of a feature.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void setFilterExpression(const QString &filterExpression)
An additional filter expression to apply, next to the filterValue.
QString filterValue() const
This value will be used to filter the features available from this model.
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName)
Returns the conditional styles set for the field UI properties.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QVariant extraIdentifierValue() const
Allows specifying one value that does not need to match the filter criteria but will still be availab...
void filterJobCompleted()
Indicates that a filter job has been completed and new data may be available.
bool validBackgroundColor() const
Check if the background color is valid for render.
QPixmap icon() const
The icon set for style generated from the set symbol.
bool extraValueDoesNotExist() const
Flag indicating that the extraIdentifierValue does not exist in the data.
void extraIdentifierValueIndexChanged(int index)
The index at which the extra identifier value is available within the model.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
friend class QgsFieldExpressionValuesGatherer
QgsConditionalLayerStyles * conditionalStyles() const
Return the conditional styles that are set for this layer.
QgsExpression * filterExpression() const
Returns the filter expression if set.
int extraIdentifierValueIndex() const
The index at which the extra identifier value is available within the model.
QList< QgsConditionalStyle > rowStyles()
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
void identifierFieldChanged()
The identifier field should be a unique field that can be used to identify individual features...
Conditional styling for a rule.
QString displayExpression() const
The display expression will be used for.
QgsFields fields() const override
Returns the list of fields of this layer.
bool isValid() const
isValid Check if this rule is valid.
static QList< QgsConditionalStyle > matchingConditionalStyles(const QList< QgsConditionalStyle > &styles, const QVariant &value, QgsExpressionContext &context)
Find and return the matching styles for the value and feature.
void setFilterValue(const QString &filterValue)
This value will be used to filter the features available from this model.
QModelIndex index(int row, int column, const QModelIndex &parent) const override
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QColor backgroundColor() const
The background color for style.
static QgsConditionalStyle compressStyles(const QList< QgsConditionalStyle > &styles)
Compress a list of styles into a single style.
void isLoadingChanged()
Indicator if the model is currently performing any feature iteration in the background.
QModelIndex parent(const QModelIndex &child) const override
void allowNullChanged()
Add a NULL entry to the list.
QgsFeatureFilterModel(QObject *parent=nullptr)
Create a new QgsFeatureFilterModel, optionally specifying a parent.
bool isLoading() const
Indicator if the model is currently performing any feature iteration in the background.
QString filterExpression() const
An additional filter expression to apply, next to the filterValue.
void filterExpressionChanged()
An additional filter expression to apply, next to the filterValue.
void endUpdate()
Notification that the model change is finished.
QString identifierField() const
The identifier field should be a unique field that can be used to identify individual features...
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
int columnCount(const QModelIndex &parent) const override
void extraIdentifierValueChanged()
Allows specifying one value that does not need to match the filter criteria but will still be availab...
void setIdentifierField(const QString &identifierField)
The identifier field should be a unique field that can be used to identify individual features...
void setSourceLayer(QgsVectorLayer *sourceLayer)
The source layer from which features will be fetched.
QColor textColor() const
The text color set for style.
void sourceLayerChanged()
The source layer from which features will be fetched.
bool validTextColor() const
Check if the text color is valid for render.
void setExtraIdentifierValue(const QVariant &extraIdentifierValue)
Allows specifying one value that does not need to match the filter criteria but will still be availab...
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
QVariant data(const QModelIndex &index, int role) const override
void setAllowNull(bool allowNull)
Add a NULL entry to the list.
QFont font() const
The font for the style.
QgsVectorLayer * sourceLayer() const
The source layer from which features will be fetched.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Used to retrieve the identifierValue (primary key) of a feature.
void setDisplayExpression(const QString &displayExpression)
The display expression will be used for.
Represents a vector layer which manages a vector based data sets.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
void extraValueDoesNotExistChanged()
Flag indicating that the extraIdentifierValue does not exist in the data.
QString rule() const
The condition rule set for the style.
~QgsFeatureFilterModel() override
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Set flags that affect how features will be fetched.
void displayExpressionChanged()
The display expression will be used for.