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