QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
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
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
17#include "qgsanimatedicon.h"
18#include "qgsapplication.h"
20#include "qgsfilterlineedit.h"
21#include "qgslogger.h"
22
23#include <QCompleter>
24#include <QKeyEvent>
25#include <QLineEdit>
26#include <QString>
27
28#include "moc_qgsfeaturelistcombobox.cpp"
29
30using namespace Qt::StringLiterals;
31
33 : QComboBox( parent )
34 , mModel( new QgsFeatureFilterModel( this ) )
35 , mCompleter( new QCompleter( mModel ) )
36{
37 setMinimumContentsLength( 1 );
38 setSizeAdjustPolicy( QComboBox::SizeAdjustPolicy::AdjustToMinimumContentsLengthWithIcon );
39 mCompleter->setCaseSensitivity( Qt::CaseInsensitive );
40 mCompleter->setFilterMode( Qt::MatchContains );
41 setEditable( true );
42 setCompleter( mCompleter );
43 mCompleter->setWidget( this );
49 connect( mModel, &QgsFeatureFilterModel::isLoadingChanged, this, &QgsFeatureListComboBox::onLoadingChanged );
50 connect( mModel, &QgsFeatureFilterModel::filterJobCompleted, this, &QgsFeatureListComboBox::onFilterUpdateCompleted );
53 connect( mModel, &QgsFeatureFilterModel::extraIdentifierValueIndexChanged, this, &QgsFeatureListComboBox::setCurrentIndex );
55 connect( mCompleter, static_cast<void ( QCompleter::* )( const QModelIndex & )>( &QCompleter::highlighted ), this, &QgsFeatureListComboBox::onItemSelected );
56 connect( mCompleter, static_cast<void ( QCompleter::* )( const QModelIndex & )>( &QCompleter::activated ), this, &QgsFeatureListComboBox::onActivated );
57 connect( mModel, &QgsFeatureFilterModel::beginUpdate, this, &QgsFeatureListComboBox::storeLineEditState );
58 connect( mModel, &QgsFeatureFilterModel::endUpdate, this, &QgsFeatureListComboBox::restoreLineEditState );
60 connect( mModel, &QgsFeatureFilterModel::dataChanged, this, &QgsFeatureListComboBox::onDataChanged );
61
62 connect( this, static_cast<void ( QgsFeatureListComboBox::* )( int )>( &QgsFeatureListComboBox::currentIndexChanged ), this, &QgsFeatureListComboBox::onCurrentIndexChanged );
63
64 mLineEdit = new QgsFilterLineEdit( nullptr, QgsApplication::nullRepresentation() );
65 mLineEdit->setSelectOnFocus( true );
66 mLineEdit->setShowClearButton( true );
67
68 setLineEdit( mLineEdit );
69 setModel( mModel );
70
71 connect( mLineEdit, &QgsFilterLineEdit::textEdited, this, &QgsFeatureListComboBox::onCurrentTextChanged );
72 connect( mLineEdit, &QgsFilterLineEdit::cleared, this, &QgsFeatureListComboBox::onFilterLineEditCleared );
73
75 // To avoid wrongly signaling a foreign key change, handle model feature found state following feature gathering separately
77
78 setToolTip( tr( "Just start typing what you are looking for." ) );
79}
80
82{
83 return mModel->sourceLayer();
84}
85
90
92{
93 QVariantList values;
94 const QStringList fields = mModel->identifierFields();
95 for ( const QString &field : fields )
96 {
97 values << feature.attribute( field );
98 }
99 setIdentifierValues( values );
100}
101
103{
104 return mModel->displayExpression();
105}
106
107void QgsFeatureListComboBox::setDisplayExpression( const QString &expression )
108{
109 mModel->setDisplayExpression( expression );
110}
111
112void QgsFeatureListComboBox::onCurrentTextChanged( const QString &text )
113{
114 mIsCurrentlyEdited = true;
115 mPopupRequested = true;
116 mModel->setFilterValue( text );
117}
118
119void QgsFeatureListComboBox::onFilterLineEditCleared()
120{
121 // Reset the combobox when the search is cleared
122 const QString clearedValue = allowNull() ? mLineEdit->nullValue() : mLineEdit->defaultValue();
123 mModel->setFilterValue( clearedValue );
124}
125
126void QgsFeatureListComboBox::onFilterUpdateCompleted()
127{
128 if ( mPopupRequested )
129 mCompleter->complete();
130
131 mPopupRequested = false;
132}
133
134void QgsFeatureListComboBox::onLoadingChanged()
135{
136 mLineEdit->setShowSpinner( mModel->isLoading() );
137}
138
139void QgsFeatureListComboBox::onItemSelected( const QModelIndex &index )
140{
141 setCurrentIndex( index.row() );
142}
143
144void QgsFeatureListComboBox::onCurrentIndexChanged( int i )
145{
146 if ( !mLineEdit->hasStateStored() )
147 mIsCurrentlyEdited = false;
148 const QModelIndex modelIndex = mModel->index( i, 0, QModelIndex() );
149 mModel->setExtraIdentifierValues( mModel->data( modelIndex, static_cast<int>( QgsFeatureFilterModel::CustomRole::IdentifierValues ) ).toList() );
150 mLineEdit->setText( mModel->data( modelIndex, static_cast<int>( QgsFeatureFilterModel::CustomRole::Value ) ).toString() );
151 mLineEdit->setFont( mModel->data( modelIndex, Qt::FontRole ).value<QFont>() );
152 QPalette palette = mLineEdit->palette();
153 palette.setBrush( mLineEdit->foregroundRole(), mModel->data( modelIndex, Qt::ForegroundRole ).value<QBrush>() );
154 mLineEdit->setPalette( palette );
155}
156
157void QgsFeatureListComboBox::onActivated( QModelIndex modelIndex )
158{
159 setIdentifierValues( mModel->data( modelIndex, static_cast<int>( QgsFeatureFilterModel::CustomRole::IdentifierValues ) ).toList() );
160 mLineEdit->setText( mModel->data( modelIndex, static_cast<int>( QgsFeatureFilterModel::CustomRole::Value ) ).toString() );
161}
162
163void QgsFeatureListComboBox::storeLineEditState()
164{
165 if ( mIsCurrentlyEdited )
166 {
167 mLineEdit->storeState();
168 }
169}
170
171void QgsFeatureListComboBox::restoreLineEditState()
172{
173 if ( mIsCurrentlyEdited )
174 {
175 mLineEdit->restoreState();
176 }
177}
178
180{
181 int index = -1;
182
183 if ( allowNull() )
184 {
185 index = findText( QgsApplication::nullRepresentation() );
186 }
187
188 return index;
189}
190
191void QgsFeatureListComboBox::onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles )
192{
193 Q_UNUSED( roles )
194 if ( !mIsCurrentlyEdited )
195 {
196 const int currentIndex = mModel->extraIdentifierValueIndex();
197 if ( currentIndex >= topLeft.row() && currentIndex <= bottomRight.row() )
198 {
199 const QModelIndex modelIndex = mModel->index( currentIndex, 0, QModelIndex() );
200 mLineEdit->setText( mModel->data( modelIndex, static_cast<int>( QgsFeatureFilterModel::CustomRole::Value ) ).toString() );
201 }
202 }
203}
204
206{
207 const QStringList list = mModel->identifierFields();
208 if ( list.isEmpty() )
209 return QString();
210 else
211 return list.at( 0 );
212}
213
215{
216 return mModel->identifierFields();
217}
218
220{
221 mModel->setIdentifierFields( QStringList() << identifierField );
222}
223
225{
226 mModel->setIdentifierFields( identifierFields );
227}
228
230{
231 return mModel->index( currentIndex(), 0, QModelIndex() );
232}
233
235{
236 Q_UNUSED( event )
237 QComboBox::focusOutEvent( event );
238 mLineEdit->setText( mModel->data( currentModelIndex(), static_cast<int>( QgsFeatureFilterModel::CustomRole::Value ) ).toString() );
239}
240
242{
243 if ( event->key() == Qt::Key_Escape )
244 {
245 mLineEdit->setText( mModel->data( currentModelIndex(), static_cast<int>( QgsFeatureFilterModel::CustomRole::Value ) ).toString() );
246 }
247 QComboBox::keyReleaseEvent( event );
248}
249
251{
252 return mModel->allowNull();
253}
254
256{
257 mModel->setAllowNull( allowNull );
259}
260
262{
263 return mModel->fetchLimit();
264}
265
267{
268 mModel->setFetchLimit( fetchLimit );
269}
270
272{
274 return mModel->extraIdentifierValues().value( 0 );
276}
277
279{
280 return mModel->extraIdentifierValues();
281}
282
284{
285 setIdentifierValues( QVariantList() << identifierValue );
286}
287
289{
290 mModel->setExtraIdentifierValues( identifierValues );
291}
292
294{
295 mModel->setExtraIdentifierValueToNull();
296}
297
299{
300 QgsFeatureRequest request;
301 request.setRequestMayBeNested( true );
302 if ( mModel->extraIdentifierValues().isEmpty() )
303 {
304 request.setFilterFids( QgsFeatureIds() ); // NULL: Return a request that's guaranteed to not return anything
305 }
306 else
307 {
308 QStringList filtersAttrs;
309 const QStringList identifierFields = mModel->identifierFields();
310 const QVariantList values = mModel->extraIdentifierValues();
311 for ( int i = 0; i < identifierFields.count(); i++ )
312 {
313 if ( i >= values.count() )
314 {
315 filtersAttrs << QgsExpression::createFieldEqualityExpression( identifierFields.at( i ), QVariant() );
316 }
317 else
318 {
319 filtersAttrs << QgsExpression::createFieldEqualityExpression( identifierFields.at( i ), values.at( i ) );
320 }
321 }
322 const QString expression = filtersAttrs.join( " AND "_L1 );
323 return request.setFilterExpression( expression );
324 }
325 return request;
326}
327
329{
330 return mModel->filterExpression();
331}
332
334{
335 mModel->setFilterExpression( filterExpression );
336}
337
339{
340 return mModel->formFeature();
341}
342
344{
345 mModel->setFormFeature( feature );
346}
347
349{
350 return mModel->parentFormFeature();
351}
352
354{
355 mModel->setParentFormFeature( feature );
356}
357
359{
360 return mModel->orderExpression();
361}
362
364{
365 mModel->setOrderExpression( orderExpression );
366}
367
369{
370 return mModel->sortOrder();
371}
372
374{
375 mModel->setSortOrder( sortOrder );
376}
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 identifierFieldsChanged()
The identifier field should be a unique field that can be used to identify individual features.
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 setSortOrder(const Qt::SortOrder sortOrder)
The order direction of the model.
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.
Qt::SortOrder sortOrder() const
The order direction of the model.
void setOrderExpression(const QString &orderExpression)
The order expression of the model.
QString orderExpression() const
The order expression of the model.
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 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 extraValueDoesNotExistChanged(bool found)
Notification whether the model has found a feature tied to the extraIdentifierValue or not.
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.
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.
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.
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.
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...
Definition qgsfeature.h:60
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...
@ ClearToNull
Reset value to null.
@ ClearToDefault
Reset value to default value (see defaultValue() ).
void cleared()
Emitted when the widget is cleared.
Represents a vector layer which manages a vector based dataset.
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:7451
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7450
QSet< QgsFeatureId > QgsFeatureIds