/* * Copyright 2003, Axel Dörfler, axeld@pinc-software.de. * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de. * Copyright 2012, John Scipione, jscipione@gmail.com * Copyright 2017, Adrien Destugues, pulkomandy@pulkomandy.tk * Copyright 2021, Andrew Lindesay, apl@lindesay.co.nz * All rights reserved. Distributed under the terms of the MIT License. */ #include #include #include #include #include #include #include #include #include U_NAMESPACE_USE class BNumberFormatImpl { public: BNumberFormatImpl(); ~BNumberFormatImpl(); NumberFormat* GetInteger(BFormattingConventions* convention); NumberFormat* GetFloat(BFormattingConventions* convention); NumberFormat* GetCurrency(BFormattingConventions* convention); NumberFormat* GetPercent(BFormattingConventions* convention); ssize_t ApplyFormatter(NumberFormat* formatter, char* string, size_t maxSize, const double value); status_t ApplyFormatter(NumberFormat* formatter, BString& string, const double value); private: NumberFormat* fIntegerFormat; NumberFormat* fFloatFormat; NumberFormat* fCurrencyFormat; NumberFormat* fPercentFormat; }; BNumberFormatImpl::BNumberFormatImpl() { // They are initialized lazily as needed fIntegerFormat = NULL; fFloatFormat = NULL; fCurrencyFormat = NULL; fPercentFormat = NULL; } BNumberFormatImpl::~BNumberFormatImpl() { delete fIntegerFormat; delete fFloatFormat; delete fCurrencyFormat; delete fPercentFormat; } NumberFormat* BNumberFormatImpl::GetInteger(BFormattingConventions* convention) { if (fIntegerFormat == NULL) { UErrorCode err = U_ZERO_ERROR; fIntegerFormat = NumberFormat::createInstance( *BFormattingConventions::Private(convention).ICULocale(), UNUM_DECIMAL, err); if (fIntegerFormat == NULL) return NULL; if (U_FAILURE(err)) { delete fIntegerFormat; fIntegerFormat = NULL; return NULL; } } return fIntegerFormat; } NumberFormat* BNumberFormatImpl::GetFloat(BFormattingConventions* convention) { if (fFloatFormat == NULL) { UErrorCode err = U_ZERO_ERROR; fFloatFormat = NumberFormat::createInstance( *BFormattingConventions::Private(convention).ICULocale(), UNUM_DECIMAL, err); if (fFloatFormat == NULL) return NULL; if (U_FAILURE(err)) { delete fFloatFormat; fFloatFormat = NULL; return NULL; } } return fFloatFormat; } NumberFormat* BNumberFormatImpl::GetCurrency(BFormattingConventions* convention) { if (fCurrencyFormat == NULL) { UErrorCode err = U_ZERO_ERROR; fCurrencyFormat = NumberFormat::createCurrencyInstance( *BFormattingConventions::Private(convention).ICULocale(), err); if (fCurrencyFormat == NULL) return NULL; if (U_FAILURE(err)) { delete fCurrencyFormat; fCurrencyFormat = NULL; return NULL; } } return fCurrencyFormat; } NumberFormat* BNumberFormatImpl::GetPercent(BFormattingConventions* convention) { if (fPercentFormat == NULL) { UErrorCode err = U_ZERO_ERROR; fPercentFormat = NumberFormat::createInstance( *BFormattingConventions::Private(convention).ICULocale(), UNUM_PERCENT, err); if (fPercentFormat == NULL) return NULL; if (U_FAILURE(err)) { delete fPercentFormat; fPercentFormat = NULL; return NULL; } } return fPercentFormat; } ssize_t BNumberFormatImpl::ApplyFormatter(NumberFormat* formatter, char* string, size_t maxSize, const double value) { BString fullString; status_t status = ApplyFormatter(formatter, fullString, value); if (status != B_OK) return status; return strlcpy(string, fullString.String(), maxSize); } status_t BNumberFormatImpl::ApplyFormatter(NumberFormat* formatter, BString& string, const double value) { if (formatter == NULL) return B_NO_MEMORY; UnicodeString icuString; formatter->format(value, icuString); string.Truncate(0); BStringByteSink stringConverter(&string); icuString.toUTF8(stringConverter); return B_OK; } BNumberFormat::BNumberFormat() : BFormat() { fPrivateData = new BNumberFormatImpl(); } BNumberFormat::BNumberFormat(const BLocale* locale) : BFormat(locale) { fPrivateData = new BNumberFormatImpl(); } BNumberFormat::BNumberFormat(const BNumberFormat &other) : BFormat(other) { fPrivateData = new BNumberFormatImpl(*other.fPrivateData); } BNumberFormat::~BNumberFormat() { delete fPrivateData; } // #pragma mark - Formatting ssize_t BNumberFormat::Format(char* string, size_t maxSize, const double value) { BString fullString; status_t status = Format(fullString, value); if (status != B_OK) return status; return strlcpy(string, fullString.String(), maxSize); } status_t BNumberFormat::Format(BString& string, const double value) { NumberFormat* formatter = fPrivateData->GetFloat(&fConventions); if (formatter == NULL) return B_NO_MEMORY; UnicodeString icuString; formatter->format(value, icuString); string.Truncate(0); BStringByteSink stringConverter(&string); icuString.toUTF8(stringConverter); return B_OK; } ssize_t BNumberFormat::Format(char* string, size_t maxSize, const int32 value) { BString fullString; status_t status = Format(fullString, value); if (status != B_OK) return status; return strlcpy(string, fullString.String(), maxSize); } status_t BNumberFormat::Format(BString& string, const int32 value) { NumberFormat* formatter = fPrivateData->GetInteger(&fConventions); if (formatter == NULL) return B_NO_MEMORY; UnicodeString icuString; formatter->format((int32_t)value, icuString); string.Truncate(0); BStringByteSink stringConverter(&string); icuString.toUTF8(stringConverter); return B_OK; } status_t BNumberFormat::SetPrecision(int precision) { NumberFormat* decimalFormatter = fPrivateData->GetFloat(&fConventions); NumberFormat* currencyFormatter = fPrivateData->GetCurrency(&fConventions); NumberFormat* percentFormatter = fPrivateData->GetPercent(&fConventions); if ((decimalFormatter == NULL) || (currencyFormatter == NULL) || (percentFormatter == NULL)) return B_ERROR; decimalFormatter->setMinimumFractionDigits(precision); decimalFormatter->setMaximumFractionDigits(precision); currencyFormatter->setMinimumFractionDigits(precision); currencyFormatter->setMaximumFractionDigits(precision); percentFormatter->setMinimumFractionDigits(precision); percentFormatter->setMaximumFractionDigits(precision); return B_OK; } ssize_t BNumberFormat::FormatMonetary(char* string, size_t maxSize, const double value) { return fPrivateData->ApplyFormatter( fPrivateData->GetCurrency(&fConventions), string, maxSize, value); } status_t BNumberFormat::FormatMonetary(BString& string, const double value) { return fPrivateData->ApplyFormatter( fPrivateData->GetCurrency(&fConventions), string, value); } ssize_t BNumberFormat::FormatPercent(char* string, size_t maxSize, const double value) { return fPrivateData->ApplyFormatter( fPrivateData->GetPercent(&fConventions), string, maxSize, value); } status_t BNumberFormat::FormatPercent(BString& string, const double value) { return fPrivateData->ApplyFormatter( fPrivateData->GetPercent(&fConventions), string, value); } status_t BNumberFormat::Parse(const BString& string, double& value) { NumberFormat* parser = fPrivateData->GetFloat(&fConventions); if (parser == NULL) return B_NO_MEMORY; UnicodeString unicode(string.String()); Formattable result(0); UErrorCode err = U_ZERO_ERROR; parser->parse(unicode, result, err); if (err != U_ZERO_ERROR) return B_BAD_DATA; value = result.getDouble(); return B_OK; } BString BNumberFormat::GetSeparator(BNumberElement element) { DecimalFormatSymbols::ENumberFormatSymbol symbol; BString result; switch(element) { case B_DECIMAL_SEPARATOR: symbol = DecimalFormatSymbols::kDecimalSeparatorSymbol; break; case B_GROUPING_SEPARATOR: symbol = DecimalFormatSymbols::kGroupingSeparatorSymbol; break; default: return result; } NumberFormat* format = fPrivateData->GetFloat(&fConventions); DecimalFormat* decimal = dynamic_cast(format); if (decimal == NULL) return result; const DecimalFormatSymbols* symbols = decimal->getDecimalFormatSymbols(); UnicodeString string = symbols->getSymbol(symbol); BStringByteSink stringConverter(&result); string.toUTF8(stringConverter); return result; }