Bitcoin Core 28.99.0
P2P Digital Currency
bitcoinunits.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2021 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 <qt/bitcoinunits.h>
6
7#include <consensus/amount.h>
8
9#include <QStringList>
10
11#include <cassert>
12
13static constexpr auto MAX_DIGITS_BTC = 16;
14
16 QAbstractListModel(parent),
17 unitlist(availableUnits())
18{
19}
20
21QList<BitcoinUnit> BitcoinUnits::availableUnits()
22{
23 QList<BitcoinUnit> unitlist;
24 unitlist.append(Unit::BTC);
25 unitlist.append(Unit::mBTC);
26 unitlist.append(Unit::uBTC);
27 unitlist.append(Unit::SAT);
28 return unitlist;
29}
30
32{
33 switch (unit) {
34 case Unit::BTC: return QString("BTC");
35 case Unit::mBTC: return QString("mBTC");
36 case Unit::uBTC: return QString::fromUtf8("µBTC (bits)");
37 case Unit::SAT: return QString("Satoshi (sat)");
38 } // no default case, so the compiler can warn about missing cases
39 assert(false);
40}
41
43{
44 switch (unit) {
45 case Unit::BTC: return longName(unit);
46 case Unit::mBTC: return longName(unit);
47 case Unit::uBTC: return QString("bits");
48 case Unit::SAT: return QString("sat");
49 } // no default case, so the compiler can warn about missing cases
50 assert(false);
51}
52
54{
55 switch (unit) {
56 case Unit::BTC: return QString("Bitcoins");
57 case Unit::mBTC: return QString("Milli-Bitcoins (1 / 1" THIN_SP_UTF8 "000)");
58 case Unit::uBTC: return QString("Micro-Bitcoins (bits) (1 / 1" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
59 case Unit::SAT: return QString("Satoshi (sat) (1 / 100" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
60 } // no default case, so the compiler can warn about missing cases
61 assert(false);
62}
63
65{
66 switch (unit) {
67 case Unit::BTC: return 100'000'000;
68 case Unit::mBTC: return 100'000;
69 case Unit::uBTC: return 100;
70 case Unit::SAT: return 1;
71 } // no default case, so the compiler can warn about missing cases
72 assert(false);
73}
74
76{
77 switch (unit) {
78 case Unit::BTC: return 8;
79 case Unit::mBTC: return 5;
80 case Unit::uBTC: return 2;
81 case Unit::SAT: return 0;
82 } // no default case, so the compiler can warn about missing cases
83 assert(false);
84}
85
86QString BitcoinUnits::format(Unit unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators, bool justify)
87{
88 // Note: not using straight sprintf here because we do NOT want
89 // localized number formatting.
90 qint64 n = (qint64)nIn;
91 qint64 coin = factor(unit);
92 int num_decimals = decimals(unit);
93 qint64 n_abs = (n > 0 ? n : -n);
94 qint64 quotient = n_abs / coin;
95 QString quotient_str = QString::number(quotient);
96 if (justify) {
97 quotient_str = quotient_str.rightJustified(MAX_DIGITS_BTC - num_decimals, ' ');
98 }
99
100 // Use SI-style thin space separators as these are locale independent and can't be
101 // confused with the decimal marker.
102 QChar thin_sp(THIN_SP_CP);
103 int q_size = quotient_str.size();
104 if (separators == SeparatorStyle::ALWAYS || (separators == SeparatorStyle::STANDARD && q_size > 4))
105 for (int i = 3; i < q_size; i += 3)
106 quotient_str.insert(q_size - i, thin_sp);
107
108 if (n < 0)
109 quotient_str.insert(0, '-');
110 else if (fPlus && n > 0)
111 quotient_str.insert(0, '+');
112
113 if (num_decimals > 0) {
114 qint64 remainder = n_abs % coin;
115 QString remainder_str = QString::number(remainder).rightJustified(num_decimals, '0');
116 return quotient_str + QString(".") + remainder_str;
117 } else {
118 return quotient_str;
119 }
120}
121
122
123// NOTE: Using formatWithUnit in an HTML context risks wrapping
124// quantities at the thousands separator. More subtly, it also results
125// in a standard space rather than a thin space, due to a bug in Qt's
126// XML whitespace canonicalisation
127//
128// Please take care to use formatHtmlWithUnit instead, when
129// appropriate.
130
131QString BitcoinUnits::formatWithUnit(Unit unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
132{
133 return format(unit, amount, plussign, separators) + QString(" ") + shortName(unit);
134}
135
136QString BitcoinUnits::formatHtmlWithUnit(Unit unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
137{
138 QString str(formatWithUnit(unit, amount, plussign, separators));
139 str.replace(QChar(THIN_SP_CP), QString(THIN_SP_HTML));
140 return QString("<span style='white-space: nowrap;'>%1</span>").arg(str);
141}
142
143QString BitcoinUnits::formatWithPrivacy(Unit unit, const CAmount& amount, SeparatorStyle separators, bool privacy)
144{
145 assert(amount >= 0);
146 QString value;
147 if (privacy) {
148 value = format(unit, 0, false, separators, true).replace('0', '#');
149 } else {
150 value = format(unit, amount, false, separators, true);
151 }
152 return value + QString(" ") + shortName(unit);
153}
154
155bool BitcoinUnits::parse(Unit unit, const QString& value, CAmount* val_out)
156{
157 if (value.isEmpty()) {
158 return false; // Refuse to parse invalid unit or empty string
159 }
160 int num_decimals = decimals(unit);
161
162 // Ignore spaces and thin spaces when parsing
163 QStringList parts = removeSpaces(value).split(".");
164
165 if(parts.size() > 2)
166 {
167 return false; // More than one dot
168 }
169 const QString& whole = parts[0];
170 QString decimals;
171
172 if(parts.size() > 1)
173 {
174 decimals = parts[1];
175 }
176 if(decimals.size() > num_decimals)
177 {
178 return false; // Exceeds max precision
179 }
180 bool ok = false;
181 QString str = whole + decimals.leftJustified(num_decimals, '0');
182
183 if(str.size() > 18)
184 {
185 return false; // Longer numbers will exceed 63 bits
186 }
187 CAmount retvalue(str.toLongLong(&ok));
188 if(val_out)
189 {
190 *val_out = retvalue;
191 }
192 return ok;
193}
194
196{
197 return QObject::tr("Amount") + " (" + shortName(unit) + ")";
198}
199
200int BitcoinUnits::rowCount(const QModelIndex &parent) const
201{
202 Q_UNUSED(parent);
203 return unitlist.size();
204}
205
206QVariant BitcoinUnits::data(const QModelIndex &index, int role) const
207{
208 int row = index.row();
209 if(row >= 0 && row < unitlist.size())
210 {
211 Unit unit = unitlist.at(row);
212 switch(role)
213 {
214 case Qt::EditRole:
215 case Qt::DisplayRole:
216 return QVariant(longName(unit));
217 case Qt::ToolTipRole:
218 return QVariant(description(unit));
219 case UnitRole:
220 return QVariant::fromValue(unit);
221 }
222 }
223 return QVariant();
224}
225
227{
228 return MAX_MONEY;
229}
230
231namespace {
232qint8 ToQint8(BitcoinUnit unit)
233{
234 switch (unit) {
235 case BitcoinUnit::BTC: return 0;
236 case BitcoinUnit::mBTC: return 1;
237 case BitcoinUnit::uBTC: return 2;
238 case BitcoinUnit::SAT: return 3;
239 } // no default case, so the compiler can warn about missing cases
240 assert(false);
241}
242
243BitcoinUnit FromQint8(qint8 num)
244{
245 switch (num) {
246 case 0: return BitcoinUnit::BTC;
247 case 1: return BitcoinUnit::mBTC;
248 case 2: return BitcoinUnit::uBTC;
249 case 3: return BitcoinUnit::SAT;
250 }
251 assert(false);
252}
253} // namespace
254
255QDataStream& operator<<(QDataStream& out, const BitcoinUnit& unit)
256{
257 return out << ToQint8(unit);
258}
259
260QDataStream& operator>>(QDataStream& in, BitcoinUnit& unit)
261{
262 qint8 input;
263 in >> input;
264 unit = FromQint8(input);
265 return in;
266}
static constexpr CAmount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition: amount.h:26
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
QDataStream & operator<<(QDataStream &out, const BitcoinUnit &unit)
static constexpr auto MAX_DIGITS_BTC
QDataStream & operator>>(QDataStream &in, BitcoinUnit &unit)
#define THIN_SP_CP
Definition: bitcoinunits.h:25
#define THIN_SP_HTML
Definition: bitcoinunits.h:27
#define THIN_SP_UTF8
Definition: bitcoinunits.h:26
@ UnitRole
Unit identifier.
Definition: bitcoinunits.h:92
int rowCount(const QModelIndex &parent) const override
static QString formatWithPrivacy(Unit unit, const CAmount &amount, SeparatorStyle separators, bool privacy)
Format as string (with unit) of fixed length to preserve privacy, if it is set.
static CAmount maxMoney()
Return maximum number of base units (Satoshis)
static QString format(Unit unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD, bool justify=false)
Format as string.
QVariant data(const QModelIndex &index, int role) const override
static QString formatHtmlWithUnit(Unit unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as HTML string (with unit)
QList< Unit > unitlist
Definition: bitcoinunits.h:109
static QString removeSpaces(QString text)
Definition: bitcoinunits.h:98
static QString getAmountColumnTitle(Unit unit)
Gets title for amount column including current display unit if optionsModel reference available *‍/.
static QString shortName(Unit unit)
Short name.
static QList< Unit > availableUnits()
Get list of units, for drop-down box.
static QString longName(Unit unit)
Long name.
static QString formatWithUnit(Unit unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as string (with unit)
static qint64 factor(Unit unit)
Number of Satoshis (1e-8) per unit.
static bool parse(Unit unit, const QString &value, CAmount *val_out)
Parse string to coin amount.
static QString description(Unit unit)
Longer description.
Unit
Bitcoin units.
Definition: bitcoinunits.h:42
BitcoinUnits(QObject *parent)
static int decimals(Unit unit)
Number of decimals left.
assert(!tx.IsCoinBase())