From 3740f52dcac6d0db740a9274916cf210b281abcb Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Thu, 26 Aug 2010 22:27:25 +0000 Subject: [PATCH] More Time preflet improvements: * fixed another instance of BToolTip deletion, when we should be releasing a reference instead (the first one was fixed by Rene - thanks BTW!) * brought BCountry back into the game, such that the localized name of the country is now being used, where possible (avoiding the " Time" suffixes in English) * country-items containing only one timezone are now being filtered (the timezone moves up one level, replacing the country item, but adopting the country's name) * added the date to the timezone-item's tooltip, in order to make it obvious which timezone is "before" and which is "behind" the date-borderline I'm pretty happy with how it works now - what's yet missing is conversion of the preflet to the layout kit and localization of the GUI. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38382 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/preferences/time/TimeZoneListItem.cpp | 2 +- src/preferences/time/ZoneView.cpp | 212 ++++++++++++++-------- src/preferences/time/ZoneView.h | 3 +- 3 files changed, 138 insertions(+), 79 deletions(-) diff --git a/src/preferences/time/TimeZoneListItem.cpp b/src/preferences/time/TimeZoneListItem.cpp index dad5a587fd..a7058f8434 100644 --- a/src/preferences/time/TimeZoneListItem.cpp +++ b/src/preferences/time/TimeZoneListItem.cpp @@ -27,7 +27,7 @@ static const BString skDefaultString; TimeZoneListItem::TimeZoneListItem(const char* text, BCountry* country, BTimeZone* timeZone) : - BStringItem(text), + BStringItem(text, 0, false), fIcon(NULL), fTimeZone(timeZone) { diff --git a/src/preferences/time/ZoneView.cpp b/src/preferences/time/ZoneView.cpp index e7dfd90b50..a8daeb3331 100644 --- a/src/preferences/time/ZoneView.cpp +++ b/src/preferences/time/ZoneView.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -92,7 +93,7 @@ TimeZoneView::CheckCanRevert() TimeZoneView::~TimeZoneView() { - if (fToolTip) + if (fToolTip != NULL) fToolTip->ReleaseReference(); } @@ -181,12 +182,22 @@ TimeZoneView::GetToolTipAt(BPoint point, BToolTip** _tip) if (item == NULL || !item->HasTimeZone()) return false; + BString nowInTimeZone; + BLocale locale; + be_locale_roster->GetDefaultLocale(&locale); + time_t now = time(NULL); + locale.FormatTime(&nowInTimeZone, now, false, &item->TimeZone()); + + BString dateInTimeZone; + locale.FormatDate(&dateInTimeZone, now, false, &item->TimeZone()); + BString toolTip = item->Text(); toolTip << '\n' << item->TimeZone().ShortName() << " / " << item->TimeZone().ShortDaylightSavingName() - << "\nNow: " << _FormatTime(item->TimeZone(), false).String(); + << "\nNow: " << nowInTimeZone << " (" << dateInTimeZone << ')'; - delete fToolTip; + if (fToolTip != NULL) + fToolTip->ReleaseReference(); fToolTip = new (std::nothrow) BTextToolTip(toolTip.String()); if (fToolTip == NULL) return false; @@ -270,13 +281,14 @@ TimeZoneView::_BuildZoneMenu() BLanguage defaultLanguage; be_locale_roster->GetDefaultLanguage(&defaultLanguage); + BMessage countryList; + be_locale_roster->GetAvailableCountries(&countryList); + countryList.AddString("countries", ""); + /* * Group timezones by regions, but filter out unwanted (duplicate) regions * and add an additional region with generic GMT-offset timezones at the end */ - BMessage zoneList; - be_locale_roster->GetAvailableTimeZones(&zoneList); - typedef std::map ZoneItemMap; ZoneItemMap zoneMap; const char* kOtherRegion = ""; @@ -287,90 +299,139 @@ TimeZoneView::_BuildZoneMenu() for (const char** region = kSupportedRegions; *region != NULL; ++region) zoneMap[*region] = NULL; - BString zoneID; - for (int i = 0; zoneList.FindString("timeZone", i, &zoneID) == B_OK; i++) { - int32 slashPos = zoneID.FindFirst('/'); + BString countryCode; + for (int c = 0; countryList.FindString("countries", c, &countryCode) + == B_OK; c++) { + BCountry country("", countryCode); + BString countryName; + country.GetName(countryName); - // ignore any "global" timezones, as those are just aliases of regional - // ones - if (slashPos <= 0) - continue; + // Now list the timezones for this country + BMessage zoneList; + be_locale_roster->GetAvailableTimeZonesForCountry(&zoneList, + countryCode.Length() == 0 ? NULL : countryCode.String()); - BString region(zoneID, slashPos); + int32 count = 0; + type_code dummy; + zoneList.GetInfo("timeZone", &dummy, &count); - if (region == "Etc") - region = kOtherRegion; + BString zoneID; + for (int tz = 0; zoneList.FindString("timeZone", tz, &zoneID) == B_OK; + tz++) { + int32 slashPos = zoneID.FindFirst('/'); - // just accept timezones from "known" regions, as all others are aliases - ZoneItemMap::iterator regionIter = zoneMap.find(region); - if (regionIter == zoneMap.end()) - continue; + // ignore any "global" timezones, as those are just aliases of + // regional ones + if (slashPos <= 0) + continue; - TimeZoneListItem* regionItem = regionIter->second; - if (regionItem == NULL) { - regionItem = new TimeZoneListItem(region, NULL, NULL); - regionItem->SetOutlineLevel(0); - regionItem->SetExpanded(false); - zoneMap[region] = regionItem; - } + BString region(zoneID, slashPos); - BTimeZone* timeZone = new BTimeZone(zoneID, &defaultLanguage); - BString tzName = timeZone->Name(); - if (tzName == "GMT+00:00") - tzName = "GMT"; - int32 openParenthesisPos = tzName.FindFirst('('); - BString country; - if (openParenthesisPos >= 0) { - if (openParenthesisPos > 0) - country.SetTo(tzName, openParenthesisPos - 1); - tzName.Remove(0, openParenthesisPos + 1); - int32 closeParenthesisPos = tzName.FindLast(')'); - if (closeParenthesisPos >= 0) - tzName.Truncate(closeParenthesisPos); - } - BString fullCountryID = region; - if (country.Length() > 0 && country != region) - fullCountryID << "/" << country; - BString fullZoneID = fullCountryID; - fullZoneID << "/" << tzName; + if (region == "Etc") + region = kOtherRegion; + else if (countryName.Length() == 0) { + // skip global timezones from other regions, we are just + // interested in the generic GMT-based ones under "Etc/" + continue; + } - // skip duplicates - ZoneItemMap::iterator zoneIter = zoneMap.find(fullZoneID); - if (zoneIter != zoneMap.end()) { - delete timeZone; - continue; - } - TimeZoneListItem* countryItem = NULL; - if (country.Length() > 0) { - ZoneItemMap::iterator countryIter = zoneMap.find(fullCountryID); - if (countryIter == zoneMap.end()) { - countryItem = new TimeZoneListItem(country, NULL, NULL); - countryItem->SetOutlineLevel(1); - countryItem->SetExpanded(false); - zoneMap[fullCountryID] = countryItem; - } else - countryItem = countryIter->second; - } + // just accept timezones from "proper" regions, others are aliases + ZoneItemMap::iterator regionIter = zoneMap.find(region); + if (regionIter == zoneMap.end()) + continue; - TimeZoneListItem* zoneItem - = new TimeZoneListItem(tzName, NULL, timeZone); - zoneItem->SetOutlineLevel(countryItem == NULL ? 1 : 2); - zoneMap[fullZoneID] = zoneItem; + BString fullCountryID = region; + if (countryName != region) + fullCountryID << "/" << countryName; - if (timeZone->ID() == defaultTimeZone.ID()) { - fCurrentZoneItem = zoneItem; - if (countryItem != NULL) - countryItem->SetExpanded(true); - regionItem->SetExpanded(true); + TimeZoneListItem* regionItem = regionIter->second; + if (regionItem == NULL) { + regionItem = new TimeZoneListItem(region, NULL, NULL); + regionItem->SetOutlineLevel(0); + zoneMap[region] = regionItem; + } + + BTimeZone* timeZone = new BTimeZone(zoneID, &defaultLanguage); + BString tzName = timeZone->Name(); + if (tzName == "GMT+00:00") + tzName = "GMT"; + + int32 openParenthesisPos = tzName.FindFirst('('); + if (openParenthesisPos >= 0) { + tzName.Remove(0, openParenthesisPos + 1); + int32 closeParenthesisPos = tzName.FindLast(')'); + if (closeParenthesisPos >= 0) + tzName.Truncate(closeParenthesisPos); + } + BString fullZoneID = fullCountryID; + fullZoneID << "/" << tzName; + + // skip duplicates + ZoneItemMap::iterator zoneIter = zoneMap.find(fullZoneID); + if (zoneIter != zoneMap.end()) { + delete timeZone; + continue; + } + + TimeZoneListItem* countryItem = NULL; + TimeZoneListItem* zoneItem = NULL; + if (count > 1 && countryName.Length() > 0) { + ZoneItemMap::iterator countryIter = zoneMap.find(fullCountryID); + if (countryIter == zoneMap.end()) { + countryItem = new TimeZoneListItem(countryName, NULL, NULL); + countryItem->SetOutlineLevel(1); + zoneMap[fullCountryID] = countryItem; + } else + countryItem = countryIter->second; + + zoneItem = new TimeZoneListItem(tzName, NULL, timeZone); + zoneItem->SetOutlineLevel(2); + } else { + BString& name = countryName.Length() > 0 ? countryName : tzName; + zoneItem = new TimeZoneListItem(name, NULL, timeZone); + zoneItem->SetOutlineLevel(1); + } + zoneMap[fullZoneID] = zoneItem; + + if (timeZone->ID() == defaultTimeZone.ID()) { + fCurrentZoneItem = zoneItem; + if (countryItem != NULL) + countryItem->SetExpanded(true); + regionItem->SetExpanded(true); + } } } fOldZoneItem = fCurrentZoneItem; ZoneItemMap::iterator zoneIter; - for (zoneIter = zoneMap.begin(); zoneIter != zoneMap.end(); ++zoneIter) + bool lastWasCountryItem = false; + TimeZoneListItem* lastCountryItem = NULL; + for (zoneIter = zoneMap.begin(); zoneIter != zoneMap.end(); ++zoneIter) { + if (zoneIter->second->OutlineLevel() == 2 && lastWasCountryItem) { + /* Some countries (e.g. Spain and Chile) have their timezones + * spread across different regions. As a result, there might still + * be country items with only one timezone below them. We manually + * filter those country items here. + */ + ZoneItemMap::iterator next = zoneIter; + ++next; + if (next != zoneMap.end() && next->second->OutlineLevel() != 2) { + fZoneList->RemoveItem(lastCountryItem); + zoneIter->second->SetText(lastCountryItem->Text()); + zoneIter->second->SetOutlineLevel(1); + delete lastCountryItem; + } + } + fZoneList->AddItem(zoneIter->second); + if (zoneIter->second->OutlineLevel() == 1) { + lastWasCountryItem = true; + lastCountryItem = zoneIter->second; + } else + lastWasCountryItem = false; + } } @@ -459,8 +520,7 @@ TimeZoneView::_SetSystemTimeZone() BString -TimeZoneView::_FormatTime(const BTimeZone& timeZone, - bool compensateForLocalOffset) +TimeZoneView::_FormatTime(const BTimeZone& timeZone) { BString result; @@ -469,7 +529,7 @@ TimeZoneView::_FormatTime(const BTimeZone& timeZone, time_t now = time(NULL); bool rtcIsGMT; _kern_get_real_time_clock_is_gmt(&rtcIsGMT); - if (!rtcIsGMT && compensateForLocalOffset) { + if (!rtcIsGMT) { int32 currentOffset = fCurrentZoneItem != NULL && fCurrentZoneItem->HasTimeZone() ? fCurrentZoneItem->OffsetFromGMT() diff --git a/src/preferences/time/ZoneView.h b/src/preferences/time/ZoneView.h index 1b306549d9..76dca5b7f9 100644 --- a/src/preferences/time/ZoneView.h +++ b/src/preferences/time/ZoneView.h @@ -44,8 +44,7 @@ private: void _UpdatePreview(); void _UpdateCurrent(); - BString _FormatTime(const BTimeZone& timeZone, - bool compensateForLocalOffset = true); + BString _FormatTime(const BTimeZone& timeZone); void _InitView(); void _BuildZoneMenu();