QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
29QgsFilterLineEdit::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 const 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 const 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
65void QgsFilterLineEdit::setDefaultValue( const QString &defaultValue )
66{
67 if ( defaultValue == mDefaultValue )
68 return;
69
70 mDefaultValue = defaultValue;
71 updateClearIcon();
72}
73
74void QgsFilterLineEdit::updateClearIcon()
75{
76 const bool showClear = shouldShowClear();
77 if ( showClear && !mClearAction )
78 {
79 mClearAction = new QAction( mClearIcon, QString(), this );
80 mClearAction->setCheckable( false );
81 addAction( mClearAction, QLineEdit::TrailingPosition );
82 connect( mClearAction, &QAction::triggered, this, &QgsFilterLineEdit::clearValue );
83 }
84 else if ( !showClear && mClearAction )
85 {
86 // pretty freakin weird... seems the deleteLater call on the mClearAction
87 // isn't sufficient to actually remove the action from the line edit, and
88 // a kind of "ghost" action gets left behind... resulting in duplicate
89 // clear actions appearing if later we re-create the action.
90 // in summary: don't remove this "removeAction" call!
91 removeAction( mClearAction );
92 mClearAction->deleteLater();
93 mClearAction = nullptr;
94 }
95}
96
97void QgsFilterLineEdit::focusInEvent( QFocusEvent *e )
98{
99 QLineEdit::focusInEvent( e );
100 if ( e->reason() == Qt::MouseFocusReason && ( isNull() || mSelectOnFocus ) )
101 {
102 mWaitingForMouseRelease = true;
103 }
104}
105
107{
108 QLineEdit::mouseReleaseEvent( e );
109 if ( mWaitingForMouseRelease )
110 {
111 mWaitingForMouseRelease = false;
112 selectAll();
113 }
114}
115
117{
118 switch ( mClearMode )
119 {
120 case ClearToNull:
121 setText( mNullValue );
122 selectAll();
123 break;
124
125 case ClearToDefault:
126 setText( mDefaultValue );
127 break;
128 }
129
130 setModified( true );
131 emit cleared();
132}
133
134void QgsFilterLineEdit::onTextChanged( const QString &text )
135{
136 updateClearIcon();
137
138 if ( isNull() )
139 {
140 setStyleSheet( QStringLiteral( "QLineEdit { font: italic; color: gray; } %1" ).arg( mStyleSheet ) );
141 emit valueChanged( QString() );
142 }
143 else
144 {
145 setStyleSheet( mStyleSheet );
146 emit valueChanged( text );
147 }
148}
149
150void QgsFilterLineEdit::updateBusySpinner()
151{
152 if ( !mBusySpinnerAction )
153 {
154 mBusySpinnerAction = addAction( mBusySpinnerAnimatedIcon->icon(), QLineEdit::TrailingPosition );
155 }
156 mBusySpinnerAction->setIcon( mBusySpinnerAnimatedIcon->icon() );
157}
158
160{
161 return mSelectOnFocus;
162}
163
164void QgsFilterLineEdit::setSelectOnFocus( bool selectOnFocus )
165{
166 if ( mSelectOnFocus == selectOnFocus )
167 return;
168
169 mSelectOnFocus = selectOnFocus;
171}
172
174{
175 return mShowSpinner;
176}
177
178void QgsFilterLineEdit::setShowSpinner( bool showSpinner )
179{
180
181 if ( showSpinner == mShowSpinner )
182 return;
183
184 if ( showSpinner )
185 {
186 if ( !mBusySpinnerAnimatedIcon )
187 mBusySpinnerAnimatedIcon = new QgsAnimatedIcon( QgsApplication::iconPath( QStringLiteral( "/mIconLoading.gif" ) ), this );
188
189 mBusySpinnerAnimatedIcon->connectFrameChanged( this, &QgsFilterLineEdit::updateBusySpinner );
190 }
191 else
192 {
193 mBusySpinnerAnimatedIcon->disconnectFrameChanged( this, &QgsFilterLineEdit::updateBusySpinner );
194 removeAction( mBusySpinnerAction );
195 mBusySpinnerAction = nullptr;
196 }
197
198 mShowSpinner = showSpinner;
199 emit showSpinnerChanged();
200}
201
202bool QgsFilterLineEdit::shouldShowClear() const
203{
204 if ( !isEnabled() || isReadOnly() || !mClearButtonVisible )
205 return false;
206
207 switch ( mClearMode )
208 {
209 case ClearToNull:
210 return !isNull();
211
212 case ClearToDefault:
213 return value() != mDefaultValue;
214 }
215 return false; //avoid warnings
216}
217
218bool QgsFilterLineEdit::event( QEvent *event )
219{
220 if ( event->type() == QEvent::ReadOnlyChange || event->type() == QEvent::EnabledChange )
221 updateClearIcon();
222
223 return QLineEdit::event( event );
224}
225
227{
228 mLineEditState.text = text();
229 mLineEditState.selectionStart = selectionStart();
230 mLineEditState.selectionLength = selectedText().length();
231 mLineEditState.cursorPosition = cursorPosition();
232 mLineEditState.hasStateStored = true;
233}
234
236{
237 setText( mLineEditState.text );
238 setCursorPosition( mLineEditState.cursorPosition );
239 if ( mLineEditState.selectionStart > -1 )
240 setSelection( mLineEditState.selectionStart, mLineEditState.selectionLength );
241 mLineEditState.hasStateStored = false;
242}
243
245void QgsSpinBoxLineEdit::focusInEvent( QFocusEvent *e )
246{
248 if ( isNull() )
249 {
250 clear();
251 }
252}
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:2304
Animated icon is keeping an animation running if there are listeners connected to frameChanged.
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.
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...
QIcon icon() const
Gets the icons representation in the current frame.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
void focusInEvent(QFocusEvent *e) override
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)
void selectOnFocusChanged()
Will select all text when this widget receives the focus.
void showSpinnerChanged()
Show a spinner icon.
virtual void clearValue()
Clears the widget and resets it to the null value.
@ ClearToNull
Reset value to null.
@ ClearToDefault
Reset value to default value (see defaultValue() )
bool isNull() const
Determine if the current text represents null.
bool selectOnFocus() const
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 setShowClearButton(bool visible)
Sets whether the widget's clear button is visible.
QgsFilterLineEdit(QWidget *parent=nullptr, const QString &nullValue=QString())
Constructor for QgsFilterLineEdit.
void setSelectOnFocus(bool selectOnFocus)
Will select all text when this widget receives the focus.
void mouseReleaseEvent(QMouseEvent *e) override
void cleared()
Emitted when the widget is cleared.
void setDefaultValue(const QString &defaultValue)
Sets the default value for the widget.
void setShowSpinner(bool showSpinner)
Show a spinner icon.
bool event(QEvent *event) override
Reimplemented to enable/disable the clear action depending on read-only status.
void valueChanged(const QString &value)
Same as textChanged() but with support for null values.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.