QGIS API Documentation  3.2.0-Bonn (bc43194)
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 <QAction>
23 #include <QToolButton>
24 #include <QStyle>
25 #include <QFocusEvent>
26 #include <QPainter>
27 
28 QgsFilterLineEdit::QgsFilterLineEdit( QWidget *parent, const QString &nullValue )
29  : QLineEdit( parent )
30  , mNullValue( nullValue )
31 {
32  // icon size is about 2/3 height of text, but minimum size of 16
33  int iconSize = std::floor( std::max( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 0.75, 16.0 ) );
34 
35  mClearIcon.addPixmap( QgsApplication::getThemeIcon( "/mIconClearText.svg" ).pixmap( QSize( iconSize, iconSize ) ), QIcon::Normal, QIcon::On );
36  mClearIcon.addPixmap( QgsApplication::getThemeIcon( "/mIconClearTextHover.svg" ).pixmap( QSize( iconSize, iconSize ) ), QIcon::Selected, QIcon::On );
37 
38  connect( this, &QLineEdit::textChanged, this,
39  &QgsFilterLineEdit::onTextChanged );
40 }
41 
43 {
44  mClearButtonVisible = visible;
45  updateClearIcon();
46 }
47 
49 {
50  if ( visible && !mSearchAction )
51  {
52  QIcon searchIcon = QgsApplication::getThemeIcon( "/search.svg" );
53  mSearchAction = new QAction( searchIcon, QString(), this );
54  mSearchAction->setCheckable( false );
55  addAction( mSearchAction, QLineEdit::LeadingPosition );
56  }
57  else if ( !visible && mSearchAction )
58  {
59  mSearchAction->deleteLater();
60  mSearchAction = nullptr;
61  }
62 }
63 
64 void QgsFilterLineEdit::updateClearIcon()
65 {
66  bool showClear = shouldShowClear();
67  if ( showClear && !mClearAction )
68  {
69  mClearAction = new QAction( mClearIcon, QString(), this );
70  mClearAction->setCheckable( false );
71  addAction( mClearAction, QLineEdit::TrailingPosition );
72  connect( mClearAction, &QAction::triggered, this, &QgsFilterLineEdit::clearValue );
73  }
74  else if ( !showClear && mClearAction )
75  {
76  // pretty freakin weird... seems the deleteLater call on the mClearAction
77  // isn't sufficient to actually remove the action from the line edit, and
78  // a kind of "ghost" action gets left behind... resulting in duplicate
79  // clear actions appearing if later we re-create the action.
80  // in summary: don't remove this "removeAction" call!
81  removeAction( mClearAction );
82  mClearAction->deleteLater();
83  mClearAction = nullptr;
84  }
85 }
86 
87 void QgsFilterLineEdit::focusInEvent( QFocusEvent *e )
88 {
89  QLineEdit::focusInEvent( e );
90  if ( e->reason() == Qt::MouseFocusReason && ( isNull() || mSelectOnFocus ) )
91  {
92  mFocusInEvent = true;
93  selectAll();
94  }
95 }
96 
98 {
99  switch ( mClearMode )
100  {
101  case ClearToNull:
102  setText( mNullValue );
103  selectAll();
104  break;
105 
106  case ClearToDefault:
107  setText( mDefaultValue );
108  break;
109  }
110 
111  setModified( true );
112  emit cleared();
113 }
114 
115 void QgsFilterLineEdit::onTextChanged( const QString &text )
116 {
117  updateClearIcon();
118 
119  if ( isNull() )
120  {
121  setStyleSheet( QStringLiteral( "QLineEdit { font: italic; color: gray; } %1" ).arg( mStyleSheet ) );
122  emit valueChanged( QString() );
123  }
124  else
125  {
126  setStyleSheet( mStyleSheet );
127  emit valueChanged( text );
128  }
129 }
130 
131 void QgsFilterLineEdit::updateBusySpinner()
132 {
133  if ( !mBusySpinnerAction )
134  {
135  mBusySpinnerAction = addAction( mBusySpinnerAnimatedIcon->icon(), QLineEdit::TrailingPosition );
136  }
137  mBusySpinnerAction->setIcon( mBusySpinnerAnimatedIcon->icon() );
138 }
139 
141 {
142  return mSelectOnFocus;
143 }
144 
146 {
147  if ( mSelectOnFocus == selectOnFocus )
148  return;
149 
150  mSelectOnFocus = selectOnFocus;
151  emit selectOnFocusChanged();
152 }
153 
155 {
156  return mShowSpinner;
157 }
158 
160 {
161 
162  if ( showSpinner == mShowSpinner )
163  return;
164 
165  if ( showSpinner )
166  {
167  if ( !mBusySpinnerAnimatedIcon )
168  mBusySpinnerAnimatedIcon = new QgsAnimatedIcon( QgsApplication::iconPath( QStringLiteral( "/mIconLoading.gif" ) ), this );
169 
170  mBusySpinnerAnimatedIcon->connectFrameChanged( this, &QgsFilterLineEdit::updateBusySpinner );
171  }
172  else
173  {
174  mBusySpinnerAnimatedIcon->disconnectFrameChanged( this, &QgsFilterLineEdit::updateBusySpinner );
175  removeAction( mBusySpinnerAction );
176  mBusySpinnerAction = nullptr;
177  }
178 
179  mShowSpinner = showSpinner;
180  emit showSpinnerChanged();
181 }
182 
183 bool QgsFilterLineEdit::shouldShowClear() const
184 {
185  if ( !isEnabled() || isReadOnly() || !mClearButtonVisible )
186  return false;
187 
188  switch ( mClearMode )
189  {
190  case ClearToNull:
191  return !isNull();
192 
193  case ClearToDefault:
194  return value() != mDefaultValue;
195  }
196  return false; //avoid warnings
197 }
198 
200 {
201  if ( event->type() == QEvent::ReadOnlyChange )
202  updateClearIcon();
203 
204  return QLineEdit::event( event );;
205 }
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:151
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.
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
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.