From a9faf943925a9041088130c4b9bb247e16d73322 Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Sun, 29 Aug 2010 20:55:00 +0000 Subject: [PATCH] * reintroduced be_locale as global information point for the current locale values * added locking to BLocale (needed since the data of the global object may change any time) * BLocale no longer passes out pointers to internal objects, it fill objects passed in by the client instead (just like be_locale_roster does) * dropped default language as member from RosterData, it is no part of the default locale * fleshed out implementation of TimeUnitFormat and DurationFormat, both of which can now be given a BLocale in order to set the strings being used during formatting git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38428 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/locale/DurationFormat.h | 31 ++++- headers/os/locale/Format.h | 10 +- headers/os/locale/Locale.h | 15 ++- headers/os/locale/TimeUnitFormat.h | 18 ++- headers/private/locale/MutableLocaleRoster.h | 1 - src/kits/locale/DurationFormat.cpp | 129 ++++++++++++++++--- src/kits/locale/Format.cpp | 64 +++++++-- src/kits/locale/Locale.cpp | 55 +++++++- src/kits/locale/LocaleRoster.cpp | 6 +- src/kits/locale/MutableLocaleRoster.cpp | 6 +- src/kits/locale/TimeUnitFormat.cpp | 90 ++++++++++++- 11 files changed, 374 insertions(+), 51 deletions(-) diff --git a/headers/os/locale/DurationFormat.h b/headers/os/locale/DurationFormat.h index 26b0fbe270..0c8aa88a0b 100644 --- a/headers/os/locale/DurationFormat.h +++ b/headers/os/locale/DurationFormat.h @@ -6,18 +6,43 @@ #define _B_DURATION_FORMAT_H_ -#include +#include #include #include +class BTimeZone; + +namespace icu_44 { + class GregorianCalendar; +} + + class BDurationFormat : public BFormat { + typedef BFormat Inherited; + public: + BDurationFormat( + const BString& separator = ", "); + BDurationFormat(const BDurationFormat& other); + virtual ~BDurationFormat(); + + BDurationFormat& operator=(const BDurationFormat& other); + + void SetSeparator(const BString& separator); + + virtual status_t SetLocale(const BLocale* locale); + status_t SetTimeZone(const BTimeZone* timeZone); + status_t Format(bigtime_t startValue, bigtime_t stopValue, BString* buffer, - time_unit_style style = B_TIME_UNIT_FULL, - const BString& separator = ", " + time_unit_style style = B_TIME_UNIT_FULL ) const; + +private: + BString fSeparator; + BTimeUnitFormat fTimeUnitFormat; + icu_44::GregorianCalendar* fCalendar; }; diff --git a/headers/os/locale/Format.h b/headers/os/locale/Format.h index fa015f175c..fdd64e294d 100644 --- a/headers/os/locale/Format.h +++ b/headers/os/locale/Format.h @@ -36,16 +36,22 @@ struct format_field_position { }; -class BFormatImpl; +class BLocale; class BFormat { +public: + status_t InitCheck() const; + + virtual status_t SetLocale(const BLocale* locale); protected: + BFormat(); BFormat(const BFormat& other); virtual ~BFormat(); BFormat& operator=(const BFormat& other); - BFormat(); + status_t fInitStatus; + BLocale* fLocale; }; diff --git a/headers/os/locale/Locale.h b/headers/os/locale/Locale.h index fc79f81738..a1d168d0c5 100644 --- a/headers/os/locale/Locale.h +++ b/headers/os/locale/Locale.h @@ -9,6 +9,7 @@ #include #include #include +#include class BCatalog; @@ -40,12 +41,13 @@ public: BLocale(const char* languageAndCountryCode = "en_US"); BLocale(const BLocale& other); - BLocale& operator=(const BLocale& other); ~BLocale(); - const BCollator* Collator() const { return &fCollator; } - const BCountry* Country() const { return &fCountry; } - const BLanguage* Language() const { return &fLanguage; } + BLocale& operator=(const BLocale& other); + + status_t GetCollator(BCollator* collator) const; + status_t GetLanguage(BLanguage* language) const; + status_t GetCountry(BCountry* country) const; const char* Code() const; bool GetName(BString& name) const; @@ -135,6 +137,7 @@ public: BString* key) const; protected: + mutable BLocker fLock; BCollator fCollator; BCountry fCountry; BLanguage fLanguage; @@ -147,6 +150,10 @@ protected: }; +// global locale object +extern const BLocale* be_locale; + + //--- collator short-hands inlines --- // #pragma mark - diff --git a/headers/os/locale/TimeUnitFormat.h b/headers/os/locale/TimeUnitFormat.h index faea760ab9..8837bf90c4 100644 --- a/headers/os/locale/TimeUnitFormat.h +++ b/headers/os/locale/TimeUnitFormat.h @@ -6,12 +6,16 @@ #define _B_TIME_UNIT_FORMAT_H_ -#include +#include #include class BString; +namespace icu_44 { + class TimeUnitFormat; +} + enum time_unit_style { B_TIME_UNIT_ABBREVIATED, // e.g. '5 hrs.' @@ -33,11 +37,23 @@ enum time_unit_element { class BTimeUnitFormat : public BFormat { + typedef BFormat Inherited; + public: + BTimeUnitFormat(); + BTimeUnitFormat(const BTimeUnitFormat& other); + virtual ~BTimeUnitFormat(); + + BTimeUnitFormat& operator=(const BTimeUnitFormat& other); + + virtual status_t SetLocale(const BLocale* locale); status_t Format(int32 value, time_unit_element unit, BString* buffer, time_unit_style style = B_TIME_UNIT_FULL ) const; + +private: + icu_44::TimeUnitFormat* fFormatter; }; diff --git a/headers/private/locale/MutableLocaleRoster.h b/headers/private/locale/MutableLocaleRoster.h index 23b47126a7..0d5e535d81 100644 --- a/headers/private/locale/MutableLocaleRoster.h +++ b/headers/private/locale/MutableLocaleRoster.h @@ -109,7 +109,6 @@ struct RosterData { BMessage fPreferredLanguages; BLocale fDefaultLocale; - BLanguage fDefaultLanguage; BTimeZone fDefaultTimeZone; RosterData(); diff --git a/src/kits/locale/DurationFormat.cpp b/src/kits/locale/DurationFormat.cpp index c07a8d9d66..8945ed9432 100644 --- a/src/kits/locale/DurationFormat.cpp +++ b/src/kits/locale/DurationFormat.cpp @@ -11,14 +11,14 @@ #include -#include +#include #include -#include -#include +#include +#include +#include - -using BPrivate::ObjectDeleter; +#include // maps our unit element to the corresponding ICU unit @@ -33,37 +33,130 @@ static const UCalendarDateFields skUnitMap[] = { }; -status_t BDurationFormat::Format(bigtime_t startValue, bigtime_t stopValue, - BString* buffer, time_unit_style style, const BString& separator) const +BDurationFormat::BDurationFormat(const BString& separator) + : + Inherited(), + fSeparator(separator), + fTimeUnitFormat() +{ + UErrorCode icuStatus = U_ZERO_ERROR; + fCalendar = new GregorianCalendar(icuStatus); + if (fCalendar == NULL) { + fInitStatus = B_NO_MEMORY; + return; + } + + fInitStatus = SetLocale(fLocale); +} + + +BDurationFormat::BDurationFormat(const BDurationFormat& other) + : + Inherited(other), + fSeparator(other.fSeparator), + fTimeUnitFormat(other.fTimeUnitFormat), + fCalendar(other.fCalendar != NULL + ? new GregorianCalendar(*other.fCalendar) : NULL) +{ + if (fCalendar == NULL && other.fCalendar != NULL) + fInitStatus = B_NO_MEMORY; +} + + +BDurationFormat::~BDurationFormat() +{ + delete fCalendar; +} + + +BDurationFormat& +BDurationFormat::operator=(const BDurationFormat& other) +{ + if (this == &other) + return *this; + + fSeparator = other.fSeparator; + fTimeUnitFormat = other.fTimeUnitFormat; + delete fCalendar; + fCalendar = other.fCalendar != NULL + ? new GregorianCalendar(*other.fCalendar) : NULL; + + if (fCalendar == NULL && other.fCalendar != NULL) + fInitStatus = B_NO_MEMORY; + + return *this; +} + + +void +BDurationFormat::SetSeparator(const BString& separator) +{ + fSeparator = separator; +} + + +status_t +BDurationFormat::SetLocale(const BLocale* locale) +{ + status_t result = Inherited::SetLocale(locale); + if (result != B_OK) + return result; + + return fTimeUnitFormat.SetLocale(locale); +} + + +status_t +BDurationFormat::SetTimeZone(const BTimeZone* timeZone) +{ + if (fCalendar == NULL) + return B_NO_INIT; + + BTimeZone::Accessor zoneAccessor; + if (timeZone == NULL) { + BTimeZone defaultTimeZone; + status_t result + = be_locale_roster->GetDefaultTimeZone(&defaultTimeZone); + if (result != B_OK) + return result; + zoneAccessor.SetTo(&defaultTimeZone); + } else + zoneAccessor.SetTo(timeZone); + + TimeZone* icuTimeZone = zoneAccessor.IcuTimeZone(); + if (icuTimeZone != NULL) + fCalendar->setTimeZone(*icuTimeZone); + + return B_OK; +} + + +status_t +BDurationFormat::Format(bigtime_t startValue, bigtime_t stopValue, + BString* buffer, time_unit_style style) const { if (buffer == NULL) return B_BAD_VALUE; UErrorCode icuStatus = U_ZERO_ERROR; - ObjectDeleter calendar = Calendar::createInstance(icuStatus); - if (calendar.Get() == NULL) - return B_NO_MEMORY; + fCalendar->setTime((UDate)startValue / 1000, icuStatus); if (!U_SUCCESS(icuStatus)) return B_ERROR; - calendar->setTime((UDate)startValue / 1000, icuStatus); - if (!U_SUCCESS(icuStatus)) - return B_ERROR; - - BTimeUnitFormat timeUnitFormat; UDate stop = (UDate)stopValue / 1000; bool needSeparator = false; for (int unit = 0; unit <= B_TIME_UNIT_LAST; ++unit) { - int delta = calendar->fieldDifference(stop, skUnitMap[unit], icuStatus); + int delta + = fCalendar->fieldDifference(stop, skUnitMap[unit], icuStatus); if (!U_SUCCESS(icuStatus)) return B_ERROR; if (delta != 0) { if (needSeparator) - buffer->Append(separator); + buffer->Append(fSeparator); else needSeparator = true; - status_t status = timeUnitFormat.Format(delta, + status_t status = fTimeUnitFormat.Format(delta, (time_unit_element)unit, buffer, style); if (status != B_OK) return status; diff --git a/src/kits/locale/Format.cpp b/src/kits/locale/Format.cpp index 9d42141dfe..e47b5a993b 100644 --- a/src/kits/locale/Format.cpp +++ b/src/kits/locale/Format.cpp @@ -1,25 +1,73 @@ #include -#include -// copy constructor -BFormat::BFormat(const BFormat &other) +#include + +#include + + +BFormat::BFormat() + : + fInitStatus(B_NO_INIT), + fLocale(NULL) { } -// destructor + +BFormat::BFormat(const BFormat &other) + : + fInitStatus(other.fInitStatus), + fLocale(other.fLocale != NULL + ? new (std::nothrow) BLocale(*other.fLocale) + : NULL) +{ +} + + BFormat::~BFormat() { + delete fLocale; } -// = + BFormat & -BFormat::operator=(const BFormat &other) +BFormat::operator=(const BFormat& other) { + if (this == &other) + return *this; + + fInitStatus = other.fInitStatus; + delete fLocale; + fLocale = other.fLocale != NULL + ? new (std::nothrow) BLocale(*other.fLocale) : NULL; + + if (fLocale == NULL && other.fLocale != NULL) + fInitStatus = B_NO_MEMORY; + return *this; } -// constructor -BFormat::BFormat() + +status_t +BFormat::InitCheck() const { + return fInitStatus; } + +status_t +BFormat::SetLocale(const BLocale* locale) +{ + if (locale != NULL) { + if (fLocale == NULL) { + fLocale = new (std::nothrow) BLocale(*locale); + if (fLocale == NULL) + return B_NO_MEMORY; + } else + *fLocale = *locale; + } else { + delete fLocale; + fLocale = NULL; + } + + return B_OK; +} diff --git a/src/kits/locale/Locale.cpp b/src/kits/locale/Locale.cpp index 979a926c78..aa03c6df51 100644 --- a/src/kits/locale/Locale.cpp +++ b/src/kits/locale/Locale.cpp @@ -5,10 +5,12 @@ #include +#include #include #include #include #include +#include #include #include @@ -85,6 +87,54 @@ BLocale::~BLocale() } +status_t +BLocale::GetCollator(BCollator* collator) const +{ + if (!collator) + return B_BAD_VALUE; + + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + + *collator = fCollator; + + return B_OK; +} + + +status_t +BLocale::GetLanguage(BLanguage* language) const +{ + if (!language) + return B_BAD_VALUE; + + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + + *language = fLanguage; + + return B_OK; +} + + +status_t +BLocale::GetCountry(BCountry* country) const +{ + if (!country) + return B_BAD_VALUE; + + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + + *country = fCountry; + + return B_OK; +} + + const char * BLocale::GetString(uint32 id) { @@ -170,8 +220,11 @@ BLocale::FormatDate(BString *string, time_t time, bool longFormat, string->Truncate(0); // We make the string empty, this way even in cases where ICU fail we at // least return something sane + BLanguage defaultLanguage; + be_locale_roster->GetDefaultLanguage(&defaultLanguage); + Locale locale(defaultLanguage.Code()); ObjectDeleter dateFormatter = CreateDateFormat(longFormat, - *fICULocale, longFormat ? fLongDateFormat : fShortDateFormat); + locale, longFormat ? fLongDateFormat : fShortDateFormat); if (dateFormatter.Get() == NULL) return B_NO_MEMORY; diff --git a/src/kits/locale/LocaleRoster.cpp b/src/kits/locale/LocaleRoster.cpp index a4eee6ef72..d5d73a97da 100644 --- a/src/kits/locale/LocaleRoster.cpp +++ b/src/kits/locale/LocaleRoster.cpp @@ -88,7 +88,7 @@ BLocaleRoster::GetDefaultCollator(BCollator* collator) const if (!lock.IsLocked()) return B_ERROR; - *collator = *gRosterData.fDefaultLocale.Collator(); + gRosterData.fDefaultLocale.GetCollator(collator); return B_OK; } @@ -104,7 +104,7 @@ BLocaleRoster::GetDefaultLanguage(BLanguage* language) const if (!lock.IsLocked()) return B_ERROR; - *language = gRosterData.fDefaultLanguage; + gRosterData.fDefaultLocale.GetLanguage(language); return B_OK; } @@ -120,7 +120,7 @@ BLocaleRoster::GetDefaultCountry(BCountry* country) const if (!lock.IsLocked()) return B_ERROR; - *country = *gRosterData.fDefaultLocale.Country(); + gRosterData.fDefaultLocale.GetCountry(country); return B_OK; } diff --git a/src/kits/locale/MutableLocaleRoster.cpp b/src/kits/locale/MutableLocaleRoster.cpp index d1f63993b1..d827ff600f 100644 --- a/src/kits/locale/MutableLocaleRoster.cpp +++ b/src/kits/locale/MutableLocaleRoster.cpp @@ -462,7 +462,6 @@ RosterData::_LoadLocaleSettings() fPreferredLanguages.MakeEmpty(); fPreferredLanguages.AddString("language", "en"); _SetDefaultLocale("en_US"); - fDefaultLanguage.SetTo("en"); return status; } @@ -599,7 +598,7 @@ RosterData::_SetPreferredLanguages(const BMessage* languages) if (languages != NULL && languages->FindString("language", &langName) == B_OK) { fDefaultLocale.SetCollator(BCollator(langName.String())); - fDefaultLanguage.SetTo(langName.String()); + fDefaultLocale.SetLanguage(langName.String()); fPreferredLanguages.RemoveName("language"); for (int i = 0; languages->FindString("language", i, &langName) == B_OK; @@ -610,7 +609,6 @@ RosterData::_SetPreferredLanguages(const BMessage* languages) fPreferredLanguages.MakeEmpty(); fPreferredLanguages.AddString("language", "en"); fDefaultLocale.SetCollator(BCollator("en")); - fDefaultLanguage.SetTo("en"); } return B_OK; @@ -917,3 +915,5 @@ MutableLocaleRoster::UnloadCatalog(BCatalogAddOn* catalog) BLocaleRoster* be_locale_roster = &BPrivate::gLocaleRoster; + +const BLocale* be_locale = &BPrivate::gRosterData.fDefaultLocale; diff --git a/src/kits/locale/TimeUnitFormat.cpp b/src/kits/locale/TimeUnitFormat.cpp index a9cbad945c..5873df2c55 100644 --- a/src/kits/locale/TimeUnitFormat.cpp +++ b/src/kits/locale/TimeUnitFormat.cpp @@ -13,10 +13,14 @@ #include #include +#include #include #include #include +#include +#include +#include // maps our unit element to the corresponding ICU unit static const TimeUnit::UTimeUnitFields skUnitMap[] = { @@ -30,19 +34,91 @@ static const TimeUnit::UTimeUnitFields skUnitMap[] = { }; -status_t BTimeUnitFormat::Format(int32 value, time_unit_element unit, +BTimeUnitFormat::BTimeUnitFormat() + : + Inherited(), + fFormatter(NULL) +{ + fInitStatus = SetLocale(fLocale); +} + + +BTimeUnitFormat::BTimeUnitFormat(const BTimeUnitFormat& other) + : + Inherited(other), + fFormatter(other.fFormatter != NULL + ? new TimeUnitFormat(*other.fFormatter) : NULL) +{ + if (fFormatter == NULL && other.fFormatter != NULL) + fInitStatus = B_NO_MEMORY; +} + + +BTimeUnitFormat::~BTimeUnitFormat() +{ + delete fFormatter; +} + + +BTimeUnitFormat& +BTimeUnitFormat::operator=(const BTimeUnitFormat& other) +{ + if (this == &other) + return *this; + + Inherited::operator=(other); + + delete fFormatter; + fFormatter = other.fFormatter != NULL + ? new TimeUnitFormat(*other.fFormatter) : NULL; + + if (fFormatter == NULL && other.fFormatter != NULL) + fInitStatus = B_NO_MEMORY; + + return *this; +} + + +status_t +BTimeUnitFormat::SetLocale(const BLocale* locale) +{ + status_t result = Inherited::SetLocale(locale); + if (result != B_OK) + return result; + + BLanguage language; + if (fLocale != NULL) + fLocale->GetLanguage(&language); + else + be_locale->GetLanguage(&language); + + Locale icuLocale(language.Code()); + UErrorCode icuStatus = U_ZERO_ERROR; + if (fFormatter == NULL) { + fFormatter = new TimeUnitFormat(icuLocale, icuStatus); + if (fFormatter == NULL) + return B_NO_MEMORY; + } else + fFormatter->setLocale(icuLocale, icuStatus); + if (!U_SUCCESS(icuStatus)) + return B_ERROR; + + return B_OK; +} + + +status_t +BTimeUnitFormat::Format(int32 value, time_unit_element unit, BString* buffer, time_unit_style style) const { if (buffer == NULL || unit < 0 || unit > B_TIME_UNIT_LAST || (style != B_TIME_UNIT_ABBREVIATED && style != B_TIME_UNIT_FULL)) return B_BAD_VALUE; + if (fFormatter == NULL) + return B_NO_INIT; + UErrorCode icuStatus = U_ZERO_ERROR; - TimeUnitFormat timeUnitFormatter(icuStatus); - - if (!U_SUCCESS(icuStatus)) - return B_ERROR; - TimeUnitAmount* timeUnitAmount = new TimeUnitAmount((double)value, skUnitMap[unit], icuStatus); if (timeUnitAmount == NULL) @@ -54,7 +130,7 @@ status_t BTimeUnitFormat::Format(int32 value, time_unit_element unit, formattable.adoptObject(timeUnitAmount); FieldPosition pos(FieldPosition::DONT_CARE); UnicodeString unicodeResult; - timeUnitFormatter.format(formattable, unicodeResult, pos, icuStatus); + fFormatter->format(formattable, unicodeResult, pos, icuStatus); if (!U_SUCCESS(icuStatus)) return B_ERROR;