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