diff options
author | jshin@chromium.org <jshin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-11 21:07:48 +0000 |
---|---|---|
committer | jshin@chromium.org <jshin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-11 21:07:48 +0000 |
commit | 8b726a7719c6b70b6b51b3a9856422352b80a8b4 (patch) | |
tree | c249620e5965140c2e60034102dd7788a1e5b3a6 /chrome/browser | |
parent | e9ce67a136015a9c0994876e1c18afb7ee610794 (diff) | |
download | chromium_src-8b726a7719c6b70b6b51b3a9856422352b80a8b4.zip chromium_src-8b726a7719c6b70b6b51b3a9856422352b80a8b4.tar.gz chromium_src-8b726a7719c6b70b6b51b3a9856422352b80a8b4.tar.bz2 |
Use the hard-coded list of timezones obtained from the Android, which
is more comprehensive than the current list.
Among the added zones are zones with non-integer hour offsets
(like Indian, Nepali and some timezones in Austrailia).
Change the display name generation as well to use "LONG"
name followed with the exemplar city of a zone. This is
necessary to distinguish between timezones like
Mountain Time (Phoenix) from Mountain Time (Denver).
BUG=chromiumos:2613
TEST=Go to the timezone setting UI and make sure
that all the timezones (including those with non-integer hour offset)
such as Indian and Nepali timezones are listed.
Review URL: http://codereview.chromium.org/3432015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@65850 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/chromeos/dom_ui/system_settings_provider.cc | 216 |
1 files changed, 183 insertions, 33 deletions
diff --git a/chrome/browser/chromeos/dom_ui/system_settings_provider.cc b/chrome/browser/chromeos/dom_ui/system_settings_provider.cc index a376cf0..cbf54a2 100644 --- a/chrome/browser/chromeos/dom_ui/system_settings_provider.cc +++ b/chrome/browser/chromeos/dom_ui/system_settings_provider.cc @@ -6,57 +6,183 @@ #include <string> +#include "app/l10n_util.h" +#include "base/i18n/rtl.h" +#include "base/lock.h" +#include "base/scoped_ptr.h" #include "base/stl_util-inl.h" #include "base/string_util.h" #include "base/stringprintf.h" #include "base/time.h" -#include "base/time.h" #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros_settings.h" #include "chrome/browser/chromeos/cros_settings_names.h" +#include "grit/generated_resources.h" +#include "unicode/calendar.h" +#include "unicode/timezone.h" +#include "unicode/ures.h" -namespace chromeos { +namespace { -static const char* kTimeZonesUtf8[] = { - "Pacific/Samoa", - "US/Hawaii", - "US/Alaska", - "US/Pacific", - "US/Mountain", - "US/Central", - "US/Eastern", +// TODO(jungshik): Using Enumerate method in ICU gives 600+ timezones. +// Even after filtering out duplicate entries with a strict identity check, +// we still have 400+ zones. Relaxing the criteria for the timezone +// identity is likely to cut down the number to < 100. Until we +// come up with a better list, we hard-code the following list as used by +// Android. +static const char* kTimeZones[] = { + "Pacific/Majuro", + "Pacific/Midway", + "Pacific/Honolulu", + "America/Anchorage", + "America/Los_Angeles", + "America/Tijuana", + "America/Denver", + "America/Phoenix", + "America/Chihuahua", + "America/Chicago", + "America/Mexico_City", + "America/Costa_Rica", + "America/Regina", + "America/New_York", + "America/Bogota", + "America/Caracas", + "America/Barbados", + "America/Manaus", "America/Santiago", + "America/St_Johns", "America/Sao_Paulo", + "America/Araguaina", + "America/Argentina/Buenos_Aires", + "America/Godthab", + "America/Montevideo", "Atlantic/South_Georgia", + "Atlantic/Azores", "Atlantic/Cape_Verde", + "Africa/Casablanca", "Europe/London", - "Europe/Rome", + "Europe/Amsterdam", + "Europe/Belgrade", + "Europe/Brussels", + "Europe/Sarajevo", + "Africa/Windhoek", + "Africa/Brazzaville", + "Asia/Amman", + "Europe/Athens", + "Asia/Beirut", + "Africa/Cairo", "Europe/Helsinki", + "Asia/Jerusalem", + "Europe/Minsk", + "Africa/Harare", + "Asia/Baghdad", "Europe/Moscow", + "Asia/Kuwait", + "Africa/Nairobi", + "Asia/Tehran", + "Asia/Baku", + "Asia/Tbilisi", + "Asia/Yerevan", "Asia/Dubai", + "Asia/Kabul", "Asia/Karachi", - "Asia/Dhaka", + "Asia/Oral", + "Asia/Yekaterinburg", + "Asia/Calcutta", + "Asia/Colombo", + "Asia/Katmandu", + "Asia/Almaty", + "Asia/Rangoon", + "Asia/Krasnoyarsk", "Asia/Bangkok", + "Asia/Shanghai", "Asia/Hong_Kong", + "Asia/Irkutsk", + "Asia/Kuala_Lumpur", + "Australia/Perth", + "Asia/Taipei", + "Asia/Seoul", "Asia/Tokyo", + "Asia/Yakutsk", + "Australia/Adelaide", + "Australia/Darwin", + "Australia/Brisbane", + "Australia/Hobart", "Australia/Sydney", + "Asia/Vladivostok", + "Pacific/Guam", "Asia/Magadan", - "Pacific/Auckland" }; + "Pacific/Auckland", + "Pacific/Fiji", + "Pacific/Tongatapu", +}; + +static Lock timezone_bundle_lock; + +struct UResClose { + inline void operator() (UResourceBundle* b) const { + ures_close(b); + } +}; + +string16 GetExemplarCity(const icu::TimeZone& zone) { + // TODO(jungshik): After upgrading to ICU 4.6, use U_ICUDATA_ZONE + static const char* zone_bundle_name = NULL; + + // These will be leaked at the end. + static UResourceBundle *zone_bundle = NULL; + static UResourceBundle *zone_strings = NULL; + + UErrorCode status = U_ZERO_ERROR; + { + AutoLock lock(timezone_bundle_lock); + if (zone_bundle == NULL) + zone_bundle = ures_open(zone_bundle_name, uloc_getDefault(), &status); + + if (zone_strings == NULL) + zone_strings = ures_getByKey(zone_bundle, "zone_strings", NULL, &status); + } + + UnicodeString zone_id; + zone.getID(zone_id); + std::string zone_id_str; + zone_id.toUTF8String(zone_id_str); + + // resource keys for timezones use ':' in place of '/'. + ReplaceSubstringsAfterOffset(&zone_id_str, 0, "/", ":"); + scoped_ptr_malloc<UResourceBundle, UResClose> zone_item( + ures_getByKey(zone_strings, zone_id_str.c_str(), NULL, &status)); + UnicodeString city; + if (U_FAILURE(status)) + goto fallback; + city = ures_getUnicodeStringByKey(zone_item.get(), "ec", &status); + if (U_SUCCESS(status)) + return string16(city.getBuffer(), city.length()); + + fallback: + ReplaceSubstringsAfterOffset(&zone_id_str, 0, ":", "/"); + // Take the last component of a timezone id (e.g. 'Baz' in 'Foo/Bar/Baz'). + // Depending on timezones, keeping all but the 1st component + // (e.g. Bar/Baz) may be better, but our current list does not have + // any timezone for which that's the case. + std::string::size_type slash_pos = zone_id_str.rfind('/'); + if (slash_pos != std::string::npos && slash_pos < zone_id_str.size()) + zone_id_str.erase(0, slash_pos + 1); + // zone id has '_' in place of ' '. + ReplaceSubstringsAfterOffset(&zone_id_str, 0, "_", " "); + return ASCIIToUTF16(zone_id_str); +} + +} // namespace anonymous + +namespace chromeos { SystemSettingsProvider::SystemSettingsProvider() { - // TODO(chocobo): For now, add all the GMT timezones. - // We may eventually want to use icu::TimeZone::createEnumeration() - // to list all the timezones and pick the ones we want to show. - // NOTE: This currently does not handle daylight savings properly - // b/c this is just a manually selected list of timezones that - // happen to span the GMT-11 to GMT+12 Today. When daylight savings - // kick in, this list might have more than one timezone in the same - // GMT bucket. - for (size_t i = 0; i < arraysize(kTimeZonesUtf8); i++) { + for (size_t i = 0; i < arraysize(kTimeZones); i++) { timezones_.push_back(icu::TimeZone::createTimeZone( - icu::UnicodeString::fromUTF8(kTimeZonesUtf8[i]))); + icu::UnicodeString(kTimeZones[i], -1, US_INV))); } CrosLibrary::Get()->GetSystemLibrary()->AddObserver(this); @@ -114,17 +240,41 @@ ListValue* SystemSettingsProvider::GetTimezoneList() { string16 SystemSettingsProvider::GetTimezoneName( const icu::TimeZone& timezone) { + // Instead of using the raw_offset, use the offset in effect now. + // For instance, US Pacific Time, the offset shown will be -7 in summer + // while it'll be -8 in winter. + int raw_offset, dst_offset; + UDate now = icu::Calendar::getNow(); + UErrorCode status = U_ZERO_ERROR; + timezone.getOffset(now, false, raw_offset, dst_offset, status); + DCHECK(U_SUCCESS(status)); + int offset = raw_offset + dst_offset; + // offset is in msec. + int minute_offset = std::abs(offset) / 60000; + int hour_offset = minute_offset / 60; + int min_remainder = minute_offset % 60; + // Some timezones have a non-integral hour offset. So, we need to + // use hh:mm form. + std::string offset_str = base::StringPrintf(offset >= 0 ? + "UTC+%d:%02d" : "UTC-%d:%02d", hour_offset, min_remainder); + + // TODO(jungshik): When coming up with a better list of timezones, we also + // have to come up with better 'display' names. One possibility is to list + // multiple cities (e.g. "Los Angeles, Vancouver .." in the order of + // the population of a country the city belongs to.). + // We can also think of using LONG_GENERIC or LOCATION once we upgrade + // to ICU 4.6. + // In the meantime, we use "LONG" name with "Exemplar City" to distinguish + // multiple timezones with the same "LONG" name but with different + // rules (e.g. US Mountain Time in Dever vs Phoneix). icu::UnicodeString name; - timezone.getDisplayName(name); - string16 output(name.getBuffer(), name.length()); - int hour_offset = timezone.getRawOffset() / 3600000; - const wchar_t* format; - if (hour_offset == 0) - format = L"(GMT) "; - else - format = L"(GMT%+d) "; - std::wstring offset = base::StringPrintf(format, hour_offset); - return WideToUTF16(offset) + output; + timezone.getDisplayName(dst_offset != 0, icu::TimeZone::LONG, name); + string16 result(l10n_util::GetStringFUTF16( + IDS_OPTIONS_SETTINGS_TIMEZONE_DISPLAY_TEMPLATE, ASCIIToUTF16(offset_str), + string16(name.getBuffer(), name.length()), GetExemplarCity(timezone))); + string16 rtl_safe_result = result; + base::i18n::AdjustStringForLocaleDirection(result, &rtl_safe_result); + return rtl_safe_result; } string16 SystemSettingsProvider::GetTimezoneID( |