Fabcoin Core  0.16.2
P2P Digital Currency
fabcoinamountfield.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2015 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <fabcoinamountfield.h>
6 
7 #include <fabcoinunits.h>
8 #include <styleSheet.h>
9 #include <qvaluecombobox.h>
10 
11 #include <QApplication>
12 #include <QAbstractSpinBox>
13 #include <QHBoxLayout>
14 #include <QKeyEvent>
15 #include <QLineEdit>
16 
20 class AmountSpinBox: public QAbstractSpinBox
21 {
22  Q_OBJECT
23 
24 public:
25  explicit AmountSpinBox(QWidget *parent):
26  QAbstractSpinBox(parent),
28  singleStep(100000), // lius
29  minAmount(0)
30  {
31  setAlignment(Qt::AlignRight);
32 
33  connect(lineEdit(), SIGNAL(textEdited(QString)), this, SIGNAL(valueChanged()));
34  }
35 
36  QValidator::State validate(QString &text, int &pos) const
37  {
38  if(text.isEmpty())
39  return QValidator::Intermediate;
40  bool valid = false;
41  parse(text, &valid);
42  /* Make sure we return Intermediate so that fixup() is called on defocus */
43  return valid ? QValidator::Intermediate : QValidator::Invalid;
44  }
45 
46  void fixup(QString &input) const
47  {
48  bool valid = false;
49  CAmount val = parse(input, &valid);
50  val = qMax(val, minAmount);
51  if(valid)
52  {
54  lineEdit()->setText(input);
55  }
56  }
57 
58  CAmount value(bool *valid_out=0) const
59  {
60  return parse(text(), valid_out);
61  }
62 
63  void setValue(const CAmount& value)
64  {
65  CAmount val = qMax(value, minAmount);
66  lineEdit()->setText(FabcoinUnits::format(currentUnit, val, false, FabcoinUnits::separatorAlways));
67  Q_EMIT valueChanged();
68  }
69 
70  void stepBy(int steps)
71  {
72  bool valid = false;
73  CAmount val = value(&valid);
74  val = val + steps * singleStep;
75  val = qMin(qMax(val, minAmount), FabcoinUnits::maxMoney());
76  setValue(val);
77  }
78 
79  void setDisplayUnit(int unit)
80  {
81  bool valid = false;
82  CAmount val = value(&valid);
83 
84  currentUnit = unit;
85 
86  if(valid)
87  setValue(val);
88  else
89  clear();
90  }
91 
92  void setSingleStep(const CAmount& step)
93  {
94  singleStep = step;
95  }
96 
97  QSize minimumSizeHint() const
98  {
99  if(cachedMinimumSizeHint.isEmpty())
100  {
101  ensurePolished();
102 
103  const QFontMetrics fm(fontMetrics());
104  int h = lineEdit()->minimumSizeHint().height();
106  w += 2; // cursor blinking space
107 
108  QStyleOptionSpinBox opt;
109  initStyleOption(&opt);
110  QSize hint(w, h);
111  QSize extra(35, 6);
112  opt.rect.setSize(hint + extra);
113  extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
114  QStyle::SC_SpinBoxEditField, this).size();
115  // get closer to final result by repeating the calculation
116  opt.rect.setSize(hint + extra);
117  extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
118  QStyle::SC_SpinBoxEditField, this).size();
119  hint += extra;
120  hint.setHeight(h);
121 
122  opt.rect = rect();
123 
124  cachedMinimumSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this)
125  .expandedTo(QApplication::globalStrut());
126  }
127  return cachedMinimumSizeHint;
128  }
129 
130  CAmount minimum() const
131  {
132  return minAmount;
133  }
134 
135  void setMinimum(const CAmount& min)
136  {
137  minAmount = min;
138  Q_EMIT valueChanged();
139  }
140 
141 
142 private:
146  mutable QSize cachedMinimumSizeHint;
147 
153  CAmount parse(const QString &text, bool *valid_out=0) const
154  {
155  CAmount val = 0;
156  bool valid = FabcoinUnits::parse(currentUnit, text, &val);
157  if(valid)
158  {
159  if(val < 0 || val > FabcoinUnits::maxMoney())
160  valid = false;
161  }
162  if(valid_out)
163  *valid_out = valid;
164  return valid ? val : 0;
165  }
166 
167 protected:
168  bool event(QEvent *event)
169  {
170  if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease)
171  {
172  QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
173  if (keyEvent->key() == Qt::Key_Comma)
174  {
175  // Translate a comma into a period
176  QKeyEvent periodKeyEvent(event->type(), Qt::Key_Period, keyEvent->modifiers(), ".", keyEvent->isAutoRepeat(), keyEvent->count());
177  return QAbstractSpinBox::event(&periodKeyEvent);
178  }
179  }
180  return QAbstractSpinBox::event(event);
181  }
182 
183  StepEnabled stepEnabled() const
184  {
185  if (isReadOnly()) // Disable steps when AmountSpinBox is read-only
186  return StepNone;
187  if (text().isEmpty()) // Allow step-up with empty field
188  return StepUpEnabled;
189 
190  StepEnabled rv = 0;
191  bool valid = false;
192  CAmount val = value(&valid);
193  if(valid)
194  {
195  if(val > minAmount)
196  rv |= StepDownEnabled;
197  if(val < FabcoinUnits::maxMoney())
198  rv |= StepUpEnabled;
199  }
200  return rv;
201  }
202 
203 Q_SIGNALS:
204  void valueChanged();
205 };
206 
207 #include <fabcoinamountfield.moc>
208 
210  QWidget(parent),
211  amount(0)
212 {
213  amount = new AmountSpinBox(this);
214  amount->setLocale(QLocale::c());
215  amount->installEventFilter(this);
216  amount->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
217 
218  QHBoxLayout *layout = new QHBoxLayout(this);
219  layout->addWidget(amount);
220  unit = new QValueComboBox(this);
221  unit->setModel(new FabcoinUnits(this));
222  unit->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
223  unit->setMinimumWidth(120);
224  layout->addWidget(unit);
225  layout->setContentsMargins(0,0,0,0);
226 
227  setLayout(layout);
228 
229  setFocusPolicy(Qt::TabFocus);
230  setFocusProxy(amount);
231 
232  // If one if the widgets changes, the combined content changes as well
233  connect(amount, SIGNAL(valueChanged()), this, SIGNAL(valueChanged()));
234  connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int)));
235 
236  // Set default based on configuration
237  unitChanged(unit->currentIndex());
238 }
239 
241 {
242  amount->clear();
243  unit->setCurrentIndex(0);
244 }
245 
247 {
248  amount->setEnabled(fEnabled);
249  unit->setEnabled(fEnabled);
250 }
251 
253 {
254  bool valid = false;
255  value(&valid);
256  setValid(valid);
257  return valid;
258 }
259 
261 {
262  if (valid)
263  amount->setStyleSheet("");
264  else
265  SetObjectStyleSheet(amount, StyleSheetNames::Invalid);
266 }
267 
268 bool FabcoinAmountField::eventFilter(QObject *object, QEvent *event)
269 {
270  if (event->type() == QEvent::FocusIn)
271  {
272  // Clear invalid flag on focus
273  setValid(true);
274  }
275  return QWidget::eventFilter(object, event);
276 }
277 
278 QWidget *FabcoinAmountField::setupTabChain(QWidget *prev)
279 {
280  QWidget::setTabOrder(prev, amount);
281  QWidget::setTabOrder(amount, unit);
282  return unit;
283 }
284 
285 CAmount FabcoinAmountField::value(bool *valid_out) const
286 {
287  return amount->value(valid_out);
288 }
289 
291 {
292  amount->setValue(value);
293 }
294 
296 {
297  amount->setReadOnly(fReadOnly);
298 }
299 
301 {
302  // Use description tooltip for current unit for the combobox
303  unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());
304 
305  // Determine new unit ID
306  int newUnit = unit->itemData(idx, FabcoinUnits::UnitRole).toInt();
307 
308  amount->setDisplayUnit(newUnit);
309 }
310 
312 {
313  unit->setValue(newUnit);
314 }
315 
317 {
318  amount->setSingleStep(step);
319 }
320 
322 {
323  return amount->minimum();
324 }
325 
327 {
328  amount->setMinimum(min);
329 }
CAmount parse(const QString &text, bool *valid_out=0) const
Parse a string into a number of base monetary units and return validity.
bool eventFilter(QObject *object, QEvent *event)
Intercept focus-in event and &#39;,&#39; key presses.
#define SetObjectStyleSheet(object, name)
Definition: styleSheet.h:10
FabcoinAmountField(QWidget *parent=0)
Unit identifier.
Definition: fabcoinunits.h:114
QSpinBox that uses fixed-point numbers internally and uses our own formatting/parsing functions...
void valueChanged()
bool validate()
Perform input validation, mark field as invalid if entered value is not valid.
#define h(i)
Definition: sha.cpp:736
AmountSpinBox(QWidget *parent)
void setSingleStep(const CAmount &step)
Set single step in satoshis.
#define c(i)
static bool parse(int unit, const QString &value, CAmount *val_out)
Parse string to coin amount.
void setDisplayUnit(int unit)
void setReadOnly(bool fReadOnly)
Make read-only.
ExecStats::duration min
Definition: ExecStats.cpp:35
void setValue(const CAmount &value)
int64_t CAmount
Amount in lius (Can be negative)
Definition: amount.h:15
CAmount minimum() const
void fixup(QString &input) const
QSize minimumSizeHint() const
AmountSpinBox * amount
static QString format(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string.
QValidator::State validate(QString &text, int &pos) const
void setValid(bool valid)
Mark current value as invalid in UI.
void stepBy(int steps)
static CAmount maxMoney()
Return maximum number of base units (Satoshis)
CAmount minimum() const
bool event(QEvent *event)
void setEnabled(bool fEnabled)
Enable/Disable.
void setValue(const QVariant &value)
void setValue(const CAmount &value)
QWidget * setupTabChain(QWidget *prev)
Qt messes up the tab chain by default in some cases (issue https://bugreports.qt-project.org/browse/QTBUG-10907), in these cases we have to set it up manually.
void setSingleStep(const CAmount &step)
StepEnabled stepEnabled() const
void setMinimum(const CAmount &min)
Fabcoin unit definitions.
Definition: fabcoinunits.h:49
void setMinimum(const CAmount &min)
void setDisplayUnit(int unit)
Change unit used to display amount.
void clear()
Make field empty and ready for new input.
CAmount value(bool *valid_out=0) const
QValueComboBox * unit