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