Largish cleanup sweep concerning the Locale Kit (sorry it got so big):

* refactored private/mutable stuff out of LocaleRoster into MutableLocaleRoster
* moved management of Locale/Time settings file and broadcasting of any changes 
  out of preflets and into MutableLocaleRoster
* added proper sorting to the listviews of the Locale preflet
* the Time preflet no longer overlaps long timezone names into the actual time
* several fixes with respect to leaking ICU objects, esp. in BCountry
* the locale roster no longer passes out references to its own BCountry object,
  but uses copies, instead - this makes locking superfluous, as the clients'
  BCountry objects can no longer be changed by the setting a new default 
  country in the locale roster
* removed pretty useless POSIX-style symbol fetching from BCountry - if we
  need that at all, it should live in the dedicated formatter classes
* adjusted readonlybootprompt, dstcheck and Deskbar to the changed Locale API
* refactored existing Time-formatter into TimeUnitFormat and DurationFormat
  (the latter of which is now used by AboutSystem)
* added stubs for Date, DateTime and Time formatters
* lots of coding style fixes throughout the Locale Kit and the Locale and Time 
  preflets
This will probably break most external apps making use of the Locale Kit - it
does break WebPositive.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37831 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Tappe 2010-08-01 20:28:19 +00:00
parent 98dc4f9c65
commit 38ac8def5a
53 changed files with 2488 additions and 2135 deletions

View File

