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