* 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
This commit is contained in:
Oliver Tappe 2010-08-29 20:55:00 +00:00
parent 279125fbd9
commit a9faf94392
11 changed files with 374 additions and 51 deletions

View File

@ -6,18 +6,43 @@
#define _B_DURATION_FORMAT_H_
#include <DateTimeFormat.h>
#include <Format.h>
#include <String.h>
#include <TimeUnitFormat.h>
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;
};

View File

@ -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;
};

View File

@ -9,6 +9,7 @@
#include <Collator.h>
#include <Country.h>
#include <Language.h>
#include <Locker.h>
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 -

View File

@ -6,12 +6,16 @@
#define _B_TIME_UNIT_FORMAT_H_
#include <DateTimeFormat.h>
#include <Format.h>
#include <SupportDefs.h>
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;
};

View File

@ -109,7 +109,6 @@ struct RosterData {
BMessage fPreferredLanguages;
BLocale fDefaultLocale;
BLanguage fDefaultLanguage;
BTimeZone fDefaultTimeZone;
RosterData();

View File

@ -11,14 +11,14 @@
#include <new>
#include <unicode/calendar.h>
#include <unicode/gregocal.h>
#include <unicode/utypes.h>
#include <AutoDeleter.h>
#include <TimeUnitFormat.h>
#include <Locale.h>
#include <LocaleRoster.h>
#include <TimeZone.h>
using BPrivate::ObjectDeleter;
#include <TimeZoneAccessor.h>
// 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 = 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;

View File

@ -1,25 +1,73 @@
#include <Format.h>
#include <FormatImpl.h>
// copy constructor
BFormat::BFormat(const BFormat &other)
#include <new>
#include <Locale.h>
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;
}

View File

@ -5,10 +5,12 @@
#include <AutoDeleter.h>
#include <Autolock.h>
#include <CalendarView.h>
#include <Catalog.h>
#include <Locale.h>
#include <LocaleRoster.h>
#include <MutableLocaleRoster.h>
#include <TimeZone.h>
#include <unicode/datefmt.h>
@ -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<DateFormat> dateFormatter = CreateDateFormat(longFormat,
*fICULocale, longFormat ? fLongDateFormat : fShortDateFormat);
locale, longFormat ? fLongDateFormat : fShortDateFormat);
if (dateFormatter.Get() == NULL)
return B_NO_MEMORY;

View File

@ -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;
}

View File

@ -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;

View File

@ -13,10 +13,14 @@
#include <new>
#include <unicode/format.h>
#include <unicode/locid.h>
#include <unicode/tmutfmt.h>
#include <unicode/utypes.h>
#include <ICUWrapper.h>
#include <Language.h>
#include <Locale.h>
#include <LocaleRoster.h>
// 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;