dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
longlongspinbox.cpp
Go to the documentation of this file.
1 
12 /*
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version approved by the KDE Free Qt Foundation.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  * for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, see <http://www.gnu.org/licenses/>
25  *
26  * Additional note on redistribution: The copyright and license notices above
27  * must be maintained in each individual source file that is a derivative work
28  * of this source file; otherwise redistribution is prohibited.
29  */
30 
31 #include "longlongspinbox.h"
32 
33 #include <QApplication>
34 #include <QEvent>
35 #include <QLineEdit>
36 #include <QStyle>
37 #include <QStyleOptionSpinBox>
38 
39 #include <limits>
40 
42  : QAbstractSpinBox(parent), m_value(0), m_singleStep(1), m_min(0), m_max(100),
43  m_displayBase(10), m_showGroupSeparator(false)
44 
45 {
46  setInputMethodHints(Qt::ImhFormattedNumbersOnly);
47 
48  connect(lineEdit(), &QLineEdit::textChanged, this, &LongLongSpinBox::lineEditChanged, Qt::UniqueConnection);
49 }
50 
52 
53 qint64 LongLongSpinBox::value() const
54 {
55  return m_value;
56 }
57 
58 void LongLongSpinBox::setValue(qint64 val)
59 {
60  if (val != m_value) {
61  m_value = val;
62  updateEdit();
63  emit valueChanged(m_value);
64  emit valueChanged(textFromValue(m_value));
65  }
66 }
67 
68 QString LongLongSpinBox::prefix() const
69 {
70  return m_prefix;
71 }
72 
73 void LongLongSpinBox::setPrefix(const QString &prefix)
74 {
75  m_prefix = prefix;
76  updateEdit();
77  m_cachedMinSize = QSize();
78  updateGeometry();
79 }
80 
81 QString LongLongSpinBox::suffix() const
82 {
83  return m_suffix;
84 }
85 
86 void LongLongSpinBox::setSuffix(const QString &suffix)
87 {
88  m_suffix = suffix;
89  updateEdit();
90  m_cachedMinSize = QSize();
91  updateGeometry();
92 }
93 
95 {
96  return stripped(text());
97 }
98 
100 {
101  return m_singleStep;
102 }
103 
105 {
106  if (val >= 0)
107  m_singleStep = val;
108 }
109 
111 {
112  return m_min;
113 }
114 
116 {
117  setRange(min, m_max < min ? min : m_max);
118 }
119 
121 {
122  return m_min;
123 }
124 
126 {
127  setRange(max < m_min ? max : m_min, max);
128 }
129 
130 void LongLongSpinBox::setRange(qint64 min, qint64 max)
131 {
132  m_min = min;
133  m_max = max < min ? min : max;
134  setValue(qBound(m_min, m_value, m_max));
135  m_cachedMinSize = QSize();
136 }
137 
139 {
140  return m_displayBase;
141 }
142 
144 {
145  if (Q_UNLIKELY(base < 2 || base > 36)) {
146  qWarning("LongLongSpinBox::setDisplayIntegerBase: Invalid base (%d)", base);
147  base = 10;
148  }
149 
150  if (base != m_displayBase) {
151  m_displayBase = base;
152  updateEdit();
153  }
154 
155  m_cachedMinSize = QSize();
156 }
157 
158 QString LongLongSpinBox::textFromValue(qint64 val) const
159 {
160  QString str;
161  if (m_displayBase == 10) {
162  str = locale().toString(val);
163  if (!m_showGroupSeparator
164  && (qAbs(val) >= 1000 || val == std::numeric_limits<qint64>::min()))
165  str.remove(locale().groupSeparator());
166  } else {
167  QLatin1String prefix = val < 0 ? QLatin1String("-") : QLatin1String();
168  str = prefix + QString::number(val, m_displayBase);
169  }
170 
171  return str;
172 }
173 
174 qint64 LongLongSpinBox::valueFromText(const QString &text)
175 {
176  QString copy = text;
177  int pos = lineEdit()->cursorPosition();
178  QValidator::State state = QValidator::Acceptable;
179  return validateAndInterpret(copy, pos, state);
180 }
181 
182 qint64 LongLongSpinBox::validateAndInterpret(QString &input, int &pos,
183  QValidator::State &state) const
184 {
185  QString copy = stripped(input, &pos);
186  state = QValidator::Acceptable;
187  qint64 num = m_min;
188 
189  if (m_max != m_min && (copy.isEmpty()
190  || (m_min < 0 && copy == QLatin1String("-"))
191  || (m_max >= 0 && copy == QLatin1String("+")))) {
192  state = QValidator::Intermediate;
193  } else if (copy.startsWith(QLatin1Char('-')) && m_min >= 0) {
194  state = QValidator::Invalid;
195  } else {
196  bool ok = false;
197  if (m_displayBase == 10) {
198  num = locale().toLongLong(copy, &ok);
199  if (!ok && copy.contains(locale().groupSeparator())
200  && (m_max >= 1000 || m_min <= - 1000)) {
201  QString copy2 = copy;
202  copy2.remove(locale().groupSeparator());
203  num = locale().toLongLong(copy2, &ok);
204  }
205  } else {
206  num = copy.toLongLong(&ok, m_displayBase);
207  }
208 
209  if (!ok) {
210  state = QValidator::Invalid;
211  } else if (num >= m_min && num <= m_max) {
212  state = QValidator::Acceptable;
213  } else if (m_max == m_min) {
214  state = QValidator::Invalid;
215  } else {
216  if ((num >= 0 && num > m_max) || (num < 0 && num < m_min))
217  state = QValidator::Invalid;
218  else
219  state = QValidator::Intermediate;
220  }
221  }
222 
223  if (state != QValidator::Acceptable)
224  num = m_max > 0 ? m_min : m_max;
225 
226  input = m_prefix + copy + m_suffix;
227 
228  return num;
229 }
230 
231 QValidator::State LongLongSpinBox::validate(QString &text, int &pos) const
232 {
233  QValidator::State state;
234  validateAndInterpret(text, pos, state);
235  return state;
236 }
237 
238 void LongLongSpinBox::fixup(QString &input) const
239 {
240  if (!isGroupSeparatorShown())
241  input.remove(locale().groupSeparator());
242 }
243 
244 QString LongLongSpinBox::stripped(const QString &t, int *pos) const
245 {
246  QStringRef text(&t);
247 
248  if (specialValueText().size() == 0 || text != specialValueText()) {
249  int from = 0;
250  int size = text.size();
251  bool changed = false;
252  if (m_prefix.size() && text.startsWith(m_prefix)) {
253  from += m_prefix.size();
254  size -= from;
255  changed = true;
256  }
257  if (m_suffix.size() && text.endsWith(m_suffix)) {
258  size -= suffix().size();
259  changed = true;
260  }
261  if (changed)
262  text = text.mid(from, size);
263  }
264 
265  const int s = text.size();
266  text = text.trimmed();
267  if (pos)
268  (*pos) -= (s - text.size());
269 
270  return text.toString();
271 }
272 
274 {
275  const bool specialValue = specialValueText().size() > 0;
276  const QString newText = specialValue ? specialValueText() :
277  m_prefix + textFromValue(m_value) + m_suffix;
278  if (newText == lineEdit()->displayText())
279  return;
280 
281  const bool empty = lineEdit()->text().isEmpty();
282  int cursor = lineEdit()->cursorPosition();
283  int selsize = lineEdit()->selectedText().size();
284  const QSignalBlocker blocker(lineEdit());
285  lineEdit()->setText(newText);
286 
287  if (!specialValue) {
288  cursor = qBound(m_prefix.size(), cursor, lineEdit()->displayText().size() - m_suffix.size());
289 
290  if (selsize > 0) {
291  lineEdit()->setSelection(cursor, selsize);
292  } else {
293  lineEdit()->setCursorPosition(empty ? m_prefix.size() : cursor);
294  }
295  }
296  update();
297 }
298 
299 QAbstractSpinBox::StepEnabled LongLongSpinBox::stepEnabled() const
300 {
301  QAbstractSpinBox::StepEnabled enabled;
302  if (m_value > m_min)
303  enabled |= StepDownEnabled;
304  if (m_value < m_max)
305  enabled |= StepUpEnabled;
306  return enabled;
307 }
308 
309 void LongLongSpinBox::stepBy(int steps)
310 {
311  setValue(qBound(m_min, m_value + steps, m_max));
312 }
313 
314 void LongLongSpinBox::setLineEdit(QLineEdit *edit)
315 {
316  QAbstractSpinBox::setLineEdit(edit);
317  if (edit) {
318  connect(lineEdit(), &QLineEdit::textChanged, this, &LongLongSpinBox::lineEditChanged, Qt::UniqueConnection);
319  }
320 }
321 
323 {
324  if (keyboardTracking()) {
325  QString tmp = t;
326  int pos = lineEdit()->cursorPosition();
327  QValidator::State state = validate(tmp, pos);
328  if (state == QValidator::Acceptable) {
329  const qint64 v = valueFromText(tmp);
330  setValue(v);
331  }
332  }
333 }
334 
336 {
337  if (m_cachedMinSize.isEmpty()) {
338  ensurePolished();
339 
340  const QFontMetrics fm(fontMetrics());
341  int h = lineEdit()->minimumSizeHint().height();
342 
343  QString s = textFromValue(m_min);
344  QString fixedContent = m_prefix + QStringLiteral(" ") + m_suffix;
345  s.truncate(18);
346  s += fixedContent;
347  int w = fm.width(s);
348  s = textFromValue(m_max);
349  s.truncate(18);
350  s += fixedContent;
351  w = std::max(w, fm.width(s));
352 
353  if (specialValueText().size())
354  w = qMax(w, fm.width(specialValueText()));
355 
356  w += 2; // cursor blinking space
357 
358  QStyleOptionSpinBox opt;
359  initStyleOption(&opt);
360  QSize hint(w, h);
361 
362  m_cachedMinSize = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this)
363  .expandedTo(QApplication::globalStrut());
364  }
365  return m_cachedMinSize;
366 }
367 
368 bool LongLongSpinBox::event(QEvent *event)
369 {
370  switch (event->type()) {
371  case QEvent::FontChange:
372  case QEvent::StyleChange:
373  m_cachedMinSize = QSize();
374  break;
375  default:
376  break;
377  }
378  return QAbstractSpinBox::event(event);
379 }
380 
void setPrefix(const QString &prefix)
QString suffix() const
void setDisplayIntegerBase(int base)
virtual QString textFromValue(qint64 val) const
void setMaximum(qint64 max)
void setMinimum(qint64 min)
void setRange(qint64 min, qint64 max)
virtual StepEnabled stepEnabled() const override
const char t[]
Definition: coreconstants.h:40
QValidator::State validate(QString &input, int &pos) const override
virtual bool event(QEvent *event) override
QString prefix() const
void lineEditChanged(const QString &t)
virtual QSize minimumSizeHint() const override
qint64 minimum() const
qint64 singleStep() const
void setValue(qint64 val)
void fixup(QString &str) const override
LongLongSpinBox(QWidget *parent=nullptr)
void setSuffix(const QString &suffix)
QString stripped(const QString &text, int *pos=nullptr) const
int displayIntegerBase() const
virtual void stepBy(int steps) override
void setSingleStep(qint64 val)
void valueChanged(qint64 val)
qint64 maximum() const
qint64 validateAndInterpret(QString &input, int &pos, QValidator::State &state) const
virtual void setLineEdit(QLineEdit *edit)
virtual qint64 valueFromText(const QString &text)
qint64 value() const
QString cleanText() const