@ -220,7 +220,6 @@ class BCatalog {
// For BCatalog add-on implementations:
class BCatalogAddOn {
friend class BLocaleRoster;
public:
BCatalogAddOn(const char *signature, const char *language,
uint32 fingerprint);
@ -269,6 +268,8 @@ class BCatalogAddOn {
const char *cmt);
static int32 MarkForTranslation(int32 id);
void SetNext(BCatalogAddOn *next);
protected:
virtual void UpdateFingerprint();

View File

@ -1,13 +1,13 @@
/*
* Copyright 2003-2010, Haiku, Inc.
* Distributed under the terms of the MIT Licence.
*/
*/
#ifndef _COLLATOR_H_
#define _COLLATOR_H_
#include <SupportDefs.h>
#include <Archivable.h>
#include <SupportDefs.h>
namespace icu_44 {
@ -33,62 +33,72 @@ enum collator_strengths {
};
// N.B.: This class is not multithread-safe, as Compare() and GetKey() change
// the ICUCollator (the strength). So if you want to use a BCollator from
// more than one thread, you need to protect it with a lock
class BCollator : public BArchivable {
public:
BCollator();
BCollator(const char *locale, int8 strength, bool ignorePunctuation);
BCollator(BMessage *archive);
~BCollator();
public:
BCollator();
BCollator(const char* locale,
int8 strength = B_COLLATE_PRIMARY,
bool ignorePunctuation = false);
BCollator(BMessage* archive);
void SetDefaultStrength(int8 strength);
int8 DefaultStrength() const;
BCollator(const BCollator& other);
void SetIgnorePunctuation(bool ignore);
bool IgnorePunctuation() const;
~BCollator();
status_t GetSortKey(const char *string, BString *key,
int8 strength = B_COLLATE_DEFAULT);
BCollator& operator=(const BCollator& source);
int Compare(const char *, const char *, int32 len = -1,
int8 strength = B_COLLATE_DEFAULT);
bool Equal(const char *, const char *, int32 len = -1,
int8 strength = B_COLLATE_DEFAULT);
bool Greater(const char *, const char *, int32 len = -1,
int8 strength = B_COLLATE_DEFAULT);
bool GreaterOrEqual(const char *, const char *, int32 len = -1,
int8 strength = B_COLLATE_DEFAULT);
void SetDefaultStrength(int8 strength);
int8 DefaultStrength() const;
// (un-)archiving API
status_t Archive(BMessage *archive, bool deep) const;
static BArchivable *Instantiate(BMessage *archive);
void SetIgnorePunctuation(bool ignore);
bool IgnorePunctuation() const;
private:
icu_44::Collator* fICUCollator;
icu_44::RuleBasedCollator* fFallbackICUCollator;
int8 fStrength;
bool fIgnorePunctuation;
status_t GetSortKey(const char* string, BString* key,
int8 strength = B_COLLATE_DEFAULT) const;
int Compare(const char* s1, const char* s2,
int8 strength = B_COLLATE_DEFAULT) const;
bool Equal(const char* s1, const char* s2,
int8 strength = B_COLLATE_DEFAULT) const;
bool Greater(const char* s1, const char* s2,
int8 strength = B_COLLATE_DEFAULT) const;
bool GreaterOrEqual(const char* s1, const char* s2,
int8 strength = B_COLLATE_DEFAULT) const;
// (un-)archiving API
status_t Archive(BMessage* archive, bool deep) const;
static BArchivable* Instantiate(BMessage* archive);
private:
status_t _SetStrength(int8 strength) const;
mutable icu_44::Collator* fICUCollator;
int8 fDefaultStrength;
bool fIgnorePunctuation;
};
inline bool
BCollator::Equal(const char *s1, const char *s2, int32 len, int8 strength)
BCollator::Equal(const char *s1, const char *s2, int8 strength) const
{
return Compare(s1, s2, len, strength) == 0;
return Compare(s1, s2, strength) == 0;
}
inline bool
BCollator::Greater(const char *s1, const char *s2, int32 len, int8 strength)
BCollator::Greater(const char *s1, const char *s2, int8 strength) const
{
return Compare(s1, s2, len, strength) > 0;
return Compare(s1, s2, strength) > 0;
}
inline bool
BCollator::GreaterOrEqual(const char *s1, const char *s2, int32 len,
int8 strength)
BCollator::GreaterOrEqual(const char *s1, const char *s2, int8 strength) const
{
return Compare(s1, s2, len, strength) >= 0;
return Compare(s1, s2, strength) >= 0;
}

View File

@ -1,10 +1,13 @@
/*
* Copyright 2003-2010, Haiku, Inc.
* Distributed under the terms of the MIT Licence.
*/
#ifndef _COUNTRY_H_
#define _COUNTRY_H_
#include <List.h>
#include <LocaleStrings.h>
#include <Locker.h>
#include <String.h>
#include <SupportDefs.h>
@ -36,101 +39,86 @@ typedef enum {
class BCountry {
public:
BCountry(const char* languageCode, const char* countryCode);
BCountry(const char* languageAndCountryCode = "en_US");
BCountry(const BCountry& other);
BCountry& operator=(const BCountry& other);
virtual ~BCountry();
public:
BCountry(const char* languageCode,
const char* countryCode);
BCountry(const char* languageAndCountryCode
= "en_US");
BCountry(const BCountry& other);
BCountry& operator=(const BCountry& other);
~BCountry();
bool Name(BString& name) const;
bool LocaleName(BString& name) const;
const char* Code() const;
status_t GetIcon(BBitmap* result);
bool GetName(BString& name) const;
bool GetLocaleName(BString& name) const;
const char* Code() const;
status_t GetIcon(BBitmap* result) const;
const char* GetString(uint32 id) const;
const char* GetLocalizedString(uint32 id) const;
// Date
// Date
status_t FormatDate(char* string, size_t maxSize, time_t time,
bool longFormat);
status_t FormatDate(BString* string, time_t time,
bool longFormat);
status_t FormatDate(BString* string, int*& fieldPositions,
int& fieldCount, time_t time, bool longFormat);
status_t DateFields(BDateElement*& fields, int& fieldCount,
bool longFormat);
status_t DateFormat(BString&, bool longFormat);
status_t SetDateFormat(const char* formatString,
bool longFormat = true);
status_t FormatDate(char* string, size_t maxSize,
time_t time, bool longFormat);
status_t FormatDate(BString* string, time_t time,
bool longFormat);
status_t FormatDate(BString* string,
int*& fieldPositions, int& fieldCount,
time_t time, bool longFormat);
status_t GetDateFields(BDateElement*& fields,
int& fieldCount, bool longFormat) const;
status_t GetDateFormat(BString&, bool longFormat) const;
status_t SetDateFormat(const char* formatString,
bool longFormat = true);
int StartOfWeek();
int StartOfWeek() const;
// Time
// Time
status_t FormatTime(char* string, size_t maxSize, time_t time,
bool longFormat);
status_t FormatTime(BString* string, time_t time,
bool longFormat);
status_t FormatTime(BString* string, int*& fieldPositions,
int& fieldCount, time_t time, bool longFormat);
status_t TimeFields(BDateElement*& fields, int& fieldCount,
bool longFormat);
status_t FormatTime(char* string, size_t maxSize,
time_t time, bool longFormat);
status_t FormatTime(BString* string, time_t time,
bool longFormat);
status_t FormatTime(BString* string,
int*& fieldPositions, int& fieldCount,
time_t time, bool longFormat);
status_t GetTimeFields(BDateElement*& fields,
int& fieldCount, bool longFormat) const;
status_t SetTimeFormat(const char* formatString,
bool longFormat = true);
status_t TimeFormat(BString&, bool longFormat);
status_t SetTimeFormat(const char* formatString,
bool longFormat = true);
status_t GetTimeFormat(BString& out,
bool longFormat) const;
// numbers
// numbers
virtual void FormatNumber(char* string, size_t maxSize, double value);
virtual status_t FormatNumber(BString* string, double value);
virtual void FormatNumber(char* string, size_t maxSize, int32 value);
virtual void FormatNumber(BString* string, int32 value);
status_t FormatNumber(char* string, size_t maxSize,
double value);
status_t FormatNumber(BString* string, double value);
status_t FormatNumber(char* string, size_t maxSize,
int32 value);
status_t FormatNumber(BString* string, int32 value);
bool DecimalPoint(BString&) const;
bool ThousandsSeparator(BString&) const;
bool Grouping(BString&) const;
// measurements
bool PositiveSign(BString&) const;
bool NegativeSign(BString&) const;
int8 Measurement() const;
// measurements
// monetary
virtual int8 Measurement() const;
ssize_t FormatMonetary(char* string, size_t maxSize,
double value);
ssize_t FormatMonetary(BString* string, double value);
// monetary
// timezones
virtual ssize_t FormatMonetary(char* string, size_t maxSize,
double value);
virtual ssize_t FormatMonetary(BString* string, double value);
int GetTimeZones(BList& timezones) const;
bool CurrencySymbol(BString&) const;
bool InternationalCurrencySymbol(BString&) const;
bool MonDecimalPoint(BString&) const;
bool MonThousandsSeparator(BString&) const;
bool MonGrouping(BString&) const;
virtual int32 MonFracDigits() const;
// timezones
int GetTimeZones(BList& timezones);
private:
icu_44::DateFormat* _LockDateFormatter(bool longFormat);
icu_44::DateFormat* _LockTimeFormatter(bool longFormat);
void _UnlockDateFormatter(bool longFormat);
void _UnlockTimeFormatter(bool longFormat);
icu_44::DateFormat* fICULongDateFormatter;
icu_44::DateFormat* fICUShortDateFormatter;
icu_44::DateFormat* fICULongTimeFormatter;
icu_44::DateFormat* fICUShortTimeFormatter;
icu_44::Locale* fICULocale;
BLocker fLongDateLock;
BLocker fShortDateLock;
BLocker fLongTimeLock;
BLocker fShortTimeLock;
private:
icu_44::Locale* fICULocale;
BString fLongDateFormat;
BString fShortDateFormat;
BString fLongTimeFormat;
BString fShortTimeFormat;
};
#endif /* _COUNTRY_H_ */

View File

@ -0,0 +1,30 @@
/*
* Copyright 2010, Haiku, Inc.
* Distributed under the terms of the MIT Licence.
*/
#ifndef _B_DATE_FORMAT_H_
#define _B_DATE_FORMAT_H_
#include <DateTimeFormat.h>
class BString;
class BDateFormat : public BDateTimeFormat {
public:
BDateFormat();
BDateFormat(const BDateFormat &other);
virtual ~BDateFormat();
// formatting
// no-frills version: Simply appends the
// formatted date to the string buffer.
// Can fail only with B_NO_MEMORY or B_BAD_VALUE.
virtual status_t Format(bigtime_t value, BString* buffer) const;
// TODO: ... all, basically!
};
#endif // _B_DATE_FORMAT_H_

View File

@ -0,0 +1,31 @@
/*
* Copyright 2010, Haiku, Inc.
* Distributed under the terms of the MIT Licence.
*/
#ifndef _B_DATE_TIME_FORMAT_H_
#define _B_DATE_TIME_FORMAT_H_
#include <Format.h>
#include <FormatParameters.h>
class BString;
class BDateTimeFormat : public BFormat {
public:
BDateTimeFormat();
BDateTimeFormat(const BDateTimeFormat &other);
virtual ~BDateTimeFormat();
// formatting
// no-frills version: Simply appends the
// formatted date to the string buffer.
// Can fail only with B_NO_MEMORY or B_BAD_VALUE.
virtual status_t Format(bigtime_t value, BString* buffer) const;
// TODO: ... basically, all of it!
};
#endif // _B_DATE_TIME_FORMAT_H_

View File

@ -0,0 +1,24 @@
/*
* Copyright 2010, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#ifndef _B_DURATION_FORMAT_H_
#define _B_DURATION_FORMAT_H_
#include <DateTimeFormat.h>
#include <String.h>
#include <TimeUnitFormat.h>
class BDurationFormat : public BFormat {
public:
status_t Format(bigtime_t startValue,
bigtime_t stopValue, BString* buffer,
time_unit_style style = B_TIME_UNIT_FULL,
const BString& separator = ", "
) const;
};
#endif

View File

@ -1,9 +1,14 @@
/*
* Copyright 2003-2010, Haiku, Inc.
* Distributed under the terms of the MIT Licence.
*/
#ifndef _B_FORMAT_H_
#define _B_FORMAT_H_
#include <FormatParameters.h>
#include <SupportDefs.h>
// types of fields contained in formatted strings
enum {
// number format fields
@ -30,16 +35,18 @@ struct format_field_position {
int32 length;
};
class BFormatImpl;
class BFormat {
protected:
BFormat(const BFormat &other);
~BFormat();
protected:
BFormat(const BFormat& other);
virtual ~BFormat();
BFormat &operator=(const BFormat &other);
BFormat& operator=(const BFormat& other);
BFormat();
BFormat();
};
#endif // _B_FORMAT_H_

View File

@ -27,8 +27,13 @@ enum script_direction {
class BLanguage {
public:
BLanguage();
BLanguage(const char* language);
BLanguage(const BLanguage& other);
~BLanguage();
BLanguage& operator=(const BLanguage& source);
status_t GetName(BString& name) const;
status_t GetTranslatedName(BString& name) const;
@ -43,19 +48,15 @@ public:
uint8 Direction() const;
status_t SetTo(const char* language);
// see definitions below
const char* GetString(uint32 id) const;
private:
friend class BLocaleRoster;
BLanguage(const char *language);
void Default();
private:
char* fStrings[B_NUM_LANGUAGE_STRINGS];
// BString fStrings[B_NUM_LANGUAGE_STRINGS];
uint8 fDirection;
icu_44::Locale* fICULocale;
icu_44::Locale* fICULocale;
};

View File

@ -7,86 +7,92 @@
#include <Collator.h>
#include <Language.h>
#include <Country.h>
#include <Language.h>
class BCatalog;
class BLocaleRoster;
class BString;
class BLocale {
public:
BLocale();
~BLocale();
public:
BLocale();
~BLocale();
BCollator *Collator() const { return fCollator; }
BCountry *Country() const { return fCountry; }
BLanguage *Language() const { return fLanguage; }
const BCollator* Collator() const { return &fCollator; }
const BCountry* Country() const { return &fCountry; }
const BLanguage* Language() const { return &fLanguage; }
// see definitions in LocaleStrings.h
const char *GetString(uint32 id);
// see definitions in LocaleStrings.h
const char* GetString(uint32 id);
void FormatString(char *target, size_t maxSize, char *fmt, ...);
void FormatString(BString *, char *fmt, ...);
void FormatDateTime(char *target, size_t maxSize, const char *fmt,
time_t);
void FormatDateTime(BString *, const char *fmt, time_t);
void FormatString(char* target, size_t maxSize,
char* fmt, ...);
void FormatString(BString* buffer, char* fmt, ...);
void FormatDateTime(char* target, size_t maxSize,
const char* fmt, time_t value);
void FormatDateTime(BString* buffer, const char* fmt,
time_t value);
// Country short-hands
// Country short-hands, TODO: all these should go, once the
// Date...Format classes are done
void FormatDate(char* target, size_t maxSize,
time_t value, bool longFormat);
void FormatDate(BString* target, time_t value,
bool longFormat);
void FormatTime(char* target, size_t maxSize,
time_t value, bool longFormat);
void FormatTime(BString* target, time_t value,
bool longFormat);
void FormatDate(char *target, size_t maxSize, time_t, bool longFormat);
void FormatDate(BString *target, time_t, bool longFormat);
void FormatTime(char *target, size_t maxSize, time_t, bool longFormat);
void FormatTime(BString *target, time_t, bool longFormat);
// Collator short-hands
int StringCompare(const char* s1,
const char* s2) const;
int StringCompare(const BString* s1,
const BString* s2) const;
// Collator short-hands
void GetSortKey(const char* string,
BString* key) const;
int StringCompare(const char *, const char *, int32 len = -1,
int8 strength = B_COLLATE_DEFAULT) const;
int StringCompare(const BString *, const BString *,
int32 len = -1, int8 strength = B_COLLATE_DEFAULT) const;
void GetSortKey(const char *string, BString *key);
protected:
BCollator *fCollator;
BLanguage *fLanguage;
BCountry *fCountry;
protected:
BCollator fCollator;
BCountry fCountry;
BLanguage fLanguage;
};
// global objects
extern BLocale *be_locale;
extern BLocaleRoster *be_locale_roster;
extern BLocale* be_locale;
//----------------------------------------------------------------------
//--- country short-hands inlines ---
inline void
BLocale::FormatDate(char *target, size_t maxSize, time_t timer, bool longFormat)
BLocale::FormatDate(char* target, size_t maxSize, time_t timer, bool longFormat)
{
fCountry->FormatDate(target, maxSize, timer, longFormat);
fCountry.FormatDate(target, maxSize, timer, longFormat);
}
inline void
BLocale::FormatDate(BString *target, time_t timer, bool longFormat)
BLocale::FormatDate(BString* target, time_t timer, bool longFormat)
{
fCountry->FormatDate(target, timer, longFormat);
fCountry.FormatDate(target, timer, longFormat);
}
inline void
BLocale::FormatTime(char *target, size_t maxSize, time_t timer, bool longFormat)
BLocale::FormatTime(char* target, size_t maxSize, time_t timer, bool longFormat)
{
fCountry->FormatTime(target, maxSize, timer, longFormat);
fCountry.FormatTime(target, maxSize, timer, longFormat);
}
inline void
BLocale::FormatTime(BString *target, time_t timer, bool longFormat)
BLocale::FormatTime(BString* target, time_t timer, bool longFormat)
{
fCountry->FormatTime(target, timer, longFormat);
fCountry.FormatTime(target, timer, longFormat);
}
@ -94,23 +100,24 @@ BLocale::FormatTime(BString *target, time_t timer, bool longFormat)
// #pragma mark -
inline int
BLocale::StringCompare(const char *string1, const char *string2, int32 length, int8 strength) const
BLocale::StringCompare(const char* s1, const char* s2) const
{
return fCollator->Compare(string1, string2, length, strength);
return fCollator.Compare(s1, s2);
}
inline int
BLocale::StringCompare(const BString *string1, const BString *string2, int32 length, int8 strength) const
BLocale::StringCompare(const BString* s1, const BString* s2) const
{
return fCollator->Compare(string1->String(), string2->String(), length, strength);
return fCollator.Compare(s1->String(), s2->String());
}
inline void
BLocale::GetSortKey(const char *string, BString *key)
BLocale::GetSortKey(const char* string, BString* key) const
{
fCollator->GetSortKey(string, key);
fCollator.GetSortKey(string, key);
}
#endif /* _B_LOCALE_H_ */

View File

@ -9,89 +9,70 @@
#include <String.h>
class BLanguage;
class BLocale;
class BCatalog;
class BCollator;
class BCountry;
class BCatalog;
class BCatalogAddOn;
class BLanguage;
class BLocale;
class BMessage;
class BTimeZone;
struct entry_ref;
namespace BPrivate {
class EditableCatalog;
}
enum {
B_LOCALE_CHANGED = '_LCC',
B_LOCALE_CHANGED = '_LCC',
};
class BLocaleRoster {
public:
BLocaleRoster();
~BLocaleRoster();
public:
BLocaleRoster();
~BLocaleRoster();
status_t GetSystemCatalog(BCatalogAddOn **catalog) const;
status_t GetDefaultCollator(BCollator **collator) const;
status_t GetDefaultLanguage(BLanguage **language) const;
status_t GetDefaultCountry(BCountry **contry) const;
status_t GetDefaultTimeZone(BTimeZone**timezone) const;
status_t GetDefaultCollator(BCollator* collator) const;
status_t GetDefaultLanguage(BLanguage* language) const;
status_t GetDefaultCountry(BCountry* country) const;
status_t GetDefaultTimeZone(BTimeZone* timezone) const;
void SetDefaultCountry(BCountry *) const;
void SetDefaultTimeZone(const char* zone) const;
void UpdateSettings(BMessage* newSettings);
status_t GetLanguage(const char* languageCode,
BLanguage** _language) const;
status_t GetLanguage(const char* languageCode, BLanguage** _language)
const;
status_t GetPreferredLanguages(BMessage* message) const;
status_t GetPreferredLanguages(BMessage *) const;
status_t SetPreferredLanguages(BMessage *);
// the message contains one or more 'language'-string-fields
// which contain the language-name(s)
status_t GetInstalledLanguages(BMessage* message) const;
// the message contains one or more
// 'language'-string-fields which
// contain the language-name(s)
status_t GetInstalledLanguages(BMessage *) const;
// the message contains one or more 'language'-string-fields
// which contain the language-name(s)
status_t GetAvailableCountries(BMessage* message) const;
status_t GetAvailableCountries(BMessage *) const;
status_t GetInstalledCatalogs(BMessage* message,
const char* sigPattern = NULL,
const char* langPattern = NULL,
int32 fingerprint = 0) const;
// the message contains...
status_t GetInstalledCatalogs(BMessage *, const char* sigPattern = NULL,
const char* langPattern = NULL, int32 fingerprint = 0) const;
// the message contains...
status_t Refresh();
// Refresh the internal data from the
// settings file(s)
BCatalog* GetCatalog();
// Get the catalog for the calling image (that needs to link with
// liblocalestub.a)
BCatalog* GetCatalog();
// Get the catalog for the calling image
// (that needs to link with liblocalestub.a)
static const char *kCatLangAttr;
static const char *kCatSigAttr;
static const char *kCatFingerprintAttr;
static const char* kCatLangAttr;
static const char* kCatSigAttr;
static const char* kCatFingerprintAttr;
static const char *kCatManagerMimeType;
static const char *kCatEditorMimeType;
static const char* kEmbeddedCatAttr;
static int32 kEmbeddedCatResId;
static const char *kEmbeddedCatAttr;
static int32 kEmbeddedCatResId;
private:
BCatalog* GetCatalog(BCatalog* catalog, vint32* catalogInitStatus);
BCatalogAddOn* LoadCatalog(const char *signature,
const char *language = NULL, int32 fingerprint = 0);
BCatalogAddOn* LoadEmbeddedCatalog(entry_ref *appOrAddOnRef);
status_t UnloadCatalog(BCatalogAddOn *addOn);
BCatalogAddOn* CreateCatalog(const char *type,
const char *signature, const char *language);
friend class BCatalog;
friend class BCatalogStub;
friend class BPrivate::EditableCatalog;
friend status_t get_add_on_catalog(BCatalog*, const char *);
private:
static BCatalog* _GetCatalog(BCatalog* catalog,
vint32* catalogInitStatus);
};
#endif /* _LOCALE_ROSTER_H_ */
extern BLocaleRoster* be_locale_roster;
#endif // _LOCALE_ROSTER_H_

View File

@ -1,25 +1,29 @@
/*
/*
* Copyright 2010, Haiku, Inc.
* Distributed under the terms of the MIT License.
* Distributed under the terms of the MIT Licence.
*/
#ifndef _B_TIME_FORMAT_H_
#define _B_TIME_FORMAT_H_
#include <NumberFormat.h>
#include <SupportDefs.h>
#include <DateTimeFormat.h>
class BString;
class BTimeFormat : public BDateTimeFormat {
public:
BTimeFormat(const BTimeFormat &other);
virtual ~BTimeFormat();
class BTimeFormat : public BNumberFormat {
public:
status_t Format(int64 number, BString *buffer) const;
// formatting
// TODO : version for char* buffer, size_t bufferSize
// TODO : parsing ?
// no-frills version: Simply appends the
// formatted date to the string buffer.
// Can fail only with B_NO_MEMORY or B_BAD_VALUE.
virtual status_t Format(bigtime_t value, BString* buffer) const;
// TODO: ... basically, all of it!
};
#endif
#endif // _B_TIME_FORMAT_H_

View File

@ -0,0 +1,44 @@
/*
* Copyright 2010, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#ifndef _B_TIME_UNIT_FORMAT_H_
#define _B_TIME_UNIT_FORMAT_H_
#include <DateTimeFormat.h>
#include <SupportDefs.h>
class BString;
enum time_unit_style {
B_TIME_UNIT_ABBREVIATED, // e.g. '5 hrs.'
B_TIME_UNIT_FULL, // e.g. '5 hours'
};
enum time_unit_element {
B_TIME_UNIT_YEAR,
B_TIME_UNIT_MONTH,
B_TIME_UNIT_WEEK,
B_TIME_UNIT_DAY,
B_TIME_UNIT_HOUR,
B_TIME_UNIT_MINUTE,
B_TIME_UNIT_SECOND,
B_TIME_UNIT_LAST = B_TIME_UNIT_SECOND
};
class BTimeUnitFormat : public BFormat {
public:
status_t Format(int32 value, time_unit_element unit,
BString* buffer,
time_unit_style style = B_TIME_UNIT_FULL
) const;
};
#endif

View File

@ -20,9 +20,11 @@ public:
status_t InitCheck() const;
private:
void _Init(const char* zoneCode);
status_t SetTo(const char* zoneCode);
static const char* kNameOfGmtZone;
private:
BString fCode;
BString fName;
int fOffsetFromGMT;

View File

@ -0,0 +1,153 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT license.
*/
#ifndef _MUTABLE_LOCALE_ROSTER_H_
#define _MUTABLE_LOCALE_ROSTER_H_
#include <Collator.h>
#include <Country.h>
#include <image.h>
#include <Language.h>
#include <List.h>
#include <Locker.h>
#include <LocaleRoster.h>
#include <Message.h>
#include <TimeZone.h>
class BLocale;
class BCatalog;
class BCatalogAddOn;
struct entry_ref;
namespace BPrivate {
class MutableLocaleRoster : public BLocaleRoster {
public:
MutableLocaleRoster();
~MutableLocaleRoster();
status_t SetDefaultCountry(const BCountry& country);
status_t SetDefaultTimeZone(const BTimeZone& zone);
status_t SetPreferredLanguages(const BMessage* message);
// the message contains one or more
// 'language'-string-fields which
// contain the language-name(s)
status_t GetSystemCatalog(BCatalogAddOn** catalog) const;
BCatalogAddOn* LoadCatalog(const char* signature,
const char* language = NULL,
int32 fingerprint = 0) const;
BCatalogAddOn* LoadEmbeddedCatalog(entry_ref* appOrAddOnRef);
status_t UnloadCatalog(BCatalogAddOn* addOn);
BCatalogAddOn* CreateCatalog(const char* type,
const char* signature,
const char* language);
};
extern MutableLocaleRoster* mutable_locale_roster;
typedef BCatalogAddOn* (*InstantiateCatalogFunc)(const char* name,
const char* language, uint32 fingerprint);
typedef BCatalogAddOn* (*CreateCatalogFunc)(const char* name,
const char* language);
typedef BCatalogAddOn* (*InstantiateEmbeddedCatalogFunc)(
entry_ref* appOrAddOnRef);
typedef status_t (*GetAvailableLanguagesFunc)(BMessage*, const char*,
const char*, int32);
/*
* info about a single catalog-add-on (representing a catalog type):
*/
struct CatalogAddOnInfo {
InstantiateCatalogFunc fInstantiateFunc;
InstantiateEmbeddedCatalogFunc fInstantiateEmbeddedFunc;
CreateCatalogFunc fCreateFunc;
GetAvailableLanguagesFunc fLanguagesFunc;
BString fName;
BString fPath;
image_id fAddOnImage;
uint8 fPriority;
BList fLoadedCatalogs;
bool fIsEmbedded;
// an embedded add-on actually isn't an
// add-on, it is included as part of the
// library.
// The DefaultCatalog is such a beast!
CatalogAddOnInfo(const BString& name,
const BString& path, uint8 priority);
~CatalogAddOnInfo();
bool MakeSureItsLoaded();
void UnloadIfPossible();
};
/*
* The global data that is shared between all roster-objects of a process.
*/
struct RosterData {
BLocker fLock;
BList fCatalogAddOnInfos;
BMessage fPreferredLanguages;
BCollator fDefaultCollator;
BCountry fDefaultCountry;
BLanguage fDefaultLanguage;
BTimeZone fDefaultTimeZone;
RosterData();
~RosterData();
void InitializeCatalogAddOns();
void CleanupCatalogAddOns();
status_t Refresh();
static int CompareInfos(const void* left,
const void* right);
status_t SetDefaultCountry(const BCountry& country);
status_t SetDefaultTimeZone(const BTimeZone& zone);
status_t SetPreferredLanguages(const BMessage* msg);
private:
status_t _LoadLocaleSettings();
status_t _SaveLocaleSettings();
status_t _LoadTimeSettings();
status_t _SaveTimeSettings();
status_t _SetDefaultCountry(const BCountry& country);
status_t _SetDefaultTimeZone(const BTimeZone& zone);
status_t _SetPreferredLanguages(const BMessage* msg);
status_t _AddDefaultCountryToMessage(
BMessage* message) const;
status_t _AddDefaultTimeZoneToMessage(
BMessage* message) const;
status_t _AddPreferredLanguagesToMessage(
BMessage* message) const;
};
extern RosterData gRosterData;
} // namespace BPrivate
#endif // _MUTABLE_LOCALE_ROSTER_H_

View File

@ -22,6 +22,7 @@
#include <AppFileInfo.h>
#include <Application.h>
#include <Bitmap.h>
#include <DurationFormat.h>
#include <File.h>
#include <FindDirectory.h>
#include <Font.h>
@ -36,7 +37,6 @@
#include <ScrollView.h>
#include <String.h>
#include <StringView.h>
#include <TimeFormat.h>
#include <TranslationUtils.h>
#include <TranslatorFormats.h>
#include <View.h>
@ -1724,12 +1724,14 @@ MemUsageToString(char string[], size_t size, system_info* info)
static const char*
UptimeToString(char string[], size_t size)
{
BTimeFormat formatter;
BDurationFormat formatter;
BString str;
formatter.Format(system_time() / 1000000, &str);
bigtime_t uptime = system_time();
bigtime_t now = (bigtime_t)time(NULL) * 1000000;
formatter.Format(now - uptime, now, &str);
str.CopyInto(string, 0, size);
string[str.Length()] = '\0';
string[std::min((size_t)str.Length(), size)] = '\0';
return string;
}

View File

@ -515,7 +515,7 @@ TBarApp::MessageReceived(BMessage* message)
case B_LOCALE_CHANGED:
{
be_locale_roster->UpdateSettings(message);
be_locale_roster->Refresh();
BMessenger(fBarWindow->FindView("_deskbar_tv_")).SendMessage(
message);

View File

@ -89,10 +89,10 @@ CalendarMenuWindow::CalendarMenuWindow(BPoint where)
fCalendarView(NULL),
fSuppressFirstClose(true)
{
BCountry* here;
be_locale_roster->GetDefaultCountry(&here);
BPrivate::week_start startOfWeek
= (BPrivate::week_start)here->StartOfWeek();
BCountry country;
be_locale_roster->GetDefaultCountry(&country);
BPrivate::week_start startOfWeek
= (BPrivate::week_start)country.StartOfWeek();
RemoveShortcut('H', B_COMMAND_KEY | B_CONTROL_KEY);
AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));

View File

@ -91,7 +91,7 @@ TTimeView::TTimeView(float maxWidth, float height, bool showSeconds,
fLastDateStr[0] = 0;
fNeedToUpdate = true;
be_locale_roster->GetDefaultCountry(&fHere);
be_locale_roster->GetDefaultCountry(&fCountry);
}
@ -105,7 +105,7 @@ TTimeView::TTimeView(BMessage* data)
data->FindBool("interval", &fInterval);
fShowingDate = false;
be_locale_roster->GetDefaultCountry(&fHere);
be_locale_roster->GetDefaultCountry(&fCountry);
}
#endif
@ -313,7 +313,7 @@ TTimeView::GetCurrentTime()
fMinute = time.tm_min;
fHour = time.tm_hour;
fHere->FormatTime(fTimeStr, 64, fTime, fShowSeconds);
fCountry.FormatTime(fTimeStr, 64, fTime, fShowSeconds);
}
@ -322,7 +322,7 @@ TTimeView::GetCurrentDate()
{
char tmp[64];
fHere->FormatDate(tmp, 64, fTime, fFullDate && CanShowFullDate());
fCountry.FormatDate(tmp, 64, fTime, fFullDate && CanShowFullDate());
// remove leading 0 from date when month is less than 10 (MM/DD/YY)
// or remove leading 0 from date when day is less than 10 (DD/MM/YY)
@ -465,6 +465,7 @@ TTimeView::AllowFullDate(bool allow)
void
TTimeView::Update()
{
be_locale_roster->GetDefaultCountry(&fCountry);
GetCurrentTime();
GetCurrentDate();

View File

@ -36,6 +36,7 @@ All rights reserved.
#include <OS.h>
#include <Country.h>
#include <Messenger.h>
#include <View.h>
@ -127,8 +128,8 @@ class TTimeView : public BView {
BMessenger fCalendarWindow;
BMessageRunner* fLongClickMessageRunner;
BCountry* fHere; // For date and time localizing purposes
BCountry fCountry; // For date and time localizing purposes
};

View File

@ -18,7 +18,7 @@
#include <GroupLayoutBuilder.h>
#include <ListView.h>
#include <Locale.h>
#include <LocaleRoster.h>
#include <MutableLocaleRoster.h>
#include <Path.h>
#include <ScrollView.h>
#include <SeparatorView.h>
@ -32,6 +32,9 @@
#include "KeymapListItem.h"
using BPrivate::mutable_locale_roster;
enum {
MSG_LANGUAGE_SELECTED = 'lngs',
MSG_KEYMAP_SELECTED = 'kmps'
@ -156,7 +159,8 @@ BootPromptWindow::MessageReceived(BMessage* message)
BMessage preferredLanguages;
preferredLanguages.AddString("language",
languageItem->Language());
be_locale_roster->SetPreferredLanguages(&preferredLanguages);
mutable_locale_roster->SetPreferredLanguages(
&preferredLanguages);
_InitCatalog(true);
}
// Calling it here is a cheap way of preventing the user to have

View File

@ -1,6 +1,6 @@
SubDir HAIKU_TOP src apps readonlybootprompt ;
UsePrivateHeaders interface shared ;
UsePrivateHeaders interface locale shared ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src preferences keymap ] ;

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright 2004, Jérôme Duval, jerome.duval@free.fr.
* Distributed under the terms of the MIT License.
*/
@ -29,7 +29,7 @@ const uint32 TIMEDALERT_UPDATE = 'taup';
class TimedAlert : public BAlert {
public:
TimedAlert(const char *title, const char *text, const char *button1,
const char *button2 = NULL, const char *button3 = NULL,
const char *button2 = NULL, const char *button3 = NULL,
button_width width = B_WIDTH_AS_USUAL, alert_type type = B_INFO_ALERT);
void MessageReceived(BMessage *);
void Show();
@ -59,12 +59,12 @@ TimedAlert::Show()
}
void
void
TimedAlert::MessageReceived(BMessage *msg)
{
if (msg->what == TIMEDALERT_UPDATE) {
BString string;
GetLabel(string);
GetLabel(string);
TextView()->SetText(string.String());
} else
BAlert::MessageReceived(msg);
@ -83,12 +83,12 @@ TimedAlert::GetLabel(BString &string)
char timestring[15];
time(&t);
localtime_r(&t, &tm);
BCountry* here;
BCountry here;
be_locale_roster->GetDefaultCountry(&here);
here->FormatTime(timestring, 15, t, false);
here.FormatTime(timestring, 15, t, false);
string += " ";
string += timestring;
@ -106,9 +106,9 @@ main(int argc, char **argv)
struct tm tm;
tzset();
time(&t);
localtime_r(&t, &tm);
localtime_r(&t, &tm);
char path[B_PATH_NAME_LENGTH];
char path[B_PATH_NAME_LENGTH];
if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, true, path, B_PATH_NAME_LENGTH) != B_OK) {
fprintf(stderr, "%s: can't find settings directory\n", argv[0]);
exit(1);
@ -148,7 +148,7 @@ main(int argc, char **argv)
if (index == 2) {
index = (new BAlert("dstcheck",
B_TRANSLATE("Would you like to set the clock?"),
B_TRANSLATE("Would you like to set the clock?"),
B_TRANSLATE("No"), B_TRANSLATE("Yes")))->Go();
if (index == 1)

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de
* Copyright 2003-2004, Oliver Tappe, zooey@hirschkaefer.de
* Distributed under the terms of the MIT License.
@ -10,11 +10,14 @@
#include <Application.h>
#include <Locale.h>
#include <LocaleRoster.h>
#include <MutableLocaleRoster.h>
#include <Node.h>
#include <Roster.h>
using BPrivate::mutable_locale_roster;
//#pragma mark - BCatalog
BCatalog::BCatalog()
:
@ -26,13 +29,14 @@ BCatalog::BCatalog()
BCatalog::BCatalog(const char *signature, const char *language,
uint32 fingerprint)
{
fCatalog = be_locale_roster->LoadCatalog(signature, language, fingerprint);
fCatalog
= mutable_locale_roster->LoadCatalog(signature, language, fingerprint);
}
BCatalog::~BCatalog()
{
be_locale_roster->UnloadCatalog(fCatalog);
mutable_locale_roster->UnloadCatalog(fCatalog);
}
@ -101,8 +105,7 @@ BCatalog::SetCatalog(const char* signature, uint32 fingerprint)
// properly maintained.
// No other method should touch fCatalog directly, either (constructor for
// example)
fCatalog
= be_locale_roster->LoadCatalog(signature, NULL, fingerprint);
fCatalog = mutable_locale_roster->LoadCatalog(signature, NULL, fingerprint);
return B_OK;
}
@ -255,12 +258,19 @@ BCatalogAddOn::CountItems() const
}
void
BCatalogAddOn::SetNext(BCatalogAddOn *next)
{
fNext = next;
}
//#pragma mark - EditableCatalog
namespace BPrivate {
EditableCatalog::EditableCatalog(const char *type, const char *signature,
const char *language)
{
fCatalog = be_locale_roster->CreateCatalog(type, signature, language);
fCatalog = mutable_locale_roster->CreateCatalog(type, signature, language);
}

View File

@ -21,6 +21,6 @@ BLocaleRoster::GetCatalog()
asm volatile(".hidden _ZN13BLocaleRoster10GetCatalogEv");
#endif
return GetCatalog(&sCatalog, &sCatalogInitOnce);
return _GetCatalog(&sCatalog, &sCatalogInitOnce);
}

View File

@ -5,23 +5,24 @@
*/
#include <ctype.h>
#include <stdlib.h>
#include <new>
#include <typeinfo>
#include <Collator.h>
#include <UnicodeChar.h>
#include <String.h>
#include <Message.h>
#include <stdlib.h>
#include <typeinfo>
#include <ctype.h>
#include <unicode/coll.h>
#include <unicode/tblcoll.h>
BCollator::BCollator()
:
fFallbackICUCollator(NULL),
fStrength(B_COLLATE_PRIMARY),
fDefaultStrength(B_COLLATE_PRIMARY),
fIgnorePunctuation(true)
{
// TODO: the collator construction will have to change; the default
@ -33,11 +34,9 @@ BCollator::BCollator()
}
BCollator::BCollator(const char *locale, int8 strength,
bool ignorePunctuation)
BCollator::BCollator(const char* locale, int8 strength, bool ignorePunctuation)
:
fFallbackICUCollator(NULL),
fStrength(strength),
fDefaultStrength(strength),
fIgnorePunctuation(ignorePunctuation)
{
UErrorCode error = U_ZERO_ERROR;
@ -45,57 +44,80 @@ BCollator::BCollator(const char *locale, int8 strength,
}
BCollator::BCollator(BMessage *archive)
: BArchivable(archive),
BCollator::BCollator(BMessage* archive)
:
BArchivable(archive),
fICUCollator(NULL),
fFallbackICUCollator(NULL),
fDefaultStrength(B_COLLATE_PRIMARY),
fIgnorePunctuation(true)
{
int32 data;
if (archive->FindInt32("loc:strength", &data) == B_OK)
fStrength = (uint8)data;
fDefaultStrength = (uint8)data;
else
fStrength = B_COLLATE_PRIMARY;
fDefaultStrength = B_COLLATE_PRIMARY;
if (archive->FindBool("loc:punctuation", &fIgnorePunctuation) != B_OK)
fIgnorePunctuation = true;
archive->FindBool("loc:punctuation", &fIgnorePunctuation);
UErrorCode error = U_ZERO_ERROR;
fFallbackICUCollator = static_cast<RuleBasedCollator*>
(Collator::createInstance(error));
RuleBasedCollator* fallbackICUCollator
= static_cast<RuleBasedCollator*>(Collator::createInstance(error));
ssize_t size;
const void* buffer = NULL;
if (archive->FindData("loc:collator", B_RAW_TYPE, &buffer, &size) == B_OK) {
fICUCollator = new RuleBasedCollator((const uint8_t*)buffer, (int)size,
fFallbackICUCollator, error);
fallbackICUCollator, error);
if (fICUCollator == NULL) {
fICUCollator = fFallbackICUCollator;
fICUCollator = fallbackICUCollator;
// Unarchiving failed, so we revert to the fallback collator
// TODO: when can this happen, can it be avoided?
}
}
}
BCollator::BCollator(const BCollator& other)
:
fICUCollator(NULL)
{
*this = other;
}
BCollator::~BCollator()
{
delete fICUCollator;
fICUCollator = NULL;
delete fFallbackICUCollator;
}
BCollator& BCollator::operator=(const BCollator& source)
{
if (&source != this) {
delete fICUCollator;
fICUCollator = source.fICUCollator != NULL
? source.fICUCollator->clone()
: NULL;
fDefaultStrength = source.fDefaultStrength;
fIgnorePunctuation = source.fIgnorePunctuation;
}
return *this;
}
void
BCollator::SetDefaultStrength(int8 strength)
{
fStrength = strength;
fDefaultStrength = strength;
}
int8
BCollator::DefaultStrength() const
{
return fStrength;
return fDefaultStrength;
}
@ -114,31 +136,11 @@ BCollator::IgnorePunctuation() const
status_t
BCollator::GetSortKey(const char *string, BString *key, int8 strength)
BCollator::GetSortKey(const char* string, BString* key, int8 strength) const
{
_SetStrength(strength);
// TODO : handle fIgnorePunctuation
if (strength == B_COLLATE_DEFAULT)
strength = fStrength;
Collator::ECollationStrength icuStrength;
switch (strength) {
case B_COLLATE_PRIMARY:
icuStrength = Collator::PRIMARY;
break;
case B_COLLATE_SECONDARY:
icuStrength = Collator::SECONDARY;
break;
case B_COLLATE_TERTIARY:
default:
icuStrength = Collator::TERTIARY;
break;
case B_COLLATE_QUATERNARY:
icuStrength = Collator::QUATERNARY;
break;
case B_COLLATE_IDENTICAL:
icuStrength = Collator::IDENTICAL;
break;
}
fICUCollator->setStrength(icuStrength);
int length = strlen(string);
@ -154,6 +156,7 @@ BCollator::GetSortKey(const char *string, BString *key, int8 strength)
buffer = (uint8_t*)realloc(buffer, requiredSize);
if (buffer == NULL)
return B_NO_MEMORY;
error = U_ZERO_ERROR;
fICUCollator->getSortKey(UnicodeString(string, length, NULL, error),
buffer, requiredSize);
@ -164,50 +167,32 @@ BCollator::GetSortKey(const char *string, BString *key, int8 strength)
if (error == U_ZERO_ERROR)
return B_OK;
return B_ERROR;
}
int
BCollator::Compare(const char *a, const char *b, int32 length, int8 strength)
BCollator::Compare(const char* s1, const char* s2, int8 strength) const
{
_SetStrength(strength);
// TODO : handle fIgnorePunctuation
if (strength == B_COLLATE_DEFAULT)
strength = fStrength;
Collator::ECollationStrength icuStrength;
switch (strength) {
case B_COLLATE_PRIMARY:
icuStrength = Collator::PRIMARY;
break;
case B_COLLATE_SECONDARY:
icuStrength = Collator::SECONDARY;
break;
case B_COLLATE_TERTIARY:
default:
icuStrength = Collator::TERTIARY;
break;
case B_COLLATE_QUATERNARY:
icuStrength = Collator::QUATERNARY;
break;
case B_COLLATE_IDENTICAL:
icuStrength = Collator::IDENTICAL;
break;
}
fICUCollator->setStrength(icuStrength);
UErrorCode error = U_ZERO_ERROR;
return fICUCollator->compare(a, b, error);
return fICUCollator->compare(s1, s2, error);
}
status_t
BCollator::Archive(BMessage *archive, bool deep) const
BCollator::Archive(BMessage* archive, bool deep) const
{
status_t status = BArchivable::Archive(archive, deep);
if (status < B_OK)
return status;
if (status == B_OK)
status = archive->AddInt32("loc:strength", fStrength);
status = archive->AddInt32("loc:strength", fDefaultStrength);
if (status == B_OK)
status = archive->AddBool("loc:punctuation", fIgnorePunctuation);
@ -231,13 +216,42 @@ BCollator::Archive(BMessage *archive, bool deep) const
}
BArchivable *
BCollator::Instantiate(BMessage *archive)
BArchivable*
BCollator::Instantiate(BMessage* archive)
{
if (validate_instantiation(archive, "BCollator"))
return new BCollator(archive);
return new(std::nothrow) BCollator(archive);
return NULL;
}
status_t
BCollator::_SetStrength(int8 strength) const
{
if (strength == B_COLLATE_DEFAULT)
strength = fDefaultStrength;
Collator::ECollationStrength icuStrength;
switch (strength) {
case B_COLLATE_PRIMARY:
icuStrength = Collator::PRIMARY;
break;
case B_COLLATE_SECONDARY:
icuStrength = Collator::SECONDARY;
break;
case B_COLLATE_TERTIARY:
default:
icuStrength = Collator::TERTIARY;
break;
case B_COLLATE_QUATERNARY:
icuStrength = Collator::QUATERNARY;
break;
case B_COLLATE_IDENTICAL:
icuStrength = Collator::IDENTICAL;
break;
}
fICUCollator->setStrength(icuStrength);
return B_OK;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
/*
* Copyright 2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Oliver Tappe <zooey@hirschkaefer.de>
*/
#include <DateFormat.h>
// default constructor
BDateFormat::BDateFormat()
: BDateTimeFormat()
{
}
// copy constructor
BDateFormat::BDateFormat(const BDateFormat &other)
: BDateTimeFormat(other)
{
}
// destructor
BDateFormat::~BDateFormat()
{
}
// Format
status_t
BDateFormat::Format(bigtime_t value, BString* buffer) const
{
return B_ERROR;
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Oliver Tappe <zooey@hirschkaefer.de>
*/
#include <DateTimeFormat.h>
// default constructor
BDateTimeFormat::BDateTimeFormat()
: BFormat()
{
}
// copy constructor
BDateTimeFormat::BDateTimeFormat(const BDateTimeFormat &other)
: BFormat(other)
{
}
// destructor
BDateTimeFormat::~BDateTimeFormat()
{
}
// Format
status_t
BDateTimeFormat::Format(bigtime_t value, BString* buffer) const
{
return B_ERROR;
}

View File

@ -25,7 +25,7 @@
#include <Roster.h>
#include <DefaultCatalog.h>
#include <LocaleRoster.h>
#include <MutableLocaleRoster.h>
#include <cstdio>
@ -596,9 +596,9 @@ default_catalog_get_available_languages(BMessage* availableLanguages,
BPath catalogPath(&appDir, catalogName.String());
BEntry file(catalogPath.Path());
BDirectory dir(&file);
char fileName[B_FILE_NAME_LENGTH];
while(dir.GetNextEntry(&file) == B_OK) {
while(dir.GetNextEntry(&file) == B_OK) {
file.GetName(fileName);
BString langName(fileName);
langName.Replace(kCatExtension,"",1);
@ -616,16 +616,16 @@ default_catalog_get_available_languages(BMessage* availableLanguages,
for (size_t i = 0; i < sizeof(which) / sizeof(which[0]); i++) {
BPath path;
if (find_directory(which[i], &path) == B_OK) {
catalogName = BString("locale/")
catalogName = BString("locale/")
<< kCatFolder
<< "/" << sigPattern;
BPath catalogPath(path.Path(), catalogName.String());
BEntry file(catalogPath.Path());
BDirectory dir(&file);
char fileName[B_FILE_NAME_LENGTH];
while(dir.GetNextEntry(&file) == B_OK) {
while(dir.GetNextEntry(&file) == B_OK) {
file.GetName(fileName);
BString langName(fileName);
langName.Replace(kCatExtension,"",1);
@ -633,6 +633,6 @@ default_catalog_get_available_languages(BMessage* availableLanguages,
}
}
}
return B_OK;
}

View File

@ -0,0 +1,75 @@
/*
* Copyright 2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Oliver Tappe <zooey@hirschkaefer.de>
*/
#include <DurationFormat.h>
#include <new>
#include <unicode/calendar.h>
#include <unicode/tmunit.h>
#include <unicode/utypes.h>
#include <AutoDeleter.h>
#include <TimeUnitFormat.h>
using BPrivate::ObjectDeleter;
// maps our unit element to the corresponding ICU unit
static const UCalendarDateFields skUnitMap[] = {
UCAL_YEAR,
UCAL_MONTH,
UCAL_WEEK_OF_MONTH,
UCAL_DAY_OF_WEEK,
UCAL_HOUR_OF_DAY,
UCAL_MINUTE,
UCAL_SECOND,
};
status_t BDurationFormat::Format(bigtime_t startValue, bigtime_t stopValue,
BString* buffer, time_unit_style style, const BString& separator) 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;
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);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
if (delta != 0) {
if (needSeparator)
buffer->Append(separator);
else
needSeparator = true;
status_t status = timeUnitFormat.Format(delta,
(time_unit_element)unit, buffer, style);
if (status != B_OK)
return status;
}
}
return B_OK;
}

View File

@ -18,8 +18,17 @@ local sources =
LibraryInit.cpp
Locale.cpp
LocaleRoster.cpp
MutableLocaleRoster.cpp
TimeZone.cpp
# in progress
DateFormat.cpp
DateTimeFormat.cpp
DurationFormat.cpp
TimeFormat.cpp
TimeUnitFormat.cpp
# old, needs investigation
Currency.cpp
FloatFormat.cpp
FloatFormatImpl.cpp
@ -36,7 +45,6 @@ local sources =
NumberFormatImpl.cpp
NumberFormatParameters.cpp
PropertyFile.cpp
TimeFormat.cpp
UnicodeChar.cpp
;

View File

@ -6,6 +6,11 @@
#include <Language.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <iostream>
#include <Catalog.h>
@ -15,11 +20,6 @@
#include <String.h>
#include <FindDirectory.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <ICUWrapper.h>
#include <unicode/locid.h>
@ -28,91 +28,62 @@
#define ICU_VERSION icu_44
static const char *gBuiltInStrings[] = {
"Yesterday",
"Today",
"Tomorrow",
"Future",
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
"^[yY]",
"^[nN]",
"yes",
"no"
};
BLanguage::BLanguage()
:
fDirection(B_LEFT_TO_RIGHT),
fICULocale(NULL)
{
SetTo(NULL);
}
BLanguage::BLanguage(const char* language)
:
fDirection(B_LEFT_TO_RIGHT)
fDirection(B_LEFT_TO_RIGHT),
fICULocale(NULL)
{
fICULocale = new ICU_VERSION::Locale(language);
SetTo(language);
}
for (int32 i = B_NUM_LANGUAGE_STRINGS;i-- > 0;)
fStrings[i] = NULL;
BLanguage::BLanguage(const BLanguage& other)
:
fICULocale(NULL)
{
*this = other;
}
BLanguage::~BLanguage()
{
delete fICULocale;
for (int32 i = B_NUM_LANGUAGE_STRINGS;i-- > 0;)
free(fStrings[i]);
}
void
BLanguage::Default()
status_t
BLanguage::SetTo(const char* language)
{
fICULocale = new ICU_VERSION::Locale("en");
fDirection = B_LEFT_TO_RIGHT;
delete fICULocale;
fICULocale = new ICU_VERSION::Locale(language);
if (fICULocale == NULL)
return B_NO_MEMORY;
for (int32 i = B_NUM_LANGUAGE_STRINGS;i-- > 0;) {
free(fStrings[i]);
fStrings[i] = strdup(gBuiltInStrings[i]);
return B_OK;
}
BLanguage& BLanguage::operator=(const BLanguage& source)
{
if (&source != this) {
delete fICULocale;
fICULocale = source.fICULocale != NULL
? source.fICULocale->clone()
: NULL;
fDirection = source.fDirection;
}
return *this;
}
@ -130,7 +101,11 @@ BLanguage::GetString(uint32 id) const
|| id > B_LANGUAGE_STRINGS_BASE + B_NUM_LANGUAGE_STRINGS)
return NULL;
return fStrings[id - B_LANGUAGE_STRINGS_BASE];
return NULL;
// TODO: fetch string from ICU
// return fStrings[id - B_LANGUAGE_STRINGS_BASE];
}

View File

@ -8,7 +8,7 @@
#include "Catalog.h"
#include "Locale.h"
#include "LocaleRoster.h"
#include "MutableLocaleRoster.h"
#include <new>
@ -25,7 +25,7 @@ CreateLocaleBackendInstance()
LibbeLocaleBackend::LibbeLocaleBackend()
{
be_locale_roster->GetSystemCatalog(&systemCatalog);
mutable_locale_roster->GetSystemCatalog(&systemCatalog);
}

View File

@ -1,4 +1,4 @@
/*
/*
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
@ -38,5 +38,5 @@ BLocale::GetString(uint32 id)
return "";
}
return fLanguage->GetString(id);
return fLanguage.GetString(id);
}

View File

@ -13,11 +13,10 @@
#include <set>
#include <assert.h>
#include <stdio.h> // for debug only
#include <syslog.h>
#include <AppFileInfo.h>
#include <Autolock.h>
#include <AppFileInfo.h>
#include <Catalog.h>
#include <Collator.h>
#include <Country.h>
@ -25,9 +24,9 @@
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <Language.h>
#include <Locale.h>
#include <MutableLocaleRoster.h>
#include <Node.h>
#include <Path.h>
#include <String.h>
@ -40,19 +39,20 @@
#include <unicode/timezone.h>
using BPrivate::CatalogAddOnInfo;
/*
* several attributes/resource-IDs used within the Locale Kit:
*/
static const char *kPriorityAttr = "ADDON:priority";
const char *BLocaleRoster::kCatLangAttr = "BEOS:LOCALE_LANGUAGE";
const char* BLocaleRoster::kCatLangAttr = "BEOS:LOCALE_LANGUAGE";
// name of catalog language, lives in every catalog file
const char *BLocaleRoster::kCatSigAttr = "BEOS:LOCALE_SIGNATURE";
const char* BLocaleRoster::kCatSigAttr = "BEOS:LOCALE_SIGNATURE";
// catalog signature, lives in every catalog file
const char *BLocaleRoster::kCatFingerprintAttr = "BEOS:LOCALE_FINGERPRINT";
const char* BLocaleRoster::kCatFingerprintAttr = "BEOS:LOCALE_FINGERPRINT";
// catalog fingerprint, may live in catalog file
const char *BLocaleRoster::kEmbeddedCatAttr = "BEOS:LOCALE_EMBEDDED_CATALOG";
const char* BLocaleRoster::kEmbeddedCatAttr = "BEOS:LOCALE_EMBEDDED_CATALOG";
// attribute which contains flattened data of embedded catalog
// this may live in an app- or add-on-file
int32 BLocaleRoster::kEmbeddedCatResId = 0xCADA;
@ -61,340 +61,6 @@ int32 BLocaleRoster::kEmbeddedCatResId = 0xCADA;
// this may live in an app- or add-on-file
typedef BCatalogAddOn *(*InstantiateCatalogFunc)(const char *name,
const char *language, uint32 fingerprint);
typedef BCatalogAddOn *(*CreateCatalogFunc)(const char *name,
const char *language);
typedef BCatalogAddOn *(*InstantiateEmbeddedCatalogFunc)(
entry_ref *appOrAddOnRef);
typedef status_t (*GetAvailableLanguagesFunc)(BMessage*, const char*,
const char*, int32);
static BLocaleRoster gLocaleRoster;
BLocaleRoster *be_locale_roster = &gLocaleRoster;
/*
* info about a single catalog-add-on (representing a catalog type):
*/
struct BCatalogAddOnInfo {
BString fName;
BString fPath;
image_id fAddOnImage;
InstantiateCatalogFunc fInstantiateFunc;
InstantiateEmbeddedCatalogFunc fInstantiateEmbeddedFunc;
CreateCatalogFunc fCreateFunc;
GetAvailableLanguagesFunc fLanguagesFunc;
uint8 fPriority;
BList fLoadedCatalogs;
bool fIsEmbedded;
// an embedded add-on actually isn't an add-on, it is included
// as part of the library. The DefaultCatalog is such a beast!
BCatalogAddOnInfo(const BString& name, const BString& path, uint8 priority);
~BCatalogAddOnInfo();
bool MakeSureItsLoaded();
void UnloadIfPossible();
};
BCatalogAddOnInfo::BCatalogAddOnInfo(const BString& name, const BString& path,
uint8 priority)
:
fName(name),
fPath(path),
fAddOnImage(B_NO_INIT),
fInstantiateFunc(NULL),
fInstantiateEmbeddedFunc(NULL),
fCreateFunc(NULL),
fLanguagesFunc(NULL),
fPriority(priority),
fIsEmbedded(path.Length()==0)
{
}
BCatalogAddOnInfo::~BCatalogAddOnInfo()
{
int32 count = fLoadedCatalogs.CountItems();
for (int32 i = 0; i < count; ++i) {
BCatalogAddOn* cat
= static_cast<BCatalogAddOn*>(fLoadedCatalogs.ItemAt(i));
delete cat;
}
fLoadedCatalogs.MakeEmpty();
UnloadIfPossible();
}
bool
BCatalogAddOnInfo::MakeSureItsLoaded()
{
if (!fIsEmbedded && fAddOnImage < B_OK) {
// add-on has not been loaded yet, so we try to load it:
BString fullAddOnPath(fPath);
fullAddOnPath << "/" << fName;
fAddOnImage = load_add_on(fullAddOnPath.String());
if (fAddOnImage >= B_OK) {
get_image_symbol(fAddOnImage, "instantiate_catalog",
B_SYMBOL_TYPE_TEXT, (void **)&fInstantiateFunc);
get_image_symbol(fAddOnImage, "instantiate_embedded_catalog",
B_SYMBOL_TYPE_TEXT, (void **)&fInstantiateEmbeddedFunc);
get_image_symbol(fAddOnImage, "create_catalog",
B_SYMBOL_TYPE_TEXT, (void **)&fCreateFunc);
get_image_symbol(fAddOnImage, "get_available_languages",
B_SYMBOL_TYPE_TEXT, (void **)&fLanguagesFunc);
log_team(LOG_DEBUG, "catalog-add-on %s has been loaded",
fName.String());
} else {
log_team(LOG_DEBUG, "could not load catalog-add-on %s (%s)",
fName.String(), strerror(fAddOnImage));
return false;
}
} else if (fIsEmbedded) {
// The built-in catalog still has to provide this function
fLanguagesFunc = default_catalog_get_available_languages;
}
return true;
}
void
BCatalogAddOnInfo::UnloadIfPossible()
{
if (!fIsEmbedded && fLoadedCatalogs.IsEmpty()) {
unload_add_on(fAddOnImage);
fAddOnImage = B_NO_INIT;
fInstantiateFunc = NULL;
fInstantiateEmbeddedFunc = NULL;
fCreateFunc = NULL;
fLanguagesFunc = NULL;
// log_team(LOG_DEBUG, "catalog-add-on %s has been unloaded",
// fName.String());
}
}
/*
* the global data that is shared between all roster-objects:
*/
struct RosterData {
BLocker fLock;
BList fCatalogAddOnInfos;
BMessage fPreferredLanguages;
// BString fCountryCodeName;
// BString fCountryDateFormat;
BCountry fDefaultCountry;
RosterData();
~RosterData();
void InitializeCatalogAddOns();
void CleanupCatalogAddOns();
static int CompareInfos(const void *left, const void *right);
void UpdateSettings(BMessage* newSettings);
};
static RosterData gRosterData;
RosterData::RosterData()
:
fLock("LocaleRosterData")
{
openlog_team("liblocale.so", LOG_PID, LOG_USER);
#ifndef DEBUG
setlogmask_team(LOG_UPTO(LOG_WARNING));
#endif
InitializeCatalogAddOns();
// Load preferences to get the preferred languages
BPath path;
BFile file;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
path.Append("Locale settings");
BMessage settingsMessage;
if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK
&& settingsMessage.Unflatten(&file) == B_OK) {
UpdateSettings(&settingsMessage);
return;
}
}
// Something went wrong (no settings file or invalid BMessage
// set everything to default values
fPreferredLanguages.AddString("language", "en");
fDefaultCountry = BCountry("en_US");
log_team(LOG_ERR, "*** No language preference found!\n");
}
RosterData::~RosterData()
{
BAutolock lock(fLock);
assert(lock.IsLocked());
CleanupCatalogAddOns();
closelog();
}
int
RosterData::CompareInfos(const void *left, const void *right)
{
return ((BCatalogAddOnInfo*)right)->fPriority
- ((BCatalogAddOnInfo*)left)->fPriority;
}
/*
iterate over add-on-folders and collect information about each
catalog-add-ons (types of catalogs) into fCatalogAddOnInfos.
*/
void
RosterData::InitializeCatalogAddOns()
{
BAutolock lock(fLock);
assert(lock.IsLocked());
// add info about embedded default catalog:
BCatalogAddOnInfo *defaultCatalogAddOnInfo
= new(std::nothrow) BCatalogAddOnInfo("Default", "",
DefaultCatalog::kDefaultCatalogAddOnPriority);
if (!defaultCatalogAddOnInfo)
return;
defaultCatalogAddOnInfo->fInstantiateFunc = DefaultCatalog::Instantiate;
defaultCatalogAddOnInfo->fInstantiateEmbeddedFunc
= DefaultCatalog::InstantiateEmbedded;
defaultCatalogAddOnInfo->fCreateFunc = DefaultCatalog::Create;
fCatalogAddOnInfos.AddItem((void*)defaultCatalogAddOnInfo);
directory_which folders[] = {
B_COMMON_ADDONS_DIRECTORY,
B_SYSTEM_ADDONS_DIRECTORY,
static_cast<directory_which>(-1)
};
BPath addOnPath;
BDirectory addOnFolder;
char buf[4096];
status_t err;
for (int f = 0; folders[f]>=0; ++f) {
find_directory(folders[f], &addOnPath);
BString addOnFolderName(addOnPath.Path());
addOnFolderName << "/locale/catalogs";
system_info info;
if (get_system_info(&info) == B_OK
&& (info.abi & B_HAIKU_ABI_MAJOR)
!= (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR)) {
switch (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) {
case B_HAIKU_ABI_GCC_2:
addOnFolderName << "/gcc2";
break;
case B_HAIKU_ABI_GCC_4:
addOnFolderName << "/gcc4";
break;
}
}
err = addOnFolder.SetTo(addOnFolderName.String());
if (err != B_OK)
continue;
// scan through all the folder's entries for catalog add-ons:
int32 count;
int8 priority;
entry_ref eref;
BNode node;
BEntry entry;
dirent *dent;
while ((count = addOnFolder.GetNextDirents((dirent *)buf, 4096)) > 0) {
dent = (dirent *)buf;
while (count-- > 0) {
if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")
&& strcmp(dent->d_name, "gcc2")
&& strcmp(dent->d_name, "gcc4")) {
// we have found (what should be) a catalog-add-on:
eref.device = dent->d_pdev;
eref.directory = dent->d_pino;
eref.set_name(dent->d_name);
entry.SetTo(&eref, true);
// traverse through any links to get to the real thang!
node.SetTo(&entry);
priority = -1;
if (node.ReadAttr(kPriorityAttr, B_INT8_TYPE, 0,
&priority, sizeof(int8)) <= 0) {
// add-on has no priority-attribute yet, so we load it
// to fetch the priority from the corresponding
// symbol...
BString fullAddOnPath(addOnFolderName);
fullAddOnPath << "/" << dent->d_name;
image_id image = load_add_on(fullAddOnPath.String());
if (image >= B_OK) {
uint8 *prioPtr;
if (get_image_symbol(image, "gCatalogAddOnPriority",
B_SYMBOL_TYPE_DATA,
(void **)&prioPtr) == B_OK) {
priority = *prioPtr;
node.WriteAttr(kPriorityAttr, B_INT8_TYPE, 0,
&priority, sizeof(int8));
} else {
log_team(LOG_ERR,
"couldn't get priority for add-on %s\n",
fullAddOnPath.String());
}
unload_add_on(image);
} else {
log_team(LOG_ERR,
"couldn't load add-on %s, error: %s\n",
fullAddOnPath.String(), strerror(image));
}
}
if (priority >= 0) {
// add-ons with priority < 0 will be ignored
BCatalogAddOnInfo* addOnInfo
= new(std::nothrow) BCatalogAddOnInfo(dent->d_name,
addOnFolderName, priority);
if (addOnInfo)
fCatalogAddOnInfos.AddItem((void*)addOnInfo);
}
}
// Bump the dirent-pointer by length of the dirent just handled:
dent = (dirent *)((char *)dent + dent->d_reclen);
}
}
}
fCatalogAddOnInfos.SortItems(CompareInfos);
}
/*
* unloads all catalog-add-ons (which will throw away all loaded catalogs, too)
*/
void
RosterData::CleanupCatalogAddOns()
{
BAutolock lock(fLock);
assert(lock.IsLocked());
int32 count = fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i<count; ++i) {
BCatalogAddOnInfo *info
= static_cast<BCatalogAddOnInfo*>(fCatalogAddOnInfos.ItemAt(i));
delete info;
}
fCatalogAddOnInfos.MakeEmpty();
}
// #pragma mark - BLocaleRoster
BLocaleRoster::BLocaleRoster()
{
}
@ -405,8 +71,177 @@ BLocaleRoster::~BLocaleRoster()
}
status_t
BLocaleRoster::Refresh()
{
return gRosterData.Refresh();
}
status_t
BLocaleRoster::GetDefaultCollator(BCollator* collator) const
{
if (!collator)
return B_BAD_VALUE;
BAutolock lock(gRosterData.fLock);
if (!lock.IsLocked())
return B_ERROR;
*collator = gRosterData.fDefaultCollator;
return B_OK;
}
status_t
BLocaleRoster::GetDefaultLanguage(BLanguage* language) const
{
if (!language)
return B_BAD_VALUE;
BAutolock lock(gRosterData.fLock);
if (!lock.IsLocked())
return B_ERROR;
*language = gRosterData.fDefaultLanguage;
return B_OK;
}
status_t
BLocaleRoster::GetDefaultCountry(BCountry* country) const
{
if (!country)
return B_BAD_VALUE;
BAutolock lock(gRosterData.fLock);
if (!lock.IsLocked())
return B_ERROR;
*country = gRosterData.fDefaultCountry;
return B_OK;
}
status_t
BLocaleRoster::GetDefaultTimeZone(BTimeZone* timezone) const
{
if (!timezone)
return B_BAD_VALUE;
BAutolock lock(gRosterData.fLock);
if (!lock.IsLocked())
return B_ERROR;
*timezone = gRosterData.fDefaultTimeZone;
return B_OK;
}
status_t
BLocaleRoster::GetLanguage(const char* languageCode,
BLanguage** _language) const
{
if (_language == NULL || languageCode == NULL || languageCode[0] == '\0')
return B_BAD_VALUE;
BLanguage* language = new(std::nothrow) BLanguage(languageCode);
if (language == NULL)
return B_NO_MEMORY;
*_language = language;
return B_OK;
}
status_t
BLocaleRoster::GetPreferredLanguages(BMessage* languages) const
{
if (!languages)
return B_BAD_VALUE;
BAutolock lock(gRosterData.fLock);
if (!lock.IsLocked())
return B_ERROR;
*languages = gRosterData.fPreferredLanguages;
return B_OK;
}
status_t
BLocaleRoster::GetInstalledLanguages(BMessage* languages) const
{
if (!languages)
return B_BAD_VALUE;
int32 i;
UnicodeString icuLanguageName;
BString languageName;
int32_t localeCount;
const Locale* icuLocaleList
= Locale::getAvailableLocales(localeCount);
// TODO: Loop over the strings and add them to a std::set to remove
// duplicates?
for (i = 0; i < localeCount; i++)
languages->AddString("langs", icuLocaleList[i].getName());
return B_OK;
}
status_t
BLocaleRoster::GetAvailableCountries(BMessage* countries) const
{
if (!countries)
return B_BAD_VALUE;
int32 i;
const char* const* countryList = uloc_getISOCountries();
for (i = 0; countryList[i] != NULL; i++)
countries->AddString("countries", countryList[i]);
return B_OK;
}
status_t
BLocaleRoster::GetInstalledCatalogs(BMessage* languageList,
const char* sigPattern, const char* langPattern, int32 fingerprint) const
{
if (languageList == NULL)
return B_BAD_VALUE;
BAutolock lock(gRosterData.fLock);
if (!lock.IsLocked())
return B_ERROR;
int32 count = gRosterData.fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info
= (CatalogAddOnInfo*)gRosterData.fCatalogAddOnInfos.ItemAt(i);
if (!info->MakeSureItsLoaded() || !info->fLanguagesFunc)
continue;
info->fLanguagesFunc(languageList, sigPattern, langPattern,
fingerprint);
}
return B_OK;
}
BCatalog*
BLocaleRoster::GetCatalog(BCatalog* catalog, vint32* catalogInitStatus)
BLocaleRoster::_GetCatalog(BCatalog* catalog, vint32* catalogInitStatus)
{
// This function is used in the translation macros, so it can't return a
// status_t. Maybe it could throw exceptions ?
@ -460,428 +295,3 @@ BLocaleRoster::GetCatalog(BCatalog* catalog, vint32* catalogInitStatus)
return catalog;
}
status_t
BLocaleRoster::GetSystemCatalog(BCatalogAddOn **catalog) const
{
if (!catalog)
return B_BAD_VALUE;
*catalog = be_locale_roster->LoadCatalog("system");
return B_OK;
}
status_t
BLocaleRoster::GetDefaultCollator(BCollator **collator) const
{
// It should just use the archived collator from the locale settings;
// if that is not available, just return the standard collator
if (!collator)
return B_BAD_VALUE;
*collator = new(std::nothrow) BCollator();
return B_OK;
}
status_t
BLocaleRoster::GetDefaultLanguage(BLanguage **language) const
{
if (!language)
return B_BAD_VALUE;
*language = new(std::nothrow) BLanguage(NULL);
return B_OK;
}
status_t
BLocaleRoster::GetDefaultCountry(BCountry **country) const
{
if (!country)
return B_BAD_VALUE;
*country = &gRosterData.fDefaultCountry;
return B_OK;
}
status_t
BLocaleRoster::GetDefaultTimeZone(BTimeZone **timezone) const
{
if (!timezone)
return B_BAD_VALUE;
*timezone = new(std::nothrow) BTimeZone();
return B_OK;
}
status_t
BLocaleRoster::GetLanguage(const char* languageCode,
BLanguage** _language) const
{
if (_language == NULL || languageCode == NULL || languageCode[0] == '\0')
return B_BAD_VALUE;
BLanguage* language = new(std::nothrow) BLanguage(languageCode);
if (language == NULL)
return B_NO_MEMORY;
*_language = language;
return B_OK;
}
void
BLocaleRoster::SetDefaultCountry(BCountry* newDefault) const
{
if (newDefault == NULL)
return;
BAutolock lock(gRosterData.fLock);
assert(lock.IsLocked());
gRosterData.fDefaultCountry = *newDefault;
}
void
BLocaleRoster::SetDefaultTimeZone(const char* zone) const
{
TimeZone::adoptDefault(TimeZone::createTimeZone(zone));
}
void
BLocaleRoster::UpdateSettings(BMessage* newSettings)
{
gRosterData.UpdateSettings(newSettings);
}
void
RosterData::UpdateSettings(BMessage* newSettings)
{
BAutolock lock(fLock);
assert(lock.IsLocked());
BString langName;
if (newSettings->FindString("language", &langName) == B_OK) {
UErrorCode icuError = U_ZERO_ERROR;
Locale icuLocale = Locale::createCanonical(langName.String());
assert(!icuLocale.isBogus());
UnicodeString ustr;
BString bstr;
BStringByteSink bbs(&bstr);
icuLocale.getDisplayName(ustr);
ustr.toUTF8(bbs);
Locale::setDefault(icuLocale, icuError);
assert(icuError == U_ZERO_ERROR);
fPreferredLanguages.RemoveName("language");
for (int i = 0; newSettings->FindString("language", i,
&langName) == B_OK; i++) {
fPreferredLanguages.AddString("language", langName);
}
} else
fPreferredLanguages.AddString("language", "en");
BString codeName;
if (newSettings->FindString("country", &codeName)
== B_OK)
fDefaultCountry = BCountry(codeName);
else
fDefaultCountry = BCountry("en_US");
BString timeFormat;
if (newSettings->FindString("shortTimeFormat", &timeFormat)
== B_OK)
fDefaultCountry.SetTimeFormat(timeFormat, false);
if (newSettings->FindString("longTimeFormat", &timeFormat)
== B_OK)
fDefaultCountry.SetTimeFormat(timeFormat, true);
}
status_t
BLocaleRoster::GetPreferredLanguages(BMessage* languages) const
{
if (!languages)
return B_BAD_VALUE;
BAutolock lock(gRosterData.fLock);
assert(lock.IsLocked());
*languages = gRosterData.fPreferredLanguages;
return B_OK;
}
status_t
BLocaleRoster::SetPreferredLanguages(BMessage *languages)
{
BAutolock lock(gRosterData.fLock);
assert(lock.IsLocked());
if (languages)
gRosterData.fPreferredLanguages = *languages;
else
gRosterData.fPreferredLanguages.MakeEmpty();
return B_OK;
}
// Get all the available languages from ICU
status_t
BLocaleRoster::GetInstalledLanguages(BMessage *languages) const
{
if (!languages)
return B_BAD_VALUE;
int32 i;
UnicodeString icuLanguageName;
BString languageName;
int32_t localeCount;
const Locale* icuLocaleList
= Locale::getAvailableLocales(localeCount);
// Loop over the strings and add them to an std::set to remove duplicates
for (i = 0; i < localeCount; i++) {
languages->AddString("langs", icuLocaleList[i].getName());
}
return B_OK;
}
// Get all the available countries from ICU
status_t
BLocaleRoster::GetAvailableCountries(BMessage *countries) const
{
if (!countries)
return B_BAD_VALUE;
int32 i;
const char* const* countryList = uloc_getISOCountries();
for (i = 0; countryList[i] != NULL; i++) {
countries->AddString("countries", countryList[i]);
}
return B_OK;
}
status_t
BLocaleRoster::GetInstalledCatalogs(BMessage * languageList,
const char* sigPattern, const char* langPattern, int32 fingerprint) const
{
if (languageList == NULL)
return B_BAD_VALUE;
int32 count = gRosterData.fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
BCatalogAddOnInfo *info
= (BCatalogAddOnInfo*)gRosterData.fCatalogAddOnInfos.ItemAt(i);
if (!info->MakeSureItsLoaded() || !info->fLanguagesFunc)
continue;
info->fLanguagesFunc(languageList, sigPattern, langPattern,
fingerprint);
}
return B_OK;
}
/*
* creates a new (empty) catalog of the given type (the request is dispatched
* to the appropriate add-on).
* If the add-on doesn't support catalog-creation or if the creation fails,
* NULL is returned, otherwise a pointer to the freshly created catalog.
* Any created catalog will be initialized with the given signature and
* language-name.
*/
BCatalogAddOn*
BLocaleRoster::CreateCatalog(const char *type, const char *signature,
const char *language)
{
if (!type || !signature || !language)
return NULL;
BAutolock lock(gRosterData.fLock);
assert(lock.IsLocked());
int32 count = gRosterData.fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
BCatalogAddOnInfo *info
= (BCatalogAddOnInfo*)gRosterData.fCatalogAddOnInfos.ItemAt(i);
if (info->fName.ICompare(type)!=0 || !info->MakeSureItsLoaded()
|| !info->fCreateFunc)
continue;
BCatalogAddOn *catalog = info->fCreateFunc(signature, language);
if (catalog) {
info->fLoadedCatalogs.AddItem(catalog);
info->UnloadIfPossible();
return catalog;
}
}
return NULL;
}
/*
* Loads a catalog for the given signature, language and fingerprint.
* The request to load this catalog is dispatched to all add-ons in turn,
* until an add-on reports success.
* If a catalog depends on another language (as 'english-british' depends
* on 'english') the dependant catalogs are automatically loaded, too.
* So it is perfectly possible that this method returns a catalog-chain
* instead of a single catalog.
* NULL is returned if no matching catalog could be found.
*/
BCatalogAddOn*
BLocaleRoster::LoadCatalog(const char *signature, const char *language,
int32 fingerprint)
{
if (!signature)
return NULL;
BAutolock lock(gRosterData.fLock);
assert(lock.IsLocked());
int32 count = gRosterData.fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
BCatalogAddOnInfo *info
= (BCatalogAddOnInfo*)gRosterData.fCatalogAddOnInfos.ItemAt(i);
if (!info->MakeSureItsLoaded() || !info->fInstantiateFunc)
continue;
BMessage languages;
if (language)
// try to load catalogs for the given language:
languages.AddString("language", language);
else
// try to load catalogs for one of the preferred languages:
GetPreferredLanguages(&languages);
BCatalogAddOn *catalog = NULL;
const char *lang;
for (int32 l=0; languages.FindString("language", l, &lang)==B_OK; ++l) {
catalog = info->fInstantiateFunc(signature, lang, fingerprint);
if (catalog)
info->fLoadedCatalogs.AddItem(catalog);
// Chain-load catalogs for languages that depend on
// other languages.
// The current implementation uses the filename in order to
// detect dependencies (parenthood) between languages (it
// traverses from "english_british_oxford" to "english_british"
// to "english"):
// TODO: use ICU facilities instead, so we can handle more
// complex things such as fr_FR@euro, or whatever, encodings
// and so on.
int32 pos;
BString langName(lang);
BCatalogAddOn *currCatalog=catalog, *nextCatalog;
while ((pos = langName.FindLast('_')) >= 0) {
// language is based on parent, so we load that, too:
// (even if the parent catalog was not found)
langName.Truncate(pos);
nextCatalog = info->fInstantiateFunc(signature,
langName.String(), fingerprint);
if (nextCatalog) {
info->fLoadedCatalogs.AddItem(nextCatalog);
if(currCatalog)
currCatalog->fNext = nextCatalog;
else
catalog = nextCatalog;
currCatalog = nextCatalog;
}
}
return catalog;
}
info->UnloadIfPossible();
}
return NULL;
}
/*
* Loads an embedded catalog from the given entry-ref (which is usually an
* app- or add-on-file. The request to load the catalog is dispatched to all
* add-ons in turn, until an add-on reports success.
* NULL is returned if no embedded catalog could be found.
*/
BCatalogAddOn*
BLocaleRoster::LoadEmbeddedCatalog(entry_ref *appOrAddOnRef)
{
if (!appOrAddOnRef)
return NULL;
BAutolock lock(gRosterData.fLock);
assert(lock.IsLocked());
int32 count = gRosterData.fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
BCatalogAddOnInfo *info
= (BCatalogAddOnInfo*)gRosterData.fCatalogAddOnInfos.ItemAt(i);
if (!info->MakeSureItsLoaded() || !info->fInstantiateEmbeddedFunc)
continue;
BCatalogAddOn *catalog = NULL;
catalog = info->fInstantiateEmbeddedFunc(appOrAddOnRef);
if (catalog) {
info->fLoadedCatalogs.AddItem(catalog);
return catalog;
}
info->UnloadIfPossible();
}
return NULL;
}
/*
* unloads the given catalog (or rather: catalog-chain).
* Every single catalog of the chain will be deleted automatically.
* Add-ons that have no more current catalogs are unloaded, too.
*/
status_t
BLocaleRoster::UnloadCatalog(BCatalogAddOn *catalog)
{
if (!catalog)
return B_BAD_VALUE;
BAutolock lock(gRosterData.fLock);
assert(lock.IsLocked());
status_t res = B_ERROR;
BCatalogAddOn *nextCatalog;
// note: as we currently aren't chainloading catalogs, there is only
// one catalog to unload...
while (catalog) {
nextCatalog = catalog->fNext;
int32 count = gRosterData.fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
BCatalogAddOnInfo *info
= static_cast<BCatalogAddOnInfo*>(
gRosterData.fCatalogAddOnInfos.ItemAt(i)
);
if (info->fLoadedCatalogs.HasItem(catalog)) {
info->fLoadedCatalogs.RemoveItem(catalog);
delete catalog;
info->UnloadIfPossible();
res = B_OK;
}
}
catalog = nextCatalog;
}
return res;
}

