aboutsummaryrefslogtreecommitdiff
path: root/src/qt/bitcoinunits.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt/bitcoinunits.cpp')
-rw-r--r--src/qt/bitcoinunits.cpp103
1 files changed, 65 insertions, 38 deletions
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 08c2bfa17..a4430c4ce 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -7,6 +7,7 @@
#include "primitives/transaction.h"
#include <QStringList>
+#include <QLocale>
BitcoinUnits::BitcoinUnits(QObject *parent):
QAbstractListModel(parent),
@@ -69,6 +70,17 @@ qint64 BitcoinUnits::factor(int unit)
}
}
+qint64 BitcoinUnits::maxAmount(int unit)
+{
+ switch(unit)
+ {
+ case BTC: return Q_INT64_C(900000000000); //less than the coin supply until the year 2170
+ case mBTC: return Q_INT64_C(900000000000000);
+ case uBTC: return Q_INT64_C(900000000000000000); // Slightly under max value for int64
+ default: return 0;
+ }
+}
+
int BitcoinUnits::decimals(int unit)
{
switch(unit)
@@ -80,37 +92,42 @@ int BitcoinUnits::decimals(int unit)
}
}
-QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators)
+QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, bool fTrim, const QLocale &locale_in)
{
// Note: not using straight sprintf here because we do NOT want
// localized number formatting.
if(!valid(unit))
return QString(); // Refuse to format invalid unit
qint64 n = (qint64)nIn;
+ QLocale locale(locale_in);
qint64 coin = factor(unit);
int num_decimals = decimals(unit);
+
qint64 n_abs = (n > 0 ? n : -n);
qint64 quotient = n_abs / coin;
qint64 remainder = n_abs % coin;
- QString quotient_str = QString::number(quotient);
- QString remainder_str = QString::number(remainder).rightJustified(num_decimals, '0');
+ // Quotient has group (decimal) separators if locale has this enabled
+ QString quotient_str = locale.toString(quotient);
+ // Remainder does not have group separators
+ locale.setNumberOptions(QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
+ QString remainder_str = locale.toString(remainder).rightJustified(num_decimals, '0');
- // Use SI-style thin space separators as these are locale independent and can't be
- // confused with the decimal marker.
- QChar thin_sp(THIN_SP_CP);
- int q_size = quotient_str.size();
- if (separators == separatorAlways || (separators == separatorStandard && q_size > 4))
- for (int i = 3; i < q_size; i += 3)
- quotient_str.insert(q_size - i, thin_sp);
+ if(fTrim)
+ {
+ // Right-trim excess zeros after the decimal point
+ int nTrim = 0;
+ for (int i = remainder_str.size()-1; i>=2 && (remainder_str.at(i) == '0'); --i)
+ ++nTrim;
+ remainder_str.chop(nTrim);
+ }
if (n < 0)
quotient_str.insert(0, '-');
else if (fPlus && n > 0)
quotient_str.insert(0, '+');
- return quotient_str + QString(".") + remainder_str;
+ return quotient_str + locale.decimalPoint() + remainder_str;
}
-
// TODO: Review all remaining calls to BitcoinUnits::formatWithUnit to
// TODO: determine whether the output is used in a plain text context
// TODO: or an HTML context (and replace with
@@ -126,54 +143,64 @@ QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, Separator
// Please take care to use formatHtmlWithUnit instead, when
// appropriate.
-QString BitcoinUnits::formatWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
+QString BitcoinUnits::formatWithUnit(int unit, const CAmount& amount, bool plussign, bool trim, const QLocale &locale)
{
- return format(unit, amount, plussign, separators) + QString(" ") + name(unit);
+ return format(unit, amount, plussign, trim) + QString(" ") + name(unit);
}
-QString BitcoinUnits::formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
+QString BitcoinUnits::formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign, bool trim, const QLocale &locale)
{
- QString str(formatWithUnit(unit, amount, plussign, separators));
+ QString str(formatWithUnit(unit, amount, plussign, trim, locale));
str.replace(QChar(THIN_SP_CP), QString(THIN_SP_HTML));
return QString("<span style='white-space: nowrap;'>%1</span>").arg(str);
}
-bool BitcoinUnits::parse(int unit, const QString &value, CAmount *val_out)
+bool BitcoinUnits::parse(int unit, const QString &value, CAmount *val_out, const QLocale &locale_in)
{
if(!valid(unit) || value.isEmpty())
return false; // Refuse to parse invalid unit or empty string
+
+ QLocale locale(locale_in);
+ qint64 coin = factor(unit);
int num_decimals = decimals(unit);
- // Ignore spaces and thin spaces when parsing
- QStringList parts = removeSpaces(value).split(".");
+ QStringList parts = value.split(locale.decimalPoint());
+ bool ok = false;
if(parts.size() > 2)
- {
- return false; // More than one dot
- }
- QString whole = parts[0];
- QString decimals;
-
+ return false; // More than one decimal point
+
+ // Parse whole part (may include locale-specific group separators)
+#if QT_VERSION < 0x050000
+ qint64 whole = locale.toLongLong(parts[0], &ok, 10);
+#else
+ qint64 whole = locale.toLongLong(parts[0], &ok);
+#endif
+ if(!ok)
+ return false; // Parse error
+ if(whole > maxAmount(unit) || whole < 0)
+ return false; // Overflow or underflow
+
+ // Parse decimals part (if present, may not include group separators)
+ qint64 decimals = 0;
if(parts.size() > 1)
{
- decimals = parts[1];
+ if(parts[1].size() > num_decimals)
+ return false; // Exceeds max precision
+ locale.setNumberOptions(QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
+#if QT_VERSION < 0x050000
+ decimals = locale.toLongLong(parts[1].leftJustified(num_decimals, '0'), &ok, 10);
+#else
+ decimals = locale.toLongLong(parts[1].leftJustified(num_decimals, '0'), &ok);
+#endif
+ if(!ok || decimals < 0)
+ return false; // Parse error
}
- if(decimals.size() > num_decimals)
- {
- return false; // Exceeds max precision
- }
- bool ok = false;
- QString str = whole + decimals.leftJustified(num_decimals, '0');
- if(str.size() > 18)
- {
- return false; // Longer numbers will exceed 63 bits
- }
- CAmount retvalue(str.toLongLong(&ok));
if(val_out)
{
- *val_out = retvalue;
+ *val_out = whole * coin + decimals;
}
return ok;
}