allow multiple units in bitcoin amount widget (for example, for sending) using a...
[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 }
70
71 bool BitcoinAmountField::validate()
72 {
73     bool valid = true;
74     if(decimals->text().isEmpty())
75     {
76         decimals->setValid(false);
77         valid = false;
78     }
79     if(!BitcoinUnits::parse(BitcoinUnits::BTC, text(), 0))
80     {
81         setValid(false);
82         valid = false;
83     }
84
85     return valid;
86 }
87
88 void BitcoinAmountField::setValid(bool valid)
89 {
90     amount->setValid(valid);
91     decimals->setValid(valid);
92 }
93
94 QString BitcoinAmountField::text() const
95 {
96     if(decimals->text().isEmpty() && amount->text().isEmpty())
97     {
98         return QString();
99     }
100     return amount->text() + QString(".") + decimals->text();
101 }
102
103 // Intercept '.' and ',' keys, if pressed focus a specified widget
104 bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event)
105 {
106     Q_UNUSED(object);
107     if(event->type() == QEvent::KeyPress)
108     {
109         QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
110         if(keyEvent->key() == Qt::Key_Period || keyEvent->key() == Qt::Key_Comma)
111         {
112             decimals->setFocus();
113             decimals->selectAll();
114         }
115     }
116     return false;
117 }
118
119 QWidget *BitcoinAmountField::setupTabChain(QWidget *prev)
120 {
121     QWidget::setTabOrder(prev, amount);
122     QWidget::setTabOrder(amount, decimals);
123     return decimals;
124 }
125
126 qint64 BitcoinAmountField::value(bool *valid_out) const
127 {
128     qint64 val_out = 0;
129     bool valid = BitcoinUnits::parse(currentUnit, text(), &val_out);
130     if(valid_out)
131     {
132         *valid_out = valid;
133     }
134     return val_out;
135 }
136
137 void BitcoinAmountField::setValue(qint64 value)
138 {
139     setText(BitcoinUnits::format(currentUnit, value));
140 }
141
142 void BitcoinAmountField::unitChanged(int idx)
143 {
144     // Use description tooltip for current unit for the combobox
145     unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());
146
147     // Determine new unit ID
148     int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt();
149
150     // Parse current value and convert to new unit
151     bool valid = false;
152     qint64 currentValue = value(&valid);
153
154     currentUnit = newUnit;
155
156     // Set max length after retrieving the value, to prevent truncation
157     amount->setMaxLength(BitcoinUnits::amountDigits(currentUnit));
158     decimals->setMaxLength(BitcoinUnits::decimals(currentUnit));
159
160     if(valid)
161     {
162         setValue(currentValue);
163     }
164     else
165     {
166         // If current value is invalid, just clear field
167         setText("");
168     }
169     setValid(true);
170
171
172 }