View File

@ -0,0 +1,861 @@
/*
* Copyright 2003-2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Oliver Tappe, zooey@hirschkaefer.de
*/
#include <MutableLocaleRoster.h>
#include <set>
#include <syslog.h>
#include <AppFileInfo.h>
#include <Autolock.h>
#include <Catalog.h>
#include <Collator.h>
#include <Country.h>
#include <DefaultCatalog.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <Language.h>
#include <Locale.h>
#include <Node.h>
#include <Path.h>
#include <Roster.h>
#include <String.h>
#include <TimeZone.h>
#include <ICUWrapper.h>
// ICU includes
#include <unicode/locid.h>
#include <unicode/timezone.h>
namespace BPrivate {
// #pragma mark - CatalogAddOnInfo
CatalogAddOnInfo::CatalogAddOnInfo(const BString& name, const BString& path,
uint8 priority)
:
fInstantiateFunc(NULL),
fInstantiateEmbeddedFunc(NULL),
fCreateFunc(NULL),
fLanguagesFunc(NULL),
fName(name),
fPath(path),
fAddOnImage(B_NO_INIT),
fPriority(priority),
fIsEmbedded(path.Length()==0)
{
}
CatalogAddOnInfo::~CatalogAddOnInfo()
{
int32 count = fLoadedCatalogs.CountItems();
for (int32 i = 0; i < count; ++i) {
BCatalogAddOn* cat
= static_cast<BCatalogAddOn*>(fLoadedCatalogs.ItemAt(i));
delete cat;
}
fLoadedCatalogs.MakeEmpty();
UnloadIfPossible();
}
bool
CatalogAddOnInfo::MakeSureItsLoaded()
{
if (!fIsEmbedded && fAddOnImage < B_OK) {
// add-on has not been loaded yet, so we try to load it:
BString fullAddOnPath(fPath);
fullAddOnPath << "/" << fName;
fAddOnImage = load_add_on(fullAddOnPath.String());
if (fAddOnImage >= B_OK) {
get_image_symbol(fAddOnImage, "instantiate_catalog",
B_SYMBOL_TYPE_TEXT, (void**)&fInstantiateFunc);
get_image_symbol(fAddOnImage, "instantiate_embedded_catalog",
B_SYMBOL_TYPE_TEXT, (void**)&fInstantiateEmbeddedFunc);
get_image_symbol(fAddOnImage, "create_catalog",
B_SYMBOL_TYPE_TEXT, (void**)&fCreateFunc);
get_image_symbol(fAddOnImage, "get_available_languages",
B_SYMBOL_TYPE_TEXT, (void**)&fLanguagesFunc);
log_team(LOG_DEBUG, "catalog-add-on %s has been loaded",
fName.String());
} else {
log_team(LOG_DEBUG, "could not load catalog-add-on %s (%s)",
fName.String(), strerror(fAddOnImage));
return false;
}
} else if (fIsEmbedded) {
// The built-in catalog still has to provide this function
fLanguagesFunc = default_catalog_get_available_languages;
}
return true;
}
void
CatalogAddOnInfo::UnloadIfPossible()
{
if (!fIsEmbedded && fLoadedCatalogs.IsEmpty()) {
unload_add_on(fAddOnImage);
fAddOnImage = B_NO_INIT;
fInstantiateFunc = NULL;
fInstantiateEmbeddedFunc = NULL;
fCreateFunc = NULL;
fLanguagesFunc = NULL;
// log_team(LOG_DEBUG, "catalog-add-on %s has been unloaded",
// fName.String());
}
}
// #pragma mark - MutableLocaleRoster
RosterData gRosterData;
static const char* kPriorityAttr = "ADDON:priority";
RosterData::RosterData()
:
fLock("LocaleRosterData")
{
openlog_team("liblocale.so", LOG_PID, LOG_USER);
#ifndef DEBUG
setlogmask_team(LOG_UPTO(LOG_WARNING));
#endif
InitializeCatalogAddOns();
Refresh();
}
RosterData::~RosterData()
{
BAutolock lock(fLock);
CleanupCatalogAddOns();
closelog();
}
int
RosterData::CompareInfos(const void* left, const void* right)
{
return ((CatalogAddOnInfo*)right)->fPriority
- ((CatalogAddOnInfo*)left)->fPriority;
}
status_t
RosterData::Refresh()
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
status_t status = _LoadLocaleSettings();
if (status == B_OK)
status = _LoadTimeSettings();
return status;
}
/*
iterate over add-on-folders and collect information about each
catalog-add-ons (types of catalogs) into fCatalogAddOnInfos.
*/
void
RosterData::InitializeCatalogAddOns()
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return;
// add info about embedded default catalog:
CatalogAddOnInfo* defaultCatalogAddOnInfo
= new(std::nothrow) CatalogAddOnInfo("Default", "",
DefaultCatalog::kDefaultCatalogAddOnPriority);
if (!defaultCatalogAddOnInfo)
return;
defaultCatalogAddOnInfo->fInstantiateFunc = DefaultCatalog::Instantiate;
defaultCatalogAddOnInfo->fInstantiateEmbeddedFunc
= DefaultCatalog::InstantiateEmbedded;
defaultCatalogAddOnInfo->fCreateFunc = DefaultCatalog::Create;
fCatalogAddOnInfos.AddItem((void*)defaultCatalogAddOnInfo);
directory_which folders[] = {
B_COMMON_ADDONS_DIRECTORY,
B_SYSTEM_ADDONS_DIRECTORY,
static_cast<directory_which>(-1)
};
BPath addOnPath;
BDirectory addOnFolder;
char buf[4096];
status_t err;
for (int f = 0; folders[f]>=0; ++f) {
find_directory(folders[f], &addOnPath);
BString addOnFolderName(addOnPath.Path());
addOnFolderName << "/locale/catalogs";
system_info info;
if (get_system_info(&info) == B_OK
&& (info.abi & B_HAIKU_ABI_MAJOR)
!= (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR)) {
switch (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) {
case B_HAIKU_ABI_GCC_2:
addOnFolderName << "/gcc2";
break;
case B_HAIKU_ABI_GCC_4:
addOnFolderName << "/gcc4";
break;
}
}
err = addOnFolder.SetTo(addOnFolderName.String());
if (err != B_OK)
continue;
// scan through all the folder's entries for catalog add-ons:
int32 count;
int8 priority;
entry_ref eref;
BNode node;
BEntry entry;
dirent* dent;
while ((count = addOnFolder.GetNextDirents((dirent*)buf, 4096)) > 0) {
dent = (dirent*)buf;
while (count-- > 0) {
if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")
&& strcmp(dent->d_name, "gcc2")
&& strcmp(dent->d_name, "gcc4")) {
// we have found (what should be) a catalog-add-on:
eref.device = dent->d_pdev;
eref.directory = dent->d_pino;
eref.set_name(dent->d_name);
entry.SetTo(&eref, true);
// traverse through any links to get to the real thang!
node.SetTo(&entry);
priority = -1;
if (node.ReadAttr(kPriorityAttr, B_INT8_TYPE, 0,
&priority, sizeof(int8)) <= 0) {
// add-on has no priority-attribute yet, so we load it
// to fetch the priority from the corresponding
// symbol...
BString fullAddOnPath(addOnFolderName);
fullAddOnPath << "/" << dent->d_name;
image_id image = load_add_on(fullAddOnPath.String());
if (image >= B_OK) {
uint8* prioPtr;
if (get_image_symbol(image, "gCatalogAddOnPriority",
B_SYMBOL_TYPE_DATA,
(void**)&prioPtr) == B_OK) {
priority = *prioPtr;
node.WriteAttr(kPriorityAttr, B_INT8_TYPE, 0,
&priority, sizeof(int8));
} else {
log_team(LOG_ERR,
"couldn't get priority for add-on %s\n",
fullAddOnPath.String());
}
unload_add_on(image);
} else {
log_team(LOG_ERR,
"couldn't load add-on %s, error: %s\n",
fullAddOnPath.String(), strerror(image));
}
}
if (priority >= 0) {
// add-ons with priority < 0 will be ignored
CatalogAddOnInfo* addOnInfo
= new(std::nothrow) CatalogAddOnInfo(dent->d_name,
addOnFolderName, priority);
if (addOnInfo)
fCatalogAddOnInfos.AddItem((void*)addOnInfo);
}
}
// Bump the dirent-pointer by length of the dirent just handled:
dent = (dirent*)((char*)dent + dent->d_reclen);
}
}
}
fCatalogAddOnInfos.SortItems(CompareInfos);
}
/*
* unloads all catalog-add-ons (which will throw away all loaded catalogs, too)
*/
void
RosterData::CleanupCatalogAddOns()
{
BAutolock lock(fLock);
if (!lock.IsLocked())
return;
int32 count = fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i<count; ++i) {
CatalogAddOnInfo* info
= static_cast<CatalogAddOnInfo*>(fCatalogAddOnInfos.ItemAt(i));
delete info;
}
fCatalogAddOnInfos.MakeEmpty();
}
status_t
RosterData::SetDefaultCountry(const BCountry& newCountry)
{
status_t status = B_OK;
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
status = _SetDefaultCountry(newCountry);
if (status == B_OK)
status = _SaveLocaleSettings();
if (status == B_OK) {
BMessage updateMessage(B_LOCALE_CHANGED);
status = _AddDefaultCountryToMessage(&updateMessage);
if (status == B_OK)
status = be_roster->Broadcast(&updateMessage);
}
return status;
}
status_t
RosterData::SetDefaultTimeZone(const BTimeZone& newZone)
{
status_t status = B_OK;
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
status = _SetDefaultTimeZone(newZone);
if (status == B_OK)
status = _SaveTimeSettings();
if (status == B_OK) {
BMessage updateMessage(B_LOCALE_CHANGED);
status = _AddDefaultTimeZoneToMessage(&updateMessage);
if (status == B_OK)
status = be_roster->Broadcast(&updateMessage);
}
return status;
}
status_t
RosterData::SetPreferredLanguages(const BMessage* languages)
{
status_t status = B_OK;
BAutolock lock(fLock);
if (!lock.IsLocked())
return B_ERROR;
status = _SetPreferredLanguages(languages);
if (status == B_OK)
status = _SaveLocaleSettings();
if (status == B_OK) {
BMessage updateMessage(B_LOCALE_CHANGED);
status = _AddPreferredLanguagesToMessage(&updateMessage);
if (status == B_OK)
status = be_roster->Broadcast(&updateMessage);
}
return status;
}
status_t
RosterData::_LoadLocaleSettings()
{
BPath path;
BFile file;
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
if (status == B_OK) {
path.Append("Locale settings");
status = file.SetTo(path.Path(), B_READ_ONLY);
}
BMessage settings;
if (status == B_OK)
status = settings.Unflatten(&file);
if (status == B_OK)
status = _SetPreferredLanguages(&settings);
if (status == B_OK) {
BString codeName;
BCountry newDefaultCountry;
if (settings.FindString("country", &codeName) == B_OK)
newDefaultCountry = BCountry(codeName);
BString timeFormat;
if (settings.FindString("shortTimeFormat", &timeFormat) == B_OK)
newDefaultCountry.SetTimeFormat(timeFormat, false);
if (settings.FindString("longTimeFormat", &timeFormat) == B_OK)
newDefaultCountry.SetTimeFormat(timeFormat, true);
_SetDefaultCountry(newDefaultCountry);
return B_OK;
}
// Something went wrong (no settings file or invalid BMessage), so we
// set everything to default values
fPreferredLanguages.AddString("language", "en");
log_team(LOG_ERR, "*** No locale settings found!\n");
return status;
}
status_t
RosterData::_LoadTimeSettings()
{
BPath path;
BFile file;
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
if (status == B_OK) {
path.Append("Time settings");
status = file.SetTo(path.Path(), B_READ_ONLY);
}
BMessage settings;
if (status == B_OK)
status = settings.Unflatten(&file);
if (status == B_OK) {
BString timeZoneCode;
if (settings.FindString("timezone", &timeZoneCode) == B_OK)
_SetDefaultTimeZone(BTimeZone(timeZoneCode.String()));
else
_SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone));
return B_OK;
}
// Something went wrong (no settings file or invalid BMessage), so we
// set everything to default values
_SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone));
log_team(LOG_ERR, "*** No time settings found!\n");
return status;
}
status_t
RosterData::_SaveLocaleSettings()
{
BMessage settings;
status_t status = _AddDefaultCountryToMessage(&settings);
if (status == B_OK)
_AddPreferredLanguagesToMessage(&settings);
BPath path;
if (status == B_OK)
status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
BFile file;
if (status == B_OK) {
path.Append("Locale settings");
status = file.SetTo(path.Path(),
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
}
if (status == B_OK)
status = settings.Flatten(&file);
if (status == B_OK)
status = file.Sync();
return status;
}
status_t
RosterData::_SaveTimeSettings()
{
BMessage settings;
status_t status = _AddDefaultTimeZoneToMessage(&settings);
BPath path;
if (status == B_OK)
status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
BFile file;
if (status == B_OK) {
path.Append("Time settings");
status = file.SetTo(path.Path(),
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
}
if (status == B_OK)
status = settings.Flatten(&file);
if (status == B_OK)
status = file.Sync();
return status;
}
status_t
RosterData::_SetDefaultCountry(const BCountry& newCountry)
{
fDefaultCountry = newCountry;
return B_OK;
}
status_t
RosterData::_SetDefaultTimeZone(const BTimeZone& newZone)
{
fDefaultTimeZone = newZone;
return B_OK;
}
status_t
RosterData::_SetPreferredLanguages(const BMessage* languages)
{
BString langName;
if (languages != NULL
&& languages->FindString("language", &langName) == B_OK) {
UErrorCode icuError = U_ZERO_ERROR;
Locale icuLocale = Locale::createCanonical(langName.String());
if (icuLocale.isBogus())
return B_ERROR;
Locale::setDefault(icuLocale, icuError);
if (!U_SUCCESS(icuError))
return B_ERROR;
fDefaultCollator = BCollator(langName.String());
fDefaultLanguage.SetTo(langName.String());
fPreferredLanguages.RemoveName("language");
for (int i = 0; languages->FindString("language", i, &langName) == B_OK;
i++) {
fPreferredLanguages.AddString("language", langName);
}
} else {
fPreferredLanguages.MakeEmpty();
fPreferredLanguages.AddString("language", "en");
}
return B_OK;
}
status_t
RosterData::_AddDefaultCountryToMessage(BMessage* message) const
{
status_t status = message->AddString("country", fDefaultCountry.Code());
BString timeFormat;
if (status == B_OK)
status = fDefaultCountry.GetTimeFormat(timeFormat, false);
if (status == B_OK)
status = message->AddString("shortTimeFormat", timeFormat.String());
if (status == B_OK)
status = fDefaultCountry.GetTimeFormat(timeFormat, true);
if (status == B_OK)
status = message->AddString("longTimeFormat", timeFormat.String());
return status;
}
status_t
RosterData::_AddDefaultTimeZoneToMessage(BMessage* message) const
{
return message->AddString("timezone", fDefaultTimeZone.Code());
}
status_t
RosterData::_AddPreferredLanguagesToMessage(BMessage* message) const
{
status_t status = B_OK;
BString langName;
for (int i = 0; fPreferredLanguages.FindString("language", i,
&langName) == B_OK; i++) {
status = message->AddString("language", langName);
if (status != B_OK)
break;
}
return status;
}
// #pragma mark - MutableLocaleRoster
static MutableLocaleRoster gLocaleRoster;
MutableLocaleRoster* mutable_locale_roster = &gLocaleRoster;
MutableLocaleRoster::MutableLocaleRoster()
{
}
MutableLocaleRoster::~MutableLocaleRoster()
{
}
status_t
MutableLocaleRoster::SetDefaultCountry(const BCountry& newCountry)
{
return gRosterData.SetDefaultCountry(newCountry);
}
status_t
MutableLocaleRoster::SetDefaultTimeZone(const BTimeZone& newZone)
{
return gRosterData.SetDefaultTimeZone(newZone);
}
status_t
MutableLocaleRoster::SetPreferredLanguages(const BMessage* languages)
{
return gRosterData.SetPreferredLanguages(languages);
}
status_t
MutableLocaleRoster::GetSystemCatalog(BCatalogAddOn** catalog) const
{
if (!catalog)
return B_BAD_VALUE;
*catalog = LoadCatalog("system");
return B_OK;
}
/*
* creates a new (empty) catalog of the given type (the request is dispatched
* to the appropriate add-on).
* If the add-on doesn't support catalog-creation or if the creation fails,
* NULL is returned, otherwise a pointer to the freshly created catalog.
* Any created catalog will be initialized with the given signature and
* language-name.
*/
BCatalogAddOn*
MutableLocaleRoster::CreateCatalog(const char* type, const char* signature,
const char* language)
{
if (!type || !signature || !language)
return NULL;
BAutolock lock(gRosterData.fLock);
if (!lock.IsLocked())
return NULL;
int32 count = gRosterData.fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info
= (CatalogAddOnInfo*)gRosterData.fCatalogAddOnInfos.ItemAt(i);
if (info->fName.ICompare(type)!=0 || !info->MakeSureItsLoaded()
|| !info->fCreateFunc)
continue;
BCatalogAddOn* catalog = info->fCreateFunc(signature, language);
if (catalog) {
info->fLoadedCatalogs.AddItem(catalog);
info->UnloadIfPossible();
return catalog;
}
}
return NULL;
}
/*
* Loads a catalog for the given signature, language and fingerprint.
* The request to load this catalog is dispatched to all add-ons in turn,
* until an add-on reports success.
* If a catalog depends on another language (as 'english-british' depends
* on 'english') the dependant catalogs are automatically loaded, too.
* So it is perfectly possible that this method returns a catalog-chain
* instead of a single catalog.
* NULL is returned if no matching catalog could be found.
*/
BCatalogAddOn*
MutableLocaleRoster::LoadCatalog(const char* signature, const char* language,
int32 fingerprint) const
{
if (!signature)
return NULL;
BAutolock lock(gRosterData.fLock);
if (!lock.IsLocked())
return NULL;
int32 count = gRosterData.fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info
= (CatalogAddOnInfo*)gRosterData.fCatalogAddOnInfos.ItemAt(i);
if (!info->MakeSureItsLoaded() || !info->fInstantiateFunc)
continue;
BMessage languages;
if (language)
// try to load catalogs for the given language:
languages.AddString("language", language);
else
// try to load catalogs for one of the preferred languages:
GetPreferredLanguages(&languages);
BCatalogAddOn* catalog = NULL;
const char* lang;
for (int32 l=0; languages.FindString("language", l, &lang)==B_OK; ++l) {
catalog = info->fInstantiateFunc(signature, lang, fingerprint);
if (catalog)
info->fLoadedCatalogs.AddItem(catalog);
// Chain-load catalogs for languages that depend on
// other languages.
// The current implementation uses the filename in order to
// detect dependencies (parenthood) between languages (it
// traverses from "english_british_oxford" to "english_british"
// to "english"):
// TODO: use ICU facilities instead, so we can handle more
// complex things such as fr_FR@euro, or whatever, encodings
// and so on.
int32 pos;
BString langName(lang);
BCatalogAddOn* currCatalog = catalog;
BCatalogAddOn* nextCatalog;
while ((pos = langName.FindLast('_')) >= 0) {
// language is based on parent, so we load that, too:
// (even if the parent catalog was not found)
langName.Truncate(pos);
nextCatalog = info->fInstantiateFunc(signature,
langName.String(), fingerprint);
if (nextCatalog) {
info->fLoadedCatalogs.AddItem(nextCatalog);
if(currCatalog)
currCatalog->SetNext(nextCatalog);
else
catalog = nextCatalog;
currCatalog = nextCatalog;
}
}
return catalog;
}
info->UnloadIfPossible();
}
return NULL;
}
/*
* Loads an embedded catalog from the given entry-ref (which is usually an
* app- or add-on-file. The request to load the catalog is dispatched to all
* add-ons in turn, until an add-on reports success.
* NULL is returned if no embedded catalog could be found.
*/
BCatalogAddOn*
MutableLocaleRoster::LoadEmbeddedCatalog(entry_ref* appOrAddOnRef)
{
if (!appOrAddOnRef)
return NULL;
BAutolock lock(gRosterData.fLock);
if (!lock.IsLocked())
return NULL;
int32 count = gRosterData.fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info
= (CatalogAddOnInfo*)gRosterData.fCatalogAddOnInfos.ItemAt(i);
if (!info->MakeSureItsLoaded() || !info->fInstantiateEmbeddedFunc)
continue;
BCatalogAddOn* catalog = NULL;
catalog = info->fInstantiateEmbeddedFunc(appOrAddOnRef);
if (catalog) {
info->fLoadedCatalogs.AddItem(catalog);
return catalog;
}
info->UnloadIfPossible();
}
return NULL;
}
/*
* unloads the given catalog (or rather: catalog-chain).
* Every single catalog of the chain will be deleted automatically.
* Add-ons that have no more current catalogs are unloaded, too.
*/
status_t
MutableLocaleRoster::UnloadCatalog(BCatalogAddOn* catalog)
{
if (!catalog)
return B_BAD_VALUE;
BAutolock lock(gRosterData.fLock);
if (!lock.IsLocked())
return B_ERROR;
status_t res = B_ERROR;
BCatalogAddOn* nextCatalog;
while (catalog) {
nextCatalog = catalog->Next();
int32 count = gRosterData.fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
CatalogAddOnInfo* info = static_cast<CatalogAddOnInfo*>(
gRosterData.fCatalogAddOnInfos.ItemAt(i));
if (info->fLoadedCatalogs.HasItem(catalog)) {
info->fLoadedCatalogs.RemoveItem(catalog);
delete catalog;
info->UnloadIfPossible();
res = B_OK;
}
}
catalog = nextCatalog;
}
return res;
}
} // namespace BPrivate
BLocaleRoster* be_locale_roster = &BPrivate::gLocaleRoster;

