26 if ( a.size() != b.size() )
29 for (
int i = 0; i < a.size(); ++i )
38 : QAbstractItemModel( parent )
40 mReloadTimer.setInterval( 100 );
41 mReloadTimer.setSingleShot(
true );
42 connect( &mReloadTimer, &QTimer::timeout,
this, &QgsFeatureFilterModel::scheduledReload );
43 setExtraIdentifierValuesUnguarded( QVariantList() );
49 connect( mGatherer, &QgsFieldExpressionValuesGatherer::finished, mGatherer, &QgsFieldExpressionValuesGatherer::deleteLater );
59 if ( mSourceLayer == sourceLayer )
90 if ( mFilterValue == filterValue )
100 return mFilterExpression;
105 if ( mFilterExpression == filterExpression )
120 return mIdentifierFields.value( 0 );
126 return createIndex( row, column,
nullptr );
132 return QModelIndex();
139 return mEntries.size();
150 if ( !index.isValid() )
155 case Qt::DisplayRole:
158 return mEntries.value( index.row() ).value;
162 const QVariantList values = mEntries.value( index.row() ).identifierValues;
163 return values.value( 0 );
167 return mEntries.value( index.row() ).identifierValues;
169 case Qt::BackgroundColorRole:
170 case Qt::TextColorRole:
171 case Qt::DecorationRole:
175 const QVariantList values = mEntries.value( index.row() ).identifierValues;
176 for (
const QVariant &value : values )
178 if ( !value.isNull() )
187 if ( role == Qt::TextColorRole )
189 return QBrush( QColor( Qt::gray ) );
191 if ( role == Qt::FontRole )
193 QFont font = QFont();
194 if ( index.row() == mExtraIdentifierValueIndex )
195 font.setBold(
true );
197 font.setItalic(
true );
212 if ( role == Qt::DecorationRole )
214 if ( role == Qt::FontRole )
225 void QgsFeatureFilterModel::updateCompleter()
228 QVector<Entry> entries = mGatherer->entries();
230 if ( mExtraIdentifierValueIndex == -1 )
232 setExtraIdentifierValuesUnguarded( QVariantList() );
236 if ( mGatherer->data().toBool() )
238 if ( !entries.isEmpty() )
240 mEntries.replace( mExtraIdentifierValueIndex, entries.at( 0 ) );
241 emit dataChanged(
index( mExtraIdentifierValueIndex, 0, QModelIndex() ),
index( mExtraIdentifierValueIndex, 0, QModelIndex() ) );
242 mShouldReloadCurrentFeature =
false;
243 setExtraValueDoesNotExist(
false );
247 setExtraValueDoesNotExist(
true );
250 mShouldReloadCurrentFeature =
false;
252 if ( mFilterValue.isEmpty() )
258 std::sort( entries.begin(), entries.end(), [](
const Entry & a,
const Entry & b ) {
return a.value.localeAwareCompare( b.value ) < 0; } );
262 entries.prepend( nullEntry() );
265 const int newEntriesSize = entries.size();
268 int currentEntryInNewList = -1;
269 if ( mExtraIdentifierValueIndex != -1 )
271 for (
int i = 0; i < newEntriesSize; ++i )
275 currentEntryInNewList = i;
276 mEntries.replace( mExtraIdentifierValueIndex, entries.at( i ) );
277 emit dataChanged(
index( mExtraIdentifierValueIndex, 0, QModelIndex() ),
index( mExtraIdentifierValueIndex, 0, QModelIndex() ) );
278 setExtraValueDoesNotExist(
false );
285 Q_ASSERT_X(
false,
"QgsFeatureFilterModel::updateCompleter",
"No extra identifier value generated. Should not get here." );
291 if ( mExtraIdentifierValueIndex != -1 )
293 if ( mExtraIdentifierValueIndex != 0 )
295 beginMoveRows( QModelIndex(), mExtraIdentifierValueIndex, mExtraIdentifierValueIndex, QModelIndex(), 0 );
296 mEntries.move( mExtraIdentifierValueIndex, 0 );
303 beginRemoveRows( QModelIndex(), firstRow, mEntries.size() - firstRow );
304 mEntries.remove( firstRow, mEntries.size() - firstRow );
307 if ( currentEntryInNewList == -1 )
309 beginInsertRows( QModelIndex(), 1, entries.size() + 1 );
312 setExtraIdentifierValuesIndex( 0 );
316 if ( currentEntryInNewList != 0 )
318 beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 );
319 mEntries = entries.mid( 0, currentEntryInNewList ) + mEntries;
324 mEntries.replace( 0, entries.at( 0 ) );
327 emit dataChanged(
index( currentEntryInNewList, 0, QModelIndex() ),
index( currentEntryInNewList, 0, QModelIndex() ) );
329 beginInsertRows( QModelIndex(), currentEntryInNewList + 1, newEntriesSize - currentEntryInNewList - 1 );
330 mEntries += entries.mid( currentEntryInNewList + 1 );
332 setExtraIdentifierValuesIndex( currentEntryInNewList );
340 void QgsFeatureFilterModel::gathererThreadFinished()
347 void QgsFeatureFilterModel::scheduledReload()
352 bool wasLoading =
false;
358 disconnect( mGatherer, &QgsFieldExpressionValuesGatherer::collectedValues,
this, &QgsFeatureFilterModel::updateCompleter );
359 disconnect( mGatherer, &QgsFieldExpressionValuesGatherer::finished,
this, &QgsFeatureFilterModel::gathererThreadFinished );
360 connect( mGatherer, &QgsFieldExpressionValuesGatherer::finished, mGatherer, &QgsFieldExpressionValuesGatherer::deleteLater );
367 if ( mShouldReloadCurrentFeature )
369 QStringList conditions;
370 for (
int i = 0; i < mIdentifierFields.count(); i++ )
372 if ( i >= mExtraIdentifierValues.count() )
385 QString filterClause;
387 if ( mFilterValue.isEmpty() && !mFilterExpression.isEmpty() )
388 filterClause = mFilterExpression;
389 else if ( mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
390 filterClause = QStringLiteral(
"(%1) ILIKE '%%2%'" ).arg( mDisplayExpression, mFilterValue );
391 else if ( !mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
392 filterClause = QStringLiteral(
"(%1) AND ((%2) ILIKE '%%3%')" ).arg( mFilterExpression, mDisplayExpression, mFilterValue );
394 if ( !filterClause.isEmpty() )
397 QSet<QString> attributes;
400 for (
const QString &fieldName : qgis::as_const( mIdentifierFields ) )
401 attributes << fieldName;
408 mGatherer->setData( mShouldReloadCurrentFeature );
410 connect( mGatherer, &QgsFieldExpressionValuesGatherer::collectedValues,
this, &QgsFeatureFilterModel::updateCompleter );
411 connect( mGatherer, &QgsFieldExpressionValuesGatherer::finished,
this, &QgsFeatureFilterModel::gathererThreadFinished );
418 QSet<QString> QgsFeatureFilterModel::requestedAttributes()
const 420 QSet<QString> requestedAttrs;
430 if ( mDisplayExpression.
isField() )
441 return requestedAttrs;
444 void QgsFeatureFilterModel::setExtraIdentifierValuesIndex(
int index,
bool force )
446 if ( mExtraIdentifierValueIndex ==
index && !force )
449 mExtraIdentifierValueIndex =
index;
453 void QgsFeatureFilterModel::reloadCurrentFeature()
455 mShouldReloadCurrentFeature =
true;
456 mReloadTimer.start();
459 void QgsFeatureFilterModel::setExtraIdentifierValuesUnguarded(
const QVariantList &
extraIdentifierValues )
461 const QVector<Entry> entries = mEntries;
464 for (
const Entry &entry : entries )
466 if ( entry.identifierValues == extraIdentifierValues )
468 setExtraIdentifierValuesIndex( index );
476 if ( mExtraIdentifierValueIndex != index )
478 beginInsertRows( QModelIndex(), 0, 0 );
479 if ( extraIdentifierValues.isEmpty() )
481 mEntries.prepend( nullEntry() );
486 for (
const QVariant &v : qgis::as_const( extraIdentifierValues ) )
487 values << QStringLiteral(
"(%1)" ).arg( v.toString() );
489 mEntries.prepend( Entry( extraIdentifierValues, values.join( QStringLiteral(
" " ) ),
QgsFeature() ) );
493 setExtraIdentifierValuesIndex( 0,
true );
495 reloadCurrentFeature();
499 QgsFeatureFilterModel::Entry QgsFeatureFilterModel::nullEntry()
522 styles += matchingFieldStyles;
527 mEntryStylesMap.insert( fid, style );
539 if ( mAllowNull == allowNull )
550 return mExtraValueDoesNotExist;
555 if ( mExtraValueDoesNotExist == extraValueDoesNotExist )
564 return mExtraIdentifierValueIndex;
569 return mIdentifierFields;
579 if ( mIdentifierFields == identifierFields )
587 void QgsFeatureFilterModel::reload()
589 mReloadTimer.start();
594 if ( mExtraIdentifierValues.isEmpty() )
597 return mExtraIdentifierValues.at( 0 );
602 if ( mExtraIdentifierValues.count() != mIdentifierFields.count() )
604 QVariantList nullValues;
605 for (
int i = 0; i < mIdentifierFields.count(); i++ )
606 nullValues << QVariant();
609 return mExtraIdentifierValues;
614 if ( extraIdentifierValue.isNull() )
622 if ( extraIdentifierValues == mExtraIdentifierValues && !mExtraIdentifierValues.isEmpty() )
625 if ( mIsSettingExtraIdentifierValue )
628 mIsSettingExtraIdentifierValue =
true;
632 setExtraIdentifierValuesUnguarded( extraIdentifierValues );
634 mIsSettingExtraIdentifierValue =
false;
641 mExtraIdentifierValues = QVariantList();
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.
void setExtraIdentifierValues(const QVariantList &extraIdentifierValues)
Allows specifying one value that does not need to match the filter criteria but will still be availab...
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.
QStringList identifierFields() const
The identifier field should be a unique field that can be used to identify individual features...
This class is a composition of two QSettings instances:
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.
QVariantList extraIdentifierValues() const
Allows specifying one value that does not need to match the filter criteria but will still be availab...
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
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.
void setExtraIdentifierValuesToNull()
Allows specifying one value that does not need to match the filter criteria but will still be availab...
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.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
friend class QgsFieldExpressionValuesGatherer
QgsConditionalLayerStyles * conditionalStyles() const
Returns 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.
Q_DECL_DEPRECATED QVariant extraIdentifierValue() const
Allows specifying one value that does not need to match the filter criteria but will still be availab...
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...
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.
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 QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
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...
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value)
Create an expression allowing to evaluate if a field is equal to a value.
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.
bool qVariantListCompare(const QVariantList &a, const QVariantList &b)
void filterExpressionChanged()
An additional filter expression to apply, next to the filterValue.
void endUpdate()
Notification that the model change is finished.
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName) const
Returns the conditional styles set for the field with matching fieldName.
QString expression() const
Returns the original, unmodified expression string.
int columnCount(const QModelIndex &parent) const override
Q_DECL_DEPRECATED QString identifierField() const
The identifier field should be a unique field that can be used to identify individual features...
void extraIdentifierValueChanged()
Allows specifying one value that does not need to match the filter criteria but will still be availab...
Q_DECL_DEPRECATED 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.
bool isField() const
Checks whether an expression consists only of a single field reference.
Q_DECL_DEPRECATED void setExtraIdentifierValue(const QVariant &extraIdentifierValue)
Allows specifying one value that does not need to match the filter criteria but will still be availab...
void setIdentifierFields(const QStringList &identifierFields)
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
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.
bool qgsVariantEqual(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether they are equal, two NULL values are always treated a...
Geometry is not required. It may still be returned if e.g. required for a filter condition.
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.
Used to retrieve the identifierValues (primary keys) of a feature.
~QgsFeatureFilterModel() override
QgsConditionalStyles rowStyles() const
Returns a list of row styles associated with the layer.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
void displayExpressionChanged()
The display expression will be used for.