QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 
156 {
157  if ( mSelectOnFocus == selectOnFocus )
158  return;
159 
160  mSelectOnFocus = selectOnFocus;
161  emit selectOnFocusChanged();
162 }
163 
165 {
166  return mShowSpinner;
167 }
168 
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 
210 {
211  if ( event->type() == QEvent::ReadOnlyChange || event->type() == QEvent::EnabledChange )
212  updateClearIcon();
213 
214  return QLineEdit::event( event );
215 }
216 
218 void QgsSpinBoxLineEdit::focusInEvent( QFocusEvent *e )
219 {
221  if ( isNull() )
222  {
223  clear();
224  }
225 }
void valueChanged(const QString &value)
Same as textChanged() but with support for null values.
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...
void setSelectOnFocus(bool selectOnFocus)
Will select all text when this widget receives the focus.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:154
void setShowSpinner(bool showSpinner)
Show a spinner icon.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
void showSpinnerChanged()
Show a spinner icon.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void selectOnFocusChanged()
Will select all text when this widget receives the focus.
void setShowSearchIcon(bool visible)
Define if a search icon shall be shown on the left of the image when no text is entered.
QgsFilterLineEdit(QWidget *parent=nullptr, const QString &nullValue=QString())
Constructor for QgsFilterLineEdit.
Reset value to default value (see defaultValue() )
virtual void clearValue()
Clears the widget and resets it to the null value.
bool event(QEvent *event) override
Reimplemented to enable/disable the clear action depending on read-only status.
bool selectOnFocus() const
Will select all text when this widget receives the focus.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window&#39;s toolbar icons.
bool showSpinner() const
Show a spinner icon.
void focusInEvent(QFocusEvent *e) override
void mouseReleaseEvent(QMouseEvent *e) override
void cleared()
Emitted when the widget is cleared.
Animated icon is keeping an animation running if there are listeners connected to frameChanged...
QIcon icon() const
Gets the icons representation in the current frame.
bool isNull() const
Determine if the current text represents null.
void setShowClearButton(bool visible)
Sets whether the widget&#39;s clear button is visible.
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...
QString value() const
Returns the text of this edit with support for handling null values.