QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsfilterlineedit.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfilterlineedit.cpp
3  ------------------------
4  begin : October 27, 2012
5  copyright : (C) 2012 by Alexander Bruy
6  email : alexander dot bruy at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsfilterlineedit.h"
19 #include "qgsapplication.h"
20 #include "qgsanimatedicon.h"
21 #include "qgis.h"
22 
23 #include <QAction>
24 #include <QToolButton>
25 #include <QStyle>
26 #include <QFocusEvent>
27 #include <QPainter>
28 
29 QgsFilterLineEdit::QgsFilterLineEdit( QWidget *parent, const QString &nullValue )
30  : QLineEdit( parent )
31  , mNullValue( nullValue )
32 {
33  // icon size is about 2/3 height of text, but minimum size of 16
34  int iconSize = std::floor( std::max( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 0.75, 16.0 ) );
35 
36  mClearIcon.addPixmap( QgsApplication::getThemeIcon( "/mIconClearText.svg" ).pixmap( QSize( iconSize, iconSize ) ), QIcon::Normal, QIcon::On );
37  mClearIcon.addPixmap( QgsApplication::getThemeIcon( "/mIconClearTextHover.svg" ).pixmap( QSize( iconSize, iconSize ) ), QIcon::Selected, QIcon::On );
38 
39  connect( this, &QLineEdit::textChanged, this,
40  &QgsFilterLineEdit::onTextChanged );
41 }
42 
44 {
45  mClearButtonVisible = visible;
46  updateClearIcon();
47 }
48 
50 {
51  if ( visible && !mSearchAction )
52  {
53  QIcon searchIcon = QgsApplication::getThemeIcon( "/search.svg" );
54  mSearchAction = new QAction( searchIcon, QString(), this );
55  mSearchAction->setCheckable( false );
56  addAction( mSearchAction, QLineEdit::LeadingPosition );
57  }
58  else if ( !visible && mSearchAction )
59  {
60  mSearchAction->deleteLater();
61  mSearchAction = nullptr;
62  }
63 }
64 
65 void QgsFilterLineEdit::updateClearIcon()
66 {
67  bool showClear = shouldShowClear();
68  if ( showClear && !mClearAction )
69  {
70  mClearAction = new QAction( mClearIcon, QString(), this );
71  mClearAction->setCheckable( false );
72  addAction( mClearAction, QLineEdit::TrailingPosition );
73  connect( mClearAction, &QAction::triggered, this, &QgsFilterLineEdit::clearValue );
74  }
75  else if ( !showClear && mClearAction )
76  {
77  // pretty freakin weird... seems the deleteLater call on the mClearAction
78  // isn't sufficient to actually remove the action from the line edit, and
79  // a kind of "ghost" action gets left behind... resulting in duplicate
80  // clear actions appearing if later we re-create the action.
81  // in summary: don't remove this "removeAction" call!
82  removeAction( mClearAction );
83  mClearAction->deleteLater();
84  mClearAction = nullptr;
85  }
86 }
87 
88 void QgsFilterLineEdit::focusInEvent( QFocusEvent *e )
89 {
90  QLineEdit::focusInEvent( e );
91  if ( e->reason() == Qt::MouseFocusReason && ( isNull() || mSelectOnFocus ) )
92  {
93  mWaitingForMouseRelease = true;
94  }
95 }
96 
98 {
99  QLineEdit::mouseReleaseEvent( e );
100  if ( mWaitingForMouseRelease )
101  {
102  mWaitingForMouseRelease = false;
103  selectAll();
104  }
105 }
106 
108 {
109  switch ( mClearMode )
110  {
111  case ClearToNull:
112  setText( mNullValue );
113  selectAll();
114  break;
115 
116  case ClearToDefault:
117  setText( mDefaultValue );
118  break;
119  }
120 
121  setModified( true );
122  emit cleared();
123 }
124 
125 void QgsFilterLineEdit::onTextChanged( const QString &text )
126 {
127  updateClearIcon();
128 
129  if ( isNull() )
130  {
131  setStyleSheet( QStringLiteral( "QLineEdit { font: italic; color: gray; } %1" ).arg( mStyleSheet ) );
132  emit valueChanged( QString() );
133  }
134  else
135  {
136  setStyleSheet( mStyleSheet );
137  emit valueChanged( text );
138  }
139 }
140 
141 void QgsFilterLineEdit::updateBusySpinner()
142 {
143  if ( !mBusySpinnerAction )
144  {
145  mBusySpinnerAction = addAction( mBusySpinnerAnimatedIcon->icon(), QLineEdit::TrailingPosition );
146  }
147  mBusySpinnerAction->setIcon( mBusySpinnerAnimatedIcon->icon() );
148 }
149 
151 {
152  return mSelectOnFocus;
153 }
154 
155 void QgsFilterLineEdit::setSelectOnFocus( bool selectOnFocus )
156 {
157  if ( mSelectOnFocus == selectOnFocus )
158  return;
159 
160  mSelectOnFocus = selectOnFocus;
161  emit selectOnFocusChanged();
162 }
163 
165 {
166  return mShowSpinner;
167 }
168 
169 void QgsFilterLineEdit::setShowSpinner( bool showSpinner )
170 {
171 
172  if ( showSpinner == mShowSpinner )
173  return;
174 
175  if ( showSpinner )
176  {
177  if ( !mBusySpinnerAnimatedIcon )
178  mBusySpinnerAnimatedIcon = new QgsAnimatedIcon( QgsApplication::iconPath( QStringLiteral( "/mIconLoading.gif" ) ), this );
179 
180  mBusySpinnerAnimatedIcon->connectFrameChanged( this, &QgsFilterLineEdit::updateBusySpinner );
181  }
182  else
183  {
184  mBusySpinnerAnimatedIcon->disconnectFrameChanged( this, &QgsFilterLineEdit::updateBusySpinner );
185  removeAction( mBusySpinnerAction );
186  mBusySpinnerAction = nullptr;
187  }
188 
189  mShowSpinner = showSpinner;
190  emit showSpinnerChanged();
191 }
192 
193 bool QgsFilterLineEdit::shouldShowClear() const
194 {
195  if ( !isEnabled() || isReadOnly() || !mClearButtonVisible )
196  return false;
197 
198  switch ( mClearMode )
199  {
200  case ClearToNull:
201  return !isNull();
202 
203  case ClearToDefault:
204  return value() != mDefaultValue;
205  }
206  return false; //avoid warnings
207 }
208 
209 bool QgsFilterLineEdit::event( QEvent *event )
210 {
211  if ( event->type() == QEvent::ReadOnlyChange || event->type() == QEvent::EnabledChange )
212  updateClearIcon();
213 
214  return QLineEdit::event( event );
215 }
216 
218 {
219  mLineEditState.text = text();
220  mLineEditState.selectionStart = selectionStart();
221  mLineEditState.selectionLength = selectedText().length();
222  mLineEditState.cursorPosition = cursorPosition();
223  mLineEditState.hasStateStored = true;
224 }
225 
227 {
228  setText( mLineEditState.text );
229  setCursorPosition( mLineEditState.cursorPosition );
230  if ( mLineEditState.selectionStart > -1 )
231  setSelection( mLineEditState.selectionStart, mLineEditState.selectionLength );
232  mLineEditState.hasStateStored = false;
233 }
234 
236 void QgsSpinBoxLineEdit::focusInEvent( QFocusEvent *e )
237 {
239  if ( isNull() )
240  {
241  clear();
242  }
243 }
QgsFilterLineEdit::value
QString value
Definition: qgsfilterlineedit.h:55
QgsFilterLineEdit::valueChanged
void valueChanged(const QString &value)
Same as textChanged() but with support for null values.
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:626
QgsFilterLineEdit::restoreState
void restoreState()
Restores the current state of the line edit (selection and cursor position)
Definition: qgsfilterlineedit.cpp:226
QgsFilterLineEdit::showSpinnerChanged
void showSpinnerChanged()
Show a spinner icon.
QgsFilterLineEdit::selectOnFocusChanged
void selectOnFocusChanged()
Will select all text when this widget receives the focus.
qgsfilterlineedit.h
qgis.h
QgsFilterLineEdit::ClearToNull
@ ClearToNull
Reset value to null.
Definition: qgsfilterlineedit.h:65
QgsFilterLineEdit::setSelectOnFocus
void setSelectOnFocus(bool selectOnFocus)
Will select all text when this widget receives the focus.
Definition: qgsfilterlineedit.cpp:155
QgsFilterLineEdit::setShowSpinner
void setShowSpinner(bool showSpinner)
Show a spinner icon.
Definition: qgsfilterlineedit.cpp:169
QgsApplication::iconPath
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
Definition: qgsapplication.cpp:615
QgsGuiUtils::iconSize
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
Definition: qgsguiutils.cpp:250
qgsapplication.h
QgsFilterLineEdit::setShowSearchIcon
void setShowSearchIcon(bool visible)
Define if a search icon shall be shown on the left of the image when no text is entered.
Definition: qgsfilterlineedit.cpp:49
QgsFilterLineEdit::QgsFilterLineEdit
QgsFilterLineEdit(QWidget *parent=nullptr, const QString &nullValue=QString())
Constructor for QgsFilterLineEdit.
Definition: qgsfilterlineedit.cpp:29
QgsFilterLineEdit::ClearToDefault
@ ClearToDefault
Reset value to default value (see defaultValue() )
Definition: qgsfilterlineedit.h:66
QgsAnimatedIcon::connectFrameChanged
bool connectFrameChanged(const typename QtPrivate::FunctionPointer< Func1 >::Object *receiver, Func1 slot)
Connect a slot that will be notified repeatedly whenever a frame changes and which should request the...
Definition: qgsanimatedicon.h:71
QgsAnimatedIcon::icon
QIcon icon() const
Gets the icons representation in the current frame.
Definition: qgsanimatedicon.cpp:41
QgsFilterLineEdit::clearValue
virtual void clearValue()
Clears the widget and resets it to the null value.
Definition: qgsfilterlineedit.cpp:107
QgsAnimatedIcon::disconnectFrameChanged
bool disconnectFrameChanged(const typename QtPrivate::FunctionPointer< Func1 >::Object *receiver, Func1 slot)
Convenience function to disconnect the same style that the frame change connection was established.
Definition: qgsanimatedicon.h:90
Qgis::UI_SCALE_FACTOR
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:182
QgsFilterLineEdit::storeState
void storeState()
Stores the current state of the line edit (selection and cursor position)
Definition: qgsfilterlineedit.cpp:217
QgsFilterLineEdit::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *e) override
Definition: qgsfilterlineedit.cpp:97
QgsAnimatedIcon
Animated icon is keeping an animation running if there are listeners connected to frameChanged.
Definition: qgsanimatedicon.h:31
QgsFilterLineEdit::event
bool event(QEvent *event) override
Reimplemented to enable/disable the clear action depending on read-only status.
Definition: qgsfilterlineedit.cpp:209
QgsFilterLineEdit::focusInEvent
void focusInEvent(QFocusEvent *e) override
Definition: qgsfilterlineedit.cpp:88
QgsFilterLineEdit::isNull
bool isNull() const
Determine if the current text represents null.
Definition: qgsfilterlineedit.h:185
QgsFilterLineEdit::selectOnFocus
bool selectOnFocus() const
Will select all text when this widget receives the focus.
Definition: qgsfilterlineedit.cpp:150
qgsanimatedicon.h
QgsFilterLineEdit::cleared
void cleared()
Emitted when the widget is cleared.
QgsFilterLineEdit::setShowClearButton
void setShowClearButton(bool visible)
Sets whether the widget's clear button is visible.
Definition: qgsfilterlineedit.cpp:43
QgsFilterLineEdit::showSpinner
bool showSpinner
Definition: qgsfilterlineedit.h:58