View File

@ -1,90 +1,28 @@
/*
* Copyright 2010, Adrien Destugues, pulkomandy@gmail.com
/*
* Copyright 2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Oliver Tappe <zooey@hirschkaefer.de>
*/
#include <TimeFormat.h>
#include <unicode/format.h>
#include <unicode/tmutfmt.h>
#include <unicode/utypes.h>
#include <ICUWrapper.h>
#define ICU_VERSION icu_44
status_t BTimeFormat::Format(int64 number, BString* buffer) const
// copy constructor
BTimeFormat::BTimeFormat(const BTimeFormat &other)
: BDateTimeFormat(other)
{
// create time unit amount instance - a combination of Number and time unit
UErrorCode status = U_ZERO_ERROR;
int64 days, hours, minutes, seconds, remainder;
days = number / (24 * 3600);
remainder = number % (24 * 3600);
hours = remainder / 3600;
remainder %= 3600;
minutes = remainder / 60;
remainder %= 60;
seconds = remainder;
TimeUnitFormat* format = new TimeUnitFormat(status);
UnicodeString formatted;
Formattable formattable;
BStringByteSink bbs(buffer);
if (!U_SUCCESS(status)) {
delete format;
return B_ERROR;
}
if (days) {
TimeUnitAmount* daysAmount = new TimeUnitAmount(days,
TimeUnit::UTIMEUNIT_DAY, status);
formattable.adoptObject(daysAmount);
formatted = ((ICU_VERSION::Format*)format)->format(formattable, formatted,
status);
}
if (hours) {
TimeUnitAmount* hoursAmount = new TimeUnitAmount(hours,
TimeUnit::UTIMEUNIT_HOUR, status);
formattable.adoptObject(hoursAmount);
if (days)
formatted.append(", ");
formatted = ((ICU_VERSION::Format*)format)->format(formattable, formatted,
status);
}
if (minutes) {
TimeUnitAmount* minutesAmount = new TimeUnitAmount(minutes,
TimeUnit::UTIMEUNIT_MINUTE, status);
formattable.adoptObject(minutesAmount);
if (days || hours)
formatted.append(", ");
formatted = ((ICU_VERSION::Format*)format)->format(formattable, formatted,
status);
}
if (seconds || (minutes == 0 && hours == 0 && days == 0)) {
TimeUnitAmount* secondsAmount = new TimeUnitAmount(seconds,
TimeUnit::UTIMEUNIT_SECOND, status);
formattable.adoptObject(secondsAmount);
if (days || hours || minutes)
formatted.append(", ");
formatted = ((ICU_VERSION::Format*)format)->format(formattable, formatted,
status);
}
formatted.toUTF8(bbs);
delete format;
return B_OK;
}
// destructor
BTimeFormat::~BTimeFormat()
{
}
// Format
status_t
BTimeFormat::Format(bigtime_t value, BString* buffer) const
{
return B_ERROR;
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Adrien Destugues <pulkomandy@gmail.com>
* Oliver Tappe <zooey@hirschkaefer.de>
*/
#include <TimeUnitFormat.h>
#include <new>
#include <unicode/format.h>
#include <unicode/tmutfmt.h>
#include <unicode/utypes.h>
#include <ICUWrapper.h>
// maps our unit element to the corresponding ICU unit
static const TimeUnit::UTimeUnitFields skUnitMap[] = {
TimeUnit::UTIMEUNIT_YEAR,
TimeUnit::UTIMEUNIT_MONTH,
TimeUnit::UTIMEUNIT_WEEK,
TimeUnit::UTIMEUNIT_DAY,
TimeUnit::UTIMEUNIT_HOUR,
TimeUnit::UTIMEUNIT_MINUTE,
TimeUnit::UTIMEUNIT_SECOND,
};
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;
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)
return B_NO_MEMORY;
if (!U_SUCCESS(icuStatus))
return B_ERROR;
Formattable formattable;
formattable.adoptObject(timeUnitAmount);
FieldPosition pos(FieldPosition::DONT_CARE);
UnicodeString unicodeResult;
timeUnitFormatter.format(formattable, unicodeResult, pos, icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
BStringByteSink byteSink(buffer);
unicodeResult.toUTF8(byteSink);
return B_OK;
}

