QGIS API Documentation  2.99.0-Master (19b062c)
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 
22 #include <QToolButton>
23 #include <QStyle>
24 #include <QFocusEvent>
25 #include <QPainter>
26 
27 QgsFilterLineEdit::QgsFilterLineEdit( QWidget *parent, const QString &nullValue )
28  : QLineEdit( parent )
29  , mNullValue( nullValue )
30 {
31  // need mouse tracking to handle cursor changes
32  setMouseTracking( true );
33 
34  QIcon clearIcon = QgsApplication::getThemeIcon( "/mIconClearText.svg" );
35 
36  // icon size is about 2/3 height of text, but minimum size of 16
37  int iconSize = std::floor( std::max( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 0.75, 16.0 ) );
38 
39  mClearIconSize = QSize( iconSize, iconSize );
40  mClearIconPixmap = clearIcon.pixmap( mClearIconSize );
41  QIcon hoverIcon = QgsApplication::getThemeIcon( "/mIconClearTextHover.svg" );
42  mClearHoverPixmap = hoverIcon.pixmap( mClearIconSize );
43 
44  QIcon searchIcon = QgsApplication::getThemeIcon( "/search.svg" );
45  mSearchIconSize = QSize( iconSize, iconSize );
46  mSearchIconPixmap = searchIcon.pixmap( mSearchIconSize );
47 
48  // Make some space for the clear icon
49  QMargins margins( textMargins( ) );
50  margins.setRight( iconSize );
51  setTextMargins( margins );
52 
53  connect( this, &QLineEdit::textChanged, this,
54  &QgsFilterLineEdit::onTextChanged );
55 }
56 
58 {
59  bool changed = mClearButtonVisible != visible;
60  mClearButtonVisible = visible;
61  if ( !visible )
62  mClearHover = false;
63 
64  if ( changed )
65  update();
66 }
67 
69 {
70  bool changed = mSearchIconVisible != visible;
71  if ( changed )
72  {
73  mSearchIconVisible = visible;
74  update();
75  }
76 }
77 
78 void QgsFilterLineEdit::mousePressEvent( QMouseEvent *e )
79 {
80  if ( !mFocusInEvent )
81  QLineEdit::mousePressEvent( e );
82  else
83  mFocusInEvent = false;
84 
85  if ( shouldShowClear() && clearRect().contains( e->pos() ) )
86  {
87  clearValue();
88  }
89 }
90 
91 void QgsFilterLineEdit::mouseMoveEvent( QMouseEvent *e )
92 {
93  QLineEdit::mouseMoveEvent( e );
94  if ( shouldShowClear() && clearRect().contains( e->pos() ) )
95  {
96  if ( !mClearHover )
97  {
98  setCursor( Qt::ArrowCursor );
99  mClearHover = true;
100  update();
101  }
102  }
103  else if ( mClearHover )
104  {
105  setCursor( Qt::IBeamCursor );
106  mClearHover = false;
107  update();
108  }
109 }
110 
111 void QgsFilterLineEdit::focusInEvent( QFocusEvent *e )
112 {
113  QLineEdit::focusInEvent( e );
114  if ( e->reason() == Qt::MouseFocusReason && ( isNull() || mSelectOnFocus ) )
115  {
116  mFocusInEvent = true;
117  selectAll();
118  }
119 }
120 
122 {
123  switch ( mClearMode )
124  {
125  case ClearToNull:
126  setText( mNullValue );
127  selectAll();
128  break;
129 
130  case ClearToDefault:
131  setText( mDefaultValue );
132  break;
133  }
134 
135  if ( mClearHover )
136  {
137  setCursor( Qt::IBeamCursor );
138  mClearHover = false;
139  }
140 
141  setModified( true );
142  emit cleared();
143 }
144 
145 void QgsFilterLineEdit::paintEvent( QPaintEvent *e )
146 {
147  QLineEdit::paintEvent( e );
148  if ( shouldShowClear() )
149  {
150  QRect r = clearRect();
151  QPainter p( this );
152  if ( mClearHover )
153  p.drawPixmap( r.left(), r.top(), mClearHoverPixmap );
154  else
155  p.drawPixmap( r.left(), r.top(), mClearIconPixmap );
156  }
157 
158  if ( mSearchIconVisible && !shouldShowClear() )
159  {
160  QRect r = searchRect();
161  QPainter p( this );
162  p.drawPixmap( r.left(), r.top(), mSearchIconPixmap );
163  }
164 
165  if ( mShowSpinner )
166  {
167  QRect r = busySpinnerRect();
168  QPainter p( this );
169  p.drawPixmap( r.left(), r.top(), mBusySpinner->icon().pixmap( r.size() ) );
170  }
171 }
172 
174 {
175  if ( mClearHover )
176  {
177  mClearHover = false;
178  update();
179  }
180 
181  QLineEdit::leaveEvent( e );
182 }
183 
184 void QgsFilterLineEdit::onTextChanged( const QString &text )
185 {
186  if ( isNull() )
187  {
188  setStyleSheet( QStringLiteral( "QLineEdit { font: italic; color: gray; } %1" ).arg( mStyleSheet ) );
189  emit valueChanged( QString() );
190  }
191  else
192  {
193  setStyleSheet( mStyleSheet );
194  emit valueChanged( text );
195  }
196 
197  if ( mClearHover && !shouldShowClear() )
198  {
199  setCursor( Qt::IBeamCursor );
200  mClearHover = false;
201  }
202 }
203 
204 void QgsFilterLineEdit::updateBusySpinner()
205 {
206  update();
207 }
208 
210 {
211  return mSelectOnFocus;
212 }
213 
215 {
216  if ( mSelectOnFocus == selectOnFocus )
217  return;
218 
219  mSelectOnFocus = selectOnFocus;
220  emit selectOnFocusChanged();
221 }
222 
224 {
225  return mShowSpinner;
226 }
227 
229 {
230  if ( showSpinner == mShowSpinner )
231  return;
232 
233  if ( showSpinner )
234  {
235  if ( !mBusySpinner )
236  mBusySpinner = new QgsAnimatedIcon( QgsApplication::iconPath( QStringLiteral( "/mIconLoading.gif" ) ), this );
237 
238  mBusySpinner->connectFrameChanged( this, &QgsFilterLineEdit::updateBusySpinner );
239  }
240  else
241  {
242  mBusySpinner->disconnectFrameChanged( this, &QgsFilterLineEdit::updateBusySpinner );
243  update();
244  }
245 
246  mShowSpinner = showSpinner;
247  emit showSpinnerChanged();
248 }
249 
250 bool QgsFilterLineEdit::shouldShowClear() const
251 {
252  if ( !isEnabled() || isReadOnly() || !mClearButtonVisible )
253  return false;
254 
255  switch ( mClearMode )
256  {
257  case ClearToNull:
258  return !isNull();
259 
260  case ClearToDefault:
261  return value() != mDefaultValue;
262  }
263  return false; //avoid warnings
264 }
265 
266 QRect QgsFilterLineEdit::clearRect() const
267 {
268  int frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
269  return QRect( rect().right() - frameWidth * 2 - mClearIconSize.width(),
270  ( rect().bottom() + 1 - mClearIconSize.height() ) / 2,
271  mClearIconSize.width(),
272  mClearIconSize.height() );
273 }
274 
275 QRect QgsFilterLineEdit::busySpinnerRect() const
276 {
277  int frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
278 
279  int offset = shouldShowClear() ? mClearIconSize.width() + frameWidth * 2 : frameWidth;
280 
281  return QRect( rect().right() - offset - mClearIconSize.width(),
282  ( rect().bottom() + 1 - mClearIconSize.height() ) / 2,
283  mClearIconSize.width(),
284  mClearIconSize.height() );
285 }
286 
287 QRect QgsFilterLineEdit::searchRect() const
288 {
289  int frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
290  return QRect( rect().left() + frameWidth * 2,
291  ( rect().bottom() + 1 - mSearchIconSize.height() ) / 2,
292  mSearchIconSize.width(),
293  mSearchIconSize.height() );
294 }
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 leaveEvent(QEvent *e) override
void setSelectOnFocus(bool selectOnFocus)
Will select all text when this widget receives the focus.
void mouseMoveEvent(QMouseEvent *e) override
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:138
void setShowSpinner(bool showSpinner)
Show a spinner icon.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
void paintEvent(QPaintEvent *e) override
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.
void mousePressEvent(QMouseEvent *e) override
Reset value to default value (see defaultValue() )
virtual void clearValue()
Clears the widget and resets it to the null value.
bool selectOnFocus() const
Will select all text when this widget receives the focus.
bool showSpinner() const
Show a spinner icon.
void focusInEvent(QFocusEvent *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
Get 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...
QgsFilterLineEdit(QWidget *parent=0, const QString &nullValue=QString())
Constructor for QgsFilterLineEdit.
QString value() const
Returns the text of this edit with support for handling null values.