PIVX Core  5.6.99
P2P Digital Currency
bitcoinunits.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2014 The Bitcoin developers
2 // Copyright (c) 2014-2015 The Dash developers
3 // Copyright (c) 2015-2021 The PIVX Core developers
4 // Distributed under the MIT/X11 software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 
7 #include "bitcoinunits.h"
8 #include "chainparams.h"
9 #include "policy/feerate.h"
10 #include "primitives/transaction.h"
11 
12 #include <QSettings>
13 #include <QStringList>
14 
15 #include <iostream>
16 
17 BitcoinUnits::BitcoinUnits(QObject* parent) : QAbstractListModel(parent),
18  unitlist(availableUnits())
19 {
20 }
21 
22 QList<BitcoinUnits::Unit> BitcoinUnits::availableUnits()
23 {
24  QList<BitcoinUnits::Unit> unitlist;
25  unitlist.append(PIV);
26  unitlist.append(mPIV);
27  unitlist.append(uPIV);
28  return unitlist;
29 }
30 
31 bool BitcoinUnits::valid(int unit)
32 {
33  switch (unit) {
34  case PIV:
35  case mPIV:
36  case uPIV:
37  return true;
38  default:
39  return false;
40  }
41 }
42 
43 QString BitcoinUnits::id(int unit)
44 {
45  switch (unit) {
46  case PIV:
47  return QString("pivx");
48  case mPIV:
49  return QString("mpivx");
50  case uPIV:
51  return QString::fromUtf8("upivx");
52  default:
53  return QString("???");
54  }
55 }
56 
57 QString BitcoinUnits::name(int unit, bool isZpiv)
58 {
59  const QString CURR_UNIT = QString(CURRENCY_UNIT.c_str());
60  QString z = "";
61  if(isZpiv) z = "z";
62  if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
63  switch (unit) {
64  case PIV:
65  return z + CURR_UNIT;
66  case mPIV:
67  return z + QString("m") + CURR_UNIT;
68  case uPIV:
69  return z + QString::fromUtf8("μ") + CURR_UNIT;
70  default:
71  return QString("???");
72  }
73  } else {
74  switch (unit) {
75  case PIV:
76  return z + QString("t") + CURR_UNIT;
77  case mPIV:
78  return z + QString("mt") + CURR_UNIT;
79  case uPIV:
80  return z + QString::fromUtf8("μt") + CURR_UNIT;
81  default:
82  return QString("???");
83  }
84  }
85 }
86 
87 QString BitcoinUnits::description(int unit)
88 {
89  const QString CURR_UNIT = QString(CURRENCY_UNIT.c_str());
90  if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
91  switch (unit) {
92  case PIV:
93  return CURR_UNIT;
94  case mPIV:
95  return QString("Milli-") + CURR_UNIT + QString(" (1 / 1" THIN_SP_UTF8 "000)");
96  case uPIV:
97  return QString("Micro-") + CURR_UNIT + QString(" (1 / 1" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
98  default:
99  return QString("???");
100  }
101  } else {
102  switch (unit) {
103  case PIV:
104  return QString("Test") + CURR_UNIT;
105  case mPIV:
106  return QString("Milli-Test") + CURR_UNIT + QString(" (1 / 1" THIN_SP_UTF8 "000)");
107  case uPIV:
108  return QString("Micro-Test") + CURR_UNIT + QString(" (1 / 1" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
109  default:
110  return QString("???");
111  }
112  }
113 }
114 
115 qint64 BitcoinUnits::factor(int unit)
116 {
117  switch (unit) {
118  case PIV:
119  return 100000000;
120  case mPIV:
121  return 100000;
122  case uPIV:
123  return 100;
124  default:
125  return 100000000;
126  }
127 }
128 
130 {
131  switch (unit) {
132  case PIV:
133  return 8;
134  case mPIV:
135  return 5;
136  case uPIV:
137  return 2;
138  default:
139  return 0;
140  }
141 }
142 
143 QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators, bool cleanRemainderZeros)
144 {
145  // Note: not using straight sprintf here because we do NOT want
146  // localized number formatting.
147  if (!valid(unit)){
148  return QString(); // Refuse to format invalid unit
149  }
150  qint64 n = (qint64)nIn;
151  qint64 coin = factor(unit);
152  int num_decimals = decimals(unit);
153  qint64 n_abs = (n > 0 ? n : -n);
154  qint64 quotient = n_abs / coin;
155  qint64 remainder = n_abs % coin;
156  QString quotient_str = QString::number(quotient);
157  QString remainder_str = QString::number(remainder).rightJustified(num_decimals, '0');
158 
159  // Use SI-style thin space separators as these are locale independent and can't be
160  // confused with the decimal marker.
161  QChar thin_sp(THIN_SP_CP);
162  int q_size = quotient_str.size();
163  if (separators == separatorAlways || (separators == separatorStandard && q_size > 4))
164  for (int i = 3; i < q_size; i += 3)
165  quotient_str.insert(q_size - i, thin_sp);
166 
167  if (n < 0)
168  quotient_str.insert(0, '-');
169  else if (fPlus && n > 0)
170  quotient_str.insert(0, '+');
171 
172  if (num_decimals <= 0)
173  return quotient_str;
174 
175  if(cleanRemainderZeros) {
176  // Clean remainder
177  QString cleanRemainder = remainder_str;
178  for (int i = (remainder_str.length() - 1); i > 1; i--) {
179  if (remainder_str.at(i) == QChar('0')) {
180  cleanRemainder = cleanRemainder.left(cleanRemainder.lastIndexOf("0"));
181  } else
182  break;
183  }
184  return quotient_str + QString(".") + cleanRemainder;
185  }
186 
187  return quotient_str + QString(".") + remainder_str;
188 }
189 
190 
191 // TODO: Review all remaining calls to BitcoinUnits::formatWithUnit to
192 // TODO: determine whether the output is used in a plain text context
193 // TODO: or an HTML context (and replace with
194 // TODO: BtcoinUnits::formatHtmlWithUnit in the latter case). Hopefully
195 // TODO: there aren't instances where the result could be used in
196 // TODO: either context.
197 
198 // NOTE: Using formatWithUnit in an HTML context risks wrapping
199 // quantities at the thousands separator. More subtly, it also results
200 // in a standard space rather than a thin space, due to a bug in Qt's
201 // XML whitespace canonicalisation
202 //
203 // Please take care to use formatHtmlWithUnit instead, when
204 // appropriate.
205 
206 QString BitcoinUnits::formatWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
207 {
208  return format(unit, amount, plussign, separators) + QString(" ") + name(unit);
209 }
210 
211 QString BitcoinUnits::formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
212 {
213  QString str(formatWithUnit(unit, amount, plussign, separators));
214  str.replace(QChar(THIN_SP_CP), QString(COMMA_HTML));
215  return QString("<span style='white-space: nowrap;'>%1</span>").arg(str);
216 }
217 
218 QString BitcoinUnits::floorWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators, bool cleanRemainderZeros, bool isZPIV)
219 {
220  QSettings settings;
221  int digits = settings.value("digits").toInt();
222 
223  QString result = format(unit, amount, plussign, separators, cleanRemainderZeros);
224  if(decimals(unit) > digits) {
225  if (!cleanRemainderZeros) {
226  result.chop(decimals(unit) - digits);
227  } else {
228  int length = result.mid(result.indexOf("."), result.length() - 1).length() - 1;
229  if (length > digits) {
230  result.chop(length - digits);
231  }
232  }
233  }
234 
235  return result + QString(" ") + name(unit, isZPIV);
236 }
237 
238 QString BitcoinUnits::floorHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators, bool cleanRemainderZeros, bool isZPIV)
239 {
240  QString str(floorWithUnit(unit, amount, plussign, separators, cleanRemainderZeros, isZPIV));
241  str.replace(QChar(THIN_SP_CP), QString(COMMA_HTML));
242  return QString("<span style='white-space: nowrap;'>%1</span>").arg(str);
243 }
244 
245 bool BitcoinUnits::parse(int unit, const QString& value, CAmount* val_out)
246 {
247  if (!valid(unit) || value.isEmpty())
248  return false; // Refuse to parse invalid unit or empty string
249  int num_decimals = decimals(unit);
250 
251  // Ignore spaces and thin spaces when parsing
252  QStringList parts = removeSpaces(value).replace(",", ".").split(".");
253 
254  if (parts.size() > 2) {
255  return false; // More than one dot
256  }
257  QString whole = parts[0];
258  QString decimals;
259 
260  if (parts.size() > 1) {
261  decimals = parts[1];
262  }
263  if (decimals.size() > num_decimals) {
264  return false; // Exceeds max precision
265  }
266  bool ok = false;
267  QString str = whole + decimals.leftJustified(num_decimals, '0');
268 
269  if (str.size() > 18) {
270  return false; // Longer numbers will exceed 63 bits
271  }
272  CAmount retvalue(str.toLongLong(&ok));
273  if (val_out) {
274  *val_out = retvalue;
275  }
276  return ok;
277 }
278 
280 {
281  QString amountTitle = QObject::tr("Amount");
282  if (BitcoinUnits::valid(unit)) {
283  amountTitle += " (" + BitcoinUnits::name(unit) + ")";
284  }
285  return amountTitle;
286 }
287 
288 int BitcoinUnits::rowCount(const QModelIndex& parent) const
289 {
290  Q_UNUSED(parent);
291  return unitlist.size();
292 }
293 
294 QVariant BitcoinUnits::data(const QModelIndex& index, int role) const
295 {
296  int row = index.row();
297  if (row >= 0 && row < unitlist.size()) {
298  Unit unit = unitlist.at(row);
299  switch (role) {
300  case Qt::EditRole:
301  case Qt::DisplayRole:
302  return QVariant(name(unit));
303  case Qt::ToolTipRole:
304  return QVariant(description(unit));
305  case UnitRole:
306  return QVariant(static_cast<int>(unit));
307  }
308  }
309  return QVariant();
310 }
311 
313 {
314  return Params().GetConsensus().nMaxMoneyOut;
315 }
int64_t CAmount
Amount in PIV (Can be negative)
Definition: amount.h:13
#define THIN_SP_CP
Definition: bitcoinunits.h:46
#define COMMA_HTML
Definition: bitcoinunits.h:22
#define THIN_SP_UTF8
Definition: bitcoinunits.h:47
const CChainParams & Params()
Return the currently selected parameters.
@ UnitRole
Unit identifier.
Definition: bitcoinunits.h:113
QList< BitcoinUnits::Unit > unitlist
Definition: bitcoinunits.h:133
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.
static QString floorHtmlWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard, bool cleanRemainderZeros=false, bool isZPIV=false)
static QString floorWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard, bool cleanRemainderZeros=false, bool isZPIV=false)
Format as string (with unit) but floor value up to "digits" settings.
QVariant data(const QModelIndex &index, int role) const
static QString id(int unit)
Identifier, e.g. for image names.
static QString formatHtmlWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
static bool valid(int unit)
Is unit ID valid?
static QString description(int unit)
Longer description.
static QString removeSpaces(QString text)
Definition: bitcoinunits.h:119
int rowCount(const QModelIndex &parent) const
static QString format(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard, bool cleanRemainderZeros=true)
Format as string.
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
PIVX units.
Definition: bitcoinunits.h:63
BitcoinUnits(QObject *parent)
static qint64 factor(int unit)
Number of Satoshis (1e-8) per unit.
static QString formatWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string (with unit)
static QString name(int unit, bool isZpiv=false)
Short name.
static const std::string MAIN
Chain name strings.
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:72
const std::string CURRENCY_UNIT
Definition: feerate.cpp:11
QSettings * settings
Definition: qtutils.cpp:197
CAmount nMaxMoneyOut
Definition: params.h:183