24 : QAbstractItemModel( parent )
26 mReloadTimer.setInterval( 100 );
27 mReloadTimer.setSingleShot(
true );
28 connect( &mReloadTimer, &QTimer::timeout,
this, &QgsFeatureFilterModel::scheduledReload );
29 setExtraIdentifierValueUnguarded( QVariant() );
35 connect( mGatherer, &QgsFieldExpressionValuesGatherer::finished, mGatherer, &QgsFieldExpressionValuesGatherer::deleteLater );
45 if ( mSourceLayer == sourceLayer )
76 if ( mFilterValue == filterValue )
86 return mFilterExpression;
91 if ( mFilterExpression == filterExpression )
107 return createIndex( row, column,
nullptr );
113 return QModelIndex();
120 return mEntries.size();
131 if ( !index.isValid() )
136 case Qt::DisplayRole:
139 return mEntries.value( index.row() ).value;
142 return mEntries.value( index.row() ).identifierValue;
144 case Qt::BackgroundColorRole:
145 case Qt::TextColorRole:
146 case Qt::DecorationRole:
149 if ( mEntries.value( index.row() ).identifierValue.isNull() )
152 if ( role == Qt::TextColorRole )
154 return QBrush( QColor( Qt::gray ) );
156 else if ( role == Qt::FontRole )
158 QFont font = QFont();
159 if ( index.row() == mExtraIdentifierValueIndex )
160 font.setBold(
true );
162 if ( mEntries.value( index.row() ).identifierValue.isNull() )
164 font.setItalic(
true );
180 if ( role == Qt::DecorationRole )
182 if ( role == Qt::FontRole )
193 void QgsFeatureFilterModel::updateCompleter()
196 QVector<Entry> entries = mGatherer->entries();
198 if ( mExtraIdentifierValueIndex == -1 )
199 setExtraIdentifierValueUnguarded( QVariant() );
202 if ( mGatherer->data().toBool() )
204 if ( !entries.isEmpty() )
206 mEntries.replace( mExtraIdentifierValueIndex, entries.at( 0 ) );
207 emit dataChanged(
index( mExtraIdentifierValueIndex, 0, QModelIndex() ),
index( mExtraIdentifierValueIndex, 0, QModelIndex() ) );
208 mShouldReloadCurrentFeature =
false;
209 setExtraValueDoesNotExist(
false );
213 setExtraValueDoesNotExist(
true );
216 mShouldReloadCurrentFeature =
false;
218 if ( mFilterValue.isEmpty() )
224 std::sort( entries.begin(), entries.end(), [](
const Entry & a,
const Entry & b ) {
return a.value.localeAwareCompare( b.value ) < 0; } );
229 const int newEntriesSize = entries.size();
232 int currentEntryInNewList = -1;
233 if ( mExtraIdentifierValueIndex != -1 )
235 for (
int i = 0; i < newEntriesSize; ++i )
237 if ( entries.at( i ).identifierValue == mExtraIdentifierValue )
239 currentEntryInNewList = i;
240 mEntries.replace( mExtraIdentifierValueIndex, entries.at( i ) );
241 emit dataChanged(
index( mExtraIdentifierValueIndex, 0, QModelIndex() ),
index( mExtraIdentifierValueIndex, 0, QModelIndex() ) );
242 setExtraValueDoesNotExist(
false );
249 Q_ASSERT_X(
false,
"QgsFeatureFilterModel::updateCompleter",
"No extra identifier value generated. Should not get here." );
255 if ( mExtraIdentifierValueIndex != -1 )
257 if ( mExtraIdentifierValueIndex != 0 )
259 beginMoveRows( QModelIndex(), mExtraIdentifierValueIndex, mExtraIdentifierValueIndex, QModelIndex(), 0 );
260 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0) 261 Entry extraEntry = mEntries.takeAt( mExtraIdentifierValueIndex );
262 mEntries.prepend( extraEntry );
264 mEntries.move( mExtraIdentifierValueIndex, 0 );
272 beginRemoveRows( QModelIndex(), firstRow, mEntries.size() - firstRow );
273 mEntries.remove( firstRow, mEntries.size() - firstRow );
276 if ( currentEntryInNewList == -1 )
278 beginInsertRows( QModelIndex(), 1, entries.size() + 1 );
281 setExtraIdentifierValueIndex( 0 );
285 if ( currentEntryInNewList != 0 )
287 beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 );
288 mEntries = entries.mid( 0, currentEntryInNewList ) + mEntries;
293 mEntries.replace( 0, entries.at( 0 ) );
296 emit dataChanged(
index( currentEntryInNewList, 0, QModelIndex() ),
index( currentEntryInNewList, 0, QModelIndex() ) );
298 beginInsertRows( QModelIndex(), currentEntryInNewList + 1, newEntriesSize - currentEntryInNewList - 1 );
299 mEntries += entries.mid( currentEntryInNewList + 1 );
301 setExtraIdentifierValueIndex( currentEntryInNewList );
309 void QgsFeatureFilterModel::gathererThreadFinished()
316 void QgsFeatureFilterModel::scheduledReload()
321 bool wasLoading =
false;
327 disconnect( mGatherer, &QgsFieldExpressionValuesGatherer::collectedValues,
this, &QgsFeatureFilterModel::updateCompleter );
328 disconnect( mGatherer, &QgsFieldExpressionValuesGatherer::finished,
this, &QgsFeatureFilterModel::gathererThreadFinished );
329 connect( mGatherer, &QgsFieldExpressionValuesGatherer::finished, mGatherer, &QgsFieldExpressionValuesGatherer::deleteLater );
336 if ( mShouldReloadCurrentFeature )
342 QString filterClause;
344 if ( mFilterValue.isEmpty() && !mFilterExpression.isEmpty() )
345 filterClause = mFilterExpression;
346 else if ( mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
347 filterClause = QStringLiteral(
"(%1) ILIKE '%%2%'" ).arg( mDisplayExpression, mFilterValue );
348 else if ( !mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
349 filterClause = QStringLiteral(
"(%1) AND ((%2) ILIKE '%%3%')" ).arg( mFilterExpression, mDisplayExpression, mFilterValue );
351 if ( !filterClause.isEmpty() )
354 QSet<QString> attributes;
357 attributes << mIdentifierField;
364 mGatherer->setData( mShouldReloadCurrentFeature );
366 connect( mGatherer, &QgsFieldExpressionValuesGatherer::collectedValues,
this, &QgsFeatureFilterModel::updateCompleter );
367 connect( mGatherer, &QgsFieldExpressionValuesGatherer::finished,
this, &QgsFeatureFilterModel::gathererThreadFinished );
374 QSet<QString> QgsFeatureFilterModel::requestedAttributes()
const 376 QSet<QString> requestedAttrs;
386 if ( mDisplayExpression.
isField() )
396 return requestedAttrs;
399 void QgsFeatureFilterModel::setExtraIdentifierValueIndex(
int index,
bool force )
401 if ( mExtraIdentifierValueIndex ==
index && !force )
404 mExtraIdentifierValueIndex =
index;
408 void QgsFeatureFilterModel::reloadCurrentFeature()
410 mShouldReloadCurrentFeature =
true;
411 mReloadTimer.start();
414 void QgsFeatureFilterModel::setExtraIdentifierValueUnguarded(
const QVariant &
extraIdentifierValue )
416 const QVector<Entry> entries = mEntries;
419 for (
const Entry &entry : entries )
421 if ( entry.identifierValue == extraIdentifierValue
422 && entry.identifierValue.isNull() == extraIdentifierValue.isNull()
423 && entry.identifierValue.isValid() == extraIdentifierValue.isValid() )
425 setExtraIdentifierValueIndex( index );
433 if ( mExtraIdentifierValueIndex != index )
435 beginInsertRows( QModelIndex(), 0, 0 );
436 if ( extraIdentifierValue.isNull() )
439 mEntries.prepend( Entry( extraIdentifierValue, QStringLiteral(
"(%1)" ).arg( extraIdentifierValue.toString() ),
QgsFeature() ) );
442 setExtraIdentifierValueIndex( 0,
true );
444 reloadCurrentFeature();
466 styles += matchingFieldStyles;
471 mEntryStylesMap.insert( fid, style );
483 if ( mAllowNull == allowNull )
494 return mExtraValueDoesNotExist;
499 if ( mExtraValueDoesNotExist == extraValueDoesNotExist )
508 return mExtraIdentifierValueIndex;
513 return mIdentifierField;
518 if ( mIdentifierField == identifierField )
525 void QgsFeatureFilterModel::reload()
527 mReloadTimer.start();
532 return mExtraIdentifierValue;
537 if (
qgsVariantEqual( extraIdentifierValue, mExtraIdentifierValue ) && mExtraIdentifierValue.isValid() )
540 if ( mIsSettingExtraIdentifierValue )
543 mIsSettingExtraIdentifierValue =
true;
547 setExtraIdentifierValueUnguarded( extraIdentifierValue );
549 mIsSettingExtraIdentifierValue =
false;
Class for parsing and evaluation of expressions (formerly called "search strings").
void filterValueChanged()
This value will be used to filter the features available from this model.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
bool validTextColor() const
Check if the text color is valid for render.
void beginUpdate()
Notification that the model is about to be changed because a job was completed.
int extraIdentifierValueIndex() const
The index at which the extra identifier value is available within the model.
This class is a composition of two QSettings instances:
QColor textColor() const
The text color set for style.
bool validBackgroundColor() const
Check if the background color is valid for render.
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.
QgsVectorLayer * sourceLayer() const
The source layer from which features will be fetched.
QFont font() const
The font for the style.
void setFilterExpression(const QString &filterExpression)
An additional filter expression to apply, next to the filterValue.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName)
Returns the conditional styles set for the field UI properties.
QString filterExpression() const
An additional filter expression to apply, next to the filterValue.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsConditionalLayerStyles * conditionalStyles() const
Returns the conditional styles that are set for this layer.
void filterJobCompleted()
Indicates that a filter job has been completed and new data may be available.
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...
bool allowNull() const
Add a NULL entry to the list.
friend class QgsFieldExpressionValuesGatherer
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...
QPixmap icon() const
The icon set for style generated from the set symbol.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Conditional styling for a rule.
QString displayExpression() const
The display expression will be used for.
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)...
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
QColor backgroundColor() const
The background color for style.
bool isField() const
Checks whether an expression consists only of a single field reference.
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.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QVariant extraIdentifierValue() const
Allows specifying one value that does not need to match the filter criteria but will still be availab...
void filterExpressionChanged()
An additional filter expression to apply, next to the filterValue.
void endUpdate()
Notification that the model change is finished.
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.
void sourceLayerChanged()
The source layer from which features will be fetched.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
QString filterValue() const
This value will be used to filter the features available from this model.
bool isLoading() const
Indicator if the model is currently performing any feature iteration in the background.
void setExtraIdentifierValue(const QVariant &extraIdentifierValue)
Allows specifying one value that does not need to match the filter criteria but will still be availab...
QString identifierField() const
The identifier field should be a unique field that can be used to identify individual features...
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
QVariant data(const QModelIndex &index, int role) const override
QString expression() const
Returns the original, unmodified expression string.
void setAllowNull(bool allowNull)
Add a NULL entry to the list.
QString rule() const
The condition rule set for the style.
bool isValid() const
isValid Check if this rule is valid.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required...
bool qgsVariantEqual(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether they are equal, NULL values are treated as equal...
Geometry is not required. It may still be returned if e.g. required for a filter condition.
bool extraValueDoesNotExist() const
Flag indicating that the extraIdentifierValue does not exist in the data.
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.
void extraValueDoesNotExistChanged()
Flag indicating that the extraIdentifierValue does not exist in the data.
~QgsFeatureFilterModel() override
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
void displayExpressionChanged()
The display expression will be used for.
QgsExpression * filterExpression() const
Returns the filter expression if set.