diff options
Diffstat (limited to 'src/qt/bitcoinunits.cpp')
| -rw-r--r-- | src/qt/bitcoinunits.cpp | 103 |
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; } |