Line data Source code
1 : // Copyright (c) 2011-2013 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 "bitcoinunits.h"
6 :
7 : #include "primitives/transaction.h"
8 :
9 : #include <QStringList>
10 :
11 0 : BitcoinUnits::BitcoinUnits(QObject *parent):
12 : QAbstractListModel(parent),
13 0 : unitlist(availableUnits())
14 : {
15 0 : }
16 :
17 0 : QList<BitcoinUnits::Unit> BitcoinUnits::availableUnits()
18 : {
19 : QList<BitcoinUnits::Unit> unitlist;
20 0 : unitlist.append(BTC);
21 0 : unitlist.append(mBTC);
22 0 : unitlist.append(uBTC);
23 0 : return unitlist;
24 : }
25 :
26 0 : bool BitcoinUnits::valid(int unit)
27 : {
28 5 : switch(unit)
29 : {
30 : case BTC:
31 : case mBTC:
32 : case uBTC:
33 : return true;
34 : default:
35 0 : return false;
36 : }
37 : }
38 :
39 0 : QString BitcoinUnits::name(int unit)
40 : {
41 0 : switch(unit)
42 : {
43 : case BTC: return QString("BTC");
44 : case mBTC: return QString("mBTC");
45 0 : case uBTC: return QString::fromUtf8("μBTC");
46 : default: return QString("???");
47 : }
48 : }
49 :
50 0 : QString BitcoinUnits::description(int unit)
51 : {
52 0 : switch(unit)
53 : {
54 : case BTC: return QString("Bitcoins");
55 : case mBTC: return QString("Milli-Bitcoins (1 / 1" THIN_SP_UTF8 "000)");
56 : case uBTC: return QString("Micro-Bitcoins (1 / 1" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
57 : default: return QString("???");
58 : }
59 : }
60 :
61 0 : qint64 BitcoinUnits::factor(int unit)
62 : {
63 0 : switch(unit)
64 : {
65 : case BTC: return 100000000;
66 0 : case mBTC: return 100000;
67 0 : case uBTC: return 100;
68 : default: return 100000000;
69 : }
70 : }
71 :
72 0 : int BitcoinUnits::decimals(int unit)
73 : {
74 : switch(unit)
75 : {
76 : case BTC: return 8;
77 : case mBTC: return 5;
78 : case uBTC: return 2;
79 : default: return 0;
80 : }
81 : }
82 :
83 0 : QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators)
84 : {
85 : // Note: not using straight sprintf here because we do NOT want
86 : // localized number formatting.
87 0 : if(!valid(unit))
88 : return QString(); // Refuse to format invalid unit
89 0 : qint64 n = (qint64)nIn;
90 0 : qint64 coin = factor(unit);
91 0 : int num_decimals = decimals(unit);
92 0 : qint64 n_abs = (n > 0 ? n : -n);
93 0 : qint64 quotient = n_abs / coin;
94 0 : qint64 remainder = n_abs % coin;
95 0 : QString quotient_str = QString::number(quotient);
96 0 : QString remainder_str = QString::number(remainder).rightJustified(num_decimals, '0');
97 :
98 : // Use SI-style thin space separators as these are locale independent and can't be
99 : // confused with the decimal marker.
100 : QChar thin_sp(THIN_SP_CP);
101 0 : int q_size = quotient_str.size();
102 0 : if (separators == separatorAlways || (separators == separatorStandard && q_size > 4))
103 0 : for (int i = 3; i < q_size; i += 3)
104 0 : quotient_str.insert(q_size - i, thin_sp);
105 :
106 0 : if (n < 0)
107 0 : quotient_str.insert(0, '-');
108 0 : else if (fPlus && n > 0)
109 0 : quotient_str.insert(0, '+');
110 0 : return quotient_str + QString(".") + remainder_str;
111 : }
112 :
113 :
114 : // TODO: Review all remaining calls to BitcoinUnits::formatWithUnit to
115 : // TODO: determine whether the output is used in a plain text context
116 : // TODO: or an HTML context (and replace with
117 : // TODO: BtcoinUnits::formatHtmlWithUnit in the latter case). Hopefully
118 : // TODO: there aren't instances where the result could be used in
119 : // TODO: either context.
120 :
121 : // NOTE: Using formatWithUnit in an HTML context risks wrapping
122 : // quantities at the thousands separator. More subtly, it also results
123 : // in a standard space rather than a thin space, due to a bug in Qt's
124 : // XML whitespace canonicalisation
125 : //
126 : // Please take care to use formatHtmlWithUnit instead, when
127 : // appropriate.
128 :
129 0 : QString BitcoinUnits::formatWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
130 : {
131 0 : return format(unit, amount, plussign, separators) + QString(" ") + name(unit);
132 : }
133 :
134 0 : QString BitcoinUnits::formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
135 : {
136 0 : QString str(formatWithUnit(unit, amount, plussign, separators));
137 0 : str.replace(QChar(THIN_SP_CP), QString(THIN_SP_HTML));
138 0 : return QString("<span style='white-space: nowrap;'>%1</span>").arg(str);
139 : }
140 :
141 :
142 5 : bool BitcoinUnits::parse(int unit, const QString &value, CAmount *val_out)
143 : {
144 10 : if(!valid(unit) || value.isEmpty())
145 : return false; // Refuse to parse invalid unit or empty string
146 5 : int num_decimals = decimals(unit);
147 :
148 : // Ignore spaces and thin spaces when parsing
149 5 : QStringList parts = removeSpaces(value).split(".");
150 :
151 5 : if(parts.size() > 2)
152 : {
153 : return false; // More than one dot
154 : }
155 10 : QString whole = parts[0];
156 5 : QString decimals;
157 :
158 5 : if(parts.size() > 1)
159 : {
160 3 : decimals = parts[1];
161 : }
162 5 : if(decimals.size() > num_decimals)
163 : {
164 : return false; // Exceeds max precision
165 : }
166 5 : bool ok = false;
167 10 : QString str = whole + decimals.leftJustified(num_decimals, '0');
168 :
169 5 : if(str.size() > 18)
170 : {
171 : return false; // Longer numbers will exceed 63 bits
172 : }
173 5 : CAmount retvalue(str.toLongLong(&ok));
174 5 : if(val_out)
175 : {
176 5 : *val_out = retvalue;
177 : }
178 5 : return ok;
179 : }
180 :
181 0 : QString BitcoinUnits::getAmountColumnTitle(int unit)
182 : {
183 : QString amountTitle = QObject::tr("Amount");
184 0 : if (BitcoinUnits::valid(unit))
185 : {
186 0 : amountTitle += " ("+BitcoinUnits::name(unit) + ")";
187 : }
188 0 : return amountTitle;
189 : }
190 :
191 0 : int BitcoinUnits::rowCount(const QModelIndex &parent) const
192 : {
193 : Q_UNUSED(parent);
194 0 : return unitlist.size();
195 : }
196 :
197 0 : QVariant BitcoinUnits::data(const QModelIndex &index, int role) const
198 : {
199 0 : int row = index.row();
200 0 : if(row >= 0 && row < unitlist.size())
201 : {
202 0 : Unit unit = unitlist.at(row);
203 0 : switch(role)
204 : {
205 : case Qt::EditRole:
206 : case Qt::DisplayRole:
207 0 : return QVariant(name(unit));
208 : case Qt::ToolTipRole:
209 0 : return QVariant(description(unit));
210 : case UnitRole:
211 0 : return QVariant(static_cast<int>(unit));
212 : }
213 : }
214 : return QVariant();
215 : }
216 :
217 0 : CAmount BitcoinUnits::maxMoney()
218 : {
219 0 : return MAX_MONEY;
220 : }
|