QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgsspinbox.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsspinbox.cpp
3  --------------------------------------
4  Date : 09.2014
5  Copyright : (C) 2014 Denis Rouzaud
6  Email : [email protected]
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include <QLineEdit>
17 #include <QMouseEvent>
18 #include <QSettings>
19 #include <QStyle>
20 
21 #include "qgsspinbox.h"
22 #include "qgsexpression.h"
23 #include "qgsapplication.h"
24 #include "qgslogger.h"
25 #include "qgsfilterlineedit.h"
26 
27 #define CLEAR_ICON_SIZE 16
28 
29 // This is required because private implementation of
30 // QAbstractSpinBoxPrivate checks for specialText emptiness
31 // and skips specialText handling if it's empty
32 QString QgsSpinBox::SPECIAL_TEXT_WHEN_EMPTY = QChar( 0x2063 );
33 
34 
35 QgsSpinBox::QgsSpinBox( QWidget *parent )
36  : QSpinBox( parent )
37 {
38  mLineEdit = new QgsSpinBoxLineEdit();
39  setLineEdit( mLineEdit );
40 
41  QSize msz = minimumSizeHint();
42  setMinimumSize( msz.width() + CLEAR_ICON_SIZE + 9 + frameWidth() * 2 + 2,
43  std::max( msz.height(), CLEAR_ICON_SIZE + frameWidth() * 2 + 2 ) );
44 
45  connect( mLineEdit, &QgsFilterLineEdit::cleared, this, &QgsSpinBox::clear );
46  connect( this, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsSpinBox::changed );
47 }
48 
50 {
51  mShowClearButton = showClearButton;
52  mLineEdit->setShowClearButton( showClearButton );
53 }
54 
55 void QgsSpinBox::setExpressionsEnabled( const bool enabled )
56 {
57  mExpressionsEnabled = enabled;
58 }
59 
60 void QgsSpinBox::changeEvent( QEvent *event )
61 {
62  QSpinBox::changeEvent( event );
63 
64  if ( event->type() == QEvent::FontChange )
65  {
66  lineEdit()->setFont( font() );
67  }
68 
69  mLineEdit->setShowClearButton( shouldShowClearForValue( value() ) );
70 }
71 
72 void QgsSpinBox::paintEvent( QPaintEvent *event )
73 {
74  mLineEdit->setShowClearButton( shouldShowClearForValue( value() ) );
75  QSpinBox::paintEvent( event );
76 }
77 
78 void QgsSpinBox::wheelEvent( QWheelEvent *event )
79 {
80  int step = singleStep();
81  if ( event->modifiers() & Qt::ControlModifier )
82  {
83  // ctrl modifier results in finer increments - 10% of usual step
84  int newStep = step / 10;
85  // step should be at least 1
86  newStep = std::max( newStep, 1 );
87 
88  setSingleStep( newStep );
89 
90  // clear control modifier before handing off event - Qt uses it for unwanted purposes
91  // (*increasing* step size, whereas QGIS UX convention is that control modifier
92  // results in finer changes!)
93  event->setModifiers( event->modifiers() & ~Qt::ControlModifier );
94  }
95  QSpinBox::wheelEvent( event );
96  setSingleStep( step );
97 }
98 
99 void QgsSpinBox::timerEvent( QTimerEvent *event )
100 {
101  // Process all events, which may include a mouse release event
102  // Only allow the timer to trigger additional value changes if the user
103  // has in fact held the mouse button, rather than the timer expiry
104  // simply appearing before the mouse release in the event queue
105  qApp->processEvents();
106  if ( QApplication::mouseButtons() & Qt::LeftButton )
107  QSpinBox::timerEvent( event );
108 }
109 
110 void QgsSpinBox::changed( int value )
111 {
112  mLineEdit->setShowClearButton( shouldShowClearForValue( value ) );
113 }
114 
116 {
117  setValue( clearValue() );
118  if ( mLineEdit->isNull() )
119  mLineEdit->clear();
120 }
121 
122 void QgsSpinBox::setClearValue( int customValue, const QString &specialValueText )
123 {
124  mClearValueMode = CustomValue;
125  mCustomClearValue = customValue;
126 
127  if ( !specialValueText.isEmpty() )
128  {
129  int v = value();
130  clear();
131  setSpecialValueText( specialValueText );
132  setValue( v );
133  }
134 }
135 
136 void QgsSpinBox::setClearValueMode( QgsSpinBox::ClearValueMode mode, const QString &specialValueText )
137 {
138  mClearValueMode = mode;
139  mCustomClearValue = 0;
140 
141  if ( !specialValueText.isEmpty() )
142  {
143  int v = value();
144  clear();
145  setSpecialValueText( specialValueText );
146  setValue( v );
147  }
148 }
149 
150 int QgsSpinBox::clearValue() const
151 {
152  if ( mClearValueMode == MinimumValue )
153  return minimum();
154  else if ( mClearValueMode == MaximumValue )
155  return maximum();
156  else
157  return mCustomClearValue;
158 }
159 
160 void QgsSpinBox::setLineEditAlignment( Qt::Alignment alignment )
161 {
162  mLineEdit->setAlignment( alignment );
163 }
164 
165 void QgsSpinBox::setSpecialValueText( const QString &txt )
166 {
167  if ( txt.isEmpty() )
168  {
169  QSpinBox::setSpecialValueText( SPECIAL_TEXT_WHEN_EMPTY );
170  mLineEdit->setNullValue( SPECIAL_TEXT_WHEN_EMPTY );
171  }
172  else
173  {
174  QSpinBox::setSpecialValueText( txt );
175  mLineEdit->setNullValue( txt );
176  }
177 }
178 
179 int QgsSpinBox::valueFromText( const QString &text ) const
180 {
181  if ( !mExpressionsEnabled )
182  {
183  return QSpinBox::valueFromText( text );
184  }
185 
186  QString trimmedText = stripped( text );
187  if ( trimmedText.isEmpty() )
188  {
189  return mShowClearButton ? clearValue() : value();
190  }
191 
192  return std::round( QgsExpression::evaluateToDouble( trimmedText, value() ) );
193 }
194 
195 QValidator::State QgsSpinBox::validate( QString &input, int &pos ) const
196 {
197  if ( !mExpressionsEnabled )
198  {
199  QValidator::State r = QSpinBox::validate( input, pos );
200  return r;
201  }
202 
203  return QValidator::Acceptable;
204 }
205 
206 int QgsSpinBox::frameWidth() const
207 {
208  return style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
209 }
210 
211 bool QgsSpinBox::shouldShowClearForValue( const int value ) const
212 {
213  if ( !mShowClearButton || !isEnabled() )
214  {
215  return false;
216  }
217  return value != clearValue();
218 }
219 
220 QString QgsSpinBox::stripped( const QString &originalText ) const
221 {
222  //adapted from QAbstractSpinBoxPrivate::stripped
223  //trims whitespace, prefix and suffix from spin box text
224  QString text = originalText;
225  if ( specialValueText().isEmpty() || text != specialValueText() )
226  {
227  // Strip SPECIAL_TEXT_WHEN_EMPTY
228  if ( text.contains( SPECIAL_TEXT_WHEN_EMPTY ) )
229  text = text.replace( SPECIAL_TEXT_WHEN_EMPTY, QString() );
230  int from = 0;
231  int size = text.size();
232  bool changed = false;
233  if ( !prefix().isEmpty() && text.startsWith( prefix() ) )
234  {
235  from += prefix().size();
236  size -= from;
237  changed = true;
238  }
239  if ( !suffix().isEmpty() && text.endsWith( suffix() ) )
240  {
241  size -= suffix().size();
242  changed = true;
243  }
244  if ( changed )
245  text = text.mid( from, size );
246  }
247 
248  text = text.trimmed();
249 
250  return text;
251 }
void wheelEvent(QWheelEvent *event) override
Definition: qgsspinbox.cpp:78
void timerEvent(QTimerEvent *event) override
Definition: qgsspinbox.cpp:99
ClearValueMode
Behavior when widget is cleared.
Definition: qgsspinbox.h:62
Reset value to maximum()
Definition: qgsspinbox.h:65
Reset value to custom value (see setClearValue() )
Definition: qgsspinbox.h:66
bool showClearButton() const
Returns whether the widget is showing a clear button.
Definition: qgsspinbox.h:87
static double evaluateToDouble(const QString &text, double fallbackValue)
Attempts to evaluate a text string as an expression to a resultant double value.
QValidator::State validate(QString &input, int &pos) const override
Definition: qgsspinbox.cpp:195
void clear() override
Sets the current value to the value defined by the clear value.
Definition: qgsspinbox.cpp:115
void setShowClearButton(bool showClearButton)
Sets whether the widget will show a clear button.
Definition: qgsspinbox.cpp:49
void setLineEditAlignment(Qt::Alignment alignment)
Set alignment in the embedded line edit widget.
Definition: qgsspinbox.cpp:160
Reset value to minimum()
Definition: qgsspinbox.h:64
QgsSpinBox(QWidget *parent=nullptr)
Constructor for QgsSpinBox.
Definition: qgsspinbox.cpp:35
void setExpressionsEnabled(bool enabled)
Sets if the widget will allow entry of simple expressions, which are evaluated and then discarded...
Definition: qgsspinbox.cpp:55
int clearValue() const
Returns the value used when clear() is called.
void paintEvent(QPaintEvent *event) override
Definition: qgsspinbox.cpp:72
#define CLEAR_ICON_SIZE
Definition: qgsspinbox.cpp:27
int valueFromText(const QString &text) const override
Definition: qgsspinbox.cpp:179
void setClearValueMode(ClearValueMode mode, const QString &clearValueText=QString())
Defines if the clear value should be the minimum or maximum values of the widget or a custom value...
Definition: qgsspinbox.cpp:136
void setClearValue(int customValue, const QString &clearValueText=QString())
Defines the clear value as a custom value and will automatically set the clear value mode to CustomVa...
Definition: qgsspinbox.cpp:122
void cleared()
Emitted when the widget is cleared.
void changeEvent(QEvent *event) override
Definition: qgsspinbox.cpp:60
void setSpecialValueText(const QString &txt)
Set the special-value text to be txt If set, the spin box will display this text instead of a numeric...
Definition: qgsspinbox.cpp:165