View File

@ -14,9 +14,12 @@
#include <ICUWrapper.h>
const char* BTimeZone::kNameOfGmtZone = "GMT";
BTimeZone::BTimeZone(const char* zoneCode)
{
_Init(zoneCode);
SetTo(zoneCode);
}
@ -53,8 +56,8 @@ BTimeZone::InitCheck() const
}
void
BTimeZone::_Init(const char* zoneCode)
status_t
BTimeZone::SetTo(const char* zoneCode)
{
TimeZone* icuTimeZone;
if (zoneCode == NULL || zoneCode[0] == '\0')
@ -86,4 +89,6 @@ BTimeZone::_Init(const char* zoneCode)
// we want seconds, not ms (which ICU gives us)
fInitStatus = B_OK;
}
return fInitStatus;
}

View File

@ -7,20 +7,21 @@
#include "LocaleSettings.h"
#include <FindDirectory.h>
#include <LocaleRoster.h>
#include <MutableLocaleRoster.h>
#include <Path.h>
#include <Roster.h>
#include <String.h>
#include <SupportDefs.h>
using BPrivate::mutable_locale_roster;
static const uint32 kMsgLocaleSettings = 'LCst';
LocaleSettings::LocaleSettings()
:
fMessage(kMsgLocaleSettings),
fSaved(false)
fMessage(kMsgLocaleSettings)
{
// Set default preferences
fMessage.AddString("language", "en");
@ -36,27 +37,14 @@ LocaleSettings::Load()
err = _Open(&file, B_READ_ONLY);
if (err != B_OK)
return err;
err = fMessage.Unflatten(&file);
if (err == B_OK)
fSaved = true;
return err;
return fMessage.Unflatten(&file);
}
status_t
LocaleSettings::Save()
{
// Save on disk for next time we reboot
BFile file;
status_t err;
err = _Open(&file, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
if (err != B_OK)
return err;
err = fMessage.Flatten(&file);
if (err == B_OK)
fSaved = true;
return err;
return B_OK;
}
@ -86,33 +74,35 @@ LocaleSettings::UpdateFrom(BMessage* message)
break;
fMessage.AddString("language", messageContent);
}
fSaved = false;
mutable_locale_roster->SetPreferredLanguages(message);
}
BCountry defaultCountry;
mutable_locale_roster->GetDefaultCountry(&defaultCountry);
bool countryChanged = false;
if (message->FindString("country", &messageContent) == B_OK) {
fMessage.ReplaceString("country", messageContent);
fMessage.RemoveName("shortTimeFormat");
fMessage.RemoveName("longTimeFormat");
fSaved = false;
defaultCountry = BCountry(messageContent.String());
countryChanged = true;
}
if (message->FindString("shortTimeFormat", &messageContent) == B_OK) {
fMessage.RemoveName("shortTimeFormat");
fMessage.AddString("shortTimeFormat", messageContent);
fSaved = false;
defaultCountry.SetTimeFormat(messageContent, false);
countryChanged = true;
}
if (message->FindString("longTimeFormat", &messageContent) == B_OK) {
fMessage.RemoveName("longTimeFormat");
fMessage.AddString("longTimeFormat", messageContent);
fSaved = false;
defaultCountry.SetTimeFormat(messageContent, true);
countryChanged = true;
}
if (fSaved == false) {
// Send to all running apps to notify them they should update their
// settings
fMessage.what = B_LOCALE_CHANGED;
be_roster->Broadcast(&fMessage);
}
if (countryChanged)
mutable_locale_roster->SetDefaultCountry(defaultCountry);
}

