Author: zooey Date: 2010-10-24 14:57:55 +0200 (Sun, 24 Oct 2010) New Revision: 39123 Changeset: http://dev.haiku-os.org/changeset/39123 Added: haiku/trunk/headers/os/locale/Country.h haiku/trunk/headers/os/locale/FormattingConventions.h haiku/trunk/headers/private/locale/FormattingConventionsPrivate.h haiku/trunk/src/kits/locale/FormattingConventions.cpp Removed: haiku/trunk/headers/os/locale/Country.h haiku/trunk/headers/private/locale/CountryPrivate.h haiku/trunk/src/preferences/locale/LocaleSettings.cpp haiku/trunk/src/preferences/locale/LocaleSettings.h Modified: haiku/trunk/headers/os/LocaleKit.h haiku/trunk/headers/os/locale/Locale.h haiku/trunk/headers/os/locale/LocaleRoster.h haiku/trunk/headers/private/locale/MutableLocaleRoster.h haiku/trunk/src/apps/deskbar/TimeView.cpp haiku/trunk/src/apps/readonlybootprompt/BootPromptWindow.cpp haiku/trunk/src/bin/dstcheck.cpp haiku/trunk/src/kits/locale/Country.cpp haiku/trunk/src/kits/locale/Jamfile haiku/trunk/src/kits/locale/Locale.cpp haiku/trunk/src/kits/locale/LocaleRoster.cpp haiku/trunk/src/kits/locale/MutableLocaleRoster.cpp haiku/trunk/src/kits/tracker/WidgetAttributeText.cpp haiku/trunk/src/preferences/locale/FormatSettingsView.cpp haiku/trunk/src/preferences/locale/FormatSettingsView.h haiku/trunk/src/preferences/locale/Jamfile haiku/trunk/src/preferences/locale/LanguageListView.cpp haiku/trunk/src/preferences/locale/LanguageListView.h haiku/trunk/src/preferences/locale/LocalePreflet.cpp haiku/trunk/src/preferences/locale/LocaleWindow.cpp haiku/trunk/src/preferences/locale/LocaleWindow.h haiku/trunk/src/preferences/time/DateTimeEdit.cpp haiku/trunk/src/preferences/time/ZoneView.cpp Log: One more monster commit (sorry ...) concerning the Locale Kit: * extracted new class BFormattingConventions from BCountry, which manages the formatting conventions from a given locale and allows to get/set the four different date/time formats supported by ICU-locales as well as number and monetary formats * overhauled the Locale preflet: + drop editing features for all formats, since I don't think they do not make much sense to have in a prefs GUI - being able to select from the existing locales should be good enough. Please note that you can still change the formats programmatically in an application. + renamed the 'Countries' tab to 'Formatting' + the locale formatting conventions list in the 'Formatting' tab is now hierarchical for easier access (less scrolling) + fixed functionality of 'Revert' and 'Defaults' buttons + added support for using the month/day-names of your preferred language during date formatting * adjusted BLocale to ask BFormattingConventions for the current formats when formatting dates and times and to offer 4 different format styles (full, long, medium and short). * adjust all classes formatting dates/times to pick the appropriate format style * BLocaleRoster no longer directly archives/unarchives the individual formatting conventions but delegates that to BFormattingConventions Modified: haiku/trunk/headers/os/LocaleKit.h =================================================================== --- haiku/trunk/headers/os/LocaleKit.h 2010-10-24 10:48:22 UTC (rev 39122) +++ haiku/trunk/headers/os/LocaleKit.h 2010-10-24 12:57:55 UTC (rev 39123) @@ -13,6 +13,7 @@ #include <Format.h> #include <FormatImpl.h> #include <FormatParameters.h> +#include <FormattingConventions.h> #include <GenericNumberFormat.h> #include <IntegerFormat.h> #include <IntegerFormatImpl.h> Added: haiku/trunk/headers/os/locale/Country.h =================================================================== --- haiku/trunk/headers/os/locale/Country.h (rev 0) +++ haiku/trunk/headers/os/locale/Country.h 2010-10-24 12:57:55 UTC (rev 39123) @@ -0,0 +1,52 @@ +/* + * 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 <String.h> +#include <SupportDefs.h> + + +class BBitmap; +class BLanguage; +class BMessage; + +namespace icu_44 { + class DateFormat; + class Locale; +} + + +class BCountry { +public: + BCountry(const char* countryCode = NULL); + BCountry(const BCountry& other); + BCountry& operator=(const BCountry& other); + ~BCountry(); + + status_t GetNativeName(BString& name) const; + status_t GetName(BString& name, + const BLanguage* displayLanguage = NULL + ) const; + + const char* Code() const; + // ISO-3166 + status_t GetIcon(BBitmap* result) const; + + status_t GetAvailableTimeZones( + BMessage* timeZones) const; + + class Private; +private: + friend class Private; + + icu_44::Locale* fICULocale; +}; + + +#endif /* _COUNTRY_H_ */ Added: haiku/trunk/headers/os/locale/FormattingConventions.h =================================================================== --- haiku/trunk/headers/os/locale/FormattingConventions.h (rev 0) +++ haiku/trunk/headers/os/locale/FormattingConventions.h 2010-10-24 12:57:55 UTC (rev 39123) @@ -0,0 +1,129 @@ +/* + * Copyright 2003-2010, Haiku, Inc. + * Distributed under the terms of the MIT Licence. + */ +#ifndef _FORMATTING_CONVENTIONS_H_ +#define _FORMATTING_CONVENTIONS_H_ + + +#include <Archivable.h> +#include <List.h> +#include <LocaleStrings.h> +#include <String.h> +#include <SupportDefs.h> + + +class BBitmap; +class BLanguage; +class BMessage; + +namespace icu_44 { + class DateFormat; + class Locale; +} + + +enum BMeasurementKind { + B_METRIC = 0, + B_US +}; + + +enum BDateFormatStyle { + B_FULL_DATE_FORMAT = 0, + B_LONG_DATE_FORMAT, + B_MEDIUM_DATE_FORMAT, + B_SHORT_DATE_FORMAT, + + B_DATE_FORMAT_STYLE_COUNT +}; + + +enum BTimeFormatStyle { + B_FULL_TIME_FORMAT = 0, + B_LONG_TIME_FORMAT, + B_MEDIUM_TIME_FORMAT, + B_SHORT_TIME_FORMAT, + + B_TIME_FORMAT_STYLE_COUNT +}; + + +class BFormattingConventions : public BArchivable { +public: + BFormattingConventions(const char* id = NULL); + BFormattingConventions( + const BFormattingConventions& other); + BFormattingConventions(const BMessage* archive); + + BFormattingConventions& operator=( + const BFormattingConventions& other); + + ~BFormattingConventions(); + + bool operator==( + const BFormattingConventions& other) const; + bool operator!=( + const BFormattingConventions& other) const; + + const char* ID() const; + const char* LanguageCode() const; + const char* CountryCode() const; + + status_t GetNativeName(BString& name) const; + status_t GetName(BString& name, + const BLanguage* displayLanguage = NULL + ) const; + + const char* GetString(uint32 id) const; + + status_t GetDateFormat(BDateFormatStyle style, + BString& outFormat) const; + status_t GetTimeFormat(BTimeFormatStyle style, + BString& outFormat) const; + status_t GetNumericFormat(BString& outFormat) const; + status_t GetMonetaryFormat(BString& outFormat) const; + + void SetExplicitDateFormat(BDateFormatStyle style, + const BString& format); + void SetExplicitTimeFormat(BTimeFormatStyle style, + const BString& format); + void SetExplicitNumericFormat(const BString& format); + void SetExplicitMonetaryFormat( + const BString& format); + + BMeasurementKind MeasurementKind() const; + + bool UseStringsFromPreferredLanguage() const; + void SetUseStringsFromPreferredLanguage(bool value); + + bool Use24HourClock() const; + void SetExplicitUse24HourClock(bool value); + void UnsetExplicitUse24HourClock(); + + virtual status_t Archive(BMessage* archive, + bool deep = true) const; + + class Private; +private: + friend class Private; + + mutable BString fCachedDateFormats[B_DATE_FORMAT_STYLE_COUNT]; + mutable BString fCachedTimeFormats[B_TIME_FORMAT_STYLE_COUNT]; + mutable BString fCachedNumericFormat; + mutable BString fCachedMonetaryFormat; + mutable int8 fCachedUse24HourClock; + + BString fExplicitDateFormats[B_DATE_FORMAT_STYLE_COUNT]; + BString fExplicitTimeFormats[B_TIME_FORMAT_STYLE_COUNT]; + BString fExplicitNumericFormat; + BString fExplicitMonetaryFormat; + int8 fExplicitUse24HourClock; + + bool fUseStringsFromPreferredLanguage; + + icu_44::Locale* fICULocale; +}; + + +#endif /* _FORMATTING_CONVENTIONS_H_ */ Modified: haiku/trunk/headers/os/locale/Locale.h =================================================================== --- haiku/trunk/headers/os/locale/Locale.h 2010-10-24 10:48:22 UTC (rev 39122) +++ haiku/trunk/headers/os/locale/Locale.h 2010-10-24 12:57:55 UTC (rev 39123) @@ -7,11 +7,16 @@ #include <Collator.h> -#include <Country.h> +#include <FormattingConventions.h> #include <Language.h> #include <Locker.h> +namespace icu_44 { + class DateFormat; +} + + class BCatalog; class BString; class BTimeZone; @@ -39,7 +44,8 @@ class BLocale { public: BLocale(const BLanguage* language = NULL, - const BCountry* country = NULL); + const BFormattingConventions* conventions + = NULL); BLocale(const BLocale& other); ~BLocale(); @@ -47,14 +53,14 @@ status_t GetCollator(BCollator* collator) const; status_t GetLanguage(BLanguage* language) const; - status_t GetCountry(BCountry* country) const; + status_t GetFormattingConventions( + BFormattingConventions* conventions) const; - void SetCountry(const BCountry& newCountry); + void SetFormattingConventions( + const BFormattingConventions& conventions); void SetCollator(const BCollator& newCollator); void SetLanguage(const BLanguage& newLanguage); - bool GetName(BString& name) const; - // see definitions in LocaleStrings.h const char* GetString(uint32 id) const; @@ -62,29 +68,34 @@ char* fmt, ...) const; void FormatString(BString* buffer, char* fmt, ...) const; - status_t FormatDateTime(char* target, size_t maxSize, - time_t time, bool longFormat) const; + + // DateTime + + // TODO: drop some of these once BDateTimeFormat + // has been implemented! + ssize_t FormatDateTime(char* target, size_t maxSize, + time_t time, BDateFormatStyle dateStyle, + BTimeFormatStyle timeStyle) const; status_t FormatDateTime(BString* buffer, time_t time, - bool longFormat, + BDateFormatStyle dateStyle, + BTimeFormatStyle timeStyle, const BTimeZone* timeZone = NULL) const; // Date // TODO: drop some of these once BDateFormat // has been implemented! - status_t FormatDate(char* string, size_t maxSize, - time_t time, bool longFormat) const; + ssize_t FormatDate(char* string, size_t maxSize, + time_t time, BDateFormatStyle style) const; status_t FormatDate(BString* string, time_t time, - bool longFormat, + BDateFormatStyle style, const BTimeZone* timeZone = NULL) const; status_t FormatDate(BString* string, int*& fieldPositions, int& fieldCount, - time_t time, bool longFormat) const; + time_t time, BDateFormatStyle style) const; 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& fieldCount, BDateFormatStyle style + ) const; int StartOfWeek() const; @@ -92,29 +103,25 @@ // TODO: drop some of these once BTimeFormat // has been implemented! - status_t FormatTime(char* string, size_t maxSize, - time_t time, bool longFormat) const; + ssize_t FormatTime(char* string, size_t maxSize, + time_t time, BTimeFormatStyle style) const; status_t FormatTime(BString* string, time_t time, - bool longFormat, + BTimeFormatStyle style, const BTimeZone* timeZone = NULL) const; status_t FormatTime(BString* string, int*& fieldPositions, int& fieldCount, - time_t time, bool longFormat) const; + time_t time, BTimeFormatStyle style) const; status_t GetTimeFields(BDateElement*& fields, - int& fieldCount, bool longFormat) const; + int& fieldCount, BTimeFormatStyle style + ) const; - status_t SetTimeFormat(const char* formatString, - bool longFormat = true); - status_t GetTimeFormat(BString& out, - bool longFormat) const; - // numbers - status_t FormatNumber(char* string, size_t maxSize, + ssize_t FormatNumber(char* string, size_t maxSize, double value) const; status_t FormatNumber(BString* string, double value) const; - status_t FormatNumber(char* string, size_t maxSize, + ssize_t FormatNumber(char* string, size_t maxSize, int32 value) const; status_t FormatNumber(BString* string, int32 value) const; @@ -123,13 +130,8 @@ ssize_t FormatMonetary(char* string, size_t maxSize, double value) const; - ssize_t FormatMonetary(BString* string, - double value) const; status_t FormatMonetary(BString* string, - int*& fieldPositions, - BNumberElement*& fieldTypes, - int& fieldCount, double value) const; - status_t GetCurrencySymbol(BString& result) const; + double value) const; // Collator short-hands int StringCompare(const char* s1, @@ -138,21 +140,18 @@ const BString* s2) const; void GetSortKey(const char* string, - BString* key) const; + BString* sortKey) const; private: - void _UpdateFormats(); + icu_44::DateFormat* _CreateDateFormatter( + const BString& format) const; + icu_44::DateFormat* _CreateTimeFormatter( + const BString& format) const; mutable BLocker fLock; BCollator fCollator; - BCountry fCountry; + BFormattingConventions fConventions; BLanguage fLanguage; - - BString fLongDateFormat; - BString fShortDateFormat; - BString fLongTimeFormat; - BString fShortTimeFormat; - }; @@ -178,9 +177,9 @@ inline void -BLocale::GetSortKey(const char* string, BString* key) const +BLocale::GetSortKey(const char* string, BString* sortKey) const { - fCollator.GetSortKey(string, key); + fCollator.GetSortKey(string, sortKey); } Modified: haiku/trunk/headers/os/locale/LocaleRoster.h =================================================================== --- haiku/trunk/headers/os/locale/LocaleRoster.h 2010-10-24 10:48:22 UTC (rev 39122) +++ haiku/trunk/headers/os/locale/LocaleRoster.h 2010-10-24 12:57:55 UTC (rev 39123) @@ -13,6 +13,7 @@ class BCatalog; class BCollator; class BCountry; +class BFormattingConventions; class BLanguage; class BLocale; class BMessage; @@ -37,7 +38,6 @@ status_t GetPreferredLanguages(BMessage* message) const; status_t GetAvailableLanguages(BMessage* message) const; - status_t GetAvailableCountries( BMessage* timeZones) const; status_t GetAvailableTimeZones( @@ -49,7 +49,7 @@ status_t GetFlagIconForCountry(BBitmap* flagIcon, const char* countryCode); - status_t GetInstalledCatalogs(BMessage* message, + status_t GetAvailableCatalogs(BMessage* message, const char* sigPattern = NULL, const char* langPattern = NULL, int32 fingerprint = 0) const; Copied: haiku/trunk/headers/private/locale/FormattingConventionsPrivate.h (from rev 39013, haiku/trunk/headers/private/locale/CountryPrivate.h) =================================================================== --- haiku/trunk/headers/private/locale/FormattingConventionsPrivate.h (rev 0) +++ haiku/trunk/headers/private/locale/FormattingConventionsPrivate.h 2010-10-24 12:57:55 UTC (rev 39123) @@ -0,0 +1,37 @@ +/* + * Copyright 2010, Oliver Tappe <zooey@xxxxxxxxxxxxxxx> + * Distributed under the terms of the MIT License. + */ +#ifndef _FORMATTING_CONVENTIONS_PRIVATE_H +#define _FORMATTING_CONVENTIONS_PRIVATE_H + + +#include <FormattingConventions.h> + + +class BFormattingConventions::Private { +public: + Private(const BFormattingConventions* conventions = NULL) + : + fFormattingConventions(conventions) + { + } + + void + SetTo(const BFormattingConventions* conventions) + { + fFormattingConventions = conventions; + } + + icu_44::Locale* + ICULocale() + { + return fFormattingConventions->fICULocale; + } + +private: + const BFormattingConventions* fFormattingConventions; +}; + + +#endif // _FORMATTING_CONVENTIONS_PRIVATE_H Modified: haiku/trunk/headers/private/locale/MutableLocaleRoster.h =================================================================== --- haiku/trunk/headers/private/locale/MutableLocaleRoster.h 2010-10-24 10:48:22 UTC (rev 39122) +++ haiku/trunk/headers/private/locale/MutableLocaleRoster.h 2010-10-24 12:57:55 UTC (rev 39123) @@ -7,7 +7,7 @@ #include <Collator.h> -#include <Country.h> +#include <FormattingConventions.h> #include <image.h> #include <Language.h> #include <List.h> @@ -34,10 +34,8 @@ MutableLocaleRoster(); ~MutableLocaleRoster(); - status_t GetDefaultLocale(BLocale* locale) const; - - status_t SetDefaultCountry(const BCountry& country); - status_t SetDefaultLocale(const BLocale& locale); + status_t SetDefaultFormattingConventions( + const BFormattingConventions& conventions); status_t SetDefaultTimeZone(const BTimeZone& zone); status_t SetPreferredLanguages(const BMessage* message); @@ -127,8 +125,8 @@ static int CompareInfos(const void* left, const void* right); - status_t SetDefaultCountry(const BCountry& country); - status_t SetDefaultLocale(const BLocale& locale); + status_t SetDefaultFormattingConventions( + const BFormattingConventions& convetions); status_t SetDefaultTimeZone(const BTimeZone& zone); status_t SetPreferredLanguages(const BMessage* msg); private: @@ -138,12 +136,12 @@ status_t _LoadTimeSettings(); status_t _SaveTimeSettings(); - status_t _SetDefaultCountry(const BCountry& country); - status_t _SetDefaultLocale(const BLocale& locale); + status_t _SetDefaultFormattingConventions( + const BFormattingConventions& conventions); status_t _SetDefaultTimeZone(const BTimeZone& zone); status_t _SetPreferredLanguages(const BMessage* msg); - status_t _AddDefaultCountryToMessage( + status_t _AddDefaultFormattingConventionsToMessage( BMessage* message) const; status_t _AddDefaultTimeZoneToMessage( BMessage* message) const; Modified: haiku/trunk/src/apps/deskbar/TimeView.cpp =================================================================== --- haiku/trunk/src/apps/deskbar/TimeView.cpp 2010-10-24 10:48:22 UTC (rev 39122) +++ haiku/trunk/src/apps/deskbar/TimeView.cpp 2010-10-24 12:57:55 UTC (rev 39123) @@ -38,7 +38,6 @@ #include <string.h> #include <Catalog.h> -#include <Country.h> #include <Debug.h> #include <Locale.h> #include <MenuItem.h> @@ -251,7 +250,8 @@ void TTimeView::GetCurrentTime() { - fLocale.FormatTime(fTimeStr, 64, fTime, fShowSeconds); + fLocale.FormatTime(fTimeStr, 64, fTime, + fShowSeconds ? B_MEDIUM_TIME_FORMAT : B_SHORT_TIME_FORMAT); } @@ -260,7 +260,7 @@ { char tmp[64]; - fLocale.FormatDate(tmp, 64, fTime, true); + fLocale.FormatDate(tmp, 64, fTime, B_FULL_DATE_FORMAT); // 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) @@ -297,7 +297,7 @@ if (buttons == B_SECONDARY_MOUSE_BUTTON) { ShowClockOptions(ConvertToScreen(point)); return; - } else if (buttons == B_PRIMARY_MOUSE_BUTTON) + } else if (buttons == B_PRIMARY_MOUSE_BUTTON) ShowCalendar(point); // invalidate last time/date strings and call the pulse @@ -361,6 +361,7 @@ GetCurrentTime(); GetCurrentDate(); + SetToolTip(fDateStr); ResizeToPreferred(); Modified: haiku/trunk/src/apps/readonlybootprompt/BootPromptWindow.cpp =================================================================== --- haiku/trunk/src/apps/readonlybootprompt/BootPromptWindow.cpp 2010-10-24 10:48:22 UTC (rev 39122) +++ haiku/trunk/src/apps/readonlybootprompt/BootPromptWindow.cpp 2010-10-24 12:57:55 UTC (rev 39123) @@ -15,6 +15,7 @@ #include <Font.h> #include <FindDirectory.h> #include <File.h> +#include <FormattingConventions.h> #include <GroupLayoutBuilder.h> #include <ListView.h> #include <Locale.h> @@ -212,8 +213,8 @@ gMutableLocaleRoster->SetPreferredLanguages(&settings); - BCountry country(language.String(), language.ToUpper()); - gMutableLocaleRoster->SetDefaultCountry(country); + BFormattingConventions conventions(language.String()); + gMutableLocaleRoster->SetDefaultFormattingConventions(conventions); } @@ -269,7 +270,7 @@ } BMessage installedCatalogs; - be_locale_roster->GetInstalledCatalogs(&installedCatalogs, + be_locale_roster->GetAvailableCatalogs(&installedCatalogs, "x-vnd.Haiku-ReadOnlyBootPrompt"); BFont font; Modified: haiku/trunk/src/bin/dstcheck.cpp =================================================================== --- haiku/trunk/src/bin/dstcheck.cpp 2010-10-24 10:48:22 UTC (rev 39122) +++ haiku/trunk/src/bin/dstcheck.cpp 2010-10-24 12:57:55 UTC (rev 39123) @@ -83,7 +83,7 @@ time(&t); localtime_r(&t, &tm); - be_locale->FormatTime(timestring, 15, t, false); + be_locale->FormatTime(timestring, 15, t, B_SHORT_TIME_FORMAT); string += " "; string += timestring; Modified: haiku/trunk/src/kits/locale/Country.cpp =================================================================== --- haiku/trunk/src/kits/locale/Country.cpp 2010-10-24 10:48:22 UTC (rev 39122) +++ haiku/trunk/src/kits/locale/Country.cpp 2010-10-24 12:57:55 UTC (rev 39123) @@ -30,20 +30,13 @@ #define ICU_VERSION icu_44 -BCountry::BCountry(const char* languageCode, const char* countryCode) +BCountry::BCountry(const char* countryCode) : - fICULocale(new ICU_VERSION::Locale(languageCode, countryCode)) + fICULocale(new ICU_VERSION::Locale("", countryCode)) { } -BCountry::BCountry(const char* languageAndCountryCode) - : - fICULocale(new ICU_VERSION::Locale(languageAndCountryCode)) -{ -} - - BCountry::BCountry(const BCountry& other) : fICULocale(new ICU_VERSION::Locale(*other.fICULocale)) @@ -98,6 +91,7 @@ UnicodeString uString; fICULocale->getDisplayName(Locale(appLanguage), uString); + name.Truncate(0); BStringByteSink stringConverter(&name); uString.toUTF8(stringConverter); @@ -108,7 +102,7 @@ const char* BCountry::Code() const { - return fICULocale->getName(); + return fICULocale->getCountry(); } @@ -128,17 +122,3 @@ return be_locale_roster->GetAvailableTimeZonesForCountry(timeZones, Code()); } - -// TODO does ICU even support this ? Is it in the keywords ? -int8 -BCountry::Measurement() const -{ - UErrorCode error = U_ZERO_ERROR; - switch (ulocdata_getMeasurementSystem(Code(), &error)) { - case UMS_US: - return B_US; - case UMS_SI: - default: - return B_METRIC; - } -} Added: haiku/trunk/src/kits/locale/FormattingConventions.cpp =================================================================== --- haiku/trunk/src/kits/locale/FormattingConventions.cpp (rev 0) +++ haiku/trunk/src/kits/locale/FormattingConventions.cpp 2010-10-24 12:57:55 UTC (rev 39123) @@ -0,0 +1,596 @@ +/* + * Copyright 2003-2009, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx + * Copyright 2009-2010, Adrien Destugues, pulkomandy@xxxxxxxxxx + * Copyright 2010, Oliver Tappe <zooey@xxxxxxxxxxxxxxx>. + * Distributed under the terms of the MIT License. + */ + + +#include <FormattingConventions.h> + +#include <AutoDeleter.h> +#include <IconUtils.h> +#include <List.h> +#include <Language.h> +#include <Locale.h> +#include <LocaleRoster.h> +#include <Resources.h> +#include <String.h> +#include <UnicodeChar.h> + +#include <unicode/datefmt.h> +#include <unicode/locid.h> +#include <unicode/smpdtfmt.h> +#include <unicode/ulocdata.h> +#include <ICUWrapper.h> + +#include <iostream> +#include <map> +#include <monetary.h> +#include <new> +#include <stdarg.h> +#include <stdlib.h> + + +#define ICU_VERSION icu_44 + + +// #pragma mark - helpers + + +static bool +FormatUsesAmPm(const BString& format) +{ + if (format.Length() == 0) + return false; + + bool inQuote = false; + for (const char* s = format.String(); *s != '\0'; ++s) { + switch (*s) { + case '\'': + inQuote = !inQuote; + break; + case 'a': + if (!inQuote) + return true; + break; + } + } + + return false; +} + + +static void +CoerceFormatTo12HourClock(BString& format) +{ + char* s = format.LockBuffer(format.Length()); + if (s == NULL) + return; + + // change format to use h instead of H, k instead of K, and append an + // am/pm marker + bool inQuote = false; + for (; *s != '\0'; ++s) { + switch (*s) { + case '\'': + inQuote = !inQuote; + break; + case 'H': + if (!inQuote) + *s = 'h'; + break; + case 'K': + if (!inQuote) + *s = 'k'; + break; + } + } + format.UnlockBuffer(format.Length()); + + format.Append(" a"); +} + + +static void +CoerceFormatTo24HourClock(BString& format) +{ + char* buffer = format.LockBuffer(format.Length()); + char* currentPos = buffer; + if (currentPos == NULL) + return; + + // change the format to use H instead of h, K instead of k, and determine + // and remove the am/pm marker (including leading whitespace) + bool inQuote = false; + bool lastWasWhitespace = false; + uint32 ch; + const char* amPmStartPos = NULL; + const char* amPmEndPos = NULL; + const char* lastWhitespaceStart = NULL; + for (char* previousPos = currentPos; (ch = BUnicodeChar::FromUTF8( + (const char**)¤tPos)) != 0; previousPos = currentPos) { + switch (ch) { + case '\'': + inQuote = !inQuote; + break; + case 'h': + if (!inQuote) + *previousPos = 'H'; + break; + case 'k': + if (!inQuote) + *previousPos = 'K'; + break; + case 'a': + if (!inQuote) { + if (lastWasWhitespace) + amPmStartPos = lastWhitespaceStart; + else + amPmStartPos = previousPos; + amPmEndPos = currentPos; + } + break; + default: + if (!inQuote && BUnicodeChar::IsWhitespace(ch)) { + if (!lastWasWhitespace) { + lastWhitespaceStart = previousPos; + lastWasWhitespace = true; + } + continue; + } + } + lastWasWhitespace = false; + } + + format.UnlockBuffer(format.Length()); + if (amPmStartPos != NULL && amPmEndPos > amPmStartPos) + format.Remove(amPmStartPos - buffer, amPmEndPos - amPmStartPos); +} + + +static void +CoerceFormatToAbbreviatedTimezone(BString& format) +{ + char* s = format.LockBuffer(format.Length()); + if (s == NULL) + return; + + // replace a single 'z' with 'V' + bool inQuote = false; + bool lastWasZ = false; + for (; *s != '\0'; ++s) { + switch (*s) { + case '\'': + inQuote = !inQuote; + break; + case 'z': + if (!inQuote && !lastWasZ && *(s+1) != 'z') + *s = 'V'; + lastWasZ = true; + continue; + } + lastWasZ = false; + } + format.UnlockBuffer(format.Length()); +} + + +// #pragma mark - BFormattingConventions + + +enum ClockHoursState { + CLOCK_HOURS_UNSET = 0, + CLOCK_HOURS_24, + CLOCK_HOURS_12 +}; + + +BFormattingConventions::BFormattingConventions(const char* id) + : + fCachedUse24HourClock(CLOCK_HOURS_UNSET), + fExplicitUse24HourClock(CLOCK_HOURS_UNSET), + fUseStringsFromPreferredLanguage(false), + fICULocale(new ICU_VERSION::Locale(id)) +{ +} + + +BFormattingConventions::BFormattingConventions( + const BFormattingConventions& other) + : + fCachedDateFormats(other.fCachedDateFormats), + fCachedTimeFormats(other.fCachedTimeFormats), + fCachedNumericFormat(other.fCachedNumericFormat), + fCachedMonetaryFormat(other.fCachedMonetaryFormat), + fCachedUse24HourClock(other.fCachedUse24HourClock), + fExplicitDateFormats(other.fExplicitDateFormats), + fExplicitTimeFormats(other.fExplicitTimeFormats), + fExplicitNumericFormat(other.fExplicitNumericFormat), + fExplicitMonetaryFormat(other.fExplicitMonetaryFormat), + fExplicitUse24HourClock(other.fExplicitUse24HourClock), + fUseStringsFromPreferredLanguage(other.fUseStringsFromPreferredLanguage), + fICULocale(new ICU_VERSION::Locale(*other.fICULocale)) +{ +} + + +BFormattingConventions::BFormattingConventions(const BMessage* archive) +{ + BString conventionsID; + status_t status = archive->FindString("conventions", &conventionsID); + fICULocale = new ICU_VERSION::Locale(conventionsID); + + for (int s = 0; s < B_DATE_FORMAT_STYLE_COUNT && status == B_OK; ++s) { + BString format; + status = archive->FindString("dateFormat", s, &format); + if (status == B_OK) + fExplicitDateFormats[s] = format; + + status = archive->FindString("timeFormat", s, &format); + if (status == B_OK) + fExplicitTimeFormats[s] = format; + } + + if (status == B_OK) { + int8 use24HourClock; + status = archive->FindInt8("use24HourClock", &use24HourClock); + if (status == B_OK) + fExplicitUse24HourClock = use24HourClock; + } + if (status == B_OK) { + bool useStringsFromPreferredLanguage; + status = archive->FindBool("useStringsFromPreferredLanguage", + &useStringsFromPreferredLanguage); + if (status == B_OK) + fUseStringsFromPreferredLanguage = useStringsFromPreferredLanguage; + } +} + + +BFormattingConventions& +BFormattingConventions::operator=(const BFormattingConventions& other) +{ + if (this == &other) + return *this; + + for (int s = 0; s < B_DATE_FORMAT_STYLE_COUNT; ++s) + fCachedDateFormats[s] = other.fCachedDateFormats[s]; + for (int s = 0; s < B_TIME_FORMAT_STYLE_COUNT; ++s) + fCachedTimeFormats[s] = other.fCachedTimeFormats[s]; + fCachedNumericFormat = other.fCachedNumericFormat; + fCachedMonetaryFormat = other.fCachedMonetaryFormat; + fCachedUse24HourClock = other.fCachedUse24HourClock; + + for (int s = 0; s < B_DATE_FORMAT_STYLE_COUNT; ++s) + fExplicitDateFormats[s] = other.fExplicitDateFormats[s]; + for (int s = 0; s < B_TIME_FORMAT_STYLE_COUNT; ++s) + fExplicitTimeFormats[s] = other.fExplicitTimeFormats[s]; + fExplicitNumericFormat = other.fExplicitNumericFormat; + fExplicitMonetaryFormat = other.fExplicitMonetaryFormat; + fExplicitUse24HourClock = other.fExplicitUse24HourClock; + + fUseStringsFromPreferredLanguage = other.fUseStringsFromPreferredLanguage; + + *fICULocale = *other.fICULocale; + + return *this; +} + + +BFormattingConventions::~BFormattingConventions() +{ + delete fICULocale; +} + + +bool +BFormattingConventions::operator==(const BFormattingConventions& other) const +{ + if (this == &other) + return true; + + for (int s = 0; s < B_DATE_FORMAT_STYLE_COUNT; ++s) { + if (fExplicitDateFormats[s] != other.fExplicitDateFormats[s]) + return false; + } + for (int s = 0; s < B_TIME_FORMAT_STYLE_COUNT; ++s) { + if (fExplicitTimeFormats[s] != other.fExplicitTimeFormats[s]) + return false; + } + + return fExplicitNumericFormat == other.fExplicitNumericFormat + && fExplicitMonetaryFormat == other.fExplicitMonetaryFormat + && fExplicitUse24HourClock == other.fExplicitUse24HourClock + && fUseStringsFromPreferredLanguage + == other.fUseStringsFromPreferredLanguage + && *fICULocale == *other.fICULocale; +} + + +bool +BFormattingConventions::operator!=(const BFormattingConventions& other) const [... truncated: 3570 lines follow ...]