QGIS API Documentation 3.43.0-Master (32433f7016e)
qgsfeaturelistcombobox.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsfeaturelistcombobox.cpp - QgsFeatureListComboBox
3 ---------------------
4 begin : 10.3.2017
5 copyright : (C) 2017 by Matthias Kuhn
6 email : matthias@opengis.ch
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 ***************************************************************************/
16
18#include "qgsanimatedicon.h"
19#include "qgsfilterlineedit.h"
20#include "qgslogger.h"
21#include "qgsapplication.h"
22#include "moc_qgsfeaturelistcombobox.cpp"
23
24#include <QCompleter>
25#include <QLineEdit>
26#include <QKeyEvent>
27
29 : QComboBox( parent )
30 , mModel( new QgsFeatureFilterModel( this ) )
31 , mCompleter( new QCompleter( mModel ) )
32{
33 setMinimumContentsLength( 1 );
34 setSizeAdjustPolicy( QComboBox::SizeAdjustPolicy::AdjustToMinimumContentsLengthWithIcon );
35 mCompleter->setCaseSensitivity( Qt::CaseInsensitive );
36 mCompleter->setFilterMode( Qt::MatchContains );
37 setEditable( true );
38 setCompleter( mCompleter );
39 mCompleter->setWidget( this );
45 connect( mModel, &QgsFeatureFilterModel::isLoadingChanged, this, &QgsFeatureListComboBox::onLoadingChanged );
46 connect( mModel, &QgsFeatureFilterModel::filterJobCompleted, this, &QgsFeatureListComboBox::onFilterUpdateCompleted );
49 connect( mModel, &QgsFeatureFilterModel::extraIdentifierValueIndexChanged, this, &QgsFeatureListComboBox::setCurrentIndex );
51 connect( mCompleter, static_cast<void ( QCompleter::* )( const QModelIndex & )>( &QCompleter::highlighted ), this, &QgsFeatureListComboBox::onItemSelected );
52 connect( mCompleter, static_cast<void ( QCompleter::* )( const QModelIndex & )>( &QCompleter::activated ), this, &QgsFeatureListComboBox::onActivated );
53 connect( mModel, &QgsFeatureFilterModel::beginUpdate, this, &QgsFeatureListComboBox::storeLineEditState );
54 connect( mModel, &QgsFeatureFilterModel::endUpdate, this, &QgsFeatureListComboBox::restoreLineEditState );
56 connect( mModel, &QgsFeatureFilterModel::dataChanged, this, &QgsFeatureListComboBox::onDataChanged );
57
58 connect( this, static_cast<void ( QgsFeatureListComboBox::* )( int )>( &QgsFeatureListComboBox::currentIndexChanged ), this, &QgsFeatureListComboBox::onCurrentIndexChanged );
59
60 mLineEdit = new QgsFilterLineEdit( nullptr, QgsApplication::nullRepresentation() );
61 mLineEdit->setSelectOnFocus( true );
62 mLineEdit->setShowClearButton( true );
63
64 setLineEdit( mLineEdit );
65 setModel( mModel );
66
67 connect( mLineEdit, &QgsFilterLineEdit::textEdited, this, &QgsFeatureListComboBox::onCurrentTextChanged );
68 connect( mLineEdit, &QgsFilterLineEdit::cleared, this, &QgsFeatureListComboBox::onFilterLineEditCleared );
69
71 // To avoid wrongly signaling a foreign key change, handle model feature found state following feature gathering separately
73
74 setToolTip( tr( "Just start typing what you are looking for." ) );
75}
76
81
86
88{
89 QVariantList values;
90 const QStringList fields = mModel->identifierFields();
91 for ( const QString &field : fields )
92 {
93 values << feature.attribute( field );
94 }
95 setIdentifierValues( values );
96}
97
99{
100 return mModel->displayExpression();
101}
102
103void QgsFeatureListComboBox::setDisplayExpression( const QString &expression )
104{
105 mModel->setDisplayExpression( expression );
106}
107
108void QgsFeatureListComboBox::onCurrentTextChanged( const QString &text )
109{
110 mIsCurrentlyEdited = true;
111 mPopupRequested = true;
112 mModel->setFilterValue( text );
113}
114
115void QgsFeatureListComboBox::onFilterLineEditCleared()
116{
117 // Reset the combobox when the search is cleared
118 const QString clearedValue = allowNull() ? mLineEdit->nullValue() : mLineEdit->defaultValue();
119 mModel->setFilterValue( clearedValue );
120}
121
122void QgsFeatureListComboBox::onFilterUpdateCompleted()
123{
124 if ( mPopupRequested )
125 mCompleter->complete();
126
127 mPopupRequested = false;
128}
129
130void QgsFeatureListComboBox::onLoadingChanged()
131{
132 mLineEdit->setShowSpinner( mModel->isLoading() );
133}
134
135void QgsFeatureListComboBox::onItemSelected( const QModelIndex &index )
136{
137 setCurrentIndex( index.row() );
138}
139
140void QgsFeatureListComboBox::onCurrentIndexChanged( int i )
141{
142 if ( !mLineEdit->hasStateStored() )
143 mIsCurrentlyEdited = false;
144 const QModelIndex modelIndex = mModel->index( i, 0, QModelIndex() );
145 mModel->setExtraIdentifierValues( mModel->data( modelIndex, static_cast<int>( QgsFeatureFilterModel::CustomRole::IdentifierValues ) ).toList() );
146 mLineEdit->setText( mModel->data( modelIndex, static_cast<int>( QgsFeatureFilterModel::CustomRole::Value ) ).toString() );
147 mLineEdit->setFont( mModel->data( modelIndex, Qt::FontRole ).value<QFont>() );
148 QPalette palette = mLineEdit->palette();
149 palette.setBrush( mLineEdit->foregroundRole(), mModel->data( modelIndex, Qt::ForegroundRole ).value<QBrush>() );
150 mLineEdit->setPalette( palette );
151}
152
153void QgsFeatureListComboBox::onActivated( QModelIndex modelIndex )
154{
155 setIdentifierValues( mModel->data( modelIndex, static_cast<int>( QgsFeatureFilterModel::CustomRole::IdentifierValues ) ).toList() );
156 mLineEdit->setText( mModel->data( modelIndex, static_cast<int>( QgsFeatureFilterModel::CustomRole::Value ) ).toString() );
157}
158
159void QgsFeatureListComboBox::storeLineEditState()
160{
161 if ( mIsCurrentlyEdited )
162 {
163 mLineEdit->storeState();
164 }
165}
166
167void QgsFeatureListComboBox::restoreLineEditState()
168{
169 if ( mIsCurrentlyEdited )
170 {
171 mLineEdit->restoreState();
172 }
173}
174
176{
177 int index = -1;
178
179 if ( allowNull() )
180 {
181 index = findText( QgsApplication::nullRepresentation() );
182 }
183
184 return index;
185}
186
187void QgsFeatureListComboBox::onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles )
188{
189 Q_UNUSED( roles )
190 if ( !mIsCurrentlyEdited )
191 {
192 const int currentIndex = mModel->extraIdentifierValueIndex();
193 if ( currentIndex >= topLeft.row() && currentIndex <= bottomRight.row() )
194 {
195 const QModelIndex modelIndex = mModel->index( currentIndex, 0, QModelIndex() );
196 mLineEdit->setText( mModel->data( modelIndex, static_cast<int>( QgsFeatureFilterModel::CustomRole::Value ) ).toString() );
197 }
198 }
199}
200
202{
203 const QStringList list = mModel->identifierFields();
204 if ( list.isEmpty() )
205 return QString();
206 else
207 return list.at( 0 );
208}
209
211{
212 return mModel->identifierFields();
213}
214
215void QgsFeatureListComboBox::setIdentifierField( const QString &identifierField )
216{
217 mModel->setIdentifierFields( QStringList() << identifierField );
218}
219
220void QgsFeatureListComboBox::setIdentifierFields( const QStringList &identifierFields )
221{
223}
224
226{
227 return mModel->index( currentIndex(), 0, QModelIndex() );
228}
229
231{
232 Q_UNUSED( event )
233 QComboBox::focusOutEvent( event );
234 mLineEdit->setText( mModel->data( currentModelIndex(), static_cast<int>( QgsFeatureFilterModel::CustomRole::Value ) ).toString() );
235}
236
238{
239 if ( event->key() == Qt::Key_Escape )
240 {
241 mLineEdit->setText( mModel->data( currentModelIndex(), static_cast<int>( QgsFeatureFilterModel::CustomRole::Value ) ).toString() );
242 }
243 QComboBox::keyReleaseEvent( event );
244}
245
247{
248 return mModel->allowNull();
249}
250
256
258{
259 return mModel->fetchLimit();
260}
261
263{
264 mModel->setFetchLimit( fetchLimit );
265}
266
273
275{
276 return mModel->extraIdentifierValues();
277}
278
279void QgsFeatureListComboBox::setIdentifierValue( const QVariant &identifierValue )
280{
281 setIdentifierValues( QVariantList() << identifierValue );
282}
283
284void QgsFeatureListComboBox::setIdentifierValues( const QVariantList &identifierValues )
285{
287}
288
293
295{
296 QgsFeatureRequest request;
297 request.setRequestMayBeNested( true );
298 if ( mModel->extraIdentifierValues().isEmpty() )
299 {
300 request.setFilterFids( QgsFeatureIds() ); // NULL: Return a request that's guaranteed to not return anything
301 }
302 else
303 {
304 QStringList filtersAttrs;
305 const QStringList identifierFields = mModel->identifierFields();
306 const QVariantList values = mModel->extraIdentifierValues();
307 for ( int i = 0; i < identifierFields.count(); i++ )
308 {
309 if ( i >= values.count() )
310 {
311 filtersAttrs << QgsExpression::createFieldEqualityExpression( identifierFields.at( i ), QVariant() );
312 }
313 else
314 {
315 filtersAttrs << QgsExpression::createFieldEqualityExpression( identifierFields.at( i ), values.at( i ) );
316 }
317 }
318 const QString expression = filtersAttrs.join( QLatin1String( " AND " ) );
319 return request.setFilterExpression( expression );
320 }
321 return request;
322}
323
325{
326 return mModel->filterExpression();
327}
328
329void QgsFeatureListComboBox::setFilterExpression( const QString &filterExpression )
330{
332}
333
335{
336 return mModel->formFeature();
337}
338
340{
341 mModel->setFormFeature( feature );
342}
343
348
350{
351 mModel->setParentFormFeature( feature );
352}
static QString nullRepresentation()
Returns the string used to represent the value NULL throughout QGIS.
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QMetaType::Type fieldType=QMetaType::Type::UnknownType)
Create an expression allowing to evaluate if a field is equal to a value.
Provides a list of features based on filter conditions.
void setExtraIdentifierValues(const QVariantList &extraIdentifierValues)
Allows specifying one value that does not need to match the filter criteria but will still be availab...
void setExtraIdentifierValueToNull() override
Allows specifying one value that does not need to match the filter criteria but will still be availab...
QStringList identifierFields
A set of fields of sourceLayer that is unique and should be used to identify features.
QVariantList extraIdentifierValues
The values that identifies the current feature.
void identifierFieldsChanged()
The identifier field should be a unique field that can be used to identify individual features.
void setIdentifierFields(const QStringList &identifierFields)
The identifier field should be a unique field that can be used to identify individual features.
This offers a combobox with autocompleter that allows selecting features from a layer.
void setIdentifierValues(const QVariantList &identifierValues)
The identifier values of the currently selected feature.
void keyPressEvent(QKeyEvent *event) override
Q_DECL_DEPRECATED void setIdentifierField(const QString &identifierField)
Field name that will be used to uniquely identify the current feature.
void setDisplayExpression(const QString &displayExpression)
The display expression will be used to display features as well as the value to match the typed text ...
QModelIndex currentModelIndex() const
The index of the currently selected item.
void setFilterExpression(const QString &filterExpression)
An additional expression to further restrict the available features.
void setIdentifierFields(const QStringList &identifierFields)
Field name that will be used to uniquely identify the current feature.
void allowNullChanged()
Determines if a NULL value should be available in the list.
QgsFeature parentFormFeature() const
Returns a parent attribute form feature to be used with the filter expression.
QgsFeatureListComboBox(QWidget *parent=nullptr)
Create a new QgsFeatureListComboBox, optionally specifying a parent.
void focusOutEvent(QFocusEvent *event) override
void setSourceLayer(QgsVectorLayer *sourceLayer)
The layer from which features should be listed.
void setParentFormFeature(const QgsFeature &feature)
Sets a parent attribute form feature to be used with the filter expression.
void modelUpdated()
The underlying model has been updated.
QgsFeature formFeature() const
Returns an attribute form feature to be used with the filter expression.
QgsFeatureRequest currentFeatureRequest() const
Shorthand for getting a feature request to query the currently selected feature.
void setIdentifierValuesToNull()
Sets the identifier values of the currently selected feature to NULL value(s).
void formFeatureChanged()
An attribute form feature to be used alongside the filter expression.
void identifierValueChanged()
The identifier value of the currently selected feature.
void sourceLayerChanged()
The layer from which features should be listed.
void setFormFeature(const QgsFeature &feature)
Sets an attribute form feature to be used with the filter expression.
void setCurrentFeature(const QgsFeature &feature)
Sets the current index by using the given feature.
int nullIndex() const
Returns the current index of the NULL value, or -1 if NULL values are not allowed.
void currentFeatureFoundChanged(bool found)
Emitted when the feature picker model changes its feature found state.
int fetchLimit() const
Returns the feature request fetch limit.
Q_DECL_DEPRECATED void setIdentifierValue(const QVariant &identifierValue)
The identifier value of the currently selected feature.
void currentFeatureChanged()
Emitted when the current feature changes.
QStringList identifierFields() const
Field name that will be used to uniquely identify the current feature.
void parentFormFeatureChanged()
A parent attribute form feature to be used alongside the filter expression.
void setAllowNull(bool allowNull)
Determines if a NULL value should be available in the list.
void displayExpressionChanged()
The display expression will be used to display features as well as the the value to match the typed t...
void identifierFieldChanged()
Field name that will be used to uniquely identify the current feature.
void setFetchLimit(int fetchLimit)
Defines the feature request fetch limit If set to 0, no limit is applied when fetching.
void filterExpressionChanged()
An additional expression to further restrict the available features.
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.
void setFilterValue(const QString &filterValue)
This value will be used to filter the features available from this model.
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.
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.
void extraIdentifierValueChanged()
Allows specifying one value that does not need to match the filter criteria but will still be availab...
@ IdentifierValues
Used to retrieve the identifierValues (primary keys) of a feature.
@ Value
Used to retrieve the displayExpression of a feature.
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.
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.
QVariant data(const QModelIndex &index, int role) const override
QModelIndex index(int row, int column, const QModelIndex &parent) const override
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.
void currentFeatureChanged()
Emitted when the current feature in the model has changed This emitted both when the extra value chan...
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.
void endUpdate()
Notification that the model change is finished.
void displayExpressionChanged()
The display expression will be used for.
void setSourceLayer(QgsVectorLayer *sourceLayer)
The source layer from which features will be fetched.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setRequestMayBeNested(bool requestMayBeNested)
In case this request may be run nested within another already running iteration on the same connectio...
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
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:58
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
void restoreState()
Restores the current state of the line edit (selection and cursor position)
void storeState()
Stores the current state of the line edit (selection and cursor position)
@ ClearToNull
Reset value to null.
@ ClearToDefault
Reset value to default value (see defaultValue() )
void setShowClearButton(bool visible)
Sets whether the widget's clear button is visible.
bool hasStateStored() const
Returns if a state is already saved.
void setSelectOnFocus(bool selectOnFocus)
Will select all text when this widget receives the focus.
void cleared()
Emitted when the widget is cleared.
void setShowSpinner(bool showSpinner)
Show a spinner icon.
void setClearMode(ClearMode mode)
Sets the clear mode for the widget.
Represents a vector layer which manages a vector based dataset.
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:6819
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:6818
QSet< QgsFeatureId > QgsFeatureIds