View File

@ -19,7 +19,6 @@ class LocaleSettings {
status_t Load();
status_t Save();
bool Saved();
bool operator==(const LocaleSettings& other);
void UpdateFrom(BMessage* message);
@ -44,7 +43,6 @@ class LocaleSettings {
status_t _Open(BFile* file, int32 mode);
BMessage fMessage;
bool fSaved;
};

View File

@ -47,10 +47,24 @@ static const uint32 kMsgPreferredLanguagesChanged = 'lang';
static int
compare_typed_list_items(const BListItem* _a, const BListItem* _b)
{
// TODO: sort them using collators.
static BCollator collator;
LanguageListItem* a = (LanguageListItem*)_a;
LanguageListItem* b = (LanguageListItem*)_b;
return strcasecmp(a->Text(), b->Text());
return collator.Compare(a->Text(), b->Text());
}
static int
compare_void_list_items(const void* _a, const void* _b)
{
static BCollator collator;
LanguageListItem* a = *(LanguageListItem**)_a;
LanguageListItem* b = *(LanguageListItem**)_b;
return collator.Compare(a->Text(), b->Text());
}
@ -62,7 +76,7 @@ LocaleWindow::LocaleWindow()
BWindow(BRect(0, 0, 0, 0), "Locale", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE
| B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS)
{
BCountry* defaultCountry;
BCountry defaultCountry;
be_locale_roster->GetDefaultCountry(&defaultCountry);
SetLayout(new BGroupLayout(B_HORIZONTAL));
@ -173,21 +187,26 @@ LocaleWindow::LocaleWindow()
be_locale_roster->GetInstalledLanguages(&countryList);
BString countryCode;
LanguageListItem* currentItem = NULL;
for (int i = 0; countryList.FindString("langs", i, &countryCode) == B_OK;
i++) {
BCountry country(countryCode);
BString countryName;
country.LocaleName(countryName);
country.GetLocaleName(countryName);
LanguageListItem* item
= new LanguageListItem(countryName, countryCode,
NULL);
listView->AddItem(item);
if (!strcmp(countryCode, defaultCountry->Code()))
listView->Select(listView->CountItems() - 1);
if (!strcmp(countryCode, defaultCountry.Code()))
currentItem = item;
}
listView->SortItems(compare_void_list_items);
if (currentItem != NULL)
listView->Select(listView->IndexOf(currentItem));
// TODO: find a real solution intead of this hack
listView->SetExplicitMinSize(
BSize(25 * be_plain_font->Size(), B_SIZE_UNSET));
@ -341,7 +360,7 @@ LocaleWindow::MessageReceived(BMessage* message)
be_app_messenger.SendMessage(&newMessage);
SettingsChanged();
BCountry* country = new BCountry(item->ID());
BCountry country(item->ID());
fFormatView->SetCountry(country);
break;
}

View File

@ -17,7 +17,7 @@
#include <GroupLayoutBuilder.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <LocaleRoster.h>
#include <MutableLocaleRoster.h>
#include <Message.h>
#include <Menu.h>
#include <MenuField.h>
@ -34,6 +34,10 @@
#include <iostream>
#include <stdio.h>
using BPrivate::mutable_locale_roster;
#undef B_TRANSLATE_CONTEXT
#define B_TRANSLATE_CONTEXT "TimeFormatSettings"
@ -144,10 +148,10 @@ IsSpecialDateChar(char charToTest)
// #pragma mark -
FormatView::FormatView(BCountry* country)
FormatView::FormatView(const BCountry& country)
:
BView("WindowsSettingsView", B_FRAME_EVENTS),
fCountry(*country)
fCountry(country)
{
SetLayout(new BGroupLayout(B_HORIZONTAL));
@ -185,8 +189,8 @@ FormatView::FormatView(BCountry* country)
f12HrRadioButton = new BRadioButton("", B_TRANSLATE("12 hour"),
new BMessage(kClockFormatChange));
fCountry.TimeFormat(fOriginalTimeFormat, false);
fCountry.TimeFormat(fOriginalLongTimeFormat, true);
fCountry.GetTimeFormat(fOriginalTimeFormat, false);
fCountry.GetTimeFormat(fOriginalLongTimeFormat, true);
if (fOriginalTimeFormat.FindFirst("a") != B_ERROR) {
f12HrRadioButton->SetValue(B_CONTROL_ON);
fCountryIs24Hr = false;
@ -356,7 +360,7 @@ FormatView::FormatView(BCountry* country)
FormatView::~FormatView()
{
be_locale_roster->SetDefaultCountry(&fCountry);
mutable_locale_roster->SetDefaultCountry(fCountry);
}
@ -510,9 +514,9 @@ FormatView::SetDefaults()
settings.SetClockTo24Hr(false);
*/
BCountry* defaultCountry;
BCountry defaultCountry;
be_locale_roster->GetDefaultCountry(&defaultCountry);
fCountry = *defaultCountry;
fCountry = defaultCountry;
// We work on a copy of the default country and set the changes when
// closing the preflet
_UpdateExamples();
@ -551,14 +555,12 @@ FormatView::Revert()
void
FormatView::SetCountry(BCountry* country)
FormatView::SetCountry(const BCountry& country)
{
fCountry = *country;
fCountry = country;
fOriginalTimeFormat.Truncate(0);
fCountry.TimeFormat(fOriginalTimeFormat, false);
fOriginalLongTimeFormat.Truncate(0);
fCountry.TimeFormat(fOriginalLongTimeFormat, true);
fCountry.GetTimeFormat(fOriginalTimeFormat, false);
fCountry.GetTimeFormat(fOriginalLongTimeFormat, true);
if (fOriginalTimeFormat.FindFirst("a") != B_ERROR) {
f12HrRadioButton->SetValue(B_CONTROL_ON);
@ -666,10 +668,12 @@ FormatView::_ParseDateFormat()
{
// TODO parse the short date too
BString dateFormatString;
fCountry.DateFormat(dateFormatString, true);
fCountry.GetDateFormat(dateFormatString, true);
const char* dateFormat = dateFormatString.String();
// Travel trough the string and parse it
printf("FV::_ParseDateFormat: df='%s'\n", dateFormat);
// Travel through the string and parse it
const char* parsePointer = dateFormat;
const char* fieldBegin = dateFormat;
@ -717,8 +721,7 @@ FormatView::_ParseDateFormat()
}
// Short date is a bit more tricky, we want to extract the separator
dateFormatString.Truncate(0);
fCountry.DateFormat(dateFormatString, false);
fCountry.GetDateFormat(dateFormatString, false);
dateFormat = dateFormatString.String();
// Travel trough the string and parse it

View File

@ -37,7 +37,7 @@ const uint32 kMenuMessage = 'FRMT';
class FormatView : public BView {
public:
FormatView(BCountry* country);
FormatView(const BCountry& country);
~FormatView();
virtual void MessageReceived(BMessage* message);
@ -46,7 +46,7 @@ public:
virtual void SetDefaults();
virtual bool IsDefaultable() const;
virtual void Revert();
virtual void SetCountry(BCountry* country);
virtual void SetCountry(const BCountry& country);
virtual void RecordRevertSettings();
virtual bool IsRevertable() const;

View File

@ -105,9 +105,9 @@ TTimeEdit::DrawSection(uint32 index, bool hasFocus)
int* fieldPositions;
int fieldCount;
BCountry* country;
BCountry country;
be_locale_roster->GetDefaultCountry(&country);
country->FormatTime(&text, fieldPositions, fieldCount, time, true);
country.FormatTime(&text, fieldPositions, fieldCount, time, true);
// TODO : this should be cached somehow to not redo it for each field
if (index * 2 + 1 > (uint32)fieldCount) {
@ -148,10 +148,10 @@ TTimeEdit::DrawSeparator(uint32 index)
int* fieldPositions;
int fieldCount;
BCountry* country;
BCountry country;
be_locale_roster->GetDefaultCountry(&country);
time_t time = fTime.Time_t();
country->FormatTime(&text, fieldPositions, fieldCount, time, true);
country.FormatTime(&text, fieldPositions, fieldCount, time, true);
// TODO : this should be cached somehow to not redo it for each field
if (index * 2 + 2 > (uint32)fieldCount) {
@ -265,9 +265,9 @@ TTimeEdit::BuildDispatch(BMessage* message)
BDateElement* dateFormat;
int fieldCount;
BCountry* here;
BCountry here;
be_locale_roster->GetDefaultCountry(&here);
here->TimeFields(dateFormat, fieldCount, true);
here.GetTimeFields(dateFormat, fieldCount, true);
if (fFocus > fieldCount) {
free(dateFormat);
return;
@ -303,9 +303,9 @@ TTimeEdit::_CheckRange()
int32 value = fHoldValue;
BDateElement* fields;
int fieldCount;
BCountry* here;
BCountry here;
be_locale_roster->GetDefaultCountry(&here);
here->TimeFields(fields, fieldCount, true);
here.GetTimeFields(fields, fieldCount, true);
if (fFocus > fieldCount) {
free(fields);
return;
@ -373,9 +373,9 @@ TTimeEdit::_IsValidDoubleDigi(int32 value)
bool isInRange = false;
BDateElement* fields;
int fieldCount;
BCountry* here;
BCountry here;
be_locale_roster->GetDefaultCountry(&here);
here->TimeFields(fields, fieldCount, true);
here.GetTimeFields(fields, fieldCount, true);
if (fFocus > fieldCount) {
free(fields);
return false;
@ -412,9 +412,9 @@ TTimeEdit::_SectionValue(int32 index) const
int32 value;
BDateElement* fields;
int fieldCount;
BCountry* here;
BCountry here;
be_locale_roster->GetDefaultCountry(&here);
here->TimeFields(fields, fieldCount, true);
here.GetTimeFields(fields, fieldCount, true);
if (index > fieldCount) {
free(fields);
return 0;
@ -487,9 +487,9 @@ TDateEdit::KeyDown(const char* bytes, int32 numBytes)
BDateElement* dateFormat;
int fieldCount;
BCountry* here;
BCountry here;
be_locale_roster->GetDefaultCountry(&here);
here->DateFields(dateFormat, fieldCount, false);
here.GetDateFields(dateFormat, fieldCount, false);
if (dateFormat[section] == B_DATE_ELEMENT_YEAR) {
int32 oldCentury = int32(fHoldValue / 100) * 100;
@ -541,9 +541,9 @@ TDateEdit::DrawSection(uint32 index, bool hasFocus)
int* fieldPositions;
int fieldCount;
BCountry* country;
BCountry country;
be_locale_roster->GetDefaultCountry(&country);
country->FormatDate(&text, fieldPositions, fieldCount, dateTime.Time_t(),
country.FormatDate(&text, fieldPositions, fieldCount, dateTime.Time_t(),
false);
// TODO : this should be cached somehow to not redo it for each field
@ -587,10 +587,10 @@ TDateEdit::DrawSeparator(uint32 index)
int* fieldPositions;
int fieldCount;
BCountry* country;
BCountry country;
be_locale_roster->GetDefaultCountry(&country);
BDateTime dateTime(fDate, BTime());
country->FormatDate(&text, fieldPositions, fieldCount, dateTime.Time_t(),
country.FormatDate(&text, fieldPositions, fieldCount, dateTime.Time_t(),
false);
// TODO : this should be cached somehow to not redo it for each field
@ -716,9 +716,9 @@ TDateEdit::BuildDispatch(BMessage* message)
BDateElement* dateFormat;
int fieldCount;
BCountry* here;
BCountry here;
be_locale_roster->GetDefaultCountry(&here);
here->DateFields(dateFormat, fieldCount, false);
here.GetDateFields(dateFormat, fieldCount, false);
if (fFocus > fieldCount) {
free(dateFormat);
return;
@ -754,9 +754,9 @@ TDateEdit::_CheckRange()
int32 value = fHoldValue;
BDateElement* fields;
int fieldCount;
BCountry* here;
BCountry here;
be_locale_roster->GetDefaultCountry(&here);
here->DateFields(fields, fieldCount, false);
here.GetDateFields(fields, fieldCount, false);
if (fFocus > fieldCount) {
free(fields);
return;
@ -811,9 +811,9 @@ TDateEdit::_IsValidDoubleDigi(int32 value)
bool isInRange = false;
BDateElement* fields;
int fieldCount;
BCountry* here;
BCountry here;
be_locale_roster->GetDefaultCountry(&here);
here->DateFields(fields, fieldCount, false);
here.GetDateFields(fields, fieldCount, false);
if (fFocus > fieldCount) {
free(fields);
return false;
@ -852,9 +852,9 @@ TDateEdit::_SectionValue(int32 index) const
int32 value = 0;
BDateElement* fields;
int fieldCount;
BCountry* here;
BCountry here;
be_locale_roster->GetDefaultCountry(&here);
here->DateFields(fields, fieldCount, false);
here.GetDateFields(fields, fieldCount, false);
if (index > fieldCount) {
free(fields);
return 0;

View File

@ -15,7 +15,6 @@
#include "TimeMessages.h"
#include "TimeWindow.h"
#include <CalendarView.h>
#include <CheckBox.h>
#include <DateTime.h>
@ -28,22 +27,18 @@
#include <String.h>
#include <StringView.h>
#include <Window.h>
#include <stdio.h>
#include <time.h>
#include <syscalls.h>
using BPrivate::BCalendarView;
using BPrivate::BDateTime;
using BPrivate::B_LOCAL_TIME;
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
# include <syscalls.h>
#else
extern "C" void _kset_tzfilename_(const char* name, size_t length, bool isGMT);
# define _kern_set_tzfilename _kset_tzfilename_
#endif
DateTimeView::DateTimeView(BRect frame)
: BView(frame, "dateTimeView", B_FOLLOW_NONE, B_WILL_DRAW
| B_NAVIGABLE_JUMP),
@ -266,6 +261,7 @@ DateTimeView::_InitView()
AddChild(fGmtTime);
fGmtTime->ResizeToPreferred();
printf("fUseGmtTime=%d\n", fUseGmtTime);
if (fUseGmtTime)
fGmtTime->SetValue(B_CONTROL_ON);
else
@ -323,20 +319,6 @@ DateTimeView::_UpdateGmtSettings()
{
_WriteRTCSettings();
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
path.Append("timezone");
BEntry entry(path.Path(), true);
if (entry.Exists()) {
entry.GetPath(&path);
// take the existing timezone and set it's gmt use
_kern_set_tzfilename(path.Path(), B_PATH_NAME_LENGTH, fUseGmtTime);
return;
}
}
// Only update GMT
_kern_set_tzfilename(NULL, 0, fUseGmtTime);
}

View File

@ -2,10 +2,10 @@ SubDir HAIKU_TOP src preferences time ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders shared ;
UsePrivateHeaders locale shared ;
UsePrivateSystemHeaders ;
Preference Time :
local sources =
AnalogClock.cpp
BaseView.cpp
Bitmaps.cpp
@ -18,6 +18,16 @@ Preference Time :
TimeZoneListItem.cpp
TZDisplay.cpp
ZoneView.cpp
;
SubDirSysHdrs $(HAIKU_ICU_HEADERS) ;
Includes [ FGristFiles $(sources) ] : $(HAIKU_ICU_HEADERS_DEPENDENCY) ;
# Dependency needed to trigger downloading/unzipping the package before
# compiling the files.
Preference Time
: $(sources)
: be libshared.a $(TARGET_LIBSUPC++) $(HAIKU_LOCALE_LIBS)
: Time.rdef
;

View File

@ -88,7 +88,7 @@ void
TTZDisplay::SetLabel(const char* label)
{
fLabel.SetTo(label);
Draw(Bounds());
Invalidate();
}
@ -103,7 +103,7 @@ void
TTZDisplay::SetText(const char* text)
{
fText.SetTo(text);
Draw(Bounds());
Invalidate();
}
@ -115,24 +115,9 @@ TTZDisplay::Time() const
void
TTZDisplay::SetTime(int32 hour, int32 minute)
TTZDisplay::SetTime(const char* time)
{
int32 ahour = hour;
if (hour > 12)
ahour = hour -12;
if (ahour == 0)
ahour = 12;
const char* ap = "AM";
if (hour > 11)
ap = "PM";
char buffer[32];
snprintf(buffer, sizeof(buffer), "%ld:%02ld %s", ahour, minute, ap);
fTime.SetTo(buffer);
fTime.SetTo(time);
Invalidate();
}

View File

@ -33,12 +33,12 @@ public:
void SetText(const char* text);
const char* Time() const;
void SetTime(int32 hour, int32 minute);
void SetTime(const char* time);
private:
BString fLabel;
BString fText;
BString fTime;
BString fLabel;
BString fText;
BString fTime;
};

View File

@ -28,7 +28,8 @@ TimeZoneListItem::TimeZoneListItem(const char* text, BCountry* country,
BTimeZone* timeZone)
:
BStringItem(text),
fIcon(NULL)
fIcon(NULL),
fTimeZone(timeZone)
{
if (country != NULL) {
fIcon = new(std::nothrow) BBitmap(BRect(0, 0, 15, 15), B_RGBA32);
@ -37,8 +38,6 @@ TimeZoneListItem::TimeZoneListItem(const char* text, BCountry* country,
fIcon = NULL;
}
}
fTimeZone = timeZone;
}
@ -95,6 +94,20 @@ TimeZoneListItem::DrawItem(BView* owner, BRect frame, bool complete)
}
bool
TimeZoneListItem::HasTimeZone() const
{
return fTimeZone != NULL;
}
const BTimeZone&
TimeZoneListItem::TimeZone() const
{
return *fTimeZone;
}
const BString&
TimeZoneListItem::Code() const
{

View File

@ -27,6 +27,8 @@ public:
void DrawItem(BView* owner, BRect frame,
bool complete = false);
bool HasTimeZone() const;
const BTimeZone& TimeZone() const;
const BString& Code() const;
const BString& Name() const;
int OffsetFromGMT() const;

View File

@ -10,16 +10,14 @@
* Oliver Tappe <zooey@hirschkaefer.de>
*/
/*
Exceptions:
doesn't calc "Time in" time.
*/
#include "ZoneView.h"
#include <stdio.h>
#include <stdlib.h>
#include <new>
#include <AutoDeleter.h>
#include <Button.h>
#include <Collator.h>
#include <Directory.h>
@ -27,7 +25,7 @@
#include <FindDirectory.h>
#include <ListItem.h>
#include <Locale.h>
#include <LocaleRoster.h>
#include <MutableLocaleRoster.h>
#include <OutlineListView.h>
#include <ScrollView.h>
#include <StorageDefs.h>
@ -38,21 +36,25 @@
#include <syscalls.h>
#include <unicode/datefmt.h>
#include <unicode/utmscale.h>
#include <ICUWrapper.h>
#include "TimeMessages.h"
#include "TimeZoneListItem.h"
#include "TZDisplay.h"
#include "TimeWindow.h"
static BCollator sCollator;
// used to sort the timezone list
using BPrivate::mutable_locale_roster;
using BPrivate::ObjectDeleter;
TimeZoneView::TimeZoneView(BRect frame)
:
BView(frame, "timeZoneView", B_FOLLOW_NONE, B_WILL_DRAW | B_NAVIGABLE_JUMP),
fCurrentZone(NULL),
fOldZone(NULL),
fCurrentZoneItem(NULL),
fOldZoneItem(NULL),
fInitialized(false)
{
_InitView();
@ -62,33 +64,30 @@ TimeZoneView::TimeZoneView(BRect frame)
bool
TimeZoneView::CheckCanRevert()
{
return fCurrentZone != fOldZone;
return fCurrentZoneItem != fOldZoneItem;
}
void
TimeZoneView::_Revert()
{
fCurrentZone = fOldZone;
int32 czone = 0;
fCurrentZoneItem = fOldZoneItem;
if (fCurrentZone != NULL) {
czone = fCityList->IndexOf(fCurrentZone);
fCityList->Select(czone);
}
// TODO : else, select ??!
if (fCurrentZoneItem != NULL) {
int32 currentZoneIndex = fZoneList->IndexOf(fCurrentZoneItem);
fZoneList->Select(currentZoneIndex);
} else
fZoneList->DeselectAll();
fZoneList->ScrollToSelection();
fCityList->ScrollToSelection();
fCurrent->SetText(((TimeZoneListItem*)fCityList->ItemAt(czone))->Text());
_SetPreview();
_SetTimeZone();
_SetSystemTimeZone();
_UpdatePreview();
_UpdateCurrent();
}
TimeZoneView::~TimeZoneView()
{
delete fCurrentZone;
delete fOldZone;
}
@ -102,23 +101,23 @@ TimeZoneView::AttachedToWindow()
fInitialized = true;
fSetZone->SetTarget(this);
fCityList->SetTarget(this);
fZoneList->SetTarget(this);
// update displays
int32 czone = 0;
if (fCurrentZone != NULL) {
czone = fCityList->IndexOf(fCurrentZone);
if (fCurrentZoneItem != NULL) {
czone = fZoneList->IndexOf(fCurrentZoneItem);
} else {
// TODO : else, select ??!
fCurrentZone = (TimeZoneListItem*)fCityList->ItemAt(0);
fCurrentZoneItem = (TimeZoneListItem*)fZoneList->ItemAt(0);
}
fCityList->Select(czone);
fZoneList->Select(czone);
fCityList->ScrollToSelection();
fCurrent->SetText(fCurrentZone->Text());
fZoneList->ScrollToSelection();
fCurrent->SetText(fCurrentZoneItem->Text());
}
fCityList->ScrollToSelection();
fZoneList->ScrollToSelection();
}
@ -144,7 +143,7 @@ TimeZoneView::MessageReceived(BMessage* message)
case H_SET_TIME_ZONE:
{
_SetTimeZone();
_SetSystemTimeZone();
((TTimeWindow*)Window())->SetRevertStatus();
break;
}
@ -154,7 +153,7 @@ TimeZoneView::MessageReceived(BMessage* message)
break;
case H_CITY_CHANGED:
_SetPreview();
_UpdatePreview();
break;
default:
@ -167,20 +166,14 @@ TimeZoneView::MessageReceived(BMessage* message)
void
TimeZoneView::_UpdateDateTime(BMessage* message)
{
int32 hour;
// only need to update once every minute
int32 minute;
if (message->FindInt32("minute", &minute) == B_OK) {
if (fLastUpdateMinute != minute) {
_UpdateCurrent();
_UpdatePreview();
// only need hour and minute
if (message->FindInt32("hour", &hour) == B_OK
&& message->FindInt32("minute", &minute) == B_OK) {
if (fHour != hour || fMinute != minute) {
fHour = hour;
fMinute = minute;
fCurrent->SetTime(hour, minute);
// do calc to get other zone time
if (fCityList->CurrentSelection() > -1)
_SetPreview();
fLastUpdateMinute = minute;
}
}
}
@ -195,14 +188,14 @@ TimeZoneView::_InitView()
frameLeft.InsetBy(10.0f, 10.0f);
// City Listing
fCityList = new BOutlineListView(frameLeft, "cityList",
fZoneList = new BOutlineListView(frameLeft, "cityList",
B_SINGLE_SELECTION_LIST);
fCityList->SetSelectionMessage(new BMessage(H_CITY_CHANGED));
fCityList->SetInvocationMessage(new BMessage(H_SET_TIME_ZONE));
fZoneList->SetSelectionMessage(new BMessage(H_CITY_CHANGED));
fZoneList->SetInvocationMessage(new BMessage(H_SET_TIME_ZONE));
_BuildRegionMenu();
BScrollView* scrollList = new BScrollView("scrollList", fCityList,
BScrollView* scrollList = new BScrollView("scrollList", fZoneList,
B_FOLLOW_ALL, 0, false, true);
AddChild(scrollList);
@ -237,7 +230,7 @@ TimeZoneView::_InitView()
void
TimeZoneView::_BuildRegionMenu()
{
BTimeZone* defaultTimeZone = NULL;
BTimeZone defaultTimeZone = NULL;
be_locale_roster->GetDefaultTimeZone(&defaultTimeZone);
// Get a list of countries and, for each country, get all the timezones and
@ -252,7 +245,7 @@ TimeZoneView::_BuildRegionMenu()
== B_OK; i++) {
BCountry country("", countryCode);
BString fullName;
country.Name(fullName);
country.GetName(fullName);
// Now list the timezones for this country
BList tzList;
@ -269,24 +262,24 @@ TimeZoneView::_BuildRegionMenu()
timeZone = (BTimeZone*)tzList.ItemAt(0);
countryItem
= new TimeZoneListItem(fullName, &country, timeZone);
fCityList->AddItem(countryItem);
if (timeZone->Code() == defaultTimeZone->Code())
fCurrentZone = countryItem;
fZoneList->AddItem(countryItem);
if (timeZone->Code() == defaultTimeZone.Code())
fCurrentZoneItem = countryItem;
break;
default:
countryItem = new TimeZoneListItem(fullName, &country, NULL);
countryItem->SetExpanded(false);
fCityList->AddItem(countryItem);
fZoneList->AddItem(countryItem);
for (int j = 0;
(timeZone = (BTimeZone*)tzList.ItemAt(j)) != NULL;
j++) {
TimeZoneListItem* tzItem = new TimeZoneListItem(
timeZone->Name(), NULL, timeZone);
fCityList->AddUnder(tzItem, countryItem);
if (timeZone->Code() == defaultTimeZone->Code())
fZoneList->AddUnder(tzItem, countryItem);
if (timeZone->Code() == defaultTimeZone.Code())
{
fCurrentZone = tzItem;
fCurrentZoneItem = tzItem;
countryItem->SetExpanded(true);
}
}
@ -294,103 +287,93 @@ TimeZoneView::_BuildRegionMenu()
}
}
fOldZone = fCurrentZone;
// add an artifical (i.e. belongs to no country) entry for GMT/UTC
BTimeZone* gmtZone = new(std::nothrow) BTimeZone(BTimeZone::kNameOfGmtZone);
TimeZoneListItem* gmtItem
= new TimeZoneListItem("- GMT/UTC (Universal Time) -", NULL, gmtZone);
fZoneList->AddItem(gmtItem);
if (gmtZone->Code() == defaultTimeZone.Code())
fCurrentZoneItem = gmtItem;
delete defaultTimeZone;
fOldZoneItem = fCurrentZoneItem;
struct ListSorter {
static int compare(const BListItem* first, const BListItem* second)
{
return sCollator.Compare(((BStringItem*)first)->Text(),
static BCollator collator;
return collator.Compare(((BStringItem*)first)->Text(),
((BStringItem*)second)->Text());
}
};
fCityList->SortItemsUnder(NULL, false, ListSorter::compare);
fZoneList->SortItemsUnder(NULL, false, ListSorter::compare);
}
void
TimeZoneView::_SetPreview()
TimeZoneView::_UpdatePreview()
{
int32 selection = fCityList->CurrentSelection();
if (selection >= 0) {
TimeZoneListItem* item
= (TimeZoneListItem*)fCityList->ItemAt(selection);
// calc preview time
time_t current = time(NULL) + item->OffsetFromGMT();
struct tm localTime;
gmtime_r(&current, &localTime);
// update prview
fPreview->SetText(item->Text());
fPreview->SetTime(localTime.tm_hour, localTime.tm_min);
fSetZone->SetEnabled((strcmp(fCurrent->Text(), item->Text()) != 0));
}
}
void
TimeZoneView::_SetCurrent(const char* text)
{
_SetTimeZone(fCurrentZone->Code().String());
time_t current = time(NULL);
struct tm localTime;
localtime_r(&current, &localTime);
fCurrent->SetText(text);
fCurrent->SetTime(localTime.tm_hour, localTime.tm_min);
}
void
TimeZoneView::_SetTimeZone()
{
/* set time based on supplied timezone. How to do this?
1) replace symlink "timezone" in B_USER_SETTINGS_DIR with a link to the
new timezone
2) set TZ environment var
3) call settz()
4) call set_timezone from OS.h passing path to timezone file
*/
int32 selection = fCityList->CurrentSelection();
int32 selection = fZoneList->CurrentSelection();
if (selection < 0)
return;
const BString& code
= ((TimeZoneListItem*)fCityList->ItemAt(selection))->Code();
_SetTimeZone(code.String());
TimeZoneListItem* item = (TimeZoneListItem*)fZoneList->ItemAt(selection);
if (!item->HasTimeZone())
return;
// update display
time_t current = time(NULL);
struct tm localTime;
localtime_r(&current, &localTime);
BString timeString = _FormatTime(item);
fPreview->SetText(item->Text());
fPreview->SetTime(timeString.String());
set_timezone(code.String());
// disable button
fSetZone->SetEnabled(false);
time_t newTime = mktime(&localTime);
localtime_r(&newTime, &localTime);
stime(&newTime);
fHour = localTime.tm_hour;
fMinute = localTime.tm_min;
fCurrentZone = (TimeZoneListItem*)(fCityList->ItemAt(selection));
_SetCurrent(((TimeZoneListItem*)fCityList->ItemAt(selection))->Text());
fSetZone->SetEnabled((strcmp(fCurrent->Text(), item->Text()) != 0));
}
void
TimeZoneView::_SetTimeZone(const char* zone)
TimeZoneView::_UpdateCurrent()
{
putenv(BString("TZ=").Append(zone).String());
tzset();
if (fCurrentZoneItem == NULL)
return;
be_locale_roster->SetDefaultTimeZone(zone);
BString timeString = _FormatTime(fCurrentZoneItem);
fCurrent->SetText(fCurrentZoneItem->Text());
fCurrent->SetTime(timeString.String());
}
void
TimeZoneView::_SetSystemTimeZone()
{
/* Set sytem timezone for all different API levels. How to do this?
* 1) tell locale-roster about new default timezone
* 2) write new POSIX-timezone file
*/
int32 selection = fZoneList->CurrentSelection();
if (selection < 0)
return;
fCurrentZoneItem = (TimeZoneListItem*)(fZoneList->ItemAt(selection));
mutable_locale_roster->SetDefaultTimeZone(fCurrentZoneItem->TimeZone());
set_timezone(fCurrentZoneItem->Code());
fSetZone->SetEnabled(false);
fLastUpdateMinute = -1;
// just to trigger updating immediately
}
BString
TimeZoneView::_FormatTime(TimeZoneListItem* zoneItem)
{
BString result;
if (zoneItem == NULL)
return result;
time_t nowInTimeZone = time(NULL) + zoneItem->OffsetFromGMT();
be_locale->FormatTime(&result, nowInTimeZone, false);
return result;
}

View File

@ -33,24 +33,28 @@ public:
private:
void _UpdateDateTime(BMessage* message);
void _SetTimeZone();
void _SetTimeZone(const char* zone);
void _SetPreview();
void _SetCurrent(const char* text);
void _SetSystemTimeZone();
void _UpdatePreview();
void _UpdateCurrent();
BString _FormatTime(TimeZoneListItem* zoneItem);
void _InitView();
void _BuildRegionMenu();
void _Revert();
private:
BOutlineListView* fCityList;
BOutlineListView* fZoneList;
BButton* fSetZone;
TTZDisplay* fCurrent;
TTZDisplay* fPreview;
int32 fHour;
int32 fMinute;
TimeZoneListItem* fCurrentZone;
TimeZoneListItem* fOldZone;
int32 fLastUpdateMinute;
TimeZoneListItem* fCurrentZoneItem;
TimeZoneListItem* fOldZoneItem;
bool fInitialized;
};