QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsfeaturepickerwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfeaturepickerwidget.cpp - QgsFeaturePickerWidget
3  ---------------------
4  begin : 03.04.2020
5  copyright : (C) 2020 by Denis Rouzaud
6  email : [email protected]
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  ***************************************************************************/
15 
16 #include <QHBoxLayout>
17 #include <QToolButton>
18 #include <QKeyEvent>
19 
20 #include "qgsfeaturepickerwidget.h"
21 #include "qgsfilterlineedit.h"
22 #include "qgsfeaturepickermodel.h"
23 
25  : QWidget( parent )
26  , mModel( new QgsFeaturePickerModel( this ) )
27  , mCompleter( new QCompleter( mModel ) )
28 {
29  QHBoxLayout *layout = new QHBoxLayout();
30  mComboBox = new QComboBox( this );
31  mComboBox->setEditable( true );
32  layout->addWidget( mComboBox );
33 
34  mPreviousButton = new QToolButton( this );
35  mPreviousButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionArrowLeft.svg" ) ) );
36  mPreviousButton->setEnabled( false );
37  mPreviousButton->setVisible( mShowBrowserButtons );
38  layout->addWidget( mPreviousButton );
39 
40  mNextButton = new QToolButton( this );
41  mNextButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionArrowRight.svg" ) ) );
42  mNextButton->setEnabled( false );
43  mNextButton->setVisible( mShowBrowserButtons );
44  layout->addWidget( mNextButton );
45  layout->setContentsMargins( 0, 0, 0, 0 );
46 
47  setLayout( layout );
48 
49  mCompleter->setCaseSensitivity( Qt::CaseInsensitive );
50  mCompleter->setFilterMode( Qt::MatchContains );
51  mComboBox->setCompleter( mCompleter );
52  mCompleter->setWidget( mComboBox );
56  connect( mModel, &QgsFeaturePickerModel::isLoadingChanged, this, &QgsFeaturePickerWidget::onLoadingChanged );
57  connect( mModel, &QgsFeaturePickerModel::filterJobCompleted, this, &QgsFeaturePickerWidget::onFilterUpdateCompleted );
61  connect( mModel, &QgsFeaturePickerModel::extraIdentifierValueIndexChanged, mComboBox, &QComboBox::setCurrentIndex );
63  connect( mCompleter, static_cast<void( QCompleter::* )( const QModelIndex & )>( &QCompleter::highlighted ), this, &QgsFeaturePickerWidget::onItemSelected );
64  connect( mCompleter, static_cast<void( QCompleter::* )( const QModelIndex & )>( &QCompleter::activated ), this, &QgsFeaturePickerWidget::onActivated );
65  connect( mModel, &QgsFeaturePickerModel::beginUpdate, this, &QgsFeaturePickerWidget::storeLineEditState );
66  connect( mModel, &QgsFeaturePickerModel::endUpdate, this, &QgsFeaturePickerWidget::restoreLineEditState );
68  connect( mModel, &QgsFeaturePickerModel::dataChanged, this, &QgsFeaturePickerWidget::onDataChanged );
69 
70  connect( mComboBox, static_cast<void( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsFeaturePickerWidget::onCurrentIndexChanged );
71 
72  connect( mPreviousButton, &QToolButton::clicked, this, [ = ]() {browseFeatures( -1 );} );
73  connect( mNextButton, &QToolButton::clicked, this, [ = ]() {browseFeatures( 1 );} );
74 
75  mLineEdit = new QgsFilterLineEdit( nullptr, QgsApplication::nullRepresentation() );
76  mLineEdit->setSelectOnFocus( true );
77  mLineEdit->setShowClearButton( allowNull() );
78 
79  mComboBox->setEditable( true );
80  mComboBox->setLineEdit( mLineEdit );
81  mComboBox->setModel( mModel );
82 
83  connect( mLineEdit, &QgsFilterLineEdit::textEdited, this, &QgsFeaturePickerWidget::onCurrentTextChanged );
84 }
85 
87 {
88  return mModel->sourceLayer();
89 }
90 
92 {
93  mModel->setSourceLayer( sourceLayer );
94 }
95 
97 {
98  mModel->setFeature( featureId );
99 }
100 
102 {
103  return mModel->feature();
104 }
105 
107 {
108  return mModel->displayExpression();
109 }
110 
111 void QgsFeaturePickerWidget::setDisplayExpression( const QString &expression )
112 {
113  mModel->setDisplayExpression( expression );
114 }
115 
116 void QgsFeaturePickerWidget::onCurrentTextChanged( const QString &text )
117 {
118  mIsCurrentlyEdited = true;
119  mPopupRequested = true;
120  mModel->setFilterValue( text );
121 }
122 
123 void QgsFeaturePickerWidget::onFilterUpdateCompleted()
124 {
125  if ( mPopupRequested )
126  mCompleter->complete();
127 
128  mPopupRequested = false;
129 }
130 
131 void QgsFeaturePickerWidget::onLoadingChanged()
132 {
133  mLineEdit->setShowSpinner( mModel->isLoading() );
134 }
135 
136 void QgsFeaturePickerWidget::onItemSelected( const QModelIndex &index )
137 {
138  mComboBox->setCurrentIndex( index.row() );
139 }
140 
141 void QgsFeaturePickerWidget::onCurrentIndexChanged( int i )
142 {
143  if ( !mLineEdit->hasStateStored() )
144  mIsCurrentlyEdited = false;
145 
146  mPreviousButton->setEnabled( i > 0 );
147  mNextButton->setEnabled( i < mComboBox->model()->rowCount() - 1 );
148 
149  if ( i < 0 )
150  return;
151 
152  QModelIndex modelIndex = mModel->index( i, 0, QModelIndex() );
153  mModel->setFeature( mModel->data( modelIndex, QgsFeaturePickerModel::FeatureIdRole ).value<QgsFeatureId>() );
154  mLineEdit->setText( mModel->data( modelIndex, QgsFeaturePickerModel::ValueRole ).toString() );
155  mLineEdit->setFont( mModel->data( modelIndex, Qt::FontRole ).value<QFont>() );
156  QPalette palette = mLineEdit->palette();
157  palette.setBrush( mLineEdit->foregroundRole(), mModel->data( modelIndex, Qt::ForegroundRole ).value<QBrush>() );
158  mLineEdit->setPalette( palette );
159 }
160 
161 void QgsFeaturePickerWidget::onActivated( QModelIndex modelIndex )
162 {
163  setFeature( mModel->data( modelIndex, QgsFeaturePickerModel::FeatureIdRole ).value<QgsFeatureId>() );
164  mLineEdit->setText( mModel->data( modelIndex, QgsFeaturePickerModel::ValueRole ).toString() );
165 }
166 
167 void QgsFeaturePickerWidget::storeLineEditState()
168 {
169  if ( mIsCurrentlyEdited )
170  {
171  mLineEdit->storeState( );
172  }
173 }
174 
175 void QgsFeaturePickerWidget::restoreLineEditState()
176 {
177  if ( mIsCurrentlyEdited )
178  {
179  mLineEdit->restoreState( );
180  }
181 }
182 
184 {
185  int index = -1;
186 
187  if ( allowNull() )
188  {
189  index = mComboBox->findText( QgsApplication::nullRepresentation( ) );
190  }
191 
192  return index;
193 }
194 
195 void QgsFeaturePickerWidget::onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles )
196 {
197  Q_UNUSED( roles )
198  if ( !mIsCurrentlyEdited )
199  {
200  const int currentIndex = mModel->extraIdentifierValueIndex();
201  if ( currentIndex >= topLeft.row() && currentIndex <= bottomRight.row() )
202  {
203  QModelIndex modelIndex = mModel->index( currentIndex, 0, QModelIndex() );
204  mLineEdit->setText( mModel->data( modelIndex, QgsFeaturePickerModel::ValueRole ).toString() );
205  }
206  }
207 }
208 
209 void QgsFeaturePickerWidget::browseFeatures( int direction )
210 {
211  int newIndex = std::min( std::max( 0, mComboBox->currentIndex() + direction ), mComboBox->model()->rowCount() - 1 );
212  mComboBox->setCurrentIndex( newIndex );
213 }
214 
216 {
217  return mModel->index( mModel->extraIdentifierValueIndex(), 0, QModelIndex() );
218 }
219 
220 void QgsFeaturePickerWidget::focusOutEvent( QFocusEvent *event )
221 {
222  Q_UNUSED( event )
223  QWidget::focusOutEvent( event );
224  mLineEdit->setText( mModel->data( currentModelIndex(), QgsFeaturePickerModel::ValueRole ).toString() );
225 }
226 
228 {
229  if ( event->key() == Qt::Key_Escape )
230  {
231  mLineEdit->setText( mModel->data( currentModelIndex(), QgsFeaturePickerModel::ValueRole ).toString() );
232  }
233  QWidget::keyReleaseEvent( event );
234 }
235 
237 {
238  return mModel->allowNull();
239 }
240 
242 {
243  mModel->setAllowNull( allowNull );
245 }
246 
248 {
249  return mModel->filterExpression();
250 }
251 
252 void QgsFeaturePickerWidget::setFilterExpression( const QString &filterExpression )
253 {
255 }
256 
258 {
259  return mModel->fetchGeometry();
260 }
261 
263 {
264  mModel->setFetchGeometry( fetchGeometry );
265 }
266 
268 {
269  return mModel->fetchLimit();
270 }
271 
273 {
274  mModel->setFetchLimit( fetchLimit );
275 }
276 
278 {
279  return mShowBrowserButtons;
280 }
281 
282 void QgsFeaturePickerWidget::setShowBrowserButtons( bool showBrowserButtons )
283 {
284  if ( showBrowserButtons == mShowBrowserButtons )
285  return;
286 
287  mShowBrowserButtons = showBrowserButtons;
288  mPreviousButton->setVisible( mShowBrowserButtons );
289  mNextButton->setVisible( mShowBrowserButtons );
291 }
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
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 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 setFetchGeometry(bool fetchGeometry)
Defines if the geometry will be fetched.
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.
QVariant data(const QModelIndex &index, int role) const override
QModelIndex index(int row, int column, const QModelIndex &parent) const override
void fetchLimitChanged()
Emitted when the fetching limit for the feature request changes.
void sourceLayerChanged()
The source layer from which features will be fetched.
@ FeatureIdRole
Used to retrieve the id of a feature.
@ ValueRole
Used to retrieve the displayExpression of a feature.
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 fetchGeometryChanged()
Emitted when the fetching of the geometry changes.
void isLoadingChanged()
Indicator if the model is currently performing any feature iteration in the background.
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.
Provides a list of features based on filter conditions.
void setFeature(const QgsFeatureId &fid)
Set the feature to the given feature id.
void featureChanged(const QgsFeature &feature)
Emitted when the current feature changes.
QgsFeature feature() const
Returns the current feature.
void keyPressEvent(QKeyEvent *event) override
void setAllowNull(bool allowNull)
Determines if a NULL value should be available in the list.
QgsFeaturePickerWidget(QWidget *parent=nullptr)
Create a new QgsFeaturePickerWidget, optionally specifying a parent.
void setFilterExpression(const QString &filterExpression)
An additional expression to further restrict the available features.
void allowNullChanged()
Determines if a NULL value should be available in the list.
QgsFeature feature() const
Returns the current feature.
void filterExpressionChanged()
An additional expression to further restrict the available features.
void displayExpressionChanged()
The display expression will be used to display features as well as the the value to match the typed t...
void layerChanged()
The layer from which features should be listed.
void modelUpdated()
The underlying model has been updated.
void setFetchLimit(int fetchLimit)
Defines the feature request fetch limit If set to 0, no limit is applied when fetching.
void setLayer(QgsVectorLayer *layer)
The layer from which features should be listed.
void showBrowserButtonsChanged()
Emitted when showing the browser buttons changes.
void setShowBrowserButtons(bool showBrowserButtons)
Defines if the browsing buttons are shown.
void fetchGeometryChanged()
Emitted when the fetching of the geometry changes.
void setFeature(QgsFeatureId featureId)
Sets the current index by using the given feature.
void featureChanged(const QgsFeature &feature)
Sends the feature as soon as it is chosen.
QModelIndex currentModelIndex() const
The index of the currently selected item.
void setDisplayExpression(const QString &displayExpression)
The display expression will be used to display features as well as the value to match the typed text ...
int nullIndex() const
Returns the current index of the NULL value, or -1 if NULL values are not allowed.
void fetchLimitChanged()
Emitted when the fetching limit for the feature request changes.
void focusOutEvent(QFocusEvent *event) override
void setFetchGeometry(bool fetchGeometry)
Defines if the geometry will be fetched.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
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() )
bool hasStateStored() const
Returns if a state is already saved.
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 data sets.
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28