Optimized Time preflet:
* use upon-demand initialization in BTimeZone to avoid unnecessary work * renamed BTimeZone::Code() to BTimeZone::ID() and adjusted all callers * avoid using BCountry in the Time preflet for the time being, this means the icon-flags are gone for now (but they could be re-added if the demand is pressing ;-) * group the timezones by regions and then by country instead The performance improvement is considerable and I personally think the new grouping is an improvement, too. Please share your thoughts! git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38322 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
039ad7e757
commit
750e57b842
@ -9,12 +9,20 @@
|
||||
#include <String.h>
|
||||
|
||||
|
||||
namespace icu_44 {
|
||||
class TimeZone;
|
||||
}
|
||||
|
||||
|
||||
class BTimeZone {
|
||||
public:
|
||||
BTimeZone(const char* zoneCode = NULL);
|
||||
BTimeZone(const char* zoneID = NULL);
|
||||
BTimeZone(const BTimeZone& other);
|
||||
~BTimeZone();
|
||||
|
||||
const BString& Code() const;
|
||||
BTimeZone& operator=(const BTimeZone& source);
|
||||
|
||||
const BString& ID() const;
|
||||
const BString& Name() const;
|
||||
const BString& DaylightSavingName() const;
|
||||
const BString& ShortName() const;
|
||||
@ -24,20 +32,22 @@ public:
|
||||
|
||||
status_t InitCheck() const;
|
||||
|
||||
status_t SetTo(const char* zoneCode);
|
||||
status_t SetTo(const char* zoneID);
|
||||
|
||||
static const char* kNameOfGmtZone;
|
||||
|
||||
private:
|
||||
BString fCode;
|
||||
BString fName;
|
||||
BString fDaylightSavingName;
|
||||
BString fShortName;
|
||||
BString fShortDaylightSavingName;
|
||||
int fOffsetFromGMT;
|
||||
bool fSupportsDaylightSaving;
|
||||
|
||||
icu_44::TimeZone* fIcuTimeZone;
|
||||
status_t fInitStatus;
|
||||
|
||||
mutable uint32 fInitializedFields;
|
||||
mutable BString fZoneID;
|
||||
mutable BString fName;
|
||||
mutable BString fDaylightSavingName;
|
||||
mutable BString fShortName;
|
||||
mutable BString fShortDaylightSavingName;
|
||||
mutable int fOffsetFromGMT;
|
||||
mutable bool fSupportsDaylightSaving;
|
||||
};
|
||||
|
||||
|
||||
|
@ -405,7 +405,7 @@ BLocale::FormatTime(BString* string, time_t time, bool longFormat,
|
||||
|
||||
if (timeZone != NULL) {
|
||||
ObjectDeleter<TimeZone> icuTimeZone
|
||||
= TimeZone::createTimeZone(timeZone->Code().String());
|
||||
= TimeZone::createTimeZone(timeZone->ID().String());
|
||||
if (icuTimeZone.Get() == NULL)
|
||||
return B_NO_MEMORY;
|
||||
timeFormatter->setTimeZone(*icuTimeZone.Get());
|
||||
|
@ -434,8 +434,6 @@ RosterData::_LoadLocaleSettings()
|
||||
BMessage settings;
|
||||
if (status == B_OK)
|
||||
status = settings.Unflatten(&file);
|
||||
if (status == B_OK)
|
||||
status = _SetPreferredLanguages(&settings);
|
||||
|
||||
if (status == B_OK) {
|
||||
BString codeName;
|
||||
@ -454,6 +452,9 @@ RosterData::_LoadLocaleSettings()
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
if (status == B_OK)
|
||||
status = _SetPreferredLanguages(&settings);
|
||||
|
||||
|
||||
// Something went wrong (no settings file or invalid BMessage), so we
|
||||
// set everything to default values
|
||||
@ -481,9 +482,9 @@ RosterData::_LoadTimeSettings()
|
||||
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()));
|
||||
BString timeZoneID;
|
||||
if (settings.FindString("timezone", &timeZoneID) == B_OK)
|
||||
_SetDefaultTimeZone(BTimeZone(timeZoneID.String()));
|
||||
else
|
||||
_SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone));
|
||||
|
||||
@ -564,6 +565,15 @@ RosterData::_SetDefaultLocale(const BLocale& newLocale)
|
||||
{
|
||||
fDefaultLocale = newLocale;
|
||||
|
||||
UErrorCode icuError = U_ZERO_ERROR;
|
||||
Locale icuLocale = Locale::createCanonical(newLocale.Code());
|
||||
if (icuLocale.isBogus())
|
||||
return B_ERROR;
|
||||
|
||||
Locale::setDefault(icuLocale, icuError);
|
||||
if (!U_SUCCESS(icuError))
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -573,7 +583,7 @@ RosterData::_SetDefaultTimeZone(const BTimeZone& newZone)
|
||||
{
|
||||
fDefaultTimeZone = newZone;
|
||||
|
||||
TimeZone* timeZone = TimeZone::createTimeZone(newZone.Code().String());
|
||||
TimeZone* timeZone = TimeZone::createTimeZone(newZone.ID().String());
|
||||
if (timeZone == NULL)
|
||||
return B_ERROR;
|
||||
TimeZone::adoptDefault(timeZone);
|
||||
@ -588,15 +598,6 @@ 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;
|
||||
|
||||
fDefaultLocale.SetCollator(BCollator(langName.String()));
|
||||
fDefaultLanguage.SetTo(langName.String());
|
||||
|
||||
@ -637,7 +638,7 @@ RosterData::_AddDefaultCountryToMessage(BMessage* message) const
|
||||
status_t
|
||||
RosterData::_AddDefaultTimeZoneToMessage(BMessage* message) const
|
||||
{
|
||||
status_t status = message->AddString("timezone", fDefaultTimeZone.Code());
|
||||
status_t status = message->AddString("timezone", fDefaultTimeZone.ID());
|
||||
|
||||
// add the offset, too, since that is used by clockconfig when setting
|
||||
// up timezone state during boot
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
#include <TimeZone.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <unicode/timezone.h>
|
||||
#include <ICUWrapper.h>
|
||||
|
||||
@ -17,20 +19,93 @@
|
||||
const char* BTimeZone::kNameOfGmtZone = "GMT";
|
||||
|
||||
|
||||
BTimeZone::BTimeZone(const char* zoneCode)
|
||||
static const BString skEmptyString;
|
||||
|
||||
|
||||
static const uint32 skNameField = 1U << 0;
|
||||
static const uint32 skDaylightSavingNameField = 1U << 1;
|
||||
static const uint32 skShortNameField = 1U << 2;
|
||||
static const uint32 skShortDaylightSavingNameField = 1U << 3;
|
||||
static const uint32 skLongGenericNameField = 1U << 4;
|
||||
static const uint32 skGenericLocationNameField = 1U << 5;
|
||||
static const uint32 skShortCommonlyUsedNameField = 1U << 6;
|
||||
static const uint32 skSupportsDaylightSavingField = 1U << 7;
|
||||
static const uint32 skOffsetFromGMTField = 1U << 8;
|
||||
|
||||
|
||||
BTimeZone::BTimeZone(const char* zoneID)
|
||||
:
|
||||
fIcuTimeZone(NULL),
|
||||
fInitStatus(B_NO_INIT),
|
||||
fInitializedFields(0)
|
||||
{
|
||||
SetTo(zoneID);
|
||||
}
|
||||
|
||||
|
||||
BTimeZone::BTimeZone(const BTimeZone& other)
|
||||
:
|
||||
fIcuTimeZone(other.fIcuTimeZone == NULL
|
||||
? NULL
|
||||
: other.fIcuTimeZone->clone()),
|
||||
fInitStatus(other.fInitStatus),
|
||||
fInitializedFields(other.fInitializedFields),
|
||||
fZoneID(other.fZoneID),
|
||||
fName(other.fName),
|
||||
fDaylightSavingName(other.fDaylightSavingName),
|
||||
fShortName(other.fShortName),
|
||||
fShortDaylightSavingName(other.fShortDaylightSavingName),
|
||||
fOffsetFromGMT(other.fOffsetFromGMT),
|
||||
fSupportsDaylightSaving(other.fSupportsDaylightSaving)
|
||||
{
|
||||
SetTo(zoneCode);
|
||||
}
|
||||
|
||||
|
||||
BTimeZone::~BTimeZone()
|
||||
{
|
||||
delete fIcuTimeZone;
|
||||
}
|
||||
|
||||
|
||||
BTimeZone& BTimeZone::operator=(const BTimeZone& source)
|
||||
{
|
||||
delete fIcuTimeZone;
|
||||
fIcuTimeZone = source.fIcuTimeZone == NULL
|
||||
? NULL
|
||||
: source.fIcuTimeZone->clone();
|
||||
fInitStatus = source.fInitStatus;
|
||||
fInitializedFields = source.fInitializedFields;
|
||||
fZoneID = source.fZoneID;
|
||||
fName = source.fName;
|
||||
fDaylightSavingName = source.fDaylightSavingName;
|
||||
fShortName = source.fShortName;
|
||||
fShortDaylightSavingName = source.fShortDaylightSavingName;
|
||||
fOffsetFromGMT = source.fOffsetFromGMT;
|
||||
fSupportsDaylightSaving = source.fSupportsDaylightSaving;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
const BString&
|
||||
BTimeZone::ID() const
|
||||
{
|
||||
return fZoneID;
|
||||
}
|
||||
|
||||
|
||||
const BString&
|
||||
BTimeZone::Name() const
|
||||
{
|
||||
if ((fInitializedFields & skNameField) == 0) {
|
||||
UnicodeString unicodeString;
|
||||
fIcuTimeZone->getDisplayName(false, TimeZone::GENERIC_LOCATION,
|
||||
unicodeString);
|
||||
BStringByteSink sink(&fName);
|
||||
unicodeString.toUTF8(sink);
|
||||
fInitializedFields |= skNameField;
|
||||
}
|
||||
|
||||
return fName;
|
||||
}
|
||||
|
||||
@ -38,6 +113,15 @@ BTimeZone::Name() const
|
||||
const BString&
|
||||
BTimeZone::DaylightSavingName() const
|
||||
{
|
||||
if ((fInitializedFields & skDaylightSavingNameField) == 0) {
|
||||
UnicodeString unicodeString;
|
||||
fIcuTimeZone->getDisplayName(true, TimeZone::GENERIC_LOCATION,
|
||||
unicodeString);
|
||||
BStringByteSink sink(&fDaylightSavingName);
|
||||
unicodeString.toUTF8(sink);
|
||||
fInitializedFields |= skDaylightSavingNameField;
|
||||
}
|
||||
|
||||
return fDaylightSavingName;
|
||||
}
|
||||
|
||||
@ -45,6 +129,15 @@ BTimeZone::DaylightSavingName() const
|
||||
const BString&
|
||||
BTimeZone::ShortName() const
|
||||
{
|
||||
if ((fInitializedFields & skShortNameField) == 0) {
|
||||
UnicodeString unicodeString;
|
||||
fIcuTimeZone->getDisplayName(false, TimeZone::SHORT_COMMONLY_USED,
|
||||
unicodeString);
|
||||
BStringByteSink sink(&fShortName);
|
||||
unicodeString.toUTF8(sink);
|
||||
fInitializedFields |= skShortNameField;
|
||||
}
|
||||
|
||||
return fShortName;
|
||||
}
|
||||
|
||||
@ -52,20 +145,38 @@ BTimeZone::ShortName() const
|
||||
const BString&
|
||||
BTimeZone::ShortDaylightSavingName() const
|
||||
{
|
||||
if ((fInitializedFields & skShortDaylightSavingNameField) == 0) {
|
||||
UnicodeString unicodeString;
|
||||
fIcuTimeZone->getDisplayName(true, TimeZone::SHORT_COMMONLY_USED,
|
||||
unicodeString);
|
||||
BStringByteSink sink(&fShortDaylightSavingName);
|
||||
unicodeString.toUTF8(sink);
|
||||
fInitializedFields |= skShortDaylightSavingNameField;
|
||||
}
|
||||
|
||||
return fShortDaylightSavingName;
|
||||
}
|
||||
|
||||
|
||||
const BString&
|
||||
BTimeZone::Code() const
|
||||
{
|
||||
return fCode;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
BTimeZone::OffsetFromGMT() const
|
||||
{
|
||||
if ((fInitializedFields & skOffsetFromGMTField) == 0) {
|
||||
int32_t rawOffset;
|
||||
int32_t dstOffset;
|
||||
UDate nowMillis = 1000 * (double)time(NULL);
|
||||
|
||||
UErrorCode error = U_ZERO_ERROR;
|
||||
fIcuTimeZone->getOffset(nowMillis, FALSE, rawOffset, dstOffset, error);
|
||||
if (!U_SUCCESS(error))
|
||||
fOffsetFromGMT = 0;
|
||||
else {
|
||||
fOffsetFromGMT = (rawOffset + dstOffset) / 1000;
|
||||
// we want seconds, not ms (which ICU gives us)
|
||||
}
|
||||
fInitializedFields |= skOffsetFromGMTField;
|
||||
}
|
||||
|
||||
return fOffsetFromGMT;
|
||||
}
|
||||
|
||||
@ -73,6 +184,11 @@ BTimeZone::OffsetFromGMT() const
|
||||
bool
|
||||
BTimeZone::SupportsDaylightSaving() const
|
||||
{
|
||||
if ((fInitializedFields & skSupportsDaylightSavingField) == 0) {
|
||||
fSupportsDaylightSaving = fIcuTimeZone->useDaylightTime();
|
||||
fInitializedFields |= skSupportsDaylightSavingField;
|
||||
}
|
||||
|
||||
return fSupportsDaylightSaving;
|
||||
}
|
||||
|
||||
@ -85,57 +201,27 @@ BTimeZone::InitCheck() const
|
||||
|
||||
|
||||
status_t
|
||||
BTimeZone::SetTo(const char* zoneCode)
|
||||
BTimeZone::SetTo(const char* zoneID)
|
||||
{
|
||||
TimeZone* icuTimeZone;
|
||||
if (zoneCode == NULL || zoneCode[0] == '\0')
|
||||
icuTimeZone = TimeZone::createDefault();
|
||||
delete fIcuTimeZone;
|
||||
fInitializedFields = 0;
|
||||
|
||||
if (zoneID == NULL || zoneID[0] == '\0')
|
||||
fIcuTimeZone = TimeZone::createDefault();
|
||||
else
|
||||
icuTimeZone = TimeZone::createTimeZone(zoneCode);
|
||||
fIcuTimeZone = TimeZone::createTimeZone(zoneID);
|
||||
|
||||
UnicodeString unicodeString;
|
||||
icuTimeZone->getID(unicodeString);
|
||||
BStringByteSink converter(&fCode);
|
||||
unicodeString.toUTF8(converter);
|
||||
|
||||
unicodeString.remove();
|
||||
icuTimeZone->getDisplayName(false, TimeZone::LONG, unicodeString);
|
||||
converter.SetTo(&fName);
|
||||
unicodeString.toUTF8(converter);
|
||||
|
||||
unicodeString.remove();
|
||||
icuTimeZone->getDisplayName(true, TimeZone::LONG, unicodeString);
|
||||
converter.SetTo(&fDaylightSavingName);
|
||||
unicodeString.toUTF8(converter);
|
||||
|
||||
unicodeString.remove();
|
||||
icuTimeZone->getDisplayName(false, TimeZone::SHORT, unicodeString);
|
||||
converter.SetTo(&fShortName);
|
||||
unicodeString.toUTF8(converter);
|
||||
|
||||
unicodeString.remove();
|
||||
icuTimeZone->getDisplayName(true, TimeZone::SHORT, unicodeString);
|
||||
converter.SetTo(&fShortDaylightSavingName);
|
||||
unicodeString.toUTF8(converter);
|
||||
|
||||
fSupportsDaylightSaving = icuTimeZone->useDaylightTime();
|
||||
|
||||
int32_t rawOffset;
|
||||
int32_t dstOffset;
|
||||
UDate nowMillis = 1000 * (double)time(NULL);
|
||||
|
||||
UErrorCode error = U_ZERO_ERROR;
|
||||
icuTimeZone->getOffset(nowMillis, FALSE, rawOffset, dstOffset, error);
|
||||
if (!U_SUCCESS(error)) {
|
||||
fOffsetFromGMT = 0;
|
||||
fInitStatus = B_ERROR;
|
||||
} else {
|
||||
fOffsetFromGMT = (rawOffset + dstOffset) / 1000;
|
||||
// we want seconds, not ms (which ICU gives us)
|
||||
fInitStatus = B_OK;
|
||||
if (fIcuTimeZone == NULL) {
|
||||
fInitStatus = B_NAME_NOT_FOUND;
|
||||
return fInitStatus;
|
||||
}
|
||||
|
||||
delete icuTimeZone;
|
||||
UnicodeString unicodeString;
|
||||
fIcuTimeZone->getID(unicodeString);
|
||||
BStringByteSink sink(&fZoneID);
|
||||
unicodeString.toUTF8(sink);
|
||||
|
||||
fInitStatus = B_OK;
|
||||
|
||||
return fInitStatus;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ SubDir HAIKU_TOP src preferences time ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
UsePrivateHeaders locale shared [ FDirName libroot time ] ;
|
||||
UsePrivateHeaders interface locale shared [ FDirName libroot time ] ;
|
||||
UsePrivateSystemHeaders ;
|
||||
|
||||
local sources =
|
||||
@ -28,7 +28,7 @@ Includes [ FGristFiles $(sources) ] : $(HAIKU_ICU_HEADERS_DEPENDENCY) ;
|
||||
|
||||
Preference Time
|
||||
: $(sources)
|
||||
: be libshared.a $(TARGET_LIBSUPC++) $(HAIKU_LOCALE_LIBS)
|
||||
: be libshared.a $(TARGET_LIBSTDC++) $(HAIKU_LOCALE_LIBS)
|
||||
: Time.rdef
|
||||
;
|
||||
|
||||
|
@ -109,12 +109,12 @@ TimeZoneListItem::TimeZone() const
|
||||
|
||||
|
||||
const BString&
|
||||
TimeZoneListItem::Code() const
|
||||
TimeZoneListItem::ID() const
|
||||
{
|
||||
if (fTimeZone == NULL)
|
||||
return skDefaultString;
|
||||
|
||||
return fTimeZone->Code();
|
||||
return fTimeZone->ID();
|
||||
}
|
||||
|
||||
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
|
||||
bool HasTimeZone() const;
|
||||
const BTimeZone& TimeZone() const;
|
||||
const BString& Code() const;
|
||||
const BString& ID() const;
|
||||
const BString& Name() const;
|
||||
int OffsetFromGMT() const;
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <map>
|
||||
#include <new>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
@ -37,6 +38,7 @@
|
||||
#include <Window.h>
|
||||
|
||||
#include <syscalls.h>
|
||||
#include <ToolTip.h>
|
||||
|
||||
#include <unicode/datefmt.h>
|
||||
#include <unicode/utmscale.h>
|
||||
@ -52,9 +54,21 @@ using BPrivate::gMutableLocaleRoster;
|
||||
using BPrivate::ObjectDeleter;
|
||||
|
||||
|
||||
struct TimeZoneItemLess {
|
||||
bool operator()(const BString& first, const BString& second)
|
||||
{
|
||||
return fCollator.Compare(first.String(), second.String()) < 0;
|
||||
}
|
||||
private:
|
||||
BCollator fCollator;
|
||||
};
|
||||
|
||||
|
||||
|
||||
TimeZoneView::TimeZoneView(BRect frame)
|
||||
:
|
||||
BView(frame, "timeZoneView", B_FOLLOW_NONE, B_WILL_DRAW | B_NAVIGABLE_JUMP),
|
||||
fToolTip(NULL),
|
||||
fCurrentZoneItem(NULL),
|
||||
fOldZoneItem(NULL),
|
||||
fInitialized(false)
|
||||
@ -70,26 +84,9 @@ TimeZoneView::CheckCanRevert()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TimeZoneView::_Revert()
|
||||
{
|
||||
fCurrentZoneItem = fOldZoneItem;
|
||||
|
||||
if (fCurrentZoneItem != NULL) {
|
||||
int32 currentZoneIndex = fZoneList->IndexOf(fCurrentZoneItem);
|
||||
fZoneList->Select(currentZoneIndex);
|
||||
} else
|
||||
fZoneList->DeselectAll();
|
||||
fZoneList->ScrollToSelection();
|
||||
|
||||
_SetSystemTimeZone();
|
||||
_UpdatePreview();
|
||||
_UpdateCurrent();
|
||||
}
|
||||
|
||||
|
||||
TimeZoneView::~TimeZoneView()
|
||||
{
|
||||
delete fToolTip;
|
||||
}
|
||||
|
||||
|
||||
@ -165,6 +162,29 @@ TimeZoneView::MessageReceived(BMessage* message)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TimeZoneView::GetToolTipAt(BPoint point, BToolTip** _tip)
|
||||
{
|
||||
TimeZoneListItem* item = static_cast<TimeZoneListItem*>(
|
||||
fZoneList->ItemAt(fZoneList->IndexOf(point)));
|
||||
if (item == NULL || !item->HasTimeZone())
|
||||
return false;
|
||||
|
||||
BString toolTip = item->Text();
|
||||
toolTip << '\n' << item->TimeZone().ShortName() << " / "
|
||||
<< item->TimeZone().ShortDaylightSavingName();
|
||||
|
||||
delete fToolTip;
|
||||
fToolTip = new (std::nothrow) BTextToolTip(toolTip.String());
|
||||
if (fToolTip == NULL)
|
||||
return false;
|
||||
|
||||
*_tip = fToolTip;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TimeZoneView::_UpdateDateTime(BMessage* message)
|
||||
{
|
||||
@ -195,7 +215,7 @@ TimeZoneView::_InitView()
|
||||
fZoneList->SetSelectionMessage(new BMessage(H_CITY_CHANGED));
|
||||
fZoneList->SetInvocationMessage(new BMessage(H_SET_TIME_ZONE));
|
||||
|
||||
_BuildRegionMenu();
|
||||
_BuildZoneMenu();
|
||||
|
||||
BScrollView* scrollList = new BScrollView("scrollList", fZoneList,
|
||||
B_FOLLOW_ALL, 0, false, true);
|
||||
@ -230,7 +250,7 @@ TimeZoneView::_InitView()
|
||||
|
||||
|
||||
void
|
||||
TimeZoneView::_BuildRegionMenu()
|
||||
TimeZoneView::_BuildZoneMenu()
|
||||
{
|
||||
BTimeZone defaultTimeZone = NULL;
|
||||
be_locale_roster->GetDefaultTimeZone(&defaultTimeZone);
|
||||
@ -239,75 +259,119 @@ TimeZoneView::_BuildRegionMenu()
|
||||
// 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);
|
||||
BMessage zoneList;
|
||||
be_locale_roster->GetAvailableTimeZones(&zoneList);
|
||||
|
||||
BString countryCode;
|
||||
for (int i = 0; countryList.FindString("countries", i, &countryCode)
|
||||
== B_OK; i++) {
|
||||
BCountry country("", countryCode);
|
||||
BString fullName;
|
||||
country.GetName(fullName);
|
||||
typedef std::map<BString, TimeZoneListItem*, TimeZoneItemLess> ZoneItemMap;
|
||||
ZoneItemMap zoneMap;
|
||||
const char* supportedRegions[] = {
|
||||
"Africa", "America", "Antarctica", "Arctic", "Asia", "Atlantic",
|
||||
"Australia", "Etc", "Europe", "Indian", "Pacific", NULL
|
||||
};
|
||||
for (const char** region = supportedRegions; *region != NULL; ++region)
|
||||
zoneMap[*region] = NULL;
|
||||
|
||||
// Now list the timezones for this country
|
||||
BList tzList;
|
||||
BString zoneID;
|
||||
for (int i = 0; zoneList.FindString("timeZone", i, &zoneID) == B_OK; i++) {
|
||||
int32 slashPos = zoneID.FindFirst('/');
|
||||
|
||||
BTimeZone* timeZone;
|
||||
TimeZoneListItem* countryItem;
|
||||
switch (country.GetTimeZones(tzList))
|
||||
{
|
||||
case 0:
|
||||
// No TZ info for this country. Sorry guys!
|
||||
break;
|
||||
case 1:
|
||||
// Only one Timezone, no need to add it to the list
|
||||
timeZone = (BTimeZone*)tzList.ItemAt(0);
|
||||
countryItem
|
||||
= new TimeZoneListItem(fullName, &country, timeZone);
|
||||
fZoneList->AddItem(countryItem);
|
||||
if (timeZone->Code() == defaultTimeZone.Code())
|
||||
fCurrentZoneItem = countryItem;
|
||||
break;
|
||||
default:
|
||||
countryItem = new TimeZoneListItem(fullName, &country, NULL);
|
||||
// ignore any "global" timezones, as those are just aliases of regional
|
||||
// ones
|
||||
if (slashPos <= 0)
|
||||
continue;
|
||||
|
||||
BString region(zoneID, slashPos);
|
||||
|
||||
// just accept timezones from "known" regions, as all others are aliases
|
||||
ZoneItemMap::iterator regionIter = zoneMap.find(region);
|
||||
if (regionIter == zoneMap.end())
|
||||
continue;
|
||||
|
||||
TimeZoneListItem* regionItem = regionIter->second;
|
||||
if (regionItem == NULL) {
|
||||
regionItem = new TimeZoneListItem(region, NULL, NULL);
|
||||
regionItem->SetOutlineLevel(0);
|
||||
regionItem->SetExpanded(false);
|
||||
zoneMap[region] = regionItem;
|
||||
}
|
||||
|
||||
BTimeZone* timeZone = new BTimeZone(zoneID);
|
||||
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;
|
||||
|
||||
// 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);
|
||||
fZoneList->AddItem(countryItem);
|
||||
zoneMap[fullCountryID] = countryItem;
|
||||
} else
|
||||
countryItem = countryIter->second;
|
||||
}
|
||||
|
||||
for (int j = 0;
|
||||
(timeZone = (BTimeZone*)tzList.ItemAt(j)) != NULL;
|
||||
j++) {
|
||||
TimeZoneListItem* tzItem = new TimeZoneListItem(
|
||||
timeZone->Name(), NULL, timeZone);
|
||||
fZoneList->AddUnder(tzItem, countryItem);
|
||||
if (timeZone->Code() == defaultTimeZone.Code())
|
||||
{
|
||||
fCurrentZoneItem = tzItem;
|
||||
countryItem->SetExpanded(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
TimeZoneListItem* zoneItem
|
||||
= new TimeZoneListItem(tzName, NULL, timeZone);
|
||||
zoneItem->SetOutlineLevel(countryItem == NULL ? 1 : 2);
|
||||
zoneMap[fullZoneID] = zoneItem;
|
||||
|
||||
if (timeZone->ID() == defaultTimeZone.ID()) {
|
||||
fCurrentZoneItem = zoneItem;
|
||||
if (countryItem != NULL)
|
||||
countryItem->SetExpanded(true);
|
||||
regionItem->SetExpanded(true);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
fOldZoneItem = fCurrentZoneItem;
|
||||
|
||||
struct ListSorter {
|
||||
static int compare(const BListItem* first, const BListItem* second)
|
||||
{
|
||||
static BCollator collator;
|
||||
return collator.Compare(((BStringItem*)first)->Text(),
|
||||
((BStringItem*)second)->Text());
|
||||
}
|
||||
};
|
||||
fZoneList->SortItemsUnder(NULL, false, ListSorter::compare);
|
||||
ZoneItemMap::iterator zoneIter;
|
||||
for (zoneIter = zoneMap.begin(); zoneIter != zoneMap.end(); ++zoneIter)
|
||||
fZoneList->AddItem(zoneIter->second);
|
||||
|
||||
fZoneList->Select(fZoneList->IndexOf(fCurrentZoneItem));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TimeZoneView::_Revert()
|
||||
{
|
||||
fCurrentZoneItem = fOldZoneItem;
|
||||
|
||||
if (fCurrentZoneItem != NULL) {
|
||||
int32 currentZoneIndex = fZoneList->IndexOf(fCurrentZoneItem);
|
||||
fZoneList->Select(currentZoneIndex);
|
||||
} else
|
||||
fZoneList->DeselectAll();
|
||||
fZoneList->ScrollToSelection();
|
||||
|
||||
_SetSystemTimeZone();
|
||||
_UpdatePreview();
|
||||
_UpdateCurrent();
|
||||
}
|
||||
|
||||
|
||||
@ -315,12 +379,16 @@ void
|
||||
TimeZoneView::_UpdatePreview()
|
||||
{
|
||||
int32 selection = fZoneList->CurrentSelection();
|
||||
if (selection < 0)
|
||||
return;
|
||||
TimeZoneListItem* item
|
||||
= selection < 0
|
||||
? NULL
|
||||
: (TimeZoneListItem*)fZoneList->ItemAt(selection);
|
||||
|
||||
TimeZoneListItem* item = (TimeZoneListItem*)fZoneList->ItemAt(selection);
|
||||
if (!item->HasTimeZone())
|
||||
if (item == NULL || !item->HasTimeZone()) {
|
||||
fPreview->SetText("");
|
||||
fPreview->SetTime("");
|
||||
return;
|
||||
}
|
||||
|
||||
BString timeString = _FormatTime(item);
|
||||
fPreview->SetText(item->Text());
|
||||
@ -360,8 +428,8 @@ TimeZoneView::_SetSystemTimeZone()
|
||||
|
||||
gMutableLocaleRoster->SetDefaultTimeZone(timeZone);
|
||||
|
||||
_kern_set_timezone(timeZone.OffsetFromGMT(), timeZone.Code().String(),
|
||||
timeZone.Code().Length());
|
||||
_kern_set_timezone(timeZone.OffsetFromGMT(), timeZone.ID().String(),
|
||||
timeZone.ID().Length());
|
||||
|
||||
fSetZone->SetEnabled(false);
|
||||
fLastUpdateMinute = -1;
|
||||
|
@ -18,6 +18,7 @@ class BMessage;
|
||||
class BPopUpMenu;
|
||||
class BOutlineListView;
|
||||
class BButton;
|
||||
class BTextToolTip;
|
||||
class TTZDisplay;
|
||||
class TimeZoneListItem;
|
||||
|
||||
@ -31,6 +32,9 @@ public:
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
bool CheckCanRevert();
|
||||
|
||||
protected:
|
||||
virtual bool GetToolTipAt(BPoint point, BToolTip** _tip);
|
||||
|
||||
private:
|
||||
void _UpdateDateTime(BMessage* message);
|
||||
|
||||
@ -41,7 +45,7 @@ private:
|
||||
BString _FormatTime(TimeZoneListItem* zoneItem);
|
||||
|
||||
void _InitView();
|
||||
void _BuildRegionMenu();
|
||||
void _BuildZoneMenu();
|
||||
|
||||
void _Revert();
|
||||
|
||||
@ -51,6 +55,8 @@ private:
|
||||
TTZDisplay* fCurrent;
|
||||
TTZDisplay* fPreview;
|
||||
|
||||
BTextToolTip* fToolTip;
|
||||
|
||||
int32 fLastUpdateMinute;
|
||||
|
||||
TimeZoneListItem* fCurrentZoneItem;
|
||||
|
Loading…
Reference in New Issue
Block a user