From 99d2aa985b7e24d8e11ab008236b819fb895b61a Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Thu, 29 Jul 2010 20:10:26 +0000 Subject: [PATCH] Improved the Time preflet (still not working properly, though) * basically rewrote TimeZone to sport a nicer to use interface * adjusted all users of TimeZone accordingly * changed TZDisplay to show the Date next to the label, in order to avoid that long timezone names draw all over it * the timezone listview is now properly sorted according to the current language (using BCollator) * fixed a couple of bugs (overflows, etc.) that caused incorrect GMT offsets to be used during computations git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37813 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/locale/TimeZone.h | 43 ++++++----- src/kits/locale/Country.cpp | 4 +- src/kits/locale/LocaleRoster.cpp | 2 +- src/kits/locale/TimeZone.cpp | 85 ++++++++++++++------- src/preferences/time/Jamfile | 22 +++--- src/preferences/time/TZDisplay.cpp | 1 + src/preferences/time/TimeZoneListItem.cpp | 35 +++++++-- src/preferences/time/TimeZoneListItem.h | 5 +- src/preferences/time/ZoneView.cpp | 92 +++++++++++++---------- 9 files changed, 178 insertions(+), 111 deletions(-) diff --git a/headers/os/locale/TimeZone.h b/headers/os/locale/TimeZone.h index 7c63425e8c..9758716171 100644 --- a/headers/os/locale/TimeZone.h +++ b/headers/os/locale/TimeZone.h @@ -1,31 +1,34 @@ /* -Copyright 2010, Haiku, Inc. -Distributed under the terms of the MIT License. -*/ + * Copyright 2010, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _TIME_ZONE_H +#define _TIME_ZONE_H -#ifndef __TIMEZONE_H__ -#define __TIMEZONE_H__ - - -class BString; -namespace icu_44 { - class TimeZone; -} +#include class BTimeZone { - public: - BTimeZone(const char* zoneCode); - ~BTimeZone(); +public: + BTimeZone(const char* zoneCode = NULL); + ~BTimeZone(); - void GetName(BString& name); - void GetCode(char* buffer, int size); - int OffsetFromGMT(); + const BString& Code() const; + const BString& Name() const; + int OffsetFromGMT() const; - private: - icu_44::TimeZone* fICUTimeZone; + status_t InitCheck() const; + +private: + void _Init(const char* zoneCode); + + BString fCode; + BString fName; + int fOffsetFromGMT; + + status_t fInitStatus; }; -#endif +#endif // _TIME_ZONE_H diff --git a/src/kits/locale/Country.cpp b/src/kits/locale/Country.cpp index 54c973a2c5..080ffd437b 100644 --- a/src/kits/locale/Country.cpp +++ b/src/kits/locale/Country.cpp @@ -1065,10 +1065,8 @@ BCountry::GetTimeZones(BList& timezones) // remaining zones after that while ((tzName = icuTimeZoneList->next(NULL, error)) != NULL) { if (error == U_ZERO_ERROR) { - BString readableName; BTimeZone* timeZone = new BTimeZone(tzName); - timeZone->GetName(readableName); - timeZoneMap.insert(std::pair(readableName, + timeZoneMap.insert(std::pair(timeZone->Name(), timeZone)); } else error = U_ZERO_ERROR; diff --git a/src/kits/locale/LocaleRoster.cpp b/src/kits/locale/LocaleRoster.cpp index 41c992f671..63ac377385 100644 --- a/src/kits/locale/LocaleRoster.cpp +++ b/src/kits/locale/LocaleRoster.cpp @@ -511,7 +511,7 @@ BLocaleRoster::GetDefaultTimeZone(BTimeZone **timezone) const if (!timezone) return B_BAD_VALUE; - *timezone = new(std::nothrow) BTimeZone(""); + *timezone = new(std::nothrow) BTimeZone(); return B_OK; } diff --git a/src/kits/locale/TimeZone.cpp b/src/kits/locale/TimeZone.cpp index 71d0197f24..22968fe28c 100644 --- a/src/kits/locale/TimeZone.cpp +++ b/src/kits/locale/TimeZone.cpp @@ -1,62 +1,89 @@ /* -Copyright 2010, Adrien Destugues -Distributed under the terms of the MIT License. -*/ + * Copyright (c) 2010, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Adrien Destugues + * Oliver Tappe + */ #include -#include - #include #include BTimeZone::BTimeZone(const char* zoneCode) { - fICUTimeZone = TimeZone::createTimeZone(zoneCode); + _Init(zoneCode); } BTimeZone::~BTimeZone() { - delete fICUTimeZone; } -void -BTimeZone::GetName(BString& name) +const BString& +BTimeZone::Name() const { - UnicodeString unicodeName; - fICUTimeZone->getDisplayName(unicodeName); - - BStringByteSink converter(&name); - unicodeName.toUTF8(converter); + return fName; } -void -BTimeZone::GetCode(char* buffer, int size) +const BString& +BTimeZone::Code() const { - UnicodeString unicodeName; - fICUTimeZone->getID(unicodeName); - - CheckedArrayByteSink converter(buffer, size); - unicodeName.toUTF8(converter); + return fCode; } int -BTimeZone::OffsetFromGMT() +BTimeZone::OffsetFromGMT() const { + return fOffsetFromGMT; +} + + +status_t +BTimeZone::InitCheck() const +{ + return fInitStatus; +} + + +void +BTimeZone::_Init(const char* zoneCode) +{ + TimeZone* icuTimeZone; + if (zoneCode == NULL || zoneCode[0] == '\0') + icuTimeZone = TimeZone::createDefault(); + else + icuTimeZone = TimeZone::createTimeZone(zoneCode); + + UnicodeString unicodeString; + icuTimeZone->getID(unicodeString); + BStringByteSink converter(&fCode); + unicodeString.toUTF8(converter); + + unicodeString.remove(); + icuTimeZone->getDisplayName(unicodeString); + converter.SetTo(&fName); + unicodeString.toUTF8(converter); + int32_t rawOffset; int32_t dstOffset; - time_t now; + UDate nowMillis = 1000 * (double)time(NULL); UErrorCode error = U_ZERO_ERROR; - fICUTimeZone->getOffset(time(&now) * 1000, FALSE, rawOffset, dstOffset - , error); - if (error != U_ZERO_ERROR) - return 0; - else - return rawOffset + dstOffset; + icuTimeZone->getOffset(nowMillis, FALSE, rawOffset, dstOffset, error); + + if (error != U_ZERO_ERROR) { + fOffsetFromGMT = 0; + fInitStatus = B_ERROR; + } else { + fOffsetFromGMT = (rawOffset + dstOffset) / 1000; + // we want seconds, not ms (which ICU gives us) + fInitStatus = B_OK; + } } diff --git a/src/preferences/time/Jamfile b/src/preferences/time/Jamfile index 7878388eb9..4d44071149 100644 --- a/src/preferences/time/Jamfile +++ b/src/preferences/time/Jamfile @@ -5,19 +5,19 @@ SetSubDirSupportedPlatformsBeOSCompatible ; UsePrivateHeaders shared ; UsePrivateSystemHeaders ; -Preference Time : - AnalogClock.cpp - BaseView.cpp - Bitmaps.cpp - DateTimeEdit.cpp - SectionEdit.cpp - DateTimeView.cpp - Time.cpp - TimeSettings.cpp +Preference Time : + AnalogClock.cpp + BaseView.cpp + Bitmaps.cpp + DateTimeEdit.cpp + SectionEdit.cpp + DateTimeView.cpp + Time.cpp + TimeSettings.cpp TimeWindow.cpp TimeZoneListItem.cpp - TZDisplay.cpp - ZoneView.cpp + TZDisplay.cpp + ZoneView.cpp : be libshared.a $(TARGET_LIBSUPC++) $(HAIKU_LOCALE_LIBS) : Time.rdef ; diff --git a/src/preferences/time/TZDisplay.cpp b/src/preferences/time/TZDisplay.cpp index 6464c1695d..b2c6cd1f1b 100644 --- a/src/preferences/time/TZDisplay.cpp +++ b/src/preferences/time/TZDisplay.cpp @@ -71,6 +71,7 @@ TTZDisplay::Draw(BRect /* updateRect */) pt.y += fontHeight; DrawString(fText.String(), pt); + pt.y -= fontHeight; pt.x = bounds.right - StringWidth(fTime.String()) - 2.0; DrawString(fTime.String(), pt); } diff --git a/src/preferences/time/TimeZoneListItem.cpp b/src/preferences/time/TimeZoneListItem.cpp index bb14ab3cf9..86cfdda189 100644 --- a/src/preferences/time/TimeZoneListItem.cpp +++ b/src/preferences/time/TimeZoneListItem.cpp @@ -21,6 +21,9 @@ #include +static const BString skDefaultString; + + TimeZoneListItem::TimeZoneListItem(const char* text, BCountry* country, BTimeZone* timeZone) : @@ -92,13 +95,31 @@ TimeZoneListItem::DrawItem(BView* owner, BRect frame, bool complete) } -void -TimeZoneListItem::Code(char* buffer) +const BString& +TimeZoneListItem::Code() const { - if (fTimeZone == NULL) { - buffer[0] = '\0'; - return; - } + if (fTimeZone == NULL) + return skDefaultString; - fTimeZone->GetCode(buffer, 50); + return fTimeZone->Code(); +} + + +const BString& +TimeZoneListItem::Name() const +{ + if (fTimeZone == NULL) + return skDefaultString; + + return fTimeZone->Name(); +} + + +int +TimeZoneListItem::OffsetFromGMT() const +{ + if (fTimeZone == NULL) + return 0; + + return fTimeZone->OffsetFromGMT(); } diff --git a/src/preferences/time/TimeZoneListItem.h b/src/preferences/time/TimeZoneListItem.h index a82425cf60..463ad2f945 100644 --- a/src/preferences/time/TimeZoneListItem.h +++ b/src/preferences/time/TimeZoneListItem.h @@ -26,7 +26,10 @@ public: void DrawItem(BView* owner, BRect frame, bool complete = false); - void Code(char* buffer); + + const BString& Code() const; + const BString& Name() const; + int OffsetFromGMT() const; private: BBitmap* fIcon; diff --git a/src/preferences/time/ZoneView.cpp b/src/preferences/time/ZoneView.cpp index 37e9a52072..faab480e71 100644 --- a/src/preferences/time/ZoneView.cpp +++ b/src/preferences/time/ZoneView.cpp @@ -7,6 +7,7 @@ * Julun * Philippe Saint-Pierre * Adrien Destugues + * Oliver Tappe */ /* @@ -20,6 +21,7 @@ #include #include +#include #include #include #include @@ -42,13 +44,17 @@ #include "TimeWindow.h" +static BCollator sCollator; + // used to sort the timezone list + + TimeZoneView::TimeZoneView(BRect frame) - : BView(frame, "timeZoneView", B_FOLLOW_NONE, B_WILL_DRAW - | B_NAVIGABLE_JUMP), fInitialized(false) + : + BView(frame, "timeZoneView", B_FOLLOW_NONE, B_WILL_DRAW | B_NAVIGABLE_JUMP), + fCurrentZone(NULL), + fOldZone(NULL), + fInitialized(false) { - fCurrentZone = NULL; - fOldZone = NULL; - // TODO : get default timezone from locale kit _InitView(); } @@ -231,10 +237,12 @@ TimeZoneView::_InitView() void TimeZoneView::_BuildRegionMenu() { - // Get a list of countries - // For each country, get all the timezones and AddItemUnder them - // (only if there are multiple ones ?) - // Unfold the current country and highlight the selected TZ + BTimeZone* defaultTimeZone = NULL; + be_locale_roster->GetDefaultTimeZone(&defaultTimeZone); + + // Get a list of countries and, for each country, get all the timezones and + // AddUnder() them (only if there are multiple ones). + // Finally expand the current country and highlight the active TZ. BMessage countryList; be_locale_roster->GetAvailableCountries(&countryList); @@ -249,6 +257,7 @@ TimeZoneView::_BuildRegionMenu() // Now list the timezones for this country BList tzList; + BTimeZone* timeZone; TimeZoneListItem* countryItem; switch (country.GetTimeZones(tzList)) { @@ -257,30 +266,47 @@ TimeZoneView::_BuildRegionMenu() break; case 1: // Only one Timezone, no need to add it to the list - countryItem = new TimeZoneListItem(fullName, &country, - (BTimeZone*)tzList.ItemAt(0)); + timeZone = (BTimeZone*)tzList.ItemAt(0); + countryItem + = new TimeZoneListItem(fullName, &country, timeZone); fCityList->AddItem(countryItem); + if (timeZone->Code() == defaultTimeZone->Code()) + fCurrentZone = countryItem; break; default: countryItem = new TimeZoneListItem(fullName, &country, NULL); + countryItem->SetExpanded(false); fCityList->AddItem(countryItem); - BTimeZone* timeZone; for (int j = 0; (timeZone = (BTimeZone*)tzList.ItemAt(j)) != NULL; j++) { - BString readableName; - timeZone->GetName(readableName); - BStringItem* tzItem = new TimeZoneListItem(readableName, - NULL, timeZone); + TimeZoneListItem* tzItem = new TimeZoneListItem( + timeZone->Name(), NULL, timeZone); fCityList->AddUnder(tzItem, countryItem); + if (timeZone->Code() == defaultTimeZone->Code()) + { + fCurrentZone = tzItem; + countryItem->SetExpanded(true); + } } break; } } - fCurrentZone = fOldZone = (TimeZoneListItem*)fCityList->ItemAt(0); - // TODO get the actual setting from locale kit + fOldZone = fCurrentZone; + + delete defaultTimeZone; + + struct ListSorter { + static int compare(const BListItem* first, const BListItem* second) + { + return sCollator.Compare(((BStringItem*)first)->Text(), + ((BStringItem*)second)->Text()); + } + }; + fCityList->SortItemsUnder(NULL, true, ListSorter::compare); + } @@ -289,26 +315,18 @@ TimeZoneView::_SetPreview() { int32 selection = fCityList->CurrentSelection(); if (selection >= 0) { - TimeZoneListItem* item = (TimeZoneListItem*)fCityList->ItemAt( - selection); - - // set timezone to selection - char buffer[50]; - item->Code(buffer); - _SetTimeZone(buffer); + TimeZoneListItem* item + = (TimeZoneListItem*)fCityList->ItemAt(selection); // calc preview time - time_t current = time(NULL); + time_t current = time(NULL) + item->OffsetFromGMT(); struct tm localTime; - localtime_r(¤t, &localTime); + gmtime_r(¤t, &localTime); // update prview fPreview->SetText(item->Text()); fPreview->SetTime(localTime.tm_hour, localTime.tm_min); - fCurrentZone->Code(buffer); - _SetTimeZone(buffer); - fSetZone->SetEnabled((strcmp(fCurrent->Text(), item->Text()) != 0)); } } @@ -317,9 +335,7 @@ TimeZoneView::_SetPreview() void TimeZoneView::_SetCurrent(const char* text) { - char buffer[50]; - fCurrentZone->Code(buffer); - _SetTimeZone(buffer); + _SetTimeZone(fCurrentZone->Code().String()); time_t current = time(NULL); struct tm localTime; @@ -345,18 +361,16 @@ TimeZoneView::_SetTimeZone() if (selection < 0) return; - char timeZoneCode[50]; - ((TimeZoneListItem*)fCityList->ItemAt(selection))->Code(timeZoneCode); - - // update environment - _SetTimeZone(timeZoneCode); + const BString& code + = ((TimeZoneListItem*)fCityList->ItemAt(selection))->Code(); + _SetTimeZone(code.String()); // update display time_t current = time(NULL); struct tm localTime; localtime_r(¤t, &localTime); - set_timezone(timeZoneCode); + set_timezone(code.String()); // disable button fSetZone->SetEnabled(false);