diff -r 000000000000 -r 2e3d3ce01487 tzservices/tzloc/src/TzLocalizer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tzservices/tzloc/src/TzLocalizer.cpp Tue Feb 02 10:12:00 2010 +0200 @@ -0,0 +1,1798 @@ +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "TzLocalizer.h" + +#include // For CTzConverter. +#include // For CRepository. + +#include "TzLocalizationSortFunctions.h" +#include "TzLocalizationDbAccessor.h" +#include "TzLocalizationResourceReader.h" +#include "tzlocalizationuserdatareader.h" +#include +#include +/** +Allocates and constructs a new CTzLocalizer object. +@return The newly created CTzLocalizer object. +*/ +EXPORT_C CTzLocalizer* CTzLocalizer::NewL() + { + CTzLocalizer* self = CTzLocalizer::NewLC(); + CleanupStack::Pop(self); + return self; + } + +/** +Allocates and constructs a new CTzLocalizer object. +The pointer to the new object is left on the cleanup stack. +@return The newly created CTzLocalizer object. +*/ +EXPORT_C CTzLocalizer* CTzLocalizer::NewLC() + { + CTzLocalizer* self = new (ELeave) CTzLocalizer(); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +EXPORT_C CTzLocalizer::~CTzLocalizer() + { + delete iStaticDataReader; + delete iUserDataReader; + iTzSession.Close(); + } + +CTzLocalizer::CTzLocalizer() + : iLanguage(User::Language()) + { + iDataSource = ETzDataSourceSystem; + } + +void CTzLocalizer::ConstructL() + { + User::LeaveIfError(iTzSession.Connect()); + + iStaticDataReader = CTzLocalizationResourceReader::NewL(); + iUserDataReader = CTzLocalizationUserDataReader::NewL(iTzSession); + + if (DbNeedsUpdatingL()) + { + TRAP_IGNORE(UpgradeDbVersionL()); + } + + SetDataSource(ETzDataSourceSystem | ETzDataSourceUser); + if(!PrepareFrequentlyUsedZonesL()) + { + // The cached zones DB was not updated using the defaults, so update it + // using the time zone IDs that are already in the DB. This ensures + // that the language of the strings in the cached zone DB is correct on + // construction. + UpdateFrequentlyUsedZonesL(); + } + SetDataSource(ETzDataSourceSystem); + } + +// Check if the DB needs upgrading +TBool CTzLocalizer::DbNeedsUpdatingL() const + { + CTzLocalizationDbAccessor* dbAccessor = CTzLocalizationDbAccessor::NewLC(); + TBool dbNeedsUpdating = dbAccessor->DbNeedsUpdatingL(); + CleanupStack::PopAndDestroy(dbAccessor); + return dbNeedsUpdating; + } + +/** +Allows the client to specify the data source which should be used for +CTzLocalizer methods which can return a combination of system time zone +localization information and user-defined time zone names. + +The following CTzLocalizer methods are affected by the use of this method: + +- GetAllTimeZonesL() +- GetCitiesL() +- GetCitiesInGroupL() +- GetAllCityGroupsL() + +@param aDataSource The data source to use. The permissible values for this +argument are defined by the TTzLocalizerDataSource type. + +@released +*/ +EXPORT_C void CTzLocalizer::SetDataSource(TUint aDataSource) + { + iDataSource = aDataSource; + } + +void CTzLocalizer::UpgradeDbVersionL() + { + // Fetch the cached zones from the old database + CTzLocalizedTimeZoneArray* timeZones = CTzLocalizedTimeZoneArray::NewLC(); + CTzLocalizedCityArray* cities = CTzLocalizedCityArray::NewLC(); + + FetchCityToUpgradeL(*timeZones, *cities, CTzLocalizedTimeZone::ECurrentZone); + FetchCityToUpgradeL(*timeZones, *cities, CTzLocalizedTimeZone::EHomeZone); + FetchCityToUpgradeL(*timeZones, *cities, CTzLocalizedTimeZone::EInterestZone); + + // delete the database and re-create it in the latest format + RecreateDbL(); + + // rewrite the cached zones + for (TInt i = CTzLocalizedTimeZone::ECurrentZone; i <= CTzLocalizedTimeZone::EInterestZone; ++i) + { + SetFrequentlyUsedZoneL(timeZones->At(i), cities->At(i), CTzLocalizedTimeZone::TTzFrequentlyUsedZone(i)); + } + + CleanupStack::PopAndDestroy(cities); + CleanupStack::PopAndDestroy(timeZones); + } + +// This function fetches a cached city and time zone as part of the DB upgrade +void CTzLocalizer::FetchCityToUpgradeL(CTzLocalizedTimeZoneArray& aTimeZoneArray, CTzLocalizedCityArray& aCityArray, CTzLocalizedTimeZone::TTzFrequentlyUsedZone aCachedZone) + { + CTzLocalizedTimeZone* zone = GetFrequentlyUsedZoneL(aCachedZone); + CleanupStack::PushL(zone); + aTimeZoneArray.AppendL(zone); + CleanupStack::Pop(zone); + + CTzLocalizedCity* city = GetFrequentlyUsedZoneCityL(aCachedZone); + CleanupStack::PushL(city); + aCityArray.AppendL(city); + CleanupStack::Pop(city); + + // Find the city from resource file with matched name defined in given "city" and set its city index to "city" + TBool hasFound = FindCityAndSetCityIndexL(*city, ETzDataSourceSystem); + // If not found and user defined data source is considered, find the city from user defined database with matched name defined in given "city" and set its city index to "city" + if (!hasFound && iDataSource&ETzDataSourceUser) + { + FindCityAndSetCityIndexL(*city, ETzDataSourceUser); + } + } + +// Close and delete old DB, and create a new one (in latest version) +void CTzLocalizer::RecreateDbL() + { + CTzLocalizationDbAccessor* dbAccessor = CTzLocalizationDbAccessor::NewLC(); + dbAccessor->RecreateDbL(iTzSession); + CleanupStack::PopAndDestroy(dbAccessor); + } + +/** +Populates the cached zones data in the persisted data writer with the default +values from the time zone server (for the current zone) or the static data +reader for the other zones. +@return ETrue if the cached Zone DB table had to be prepared using the defaults, + EFalse if not. +*/ +TBool CTzLocalizer::PrepareFrequentlyUsedZonesL() + { + CTzLocalizedTimeZoneArray* frequentlyUsedZones = CTzLocalizedTimeZoneArray::NewLC(); + CTzLocalizedCityArray* cachedCities = CTzLocalizedCityArray::NewLC(); + TBool frequentlyUsedZonesNeedUpdating = EFalse; + + // Loop to fill up the frequentlyUsedZones and cachedCities arrays to send to + // WriteAllZonesL(). It also keeps track of whether the update is actually necessary + for(TInt i = CTzLocalizedTimeZone::ECurrentZone; i < CTzLocalizedTimeZone::ECachedTimeZones; ++i) + { + CTzLocalizedTimeZone::TTzFrequentlyUsedZone freqUsedZone = (CTzLocalizedTimeZone::TTzFrequentlyUsedZone)i; + CTzLocalizedTimeZoneRecord* timeZoneRecord = iTzSession.LocalizationReadFrequentlyUsedZoneL(freqUsedZone); + CleanupStack::PushL(timeZoneRecord); + CTzLocalizedTimeZone* timeZone = CreateTimeZoneL(*timeZoneRecord); + CleanupStack::PopAndDestroy(timeZoneRecord); + CleanupStack::PushL(timeZone); + + CTzLocalizedCityRecord* cityRecord = iTzSession.LocalizationReadCachedTimeZoneCityL(freqUsedZone); + CleanupStack::PushL(cityRecord); + CTzLocalizedCity* city = CreateCityL(*cityRecord); + CleanupStack::PopAndDestroy(cityRecord); + CleanupStack::PushL(city); + + // Check if the persisted cached zone is not set yet. + if (timeZone->TimeZoneId() == 0 || city->TimeZoneId() == 0) + { + CleanupStack::PopAndDestroy(city); + city = NULL; + CleanupStack::PopAndDestroy(timeZone); + timeZone = NULL; + + if(freqUsedZone == CTzLocalizedTimeZone::ECurrentZone) + { + TInt id = GetTimeZoneIdFromTzServerL(); + timeZone = GetLocalizedTimeZoneL(id, EFalse); + } + else + { + timeZone = GetFrequentlyUsedDefaultZoneL(freqUsedZone); + } + CleanupStack::PushL(timeZone); + city = ReadDefaultCityL(timeZone->TimeZoneId(), EFalse); + CleanupStack::PushL(city); + frequentlyUsedZonesNeedUpdating = ETrue; + } + + cachedCities->AppendL(city); + // ownership is transferred into the array + CleanupStack::Pop(city); + frequentlyUsedZones->AppendL(timeZone); + // ownership is transferred into the array + CleanupStack::Pop(timeZone); + } + + if (frequentlyUsedZonesNeedUpdating) + { + WriteAllFrequentlyUsedZonesL(*frequentlyUsedZones, *cachedCities); + } + + CleanupStack::PopAndDestroy(cachedCities); + CleanupStack::PopAndDestroy(frequentlyUsedZones); + + return frequentlyUsedZonesNeedUpdating; + } + +/** +Updates the cached zone information in the persisted data writer with the +strings that are currently in static data. +*/ +void CTzLocalizer::UpdateFrequentlyUsedZonesL() + { + CTzLocalizedTimeZoneArray* frequentlyUsedZones = CTzLocalizedTimeZoneArray::NewLC(); + CTzLocalizedCityArray* cachedCities = CTzLocalizedCityArray::NewLC(); + + for(TInt i = CTzLocalizedTimeZone::ECurrentZone; i < CTzLocalizedTimeZone::ECachedTimeZones; ++i) + { + CTzLocalizedTimeZone::TTzFrequentlyUsedZone freqUsedZone = (CTzLocalizedTimeZone::TTzFrequentlyUsedZone)i; + + // Find out what the time zone Id of the cached zone is + CTzLocalizedTimeZoneRecord* timeZoneRecord = iTzSession.LocalizationReadFrequentlyUsedZoneL(freqUsedZone); + TInt timeZoneId = timeZoneRecord->Id(); + delete timeZoneRecord; + + // Update the time zone + CTzLocalizedTimeZone* timeZone = GetLocalizedTimeZoneL(timeZoneId, EFalse); + CleanupStack::PushL(timeZone); + + + // Does the cached city still exist in this time zone? + + // Get all the cities in this cached zone + CTzLocalizedCityArray* citiesInTimeZone = GetCitiesL(*timeZone); + CleanupStack::PushL(citiesInTimeZone); + + TIdentityRelation identity(NTzLocalSortAndFind::FindCityByName); + + // search for the city that was used to set this cached zone + // in the previous language (it might be a user defined city or + // it might have the same name in the new language) + CTzLocalizedCityRecord* cityRecord = iTzSession.LocalizationReadCachedTimeZoneCityL(freqUsedZone); + CleanupStack::PushL(cityRecord); + CTzLocalizedCity* city = CreateCityL(*cityRecord); + CleanupStack::PopAndDestroy(cityRecord); + CleanupStack::PushL(city); + TInt index = citiesInTimeZone->Find(city,identity); + if (index == KErrNotFound) + { + // if city with this name can't be found, use the city with the same index in this time zone group + if (city->CityIndex() >= 0 && city->CityIndex() < citiesInTimeZone->Count()) + { + index = city->CityIndex(); + } + } + CleanupStack::PopAndDestroy(city); + city = NULL; + + if(index != KErrNotFound) + // city still exists in the new language + { + // Point city to array member. + // This ensures all city info is valid + city = &(citiesInTimeZone->At(index)); + // we're taking ownership of this element, so remove it + // from the array + citiesInTimeZone->Remove(index); + } + else + // city not found - use the default city for the zone instead + { + city = ReadDefaultCityL(timeZone->TimeZoneId(), EFalse); + } + + CleanupStack::PopAndDestroy(citiesInTimeZone); + + CleanupStack::PushL(city); + cachedCities->AppendL(city); + CleanupStack::Pop(city); + frequentlyUsedZones->AppendL(timeZone); + CleanupStack::Pop(timeZone); + } + + WriteAllFrequentlyUsedZonesL(*frequentlyUsedZones,*cachedCities); + CleanupStack::PopAndDestroy(cachedCities); + CleanupStack::PopAndDestroy(frequentlyUsedZones); + } + +/** +Get the localized default time zone for the given frequently used time zone. +The default time zone for each of the possible frequently used time zones may be +specified in the TZ Server repository or in the TZ Localization resource file. +Check the possible sources in this order. + +@param aFreqUsedZone The frequently used time zone for which the localized +default time zone is required. + +@return The localized default time zone for the given frequently used time zone. +*/ +CTzLocalizedTimeZone* CTzLocalizer::GetFrequentlyUsedDefaultZoneL(CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFreqUsedZone) + { + // Assume that we will not find the key in the repository or that we do find + // the key but it has no value. If either of these scenarios is true then + // we will use the time zone identifier recorded in the resource file for + // the default time zone. + TBool readFreqUsedZoneFromRscFile = ETrue; + + TUint32 defaultTimeZoneKey = GetFrequentlyUsedDefaultZoneCenRepKeyL(aFreqUsedZone); + TInt defaultTimeZoneId = 0; + + CRepository* tzRepository = CRepository::NewL(NTzUpdate::KPropertyCategory); + CleanupStack::PushL(tzRepository); + TInt err = tzRepository->Get(defaultTimeZoneKey, defaultTimeZoneId); + CleanupStack::PopAndDestroy(tzRepository); + + CTzLocalizedTimeZone* defaultTimeZone = 0; + + // The key may not exist in the repository so this is not an error + // condition. + if(err != KErrNotFound) + { + User::LeaveIfError(err); + + // The key exists - check that it has a value. + if(defaultTimeZoneId != 0) + { + readFreqUsedZoneFromRscFile = EFalse; + defaultTimeZone = iStaticDataReader->ReadTimeZoneL(defaultTimeZoneId); + } + } + + if(readFreqUsedZoneFromRscFile) + { + defaultTimeZone = iStaticDataReader->ReadFrequentlyUsedZoneL(aFreqUsedZone); + } + + return defaultTimeZone; + } + +/** +Get the TZ Server's CenRep repository key for the given frequently used zone. + +@param aFreqUsedZone The frequently used time zone for which the TZ Server's +CenRep repository key is required. + +@return The TZ Server's CenRep repository key for the given frequently used +zone. +*/ +TUint32 CTzLocalizer::GetFrequentlyUsedDefaultZoneCenRepKeyL(CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFreqUsedZone) + { + // These key values are copied from those defined in tzconfigagent.h. We + // want to keep the key values private - this is one way to do it. + const TUint32 KDefaultHomeTimeZoneKey = 0x3UL; + const TUint32 KDefaultInterestTimeZoneKey = 0x4UL; + const TUint32 KDefaultRecent1TimeZoneKey = 0x5UL; + const TUint32 KDefaultRecent2TimeZoneKey = 0x6UL; + + TUint32 key = 0; + + switch(aFreqUsedZone) + { + case CTzLocalizedTimeZone::EHomeZone: + { + key = KDefaultHomeTimeZoneKey; + } + break; + + case CTzLocalizedTimeZone::EInterestZone: + { + key = KDefaultInterestTimeZoneKey; + } + break; + + case CTzLocalizedTimeZone::ERecentZone1: + { + key = KDefaultRecent1TimeZoneKey; + } + break; + + case CTzLocalizedTimeZone::ERecentZone2: + { + key = KDefaultRecent2TimeZoneKey; + } + break; + + default: + { + User::Leave(KErrArgument); + } + } + + return key; + } + +/** +Gets the localized time zone that matches the time zone ID specified. +The calling function takes ownership of the returned localized time zone. +@param aTimeZoneId A positive time zone ID of the localized time zone to return. +@return The localized time zone. +*/ +EXPORT_C CTzLocalizedTimeZone* CTzLocalizer::GetLocalizedTimeZoneL(TInt aTimeZoneId) const + { + return GetLocalizedTimeZoneL(aTimeZoneId, ETrue); + } + +/** +Gets the localized time zone that aCity is a member of. +The calling function takes ownership of the returned localized time zone. +@param aCity Any city in the time zone to return. +@return The localized time zone. +*/ +EXPORT_C CTzLocalizedTimeZone* CTzLocalizer::GetLocalizedTimeZoneL(const CTzLocalizedCity& aCity) const + { + if(IsOperateOnUserDbL(aCity.TzLocalizedId().TimeZoneId(), ETrue)) + { + return iUserDataReader->ReadTimeZoneL(aCity.TzLocalizedId()); + } + else + { + return iStaticDataReader->ReadTimeZoneL(aCity.TzLocalizedId()); + } + } + +/** +Gets an array of all available localizable time zones, sorted according to aSortOrder. +The calling function takes ownership of the returned array. +@param aSortOrder Specifies the sort order of the returned array. +@return Array of all available localizable time zones. +*/ +EXPORT_C CTzLocalizedTimeZoneArray* CTzLocalizer::GetAllTimeZonesL(const TTzSortOrder aSortOrder) + { + CTzLocalizedTimeZoneArray* allTimeZones = CTzLocalizedTimeZoneArray::NewLC(); + if(iDataSource&ETzDataSourceSystem) + { + iStaticDataReader->ReadAllTimeZonesL(*allTimeZones); + } + //User time zones will be appended + if (iDataSource&ETzDataSourceUser) + { + iUserDataReader->ReadAllTimeZonesL(*allTimeZones); + } + + if ((aSortOrder == ETzUTCAscending) || (aSortOrder == ETzUTCDescending)) + { + PrepareForUTCSortL(*allTimeZones); + } + + if (aSortOrder != ETzUnsorted) + { + TLinearOrder sortOrder(TimeZoneSortOrderL(aSortOrder)); + allTimeZones->Sort(sortOrder); + } + + CleanupStack::Pop(allTimeZones); + + return allTimeZones; + } + +/** +Sets the time zone in the time zone server to be that of the +supplied time zone id. The current cached zone is also updated. +@param aTimeZoneId A positive time zone ID of the new time zone. +*/ +EXPORT_C void CTzLocalizer::SetTimeZoneL(TInt aTimeZoneId) + { + SetFrequentlyUsedZoneL(aTimeZoneId, CTzLocalizedTimeZone::ECurrentZone); + } + +/** +Gets the default city for the specified time zone. +The calling function takes ownership of the returned city. +@param aTimeZoneId A positive time zone ID of the default city to return. +@return The default city for the specified time zone. +*/ +EXPORT_C CTzLocalizedCity* CTzLocalizer::GetDefaultCityL(TInt aTimeZoneId) const + { + return ReadDefaultCityL(aTimeZoneId, ETrue); + } + +/** +Gets the default city for the time zone the specified city is a member of. +The calling function takes ownership of the returned city. +@param aCity Any city in the required time zone. +@return The default city. +*/ +EXPORT_C CTzLocalizedCity* CTzLocalizer::GetDefaultCityL(const CTzLocalizedCity& aCity) const + { + return ReadDefaultCityL(aCity.TzLocalizedId().TimeZoneId(), ETrue); + } + +/** +Gets the default city for the specified time zone. +The calling function takes ownership of the returned city. +@param aTimeZone A time zone. +@return The default city for the specified time zone. +*/ +EXPORT_C CTzLocalizedCity* CTzLocalizer::GetDefaultCityL(const CTzLocalizedTimeZone& aTimeZone) const + { + return ReadDefaultCityL(aTimeZone.TzLocalizedId().TimeZoneId(), ETrue); + } + +/** +Returns all cities defined in the static and persisted data. +The calling function takes ownership of the returned array. +@param aSortOrder Specifies the order in which the returned array will be sorted. +It can have one of the following values: ETzUnsorted, ETzUTCAscending, ETzUTCDescending, +ETzAlphaNameAscending, or ETzAlphaNameDescending. +@return Pointer to the array of cities. +*/ +EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesL(const TTzSortOrder aSortOrder) + { + //Create an empty city array and retrieve all cities + CTzLocalizedCityArray* cities = CTzLocalizedCityArray::NewLC(); + if(iDataSource&ETzDataSourceSystem) + { + iStaticDataReader->ReadCitiesL(*cities); + } + if(iDataSource&ETzDataSourceUser) + {//Cities stored in the user tz database will be appended. + iUserDataReader->ReadCitiesL(*cities); + } + RPointerArray cityRecords; + CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray, &cityRecords)); + iTzSession.LocalizationReadCitiesL(cityRecords); + PopulateCityArrayL(cityRecords, *cities); + CleanupStack::PopAndDestroy(); // cityRecords + + if ((aSortOrder == ETzUTCAscending) || (aSortOrder == ETzUTCDescending)) + { + //get utc offset for each city if required + PrepareForUTCSortL(*cities); + } + + if (aSortOrder != ETzUnsorted) + { + TLinearOrder sortOrder(CitySortOrderL(aSortOrder)); + cities->Sort(sortOrder); + } + + CleanupStack::Pop(cities); + return cities; + } + +/** +Gets all the cities defined in the static and persisted data that belong +to the time zone identified by aTimeZoneId. +The calling function takes ownership of the returned array. +@param aTimeZoneId A positive time zone ID that identifies the time zone of +the cities to return. +@param aSortOrder Defines the order in which the returned array will be sorted. +It can have one of the following values: ETzUnsorted, ETzAlphaNameAscending, +ETzAlphaNameDescending. +@leave KErrArgument An invalid sort order is specified. +@return A pointer to the array of cities. +*/ +EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesL(TInt aTimeZoneId, const TTzSortOrder aSortOrder) + { + CTzLocalizedCityArray* cities = CTzLocalizedCityArray::NewLC(); + ReadCitiesL(*cities, aTimeZoneId, ETrue); + + RPointerArray cityRecords; + CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray, &cityRecords)); + iTzSession.LocalizationReadCitiesL(cityRecords, aTimeZoneId); + PopulateCityArrayL(cityRecords, *cities); + CleanupStack::PopAndDestroy(); // cityRecords + + //Only sort alphabetically if requested. + //We have all cities in a time zone, so there is no need to sort by UTC offset + if ((aSortOrder == ETzAlphaNameAscending) || (aSortOrder == ETzAlphaNameDescending)) + { + TLinearOrder sortOrder(CitySortOrderL(aSortOrder)); + cities->Sort(sortOrder); + } + else if(aSortOrder != ETzUnsorted) + { + User::Leave(KErrArgument); + } + + CleanupStack::Pop(cities); + + return cities; + } + +/** +Gets all the cities defined in the static and persisted data that belong to +the same time zone as aCity. +The calling function takes ownership of the returned array. +@param aCity Any city in the desired time zone. +@param aSortOrder Specifies the order in which the returned array will be sorted. +@return A pointer to the array of cities. +*/ +EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesL(const CTzLocalizedCity& aCity,const TTzSortOrder aSortOrder) + { + CTzLocalizedCityArray* cities = CTzLocalizedCityArray::NewLC(); + GetCitiesL(*cities,aCity.TzLocalizedId(),ETrue,aSortOrder); + CleanupStack::Pop(cities); + return cities; + } + +/** +Gets all the cities defined in the static and persisted data that belong to +aTimeZone. +The calling function takes ownership of the array. +@param aTimeZone The required time zone +@param aSortOrder Specifies the order in which the returned array will be sorted +@return A pointer to the array of cities. +*/ +EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesL(const CTzLocalizedTimeZone& aTimeZone, const TTzSortOrder aSortOrder) + { + CTzLocalizedCityArray* cities = CTzLocalizedCityArray::NewLC(); + GetCitiesL(*cities,aTimeZone.TzLocalizedId(),ETrue,aSortOrder); + CleanupStack::Pop(cities); + return cities; + } + +/** +Adds to the specified city array all cities defined in the static and persisted +data that are members of the time zone referenced by aLocalizedId. +@param The array of cities to add the cities to. +@param aLocalizedId A TzLocalizedId identifying a time zone +@param aSortOrder Specifies the order in which the returned array will be +sorted. CTzLocalizedCityArray can take the following sort orders: +ETzUnsorted, ETzAlphaNameAscending, ETzAlphaNameDescending. +@leave KErrArgument An invalid sort order is asked for. +*/ +void CTzLocalizer::GetCitiesL(CTzLocalizedCityArray& aCities, const TTzLocalizedId& aLocalizedId, + TBool aUseDataSource, const TTzSortOrder aSortOrder) + { + ReadCitiesL(aCities, aLocalizedId.TimeZoneId(), aUseDataSource); + + RPointerArray cityRecords; + CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray, &cityRecords)); + iTzSession.LocalizationReadCitiesL(cityRecords, aLocalizedId.TimeZoneId()); + PopulateCityArrayL(cityRecords, aCities); + CleanupStack::PopAndDestroy(); // cityRecords + + //Only sort alphabetically if requested. + //We have all cities in a time zone, so there is no need to sort by UTC offset + if ((aSortOrder == ETzAlphaNameAscending) || (aSortOrder == ETzAlphaNameDescending)) + { + TLinearOrder sortOrder(CitySortOrderL(aSortOrder)); + aCities.Sort(sortOrder); + } + else if(aSortOrder != ETzUnsorted) + { + User::Leave(KErrArgument); + } + } + +/** +Creates a user defined city, specifying the time zone and +optionally the group to which it belongs. +@param aTimeZoneId A positive time zone ID of the city to add. +@param aCityName The name of the city to add. +@param aGroupId The ID of the city group to add the city to. Zero if the city doesn't +belong to a group. Currently supports up to 255 groups +@return The newly created city. The calling function takes ownership. +@leave KErrAlreadyExists The specified city already exists in the time zone. +@leave KErrNotFound aTimeZoneId or aGroupId is not found. +@leave KErrArgument aGroupId is invalid +*/ +EXPORT_C CTzLocalizedCity* CTzLocalizer::AddCityL(TInt aTimeZoneId,const TDesC& aCityName, TInt aGroupId) + { + //Check that aGroupId is a valid TUint8 and leave if not. + //Group number > 255 is not supported + __ASSERT_ALWAYS(aGroupId >= 0 && aGroupId <256 , User::Leave(KErrArgument)); + + // Check that the group exists - this code will leave with + // KErrNotFound if the group does not exist. + // Do not need to check when the gtoup ID is zero as this specifies a groupless city + if(aGroupId != 0) + { + CTzLocalizedCityGroup* group = GetCityGroupL(aGroupId); + delete group; + } + + //Check that the city doesn't exist in this time zone + CTzLocalizedCityArray* staticCityArray = CTzLocalizedCityArray::NewLC(); + ReadCitiesL(*staticCityArray, aTimeZoneId, EFalse); + + TInt count = staticCityArray->Count(); + for (TInt x = 0; x < count; ++x) + { + CTzLocalizedCity& city = staticCityArray->At(x); + if (aCityName == city.Name()) + { + User::Leave(KErrAlreadyExists); + } + } + // Copy the TzLocalizedID (timezoneID/resourceId pair) for these cities to + // put in the new city + TTzLocalizedId localizedId(staticCityArray->At(0).TzLocalizedId()); + CleanupStack::PopAndDestroy(staticCityArray); + + //City doesn't exist - we can try and add it + CTzLocalizedCity* newCity = CTzLocalizedCity::NewLC(aCityName,localizedId,(TUint8)aGroupId); + + //WriteCityL checks to see if a city with the same Time Zone ID + //is already in the persisted cities, while adding the city. + iTzSession.LocalizationWriteCityL(newCity->Name(), (TInt)newCity->TimeZoneId(), newCity->GroupId(), + newCity->TzLocalizedId().ResourceId()); + CleanupStack::Pop(newCity); + return newCity; + } + +/** +Removes a city from the user defined city collection. +The calling function loses ownership of aCity. +@param aCity The city to remove. +*/ +EXPORT_C void CTzLocalizer::RemoveCityL(CTzLocalizedCity* aCity) + { + if(aCity) + { + CleanupStack::PushL(aCity); + iTzSession.LocalizationDeleteCityL(aCity->Name(), aCity->TimeZoneId()); + CleanupStack::PopAndDestroy(aCity); + } + else + { + User::Leave(KErrArgument); + } + } + +/** +Gets a list of all the existing city groups. +The calling function takes ownership of the returned array. +@param aSortOrder Specifies the order in which the returned array will be +sorted. Possible values are ETzAlphaNameAscending or ETzAlphaNameDescending. +@return Array of all existing city groups. +*/ +EXPORT_C CTzLocalizedCityGroupArray* CTzLocalizer::GetAllCityGroupsL(const TTzSortOrder aSortOrder) const + { + CTzLocalizedCityGroupArray* cityGroups = CTzLocalizedCityGroupArray::NewLC(); + if(iDataSource&ETzDataSourceSystem) + { + iStaticDataReader->ReadAllGroupsL(*cityGroups); + } + if(iDataSource&ETzDataSourceUser) + { + iUserDataReader->ReadAllGroupsL(*cityGroups); + } + + if (aSortOrder == ETzAlphaNameAscending) + { + TLinearOrder order(NTzLocalSortAndFind::SortCityGroupNameAscending); + cityGroups->Sort(order); + } + else if (aSortOrder == ETzAlphaNameDescending) + { + TLinearOrder order(NTzLocalSortAndFind::SortCityGroupNameDescending); + cityGroups->Sort(order); + } + CleanupStack::Pop(cityGroups); + return cityGroups; + } + +/** +Gets the city group with the specified ID. +The calling function takes ownership of the returned CTzLocalizedCityGroup. +@param aGroupId The ID of the city group to get. +@return The matching city group. +@leave KErrArgument aGroupId is invalid +*/ +EXPORT_C CTzLocalizedCityGroup* CTzLocalizer::GetCityGroupL(TInt aGroupId) const + { + //Check that aGroupId is a valid TUint8 and leave if not. + //Group number > 255 is not supported + __ASSERT_ALWAYS(aGroupId >= 0 && aGroupId <256 , User::Leave(KErrArgument)); + return iStaticDataReader->ReadGroupL((TUint8)aGroupId); + } + +/** +Gets the city group to which the specified city belongs. +The calling function takes ownership of the returned CTzLocalizedCityGroup. +@param aCity Any city in the required city group. +@return The city group. +*/ +EXPORT_C CTzLocalizedCityGroup* CTzLocalizer::GetCityGroupL(const CTzLocalizedCity& aCity) const + { + return iStaticDataReader->ReadGroupL(aCity.GroupId()); + } + +/** +Returns all cities defined in the static and persisted data that are members +of the group with the specified group ID. +The calling function takes ownership of the array. +@param aGroupId The group ID. +@param aSortOrder Specifies the order in which the returned array will be sorted. +The following sort orders are supported: ETzUnsorted, ETzUTCAscending, ETzUTCDescending, +ETzAlphaNameAscending, ETzAlphaNameDescending. +@return Pointer to the array of cities. +@leave KErrArgument aGroupId is invalid +*/ +EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesInGroupL(TInt aGroupId,const TTzSortOrder aSortOrder) + { + //Check that aGroupId is a valid TUint8 and leave if not. + //Group number > 255 is not supported + __ASSERT_ALWAYS(aGroupId >= 0 && aGroupId <256 , User::Leave(KErrArgument)); + + CTzLocalizedCityArray* cities = CTzLocalizedCityArray::NewLC(); + + if(iDataSource&ETzDataSourceSystem) + { + iStaticDataReader->ReadCitiesInGroupL(*cities,(TUint8)aGroupId); + } + if(aGroupId == KTzCityNotInGroupId && iDataSource&ETzDataSourceUser) + {//All user time zone are groupless + iUserDataReader->ReadCitiesInGroupL(*cities, KTzCityNotInGroupId); + } + + RPointerArray cityRecords; + CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray, &cityRecords)); + iTzSession.LocalizationReadCitiesInGroupL(cityRecords, (TUint8)aGroupId); + PopulateCityArrayL(cityRecords, *cities); + CleanupStack::PopAndDestroy(); // cityRecords + + if ((aSortOrder == ETzUTCAscending) || (aSortOrder == ETzUTCDescending)) + { + PrepareForUTCSortL(*cities); + } + + if (aSortOrder != ETzUnsorted) + { + TLinearOrder sortOrder(CitySortOrderL(aSortOrder)); + cities->Sort(sortOrder); + } + CleanupStack::Pop(cities); + return cities; + } + +/** +Returns all cities defined in the static and persisted data that are members +of the same group as the specified city. +The calling function takes ownership of the array. +@param aCity Any city in the desired city group. +@param aSortOrder Specifies the order in which the returned array will be sorted. +The following sort orders are supported: ETzUnsorted, ETzUTCAscending, ETzUTCDescending, +ETzAlphaNameAscending, ETzAlphaNameDescending. +@return Pointer to an array of cities. +*/ +EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesInGroupL(const CTzLocalizedCity& aCity,const TTzSortOrder aSortOrder) + { + return GetCitiesInGroupL(aCity.GroupId(),aSortOrder); + } + +/** +Returns all cities defined in the static and persisted data that are members +of the specified city group. +The calling function takes ownership of the array. +@param aCityGroup The city group of interest. +@param aSortOrder Specifies the order in which the returned array will be sorted. +The following sort orders are supported: ETzUnsorted, ETzUTCAscending, +ETzUTCDescending, ETzAlphaNameAscending, ETzAlphaNameDescending. +@return Pointer to an array of cities. +*/ +EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesInGroupL(const CTzLocalizedCityGroup& aCityGroup,const TTzSortOrder aSortOrder) + { + return GetCitiesInGroupL(aCityGroup.Id(),aSortOrder); + } + +/** +Gets the cached time zone identified by aFrequentlyUsedZone. +The calling function takes ownership of the returned zone. +When retrieving the current zone (CTzLocalizedTimeZone::ECurrentZone), the time zone +server is queried to make sure that the system's current time zone has not been updated +since the current zone was cached. +If the system's time zone has been updated, the new localised zone is stored in the database. +@param aFrequentlyUsedZone Identifies the cached zone to return. +@return The cached zone. +*/ +EXPORT_C CTzLocalizedTimeZone* CTzLocalizer::GetFrequentlyUsedZoneL(const CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFrequentlyUsedZone) + { + CTzLocalizedTimeZone* timeZone; + + if (aFrequentlyUsedZone == CTzLocalizedTimeZone::ECurrentZone) + { + //Get cached current zone + CTzLocalizedTimeZoneRecord* frequentlyUsedZoneRecord = iTzSession.LocalizationReadFrequentlyUsedZoneL(aFrequentlyUsedZone); + CleanupStack::PushL(frequentlyUsedZoneRecord); + CTzLocalizedTimeZone* frequentlyUsedZone = CreateTimeZoneL(*frequentlyUsedZoneRecord); + CleanupStack::PopAndDestroy(frequentlyUsedZoneRecord); + CleanupStack::PushL(frequentlyUsedZone); + + TInt currentTimeZoneId = GetTimeZoneIdFromTzServerL(); + if (frequentlyUsedZone->TimeZoneId() != currentTimeZoneId) + { + //Current timezone has changed. Set the current zone in the cache and return it + CTzLocalizedTimeZone* currentZone = GetLocalizedTimeZoneL(currentTimeZoneId, EFalse); + CleanupStack::PushL(currentZone); + timeZone = currentZone; + + CTzLocalizedCity* city = ReadDefaultCityL(timeZone->TimeZoneId(), EFalse); + CleanupStack::PushL(city); + SetFrequentlyUsedZoneL(*timeZone, *city, CTzLocalizedTimeZone::ECurrentZone); + CleanupStack::PopAndDestroy(city); + + CleanupStack::Pop(currentZone); + CleanupStack::PopAndDestroy(frequentlyUsedZone); + frequentlyUsedZone = NULL; + } + else + { + //Return the cached zone. + timeZone = frequentlyUsedZone; + CleanupStack::Pop(frequentlyUsedZone); + frequentlyUsedZone = NULL; + } + } + + else + { + CTzLocalizedTimeZoneRecord* timeZoneRecord = iTzSession.LocalizationReadFrequentlyUsedZoneL(aFrequentlyUsedZone); + CleanupStack::PushL(timeZoneRecord); + timeZone = CreateTimeZoneL(*timeZoneRecord); + CleanupStack::PopAndDestroy(timeZoneRecord); + } + + return timeZone; + } + +/** +Retrieves the integer time zone ID of the current time zone from the time zone +server (app-services/Tz). +@return The integer time zone ID according to the time zone server. +*/ +TInt CTzLocalizer::GetTimeZoneIdFromTzServerL() + { + // Get current time zone using the current CTzId from the time zone server + CTzId* currentCTzId = iTzSession.GetTimeZoneIdL(); + CleanupStack::PushL(currentCTzId); + + TUint timeZoneIdInt = currentCTzId->TimeZoneNumericID(); + + CleanupStack::PopAndDestroy(currentCTzId); + + // Is the time zone ID the unknown/invalid ID? + // This is temporary measure that is required until PREQ 234' TzServer + // changes are introduced + const TUint32 KUnknownTZId = 0x0ffffff0; + if((TUint32)timeZoneIdInt == KUnknownTZId) + { + // Return the ID of the DEFAULT home zone instead + CTzLocalizedTimeZone* homeZone = iStaticDataReader->ReadFrequentlyUsedZoneL(CTzLocalizedTimeZone::EHomeZone); + CleanupStack::PushL(homeZone); + timeZoneIdInt = homeZone->TimeZoneId(); + CleanupStack::PopAndDestroy(homeZone); + } + + return timeZoneIdInt; + } + +/** +Gets the city that was used to set the specified cached time zone. +The calling function takes ownership of the returned city. +If a city was not used to set the cached zone, the default +city for the zone is returned. +@param aFrequentlyUsedZone Indicates one of the five cached zones. +@return The city used to set the cached zone. +*/ +EXPORT_C CTzLocalizedCity* CTzLocalizer::GetFrequentlyUsedZoneCityL(const CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFrequentlyUsedZone) + { + CTzLocalizedCityRecord* cityRecord = iTzSession.LocalizationReadCachedTimeZoneCityL(aFrequentlyUsedZone); + CleanupStack::PushL(cityRecord); + CTzLocalizedCity* city = CreateCityL(*cityRecord); + CleanupStack::PopAndDestroy(cityRecord); + + // check that the city contains valid information + if(city->TimeZoneId() == 0) + // if not, get of the default cached zone's default city from the static reader + { + delete city; + city = NULL; + + if(aFrequentlyUsedZone != CTzLocalizedTimeZone::ECurrentZone) + { + city = iStaticDataReader->ReadCachedTimeZoneCityL(aFrequentlyUsedZone); + } + else + { + // use GetFrequentlyUsedZoneL(), because it deals with the current zone correctly + CTzLocalizedTimeZone* defaultFrequentlyUsedZone = GetFrequentlyUsedZoneL(aFrequentlyUsedZone); + CleanupStack::PushL(defaultFrequentlyUsedZone); + // then get the city + city = ReadDefaultCityL(defaultFrequentlyUsedZone->TimeZoneId(), EFalse); + CleanupStack::PopAndDestroy(defaultFrequentlyUsedZone); + } + } + else + { + if(aFrequentlyUsedZone == CTzLocalizedTimeZone::ECurrentZone) + { + CleanupStack::PushL(city); + CTzLocalizedTimeZone* timeZone = GetLocalizedTimeZoneL(*city, EFalse); + TUint16 tzId = timeZone->TimeZoneId(); + delete timeZone; + CTzLocalizedTimeZone* currentTimeZone = GetFrequentlyUsedZoneL(CTzLocalizedTimeZone::ECurrentZone); + TUint16 currentTzId = currentTimeZone->TimeZoneId(); + delete currentTimeZone; + if (tzId != currentTzId) + { + CleanupStack::PopAndDestroy(city); + city = NULL; + city = ReadDefaultCityL(currentTzId, EFalse); + } + else + { + CleanupStack::Pop(city); + } + } + + } + + return city; + } + +/** +Sets the ID of the specified cached time zone. +@param aTimeZoneId A positive time zone ID to assign to aFrequentlyUsedZone. Must not +be zero or the function leaves with KErrArgument. +@param aFrequentlyUsedZone Identifies the cached zone whose ID will be set. This must be +either CTzLocalizedTimeZone::ECurrentZone, CTzLocalizedTimeZone::EHomeZone or +CTzLocalizedTimeZone::EInterestZone, or the function leaves with KErrArgument. +N.B. When the current zone is set, the time zone of the device is altered. +*/ +EXPORT_C void CTzLocalizer::SetFrequentlyUsedZoneL(TInt aTimeZoneId,const CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFrequentlyUsedZone) + { + // The time zone ID must be a non-zero number to be valid + __ASSERT_ALWAYS(aTimeZoneId > 0, User::Leave(KErrArgument)); + CTzLocalizedTimeZone* aTimeZone = GetLocalizedTimeZoneL(aTimeZoneId, EFalse); + CleanupStack::PushL(aTimeZone); + SetFrequentlyUsedZoneL(*aTimeZone,aFrequentlyUsedZone); + CleanupStack::PopAndDestroy(aTimeZone); + } + +/** +Sets the value of the specified cached time zone. +@param aTimeZone The value to assign to aFrequentlyUsedZone. It must have an ID greater +than zero or the function leaves with KErrArgument. +@param aFrequentlyUsedZone Identifies the cached zone whose ID will be set. This must be +either CTzLocalizedTimeZone::ECurrentZone, CTzLocalizedTimeZone::EHomeZone or +CTzLocalizedTimeZone::EInterestZone, or the function leaves with KErrArgument. +N.B. When the current zone is set, the time zone of the device is altered. +*/ +EXPORT_C void CTzLocalizer::SetFrequentlyUsedZoneL(const CTzLocalizedTimeZone& aTimeZone, const CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFrequentlyUsedZone) + { + // The time zone ID must be a non-zero number to be valid + __ASSERT_ALWAYS(aTimeZone.TimeZoneId() > 0, User::Leave(KErrArgument)); + CTzLocalizedCity* city = ReadDefaultCityL(aTimeZone.TimeZoneId(), EFalse); + CleanupStack::PushL(city); + // Update the time zone server, if the current zone is being updated + if(aFrequentlyUsedZone == CTzLocalizedTimeZone::ECurrentZone) + { + DoSetTimeZoneL(aTimeZone.TimeZoneId()); + } + else if(aFrequentlyUsedZone == CTzLocalizedTimeZone::EHomeZone) + { + ChangeHomeTimeZoneL(aTimeZone.TimeZoneId()); + } + SetFrequentlyUsedZoneL(aTimeZone, *city, aFrequentlyUsedZone); + CleanupStack::PopAndDestroy(city); + } + +/** +Sets the value of the specified cached zone to be the zone which aCity +is located in. +Setting a cached zone by city also stores the city used to select the time zone. +@param aCity Any city in the time zone to set. It must have a time zone ID greater +than zero or the function leaves with KErrArgument. +@param aFrequentlyUsedZone Indicates which of the cached zones to set. This must be +either CTzLocalizedTimeZone::ECurrentZone, CTzLocalizedTimeZone::EHomeZone or +CTzLocalizedTimeZone::EInterestZone, or the function leaves with KErrArgument. +N.B. When the current zone is set, the time zone of the device is altered. +*/ +EXPORT_C void CTzLocalizer::SetFrequentlyUsedZoneL(const CTzLocalizedCity& aCity,const CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFrequentlyUsedZone) + { + // The time zone ID must be a non-zero number to be valid + __ASSERT_ALWAYS(aCity.TimeZoneId() > 0, User::Leave(KErrArgument)); + CTzLocalizedTimeZone* timeZone = GetLocalizedTimeZoneL(aCity, EFalse); + CleanupStack::PushL(timeZone); + // Update the time zone server, if the current zone is being updated + if(aFrequentlyUsedZone == CTzLocalizedTimeZone::ECurrentZone) + { + DoSetTimeZoneL(aCity.TimeZoneId()); + } + else if(aFrequentlyUsedZone == CTzLocalizedTimeZone::EHomeZone) + { + ChangeHomeTimeZoneL(timeZone->TimeZoneId()); + } + SetFrequentlyUsedZoneL(*timeZone, aCity, aFrequentlyUsedZone); + CleanupStack::PopAndDestroy(timeZone); + } + +void CTzLocalizer::ChangeHomeTimeZoneL(TInt aNewId) + { + NTzUpdate::TTimeZoneChange change; + change.iNewTimeZoneId = aNewId; + CTzLocalizedTimeZoneRecord* oldTz = iTzSession.LocalizationReadFrequentlyUsedZoneL(CTzLocalizedTimeZone::EHomeZone); + change.iOldTimeZoneId = oldTz->Id(); + delete oldTz; // don't need to put on cleanup stack because previous line can't leave + + RTz tz; + User::LeaveIfError(tz.Connect()); + CleanupClosePushL(tz); + tz.NotifyHomeTimeZoneChangedL(change); + CleanupStack::PopAndDestroy(&tz); + } + +/** +Set the time zone in the time zone server to be that of the +supplied time zone id +@param aTimeZoneId The time zone id of the new time zone. +@internalTechnology +*/ +void CTzLocalizer::DoSetTimeZoneL(TInt aTimeZoneId) + { + // Create a new CTzId with the new time zone ID in it + CTzId* newCTzId = CTzId::NewL(aTimeZoneId); + CleanupStack::PushL(newCTzId); + + //Connect to time zone server + RTz tz; + User::LeaveIfError(tz.Connect()); + CleanupClosePushL(tz); + + tz.SetTimeZoneL(*newCTzId); + + CleanupStack::PopAndDestroy(); //tz + CleanupStack::PopAndDestroy(newCTzId); + } + +/** +Prepares a CTzLocalizedTimeZoneArray or CTzLocalizedCityArray for sorting by UTC offset. +All array elements which have not already had the UTC offset set will retrieve the +correct offset from App-Services/Tz. +@param aArray +@internalTechnology +*/ +template +void CTzLocalizer::PrepareForUTCSortL(T& aArray) + { + //Prepare an array of timezone IDs to give to the time zone server + RArray timeZoneIds; + CleanupClosePushL(timeZoneIds); + TInt i; + TInt count = aArray.Count(); + for(i=0; i utcOffsets; + CleanupClosePushL(utcOffsets); + + //Connect to Time Zone Server + RTz tz; + User::LeaveIfError(tz.Connect()); + CleanupClosePushL(tz); + + // Pass the arrays to tz - the time zone server will populate the array + // of UTC Offsets based using the array of Time Zone IDs + tz.GetOffsetsForTimeZoneIdsL(timeZoneIds, utcOffsets); + + //Finished with Time Zone Server + CleanupStack::PopAndDestroy(); //tz + + // copy the utc offsets from one array to the other + for(i=0; i 0) + // A non-zero Time Zone ID has been supplied, so search through the cities within that Time Zone. + { + citiesToSearch = GetCitiesL(aTimeZoneId); + } + else + // Search through all cities + { + citiesToSearch= GetCitiesL(); + } + + TIdentityRelation identity(NTzLocalSortAndFind::FindCityByName); + + TInt index = citiesToSearch->Find(aCity,identity); + + if (index != KErrNotFound) + { + foundCity = &(citiesToSearch->At(index)); + // ownership is transferred to calling function + // we don't want this pointer deleted when the array is + citiesToSearch->Remove(index); + } + else + { + foundCity = NULL; + } + + CleanupStack::PopAndDestroy(aCity); + + delete citiesToSearch; + citiesToSearch = NULL; + + return foundCity; + } +/** +Searches for a time zone with the specified name. +All text fields of the time zone are searched. +@param aTimeZoneName the name of the time zone to search for. +@return If successful, a pointer to a CTzLocalizedTimeZone. +The calling function takes ownership of the returned pointer. +If the search string is not found, NULL is returned. +*/ +EXPORT_C CTzLocalizedTimeZone* CTzLocalizer::FindTimeZoneByNameL(const TDesC& aTimeZoneName) + { + CTzLocalizedTimeZone* foundTimeZone; + //Create a dummy time zone for the search + TTzLocalizedId id(0, 0); + CTzLocalizedTimeZone* timeZone = CTzLocalizedTimeZone::NewLC(id,aTimeZoneName,aTimeZoneName,aTimeZoneName,aTimeZoneName); + //Get all the time zones + CTzLocalizedTimeZoneArray* allTimeZones = GetAllTimeZonesL(); + + TIdentityRelation identity(NTzLocalSortAndFind::FindTimeZoneByName); + + TInt index = allTimeZones->Find(timeZone,identity); + + if (index != KErrNotFound) + { + foundTimeZone = &(allTimeZones->At(index)); + allTimeZones->Remove(index); + } + else + { + foundTimeZone = NULL; + } + + CleanupStack::PopAndDestroy(timeZone); + + delete allTimeZones; + allTimeZones = NULL; + + return foundTimeZone; + } + +/** +Searches for a city group with the specified name. +@param aCityGroupName The name of the city group to search for. +@return If successful, a pointer to a CTzLocalizedCityGroup. +The calling function takes ownership of the returned pointer. +If the search string is not found, NULL is returned. +*/ +EXPORT_C CTzLocalizedCityGroup* CTzLocalizer::FindCityGroupByNameL(const TDesC& aCityGroupName) + { + CTzLocalizedCityGroup* foundCityGroup; + //Create a dummy city group for the search + CTzLocalizedCityGroup* aCityGroup = CTzLocalizedCityGroup::NewLC(aCityGroupName,0); + //Get all the city groups + CTzLocalizedCityGroupArray* allCityGroups = GetAllCityGroupsL(); + + TIdentityRelation identity(NTzLocalSortAndFind::FindCityGroupByName); + + TInt index = allCityGroups->Find(aCityGroup,identity); + + if (index != KErrNotFound) + { + foundCityGroup = &(allCityGroups->At(index)); + allCityGroups->Remove(index); + } + else + { + foundCityGroup = NULL; + } + + CleanupStack::PopAndDestroy(aCityGroup); + + delete allCityGroups; + allCityGroups = NULL; + + return foundCityGroup; + } + +/** +Tests whether the language of the loaded static data is still correct. If it +is not, the static data is reloaded. +Method could leave while creating a data reader. +@return ETrue if the system language (as returned by User::Language()) has changed, +EFalse if it has not. +@see User::Language() +*/ +EXPORT_C TBool CTzLocalizer::CheckLanguage() + { + TBool languageChange = (iLanguage != User::Language()); + + if(languageChange) + // the language has changed - reload the static data and repopulate the + // cached zones database + { + iLanguage = User::Language(); + delete iStaticDataReader; + iStaticDataReader = 0; + iStaticDataReader = CTzLocalizationResourceReader::NewL(); // Method could leave while creating a data reader + UpdateFrequentlyUsedZonesL(); + } + + return languageChange; + } + +/** +Returns all cities defined in the static and persisted data that have +the specified UTC offset. +The calling function takes ownership of the array. +@param aUTCOffsetInMinutes The offset in minutes. +@param aSortOrder Specifies the order in which the returned array will be sorted. +Only ETzUnsorted, ETzAlphaNameAscending and ETzAlphaNameDescending will have any effect, +as all elements in the returned array will have the same UTC offset. +@return Pointer to the array of cities. +*/ +EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesWithUTCOffsetL(TInt aUTCOffsetInMinutes, const TTzSortOrder aSortOrder) + { + //Fetch all the cities sorted by UTC offset + CTzLocalizedCityArray* allCities = GetCitiesL(ETzUTCAscending); + TInt count = allCities->Count(); + + CTzLocalizedCity* city; + for (TInt x = count-1; x >= 0; --x) + { + city = &(allCities->At(x)); + if (city->UTCOffset() != aUTCOffsetInMinutes) + { + allCities->Remove(x); + delete city; + } + } + + //Only sort the city array alphabetically if requested + if ((aSortOrder == ETzAlphaNameAscending) | (aSortOrder == ETzAlphaNameDescending)) + { + TLinearOrder sortOrder(CitySortOrderL(aSortOrder)); + allCities->Sort(sortOrder); + } + + return allCities; + } +/** +Returns all the time zones defined in the static data that have +the specified UTC offset. +The calling function takes ownership of the array. +@param aUTCOffsetInMinutes The UTC offset in minutes. +@param aSortOrder Specifies the order in which the returned array will be sorted. +Sort orders ETzUTCAscending and ETzUTCDescending will not have any effect +as all elements in the returned array will have the same UTC offset. +@return Pointer to the array of time zones. +*/ +EXPORT_C CTzLocalizedTimeZoneArray* CTzLocalizer::GetTimeZonesWithUTCOffsetL(TInt aUTCOffsetInMinutes, const TTzSortOrder aSortOrder) + { + //Fetch all the time zones sorted by UTC offset + CTzLocalizedTimeZoneArray* allTimeZones = GetAllTimeZonesL(ETzUTCAscending); + TInt count = allTimeZones->Count(); + + CTzLocalizedTimeZone* timeZone; + for (TInt x = count-1; x >= 0; --x) + { + timeZone = &(allTimeZones->At(x)); + if (timeZone->UTCOffset() != aUTCOffsetInMinutes) + { + allTimeZones->Remove(x); + delete timeZone; + } + } + + //Only sort the time zone array alphabetically if requested + if ((aSortOrder != ETzAlphaNameAscending) && (aSortOrder > ETzUTCDescending)) + { + TLinearOrder sortOrder(TimeZoneSortOrderL(aSortOrder)); + allTimeZones->Sort(sortOrder); + } + return allTimeZones; + } +/** +Gets the correct TLinearOrder to sort by. +@param aSortOrder +@return the TLinearOrder to sort by +@internalTechnology +*/ +TLinearOrder CTzLocalizer::CitySortOrderL(const TTzSortOrder aSortOrder) + { + + TLinearOrder sortOrder(NTzLocalSortAndFind::SortCityUTCAscending); + + switch (aSortOrder) + { + case ETzUTCAscending: + { + //Sort order already set + } + break; + + case ETzUTCDescending: + { + sortOrder = TLinearOrder(NTzLocalSortAndFind::SortCityUTCDescending); + } + break; + + case ETzAlphaNameAscending: + { + sortOrder = TLinearOrder(NTzLocalSortAndFind::SortCityNameAscending); + } + break; + + case ETzAlphaNameDescending: + { + sortOrder = TLinearOrder(NTzLocalSortAndFind::SortCityNameDescending); + } + break; + + case ETzAlphaStandardNameAscending: //FALL THROUGH - these aren't supported + case ETzAlphaDaylightNameAscending: + case ETzAlphaShortStandardNameAscending: + case ETzAlphaShortDaylightNameAscending: + case ETzAlphaStandardNameDescending: + case ETzAlphaDaylightNameDescending: + case ETzAlphaShortStandardNameDescending: + case ETzAlphaShortDaylightNameDescending: + default: + { + User::Leave(KErrArgument); + } + } + return sortOrder; + } +/** +Gets the correct TLinearOrder to sort by +@param aSortOrder +@return the TLinearOrder to sort by +@internalTechnology +*/ +TLinearOrder CTzLocalizer::TimeZoneSortOrderL(const TTzSortOrder aSortOrder) + { + TLinearOrder sortOrder(NTzLocalSortAndFind::SortUTCAscending); + + switch (aSortOrder) + { + case ETzUTCAscending: + { + // Sort order already set + } + break; + + case ETzUTCDescending: + { + sortOrder = TLinearOrder(NTzLocalSortAndFind::SortUTCDescending); + } + break; + + case ETzAlphaNameAscending: //Standard Name + case ETzAlphaStandardNameAscending: + { + sortOrder = TLinearOrder(NTzLocalSortAndFind::SortAlphaStdNameAscending); + } + break; + + case ETzAlphaDaylightNameAscending: + { + sortOrder = TLinearOrder(NTzLocalSortAndFind::SortAlphaDSTNameAscending); + } + break; + + case ETzAlphaShortStandardNameAscending: + { + sortOrder = TLinearOrder(NTzLocalSortAndFind::SortAlphaShortStdNameAscending); + } + break; + + case ETzAlphaShortDaylightNameAscending: + { + sortOrder = TLinearOrder(NTzLocalSortAndFind::SortAlphaShortDSTNameAscending); + } + break; + + case ETzAlphaNameDescending: //Standard Name + case ETzAlphaStandardNameDescending: + { + sortOrder = TLinearOrder(NTzLocalSortAndFind::SortAlphaStdNameDescending); + } + break; + + case ETzAlphaDaylightNameDescending: + { + sortOrder = TLinearOrder(NTzLocalSortAndFind::SortAlphaDSTNameDescending); + } + break; + + case ETzAlphaShortStandardNameDescending: + { + sortOrder = TLinearOrder(NTzLocalSortAndFind::SortAlphaShortStdNameDescending); + } + break; + + case ETzAlphaShortDaylightNameDescending: + { + sortOrder = TLinearOrder(NTzLocalSortAndFind::SortAlphaShortDSTNameDescending); + } + break; + + default: + { + User::Leave(KErrArgument); + } + } + return sortOrder; + } + +/* Find the city matching the name defined in aLocalizedCity and set its city index to aLocalizedCity +@param aLocalizedCity A CTzLocalizedCity object +@param aDataSource A data source flag +@return Return ETrue if the city has been found, otherwise EFalse. + */ +TBool CTzLocalizer::FindCityAndSetCityIndexL(CTzLocalizedCity& aLocalizedCity, TTzLocalizerDataSource aDataSource) + { + TBool hasFound = EFalse; + CTzLocalizedCityArray* citiesInDb = CTzLocalizedCityArray::NewLC(); + if(aDataSource == ETzDataSourceSystem) + { + iStaticDataReader->ReadCitiesL(*citiesInDb); + } + else + { + iUserDataReader->ReadCitiesL(*citiesInDb); + } + + TInt KCityCount = citiesInDb->Count(); + for (TInt i = 0; i < KCityCount; ++i) + { + if (citiesInDb->At(i).Name() == aLocalizedCity.Name()) + { + aLocalizedCity.SetCityIndex(citiesInDb->At(i).CityIndex()); + hasFound = ETrue; + break; + } + } + CleanupStack::PopAndDestroy(citiesInDb); + return hasFound; + } + +TBool CTzLocalizer::IsOperateOnUserDbL(TInt aTimeZoneId, TBool aUseDataSource) const + { + TBool userDbOperation = EFalse; + if (iDataSource&ETzDataSourceUser || !aUseDataSource) + { + CTzId* tzid = CTzId::NewL(aTimeZoneId); + userDbOperation = tzid->IsUserTzId(); + delete tzid; + } + return userDbOperation; + } + +void CTzLocalizer::ReadCitiesL(CTzLocalizedCityArray& aCityArray, TInt aTimeZoneId, TBool aUseDataSource) const + { + if (IsOperateOnUserDbL(aTimeZoneId, aUseDataSource)) + { + iUserDataReader->ReadCitiesL(aCityArray, aTimeZoneId); + } + else if (iDataSource&ETzDataSourceSystem) + { + iStaticDataReader->ReadCitiesL(aCityArray, aTimeZoneId); + } + } + +CTzLocalizedCity* CTzLocalizer::ReadDefaultCityL(TInt aTimeZoneId, TBool aUseDataSource) const + { + if (IsOperateOnUserDbL(aTimeZoneId, aUseDataSource)) + { + return iUserDataReader->ReadDefaultCityL(aTimeZoneId); + } + else if(iDataSource&ETzDataSourceSystem) + { + return iStaticDataReader->ReadDefaultCityL(aTimeZoneId); + } + return NULL; + } + +/** +Sets all the cached zones and their associated cities to be those that are +supplied. +@param aTimeZones Array of time zones to be written. +@param aCities Array of cities to be written. +@internalTechnology +*/ +void CTzLocalizer::WriteAllFrequentlyUsedZonesL(const CTzLocalizedTimeZoneArray& aTimeZones, const CTzLocalizedCityArray& aCities) + { + // Ensure that the numbers of items in the arrays are the expected amount + __ASSERT_ALWAYS(aTimeZones.Count() == CTzLocalizedTimeZone::ECachedTimeZones && + aCities.Count() == CTzLocalizedTimeZone::ECachedTimeZones, User::Leave(KErrArgument)); + + RPointerArray timeZones; + CleanupStack::PushL(TCleanupItem(CleanupTimeZonePointerArray,&timeZones)); + TInt i = 0; + TInt end = aTimeZones.Count(); + timeZones.ReserveL(end); + while (i < end) + { + CTzLocalizedTimeZoneRecord* newTimeZone = CreateTimeZoneRecordL(aTimeZones.At(i)); + timeZones.Append(newTimeZone); + ++i; + } + + RPointerArray cities; + CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray,&cities)); + i = 0; + end = aCities.Count(); + cities.ReserveL(end); + while (i < end) + { + CTzLocalizedCityRecord* newCity = CreateCityRecordL(aCities.At(i)); + cities.Append(newCity); + ++i; + } + + iTzSession.LocalizationWriteAllFrequentlyUsedZonesL(timeZones, cities); + + CleanupStack::PopAndDestroy(); // cities + CleanupStack::PopAndDestroy(); // timeZones + } + +void CTzLocalizer::SetFrequentlyUsedZoneL(const CTzLocalizedTimeZone& aTimeZone, const CTzLocalizedCity& aCity, + const CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFrequentlyUsedZone) + { + CTzLocalizedTimeZoneRecord* timeZoneRecord = CreateTimeZoneRecordLC(aTimeZone); + CTzLocalizedCityRecord* cityRecord = CreateCityRecordLC(aCity); + iTzSession.LocalizationWriteFrequentlyUsedZoneL(*timeZoneRecord, *cityRecord, aFrequentlyUsedZone); + CleanupStack::PopAndDestroy(cityRecord); + CleanupStack::PopAndDestroy(timeZoneRecord); + } + +CTzLocalizedTimeZone* CTzLocalizer::GetLocalizedTimeZoneL(TInt aTimeZoneId, TBool aUseDataSource) const + { + if (IsOperateOnUserDbL(aTimeZoneId, aUseDataSource)) + { + return iUserDataReader->ReadTimeZoneL(aTimeZoneId); + } + else + { + return iStaticDataReader->ReadTimeZoneL(aTimeZoneId); + } + } + +CTzLocalizedTimeZone* CTzLocalizer::GetLocalizedTimeZoneL(const CTzLocalizedCity& aCity, TBool aUseDataSource) const + { + if(IsOperateOnUserDbL(aCity.TzLocalizedId().TimeZoneId(), aUseDataSource)) + { + return iUserDataReader->ReadTimeZoneL(aCity.TzLocalizedId()); + } + else + { + return iStaticDataReader->ReadTimeZoneL(aCity.TzLocalizedId()); + } + } + +void CTzLocalizer::PopulateCityArrayL(const RPointerArray& aCityRecords, + CTzLocalizedCityArray& aCities) + { + TInt i = 0; + TInt end = aCityRecords.Count(); + aCities.ReserveL(aCities.Count() + end); + while (i < end) + { + CTzLocalizedCityRecord* record = aCityRecords[i]; + TTzLocalizedId id(record->TzId(), record->TzResourceId()); + CTzLocalizedCity* city = CTzLocalizedCity::NewL(record->Name(), id, record->GroupId()); + city->SetCityIndex(record->Index()); + aCities.AppendL(city); // Won't leave since we have reserved the necessary space + ++i; + } + } + +CTzLocalizedTimeZoneRecord* CTzLocalizer::CreateTimeZoneRecordL(const CTzLocalizedTimeZone& aTimeZone) + { + return CTzLocalizedTimeZoneRecord::NewL(aTimeZone.TimeZoneId(), aTimeZone.StandardName(), + aTimeZone.DaylightName(), aTimeZone.ShortStandardName(), aTimeZone.ShortDaylightName(), + aTimeZone.TzLocalizedId().ResourceId()); + } + +CTzLocalizedTimeZoneRecord* CTzLocalizer::CreateTimeZoneRecordLC(const CTzLocalizedTimeZone& aTimeZone) + { + return CTzLocalizedTimeZoneRecord::NewLC(aTimeZone.TimeZoneId(), aTimeZone.StandardName(), + aTimeZone.DaylightName(), aTimeZone.ShortStandardName(), aTimeZone.ShortDaylightName(), + aTimeZone.TzLocalizedId().ResourceId()); + } + +CTzLocalizedCityRecord* CTzLocalizer::CreateCityRecordL(const CTzLocalizedCity& aCity) + { + return CTzLocalizedCityRecord::NewL(aCity.Name(), aCity.GroupId(), aCity.CityIndex(), + aCity.TimeZoneId(), aCity.TzLocalizedId().ResourceId()); + } + +CTzLocalizedCityRecord* CTzLocalizer::CreateCityRecordLC(const CTzLocalizedCity& aCity) + { + return CTzLocalizedCityRecord::NewLC(aCity.Name(), aCity.GroupId(), aCity.CityIndex(), + aCity.TimeZoneId(), aCity.TzLocalizedId().ResourceId()); + } + +CTzLocalizedTimeZone* CTzLocalizer::CreateTimeZoneL(const CTzLocalizedTimeZoneRecord& aTimeZoneRecord) + { + TTzLocalizedId id(aTimeZoneRecord.Id(), aTimeZoneRecord.ResourceId()); + return CTzLocalizedTimeZone::NewL(id, aTimeZoneRecord.StandardName(), + aTimeZoneRecord.DaylightName(), aTimeZoneRecord.ShortStandardName(), + aTimeZoneRecord.ShortDaylightName()); + } + +CTzLocalizedCity* CTzLocalizer::CreateCityL(const CTzLocalizedCityRecord& aCityRecord) + { + TTzLocalizedId tzId(aCityRecord.TzId(), aCityRecord.TzResourceId()); + CTzLocalizedCity* city = CTzLocalizedCity::NewL(aCityRecord.Name(), tzId, aCityRecord.GroupId()); + city->SetCityIndex(aCityRecord.Index()); + return city; + } + +void CTzLocalizer::CleanupTimeZonePointerArray(TAny* aArray) + { + RPointerArray* array = static_cast* >(aArray); + if (array) + { + array->ResetAndDestroy(); + array->Close(); + } + } + +void CTzLocalizer::CleanupCityPointerArray(TAny* aArray) + { + RPointerArray* array = static_cast* >(aArray); + if (array) + { + array->ResetAndDestroy(); + array->Close(); + } + }