QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgsfeaturelistcombobox.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfieldlistcombobox.cpp - QgsFieldListComboBox
3 
4  ---------------------
5  begin : 10.3.2017
6  copyright : (C) 2017 by Matthias Kuhn
7  email : [email protected]
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 #include "qgsfeaturelistcombobox.h"
17 
18 #include "qgsfeaturefiltermodel.h"
19 #include "qgsanimatedicon.h"
20 #include "qgsfilterlineedit.h"
21 #include "qgslogger.h"
22 
23 #include <QCompleter>
24 #include <QLineEdit>
25 #include <QKeyEvent>
26 
28  : QComboBox( parent )
29  , mModel( new QgsFeatureFilterModel( this ) )
30  , mCompleter( new QCompleter( mModel ) )
31 {
32  mCompleter->setCaseSensitivity( Qt::CaseInsensitive );
33  mCompleter->setFilterMode( Qt::MatchContains );
34  setCompleter( mCompleter );
35  mCompleter->setWidget( this );
39  connect( mModel, &QgsFeatureFilterModel::isLoadingChanged, this, &QgsFeatureListComboBox::onLoadingChanged );
40  connect( mModel, &QgsFeatureFilterModel::filterJobCompleted, this, &QgsFeatureListComboBox::onFilterUpdateCompleted );
43  connect( mModel, &QgsFeatureFilterModel::extraIdentifierValueIndexChanged, this, &QgsFeatureListComboBox::setCurrentIndex );
45  connect( mCompleter, static_cast<void( QCompleter::* )( const QModelIndex & )>( &QCompleter::highlighted ), this, &QgsFeatureListComboBox::onItemSelected );
46  connect( mCompleter, static_cast<void( QCompleter::* )( const QModelIndex & )>( &QCompleter::activated ), this, &QgsFeatureListComboBox::onActivated );
47  connect( mModel, &QgsFeatureFilterModel::beginUpdate, this, &QgsFeatureListComboBox::storeLineEditState );
48  connect( mModel, &QgsFeatureFilterModel::endUpdate, this, &QgsFeatureListComboBox::restoreLineEditState );
50  connect( mModel, &QgsFeatureFilterModel::dataChanged, this, &QgsFeatureListComboBox::onDataChanged );
51 
52  connect( this, static_cast<void( QgsFeatureListComboBox::* )( int )>( &QgsFeatureListComboBox::currentIndexChanged ), this, &QgsFeatureListComboBox::onCurrentIndexChanged );
53 
54  mLineEdit = new QgsFilterLineEdit( nullptr, QgsApplication::nullRepresentation() );
55  mLineEdit->setSelectOnFocus( true );
56  mLineEdit->setShowClearButton( true );
57 
58  setEditable( true );
59  setLineEdit( mLineEdit );
60  setModel( mModel );
61 
62  connect( mLineEdit, &QgsFilterLineEdit::textEdited, this, &QgsFeatureListComboBox::onCurrentTextChanged );
63 
64  setToolTip( tr( "Just start typing what you are looking for." ) );
65 }
66 
68 {
69  return mModel->sourceLayer();
70 }
71 
73 {
74  mModel->setSourceLayer( sourceLayer );
75 }
76 
78 {
79  return mModel->displayExpression();
80 }
81 
82 void QgsFeatureListComboBox::setDisplayExpression( const QString &expression )
83 {
84  mModel->setDisplayExpression( expression );
85 }
86 
87 void QgsFeatureListComboBox::onCurrentTextChanged( const QString &text )
88 {
89  mIsCurrentlyEdited = true;
90  mPopupRequested = true;
91  mModel->setFilterValue( text );
92 }
93 
94 void QgsFeatureListComboBox::onFilterUpdateCompleted()
95 {
96  if ( mPopupRequested )
97  mCompleter->complete();
98 
99  mPopupRequested = false;
100 }
101 
102 void QgsFeatureListComboBox::onLoadingChanged()
103 {
104  mLineEdit->setShowSpinner( mModel->isLoading() );
105 }
106 
107 void QgsFeatureListComboBox::onItemSelected( const QModelIndex &index )
108 {
109  setCurrentIndex( index.row() );
110 }
111 
112 void QgsFeatureListComboBox::onCurrentIndexChanged( int i )
113 {
114  if ( !mHasStoredEditState )
115  mIsCurrentlyEdited = false;
116  QModelIndex modelIndex = mModel->index( i, 0, QModelIndex() );
118  mLineEdit->setText( mModel->data( modelIndex, QgsFeatureFilterModel::ValueRole ).toString() );
119  mLineEdit->setFont( mModel->data( modelIndex, Qt::FontRole ).value<QFont>() );
120  QPalette palette = mLineEdit->palette();
121  palette.setBrush( mLineEdit->foregroundRole(), mModel->data( modelIndex, Qt::ForegroundRole ).value<QBrush>() );
122  mLineEdit->setPalette( palette );
123 }
124 
125 void QgsFeatureListComboBox::onActivated( QModelIndex modelIndex )
126 {
128  mLineEdit->setText( mModel->data( modelIndex, QgsFeatureFilterModel::ValueRole ).toString() );
129 }
130 
131 void QgsFeatureListComboBox::storeLineEditState()
132 {
133  if ( mIsCurrentlyEdited )
134  {
135  mHasStoredEditState = true;
136  mLineEditState.store( mLineEdit );
137  }
138 }
139 
140 void QgsFeatureListComboBox::restoreLineEditState()
141 {
142  if ( mIsCurrentlyEdited )
143  {
144  mHasStoredEditState = false;
145  mLineEditState.restore( mLineEdit );
146  }
147 }
148 
150 {
151  int index = -1;
152 
153  if ( allowNull() )
154  {
155  index = findText( QgsApplication::nullRepresentation( ) );
156  }
157 
158  return index;
159 }
160 
161 void QgsFeatureListComboBox::onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles )
162 {
163  Q_UNUSED( roles )
164  if ( !mIsCurrentlyEdited )
165  {
166  const int currentIndex = mModel->extraIdentifierValueIndex();
167  if ( currentIndex >= topLeft.row() && currentIndex <= bottomRight.row() )
168  {
169  QModelIndex modelIndex = mModel->index( currentIndex, 0, QModelIndex() );
170  mLineEdit->setText( mModel->data( modelIndex, QgsFeatureFilterModel::ValueRole ).toString() );
171  }
172  }
173 }
174 
176 {
177  return mModel->identifierField();
178 }
179 
181 {
182  mModel->setIdentifierField( identifierField );
183 }
184 
186 {
187  return mModel->index( mModel->extraIdentifierValueIndex(), 0, QModelIndex() );
188 }
189 
190 void QgsFeatureListComboBox::focusOutEvent( QFocusEvent *event )
191 {
192  Q_UNUSED( event )
193  QComboBox::focusOutEvent( event );
194  mLineEdit->setText( mModel->data( currentModelIndex(), QgsFeatureFilterModel::ValueRole ).toString() );
195 }
196 
198 {
199  if ( event->key() == Qt::Key_Escape )
200  {
201  mLineEdit->setText( mModel->data( currentModelIndex(), QgsFeatureFilterModel::ValueRole ).toString() );
202  }
203  QComboBox::keyReleaseEvent( event );
204 }
205 
207 {
208  return mModel->allowNull();
209 }
210 
212 {
213  mModel->setAllowNull( allowNull );
214 }
215 
217 {
218  return mModel->extraIdentifierValue();
219 }
220 
222 {
223  mModel->setExtraIdentifierValue( identifierValue );
224 }
225 
227 {
228  if ( mModel->extraIdentifierValue().isNull() )
229  return QgsFeatureRequest().setFilterFids( QgsFeatureIds() ); // NULL: Return a request that's guaranteed to not return anything
230  else
231  return QgsFeatureRequest().setFilterExpression( QStringLiteral( "%1 = %2" ).arg( QgsExpression::quotedColumnRef( mModel->identifierField() ), QgsExpression::quotedValue( mModel->extraIdentifierValue() ) ) );
232 }
233 
235 {
236  return mModel->filterExpression();
237 }
238 
240 {
241  mModel->setFilterExpression( filterExpression );
242 }
243 
244 void QgsFeatureListComboBox::LineEditState::store( QLineEdit *lineEdit )
245 {
246  text = lineEdit->text();
247  selectionStart = lineEdit->selectionStart();
248  selectionLength = lineEdit->selectedText().length();
249  cursorPosition = lineEdit->cursorPosition();
250 
251 }
252 
253 void QgsFeatureListComboBox::LineEditState::restore( QLineEdit *lineEdit ) const
254 {
255  lineEdit->setText( text );
256  lineEdit->setCursorPosition( cursorPosition );
257  if ( selectionStart > -1 )
258  lineEdit->setSelection( selectionStart, selectionLength );
259 }
void setIdentifierValue(const QVariant &identifierValue)
The identifier value of the currently selected feature.
Provides a list of features based on filter conditions.
This offers a combobox with autocompleter that allows selecting features from a layer.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
void setSelectOnFocus(bool selectOnFocus)
Will select all text when this widget receives the focus.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
void beginUpdate()
Notification that the model is about to be changed because a job was completed.
Used to retrieve the displayExpression of a feature.
void identifierFieldChanged()
Field name that will be used to uniquely identify the current feature.
int nullIndex() const
Returns the current index of the NULL value, or -1 if NULL values are not allowed.
void setFilterExpression(const QString &filterExpression)
An additional filter expression to apply, next to the filterValue.
void setShowSpinner(bool showSpinner)
Show a spinner icon.
QString displayExpression() const
The display expression will be used to display features as well as the value to match the typed text ...
void displayExpressionChanged()
The display expression will be used to display features as well as the the value to match the typed t...
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.
void setSourceLayer(QgsVectorLayer *sourceLayer)
The layer from which features should be listed.
void filterExpressionChanged()
An additional expression to further restrict the available features.
QString identifierField() const
Field name that will be used to uniquely identify the current feature.
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...
QgsFeatureRequest currentFeatureRequest() const
Shorthand for getting a feature request to query the currently selected feature.
void setAllowNull(bool allowNull)
Determines if a NULL value should be available in the list.
QgsFeatureListComboBox(QWidget *parent=nullptr)
Create a new QgsFeatureListComboBox, optionally specifying a parent.
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
QString identifierField
A field of sourceLayer that is unique and should be used to identify features.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QLineEdit subclass with built in support for clearing the widget&#39;s value and handling custom null val...
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
QVariant extraIdentifierValue
The value that identifies the current feature.
void identifierValueChanged()
The identifier value of the currently selected feature.
QModelIndex currentModelIndex() const
The index of the currently selected item.
void isLoadingChanged()
Indicator if the model is currently performing any feature iteration in the background.
void allowNullChanged()
Add a NULL entry to the list.
bool allowNull() const
Determines if a NULL value should be available in the list.
void filterExpressionChanged()
An additional filter expression to apply, next to the filterValue.
void endUpdate()
Notification that the model change is finished.
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 setFilterExpression(const QString &filterExpression)
An additional expression to further restrict the available features.
void sourceLayerChanged()
The source layer from which features will be fetched.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
void allowNullChanged()
Determines if a NULL value should be available in the list.
void keyPressEvent(QKeyEvent *event) override
void setExtraIdentifierValue(const QVariant &extraIdentifierValue)
Allows specifying one value that does not need to match the filter criteria but will still be availab...
void sourceLayerChanged()
The layer from which features should be listed.
QString filterExpression() const
An additional expression to further restrict the available features.
void focusOutEvent(QFocusEvent *event) override
QVariant data(const QModelIndex &index, int role) const override
void setAllowNull(bool allowNull)
Add a NULL entry to the list.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required...
Used to retrieve the identifierValue (primary key) of a feature.
void setDisplayExpression(const QString &displayExpression)
The display expression will be used for.
void setShowClearButton(bool visible)
Sets whether the widget&#39;s clear button is visible.
Represents a vector layer which manages a vector based data sets.
void setDisplayExpression(const QString &displayExpression)
The display expression will be used to display features as well as the value to match the typed text ...
void modelUpdated()
The underlying model has been updated.
void setIdentifierField(const QString &identifierField)
Field name that will be used to uniquely identify the current feature.
QgsVectorLayer * sourceLayer() const
The layer from which features should be listed.
void displayExpressionChanged()
The display expression will be used for.
QVariant identifierValue() const
The identifier value of the currently selected feature.