Reset unit to default when clearing the field, to prevent confusion
[novacoin.git] / src / qt / bitcoinamountfield.cpp
1 #include "bitcoinamountfield.h"
2 #include "qvalidatedlineedit.h"
3 #include "bitcoinunits.h"
4
5 #include <QLabel>
6 #include <QLineEdit>
7 #include <QRegExpValidator>
8 #include <QHBoxLayout>
9 #include <QKeyEvent>
10 #include <QComboBox>
11
12 BitcoinAmountField::BitcoinAmountField(QWidget *parent):
13         QWidget(parent), amount(0), decimals(0), currentUnit(-1)
14 {
15     amount = new QValidatedLineEdit(this);
16     amount->setValidator(new QRegExpValidator(QRegExp("[0-9]*"), this));
17     amount->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
18     amount->installEventFilter(this);
19     amount->setMaximumWidth(100);
20     decimals = new QValidatedLineEdit(this);
21     decimals->setValidator(new QRegExpValidator(QRegExp("[0-9]+"), this));
22     decimals->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
23     decimals->setMaximumWidth(75);
24
25     QHBoxLayout *layout = new QHBoxLayout(this);
26     layout->setSpacing(0);
27     layout->addWidget(amount);
28     layout->addWidget(new QLabel(QString(".")));
29     layout->addWidget(decimals);
30     unit = new QComboBox(this);
31     unit->setModel(new BitcoinUnits(this));
32     layout->addWidget(unit);
33     layout->addStretch(1);
34     layout->setContentsMargins(0,0,0,0);
35
36     setLayout(layout);
37
38     setFocusPolicy(Qt::TabFocus);
39     setFocusProxy(amount);
40
41     // If one if the widgets changes, the combined content changes as well
42     connect(amount, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged()));
43     connect(decimals, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged()));
44     connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int)));
45
46     // TODO: set default based on configuration
47     unitChanged(unit->currentIndex());
48 }
49
50 void BitcoinAmountField::setText(const QString &text)
51 {
52     const QStringList parts = text.split(QString("."));
53     if(parts.size() == 2)
54     {
55         amount->setText(parts[0]);
56         decimals->setText(parts[1]);
57     }
58     else
59     {
60         amount->setText(QString());
61         decimals->setText(QString());
62     }
63 }
64
65 void BitcoinAmountField::clear()
66 {
67     amount->clear();
68     decimals->clear();
69     // TODO: set default based on configuration
70     unit->setCurrentIndex(0);
71 }
72
73 bool BitcoinAmountField::validate()
74 {
75     bool valid = true;
76     if(decimals->text().isEmpty())
77     {
78         decimals->setValid(false);
79         valid = false;
80     }
81     if(!BitcoinUnits::parse(BitcoinUnits::BTC, text(), 0))
82     {
83         setValid(false);
84         valid = false;
85     }
86
87     return valid;
88 }
89
90 void BitcoinAmountField::setValid(bool valid)
91 {
92     amount->setValid(valid);
93     decimals->setValid(valid);
94 }
95
96 QString BitcoinAmountField::text() const
97 {
98     if(decimals->text().isEmpty() && amount->text().isEmpty())
99     {
100         return QString();
101     }
102     return amount->text() + QString(".") + decimals->text();
103 }
104
105 // Intercept '.' and ',' keys, if pressed focus a specified widget
106 bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event)
107 {
108     Q_UNUSED(object);
109     if(event->type() == QEvent::KeyPress)
110     {
111         QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
112         if(keyEvent->key() == Qt::Key_Period || keyEvent->key() == Qt::Key_Comma)
113         {
114             decimals->setFocus();
115             decimals->selectAll();
116         }
117     }
118     return false;
119 }
120
121 QWidget *BitcoinAmountField::setupTabChain(QWidget *prev)
122 {
123     QWidget::setTabOrder(prev, amount);
124     QWidget::setTabOrder(amount, decimals);
125     return decimals;
126 }
127
128 qint64 BitcoinAmountField::value(bool *valid_out) const
129 {
130     qint64 val_out = 0;
131     bool valid = BitcoinUnits::parse(currentUnit, text(), &val_out);
132     if(valid_out)
133     {
134         *valid_out = valid;
135     }
136     return val_out;
137 }
138
139 void BitcoinAmountField::setValue(qint64 value)
140 {
141     setText(BitcoinUnits::format(currentUnit, value));
142 }
143
144 void BitcoinAmountField::unitChanged(int idx)
145 {
146     // Use description tooltip for current unit for the combobox
147     unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());
148
149     // Determine new unit ID
150     int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt();
151
152     // Parse current value and convert to new unit
153     bool valid = false;
154     qint64 currentValue = value(&valid);
155
156     currentUnit = newUnit;
157
158     // Set max length after retrieving the value, to prevent truncation
159     amount->setMaxLength(BitcoinUnits::amountDigits(currentUnit));
160     decimals->setMaxLength(BitcoinUnits::decimals(currentUnit));
161
162     if(valid)
163     {
164         setValue(currentValue);
165     }
166     else
167     {
168         // If current value is invalid, just clear field
169         setText("");
170     }
171     setValid(true);
172
173
174 }