tzservices/tzloc/src/TzLocalizer.cpp
changeset 0 2e3d3ce01487
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "TzLocalizer.h"
       
    17 
       
    18 #include <tzconverter.h>					// For CTzConverter.
       
    19 #include <centralrepository.h>				// For CRepository.
       
    20 
       
    21 #include "TzLocalizationSortFunctions.h"
       
    22 #include "TzLocalizationDbAccessor.h"
       
    23 #include "TzLocalizationResourceReader.h"
       
    24 #include "tzlocalizationuserdatareader.h"
       
    25 #include <tzlocalizedtimezonerecord.h>
       
    26 #include <tzlocalizedcityrecord.h>
       
    27 /**
       
    28 Allocates and constructs a new CTzLocalizer object.
       
    29 @return The newly created CTzLocalizer object.
       
    30 */
       
    31 EXPORT_C CTzLocalizer* CTzLocalizer::NewL()
       
    32 	{
       
    33 	CTzLocalizer* self = CTzLocalizer::NewLC();
       
    34 	CleanupStack::Pop(self);
       
    35 	return self;
       
    36 	}
       
    37 
       
    38 /**
       
    39 Allocates and constructs a new CTzLocalizer object.
       
    40 The pointer to the new object is left on the cleanup stack.
       
    41 @return The newly created CTzLocalizer object.
       
    42 */
       
    43 EXPORT_C CTzLocalizer* CTzLocalizer::NewLC()
       
    44 	{
       
    45 	CTzLocalizer* self = new (ELeave) CTzLocalizer();
       
    46 	CleanupStack::PushL(self);
       
    47 	self->ConstructL();
       
    48 	return self;
       
    49 	}
       
    50 
       
    51 EXPORT_C CTzLocalizer::~CTzLocalizer()
       
    52 	{
       
    53 	delete iStaticDataReader;
       
    54 	delete iUserDataReader;
       
    55 	iTzSession.Close();
       
    56 	}
       
    57 
       
    58 CTzLocalizer::CTzLocalizer()
       
    59 	: iLanguage(User::Language())
       
    60 	{
       
    61 	iDataSource = ETzDataSourceSystem;
       
    62 	}
       
    63 
       
    64 void CTzLocalizer::ConstructL()
       
    65 	{
       
    66 	User::LeaveIfError(iTzSession.Connect());
       
    67 
       
    68 	iStaticDataReader = CTzLocalizationResourceReader::NewL();
       
    69    	iUserDataReader	= CTzLocalizationUserDataReader::NewL(iTzSession);
       
    70 
       
    71 	if (DbNeedsUpdatingL())
       
    72 		{
       
    73         TRAP_IGNORE(UpgradeDbVersionL());
       
    74 		}
       
    75 
       
    76 	SetDataSource(ETzDataSourceSystem | ETzDataSourceUser);
       
    77 	if(!PrepareFrequentlyUsedZonesL())
       
    78 		{
       
    79 		// The cached zones DB was not updated using the defaults, so update it
       
    80 		// using the time zone IDs that are already in the DB.  This ensures
       
    81 		// that the language of the strings in the cached zone DB is correct on
       
    82 		// construction.
       
    83 		UpdateFrequentlyUsedZonesL();
       
    84 		}
       
    85 	SetDataSource(ETzDataSourceSystem);
       
    86 	}
       
    87 
       
    88 // Check if the DB needs upgrading
       
    89 TBool CTzLocalizer::DbNeedsUpdatingL() const
       
    90     {
       
    91     CTzLocalizationDbAccessor* dbAccessor = CTzLocalizationDbAccessor::NewLC();
       
    92     TBool dbNeedsUpdating = dbAccessor->DbNeedsUpdatingL();
       
    93     CleanupStack::PopAndDestroy(dbAccessor);
       
    94     return dbNeedsUpdating;
       
    95     }
       
    96 
       
    97 /**
       
    98 Allows the client to specify the data source which should be used for
       
    99 CTzLocalizer methods which can return a combination of system time zone
       
   100 localization information and user-defined time zone names.
       
   101 
       
   102 The following CTzLocalizer methods are affected by the use of this method:
       
   103 
       
   104 - GetAllTimeZonesL()
       
   105 - GetCitiesL()
       
   106 - GetCitiesInGroupL()
       
   107 - GetAllCityGroupsL()
       
   108 
       
   109 @param aDataSource The data source to use.  The permissible values for this
       
   110 argument are defined by the TTzLocalizerDataSource type.
       
   111 
       
   112 @released
       
   113 */
       
   114 EXPORT_C  void CTzLocalizer::SetDataSource(TUint aDataSource)
       
   115 	{
       
   116 	iDataSource = aDataSource;
       
   117 	}
       
   118 
       
   119 void CTzLocalizer::UpgradeDbVersionL()
       
   120     {
       
   121     // Fetch the cached zones from the old database
       
   122     CTzLocalizedTimeZoneArray* timeZones = CTzLocalizedTimeZoneArray::NewLC();
       
   123     CTzLocalizedCityArray* cities = CTzLocalizedCityArray::NewLC();
       
   124 
       
   125     FetchCityToUpgradeL(*timeZones, *cities, CTzLocalizedTimeZone::ECurrentZone);
       
   126     FetchCityToUpgradeL(*timeZones, *cities, CTzLocalizedTimeZone::EHomeZone);
       
   127     FetchCityToUpgradeL(*timeZones, *cities, CTzLocalizedTimeZone::EInterestZone);
       
   128 
       
   129     // delete the database and re-create it in the latest format
       
   130     RecreateDbL();
       
   131 
       
   132     // rewrite the cached zones
       
   133     for (TInt i = CTzLocalizedTimeZone::ECurrentZone; i <= CTzLocalizedTimeZone::EInterestZone; ++i)
       
   134         {
       
   135         SetFrequentlyUsedZoneL(timeZones->At(i), cities->At(i), CTzLocalizedTimeZone::TTzFrequentlyUsedZone(i));
       
   136         }
       
   137 
       
   138     CleanupStack::PopAndDestroy(cities);
       
   139     CleanupStack::PopAndDestroy(timeZones);
       
   140     }
       
   141 
       
   142 // This function fetches a cached city and time zone as part of the DB upgrade
       
   143 void CTzLocalizer::FetchCityToUpgradeL(CTzLocalizedTimeZoneArray& aTimeZoneArray, CTzLocalizedCityArray& aCityArray, CTzLocalizedTimeZone::TTzFrequentlyUsedZone aCachedZone)
       
   144     {
       
   145     CTzLocalizedTimeZone* zone = GetFrequentlyUsedZoneL(aCachedZone);
       
   146     CleanupStack::PushL(zone);
       
   147     aTimeZoneArray.AppendL(zone);
       
   148     CleanupStack::Pop(zone);
       
   149 
       
   150     CTzLocalizedCity* city = GetFrequentlyUsedZoneCityL(aCachedZone);
       
   151     CleanupStack::PushL(city);
       
   152     aCityArray.AppendL(city);
       
   153     CleanupStack::Pop(city);
       
   154 
       
   155     //  Find the city from resource file with matched name defined in given "city" and set its city index to "city"
       
   156     TBool hasFound = FindCityAndSetCityIndexL(*city, ETzDataSourceSystem);
       
   157     //  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"
       
   158     if (!hasFound && iDataSource&ETzDataSourceUser)
       
   159 	   {
       
   160 	   FindCityAndSetCityIndexL(*city, ETzDataSourceUser);
       
   161 	   }
       
   162    }
       
   163 
       
   164 // Close and delete old DB, and create a new one (in latest version)
       
   165 void CTzLocalizer::RecreateDbL()
       
   166     {
       
   167     CTzLocalizationDbAccessor* dbAccessor = CTzLocalizationDbAccessor::NewLC();
       
   168     dbAccessor->RecreateDbL(iTzSession);
       
   169     CleanupStack::PopAndDestroy(dbAccessor);
       
   170     }
       
   171 
       
   172 /**
       
   173 Populates the cached zones data in the persisted data writer with the default
       
   174 values from the time zone server (for the current zone) or the static data
       
   175 reader for the other zones.
       
   176 @return ETrue if the cached Zone DB table had to be prepared using the defaults,
       
   177 		EFalse if not.
       
   178 */
       
   179 TBool CTzLocalizer::PrepareFrequentlyUsedZonesL()
       
   180 	{
       
   181 	CTzLocalizedTimeZoneArray* frequentlyUsedZones = CTzLocalizedTimeZoneArray::NewLC();
       
   182 	CTzLocalizedCityArray* cachedCities = CTzLocalizedCityArray::NewLC();
       
   183 	TBool frequentlyUsedZonesNeedUpdating = EFalse;
       
   184 
       
   185 	// Loop to fill up the frequentlyUsedZones and cachedCities arrays to send to
       
   186 	// WriteAllZonesL().  It also keeps track of whether the update is actually necessary
       
   187 	for(TInt i = CTzLocalizedTimeZone::ECurrentZone; i < CTzLocalizedTimeZone::ECachedTimeZones; ++i)
       
   188 		{
       
   189 		CTzLocalizedTimeZone::TTzFrequentlyUsedZone freqUsedZone = (CTzLocalizedTimeZone::TTzFrequentlyUsedZone)i;
       
   190 		CTzLocalizedTimeZoneRecord* timeZoneRecord = iTzSession.LocalizationReadFrequentlyUsedZoneL(freqUsedZone);
       
   191 		CleanupStack::PushL(timeZoneRecord);
       
   192 		CTzLocalizedTimeZone* timeZone = CreateTimeZoneL(*timeZoneRecord);
       
   193 		CleanupStack::PopAndDestroy(timeZoneRecord);
       
   194 		CleanupStack::PushL(timeZone);
       
   195 
       
   196 		CTzLocalizedCityRecord* cityRecord = iTzSession.LocalizationReadCachedTimeZoneCityL(freqUsedZone);
       
   197 		CleanupStack::PushL(cityRecord);
       
   198 		CTzLocalizedCity* city = CreateCityL(*cityRecord);
       
   199 		CleanupStack::PopAndDestroy(cityRecord);
       
   200 		CleanupStack::PushL(city);
       
   201 
       
   202 		// Check if the persisted cached zone is not set yet.
       
   203 		if (timeZone->TimeZoneId() == 0 || city->TimeZoneId() == 0)
       
   204 			{
       
   205 			CleanupStack::PopAndDestroy(city);
       
   206 			city = NULL;
       
   207 			CleanupStack::PopAndDestroy(timeZone);
       
   208 			timeZone = NULL;
       
   209 
       
   210 			if(freqUsedZone == CTzLocalizedTimeZone::ECurrentZone)
       
   211 				{
       
   212 				TInt id = GetTimeZoneIdFromTzServerL();
       
   213 				timeZone = GetLocalizedTimeZoneL(id, EFalse);
       
   214 				}
       
   215 			else
       
   216 				{
       
   217 				timeZone = GetFrequentlyUsedDefaultZoneL(freqUsedZone);
       
   218 				}
       
   219 			CleanupStack::PushL(timeZone);
       
   220 			city = ReadDefaultCityL(timeZone->TimeZoneId(), EFalse);
       
   221 			CleanupStack::PushL(city);
       
   222 			frequentlyUsedZonesNeedUpdating = ETrue;
       
   223 			}
       
   224 
       
   225 		cachedCities->AppendL(city);
       
   226 		// ownership is transferred into the array
       
   227 		CleanupStack::Pop(city);
       
   228 		frequentlyUsedZones->AppendL(timeZone);
       
   229 		// ownership is transferred into the array
       
   230 		CleanupStack::Pop(timeZone);
       
   231 		}
       
   232 
       
   233 	if (frequentlyUsedZonesNeedUpdating)
       
   234 		{
       
   235 		WriteAllFrequentlyUsedZonesL(*frequentlyUsedZones, *cachedCities);
       
   236 		}
       
   237 
       
   238 	CleanupStack::PopAndDestroy(cachedCities);
       
   239 	CleanupStack::PopAndDestroy(frequentlyUsedZones);
       
   240 
       
   241 	return frequentlyUsedZonesNeedUpdating;
       
   242 	}
       
   243 
       
   244 /**
       
   245 Updates the cached zone information in the persisted data writer with the
       
   246 strings that are currently in static data.
       
   247 */
       
   248 void CTzLocalizer::UpdateFrequentlyUsedZonesL()
       
   249 	{
       
   250 	CTzLocalizedTimeZoneArray* frequentlyUsedZones = CTzLocalizedTimeZoneArray::NewLC();
       
   251 	CTzLocalizedCityArray* cachedCities = CTzLocalizedCityArray::NewLC();
       
   252 
       
   253 	for(TInt i = CTzLocalizedTimeZone::ECurrentZone; i < CTzLocalizedTimeZone::ECachedTimeZones; ++i)
       
   254 		{
       
   255 		CTzLocalizedTimeZone::TTzFrequentlyUsedZone freqUsedZone = (CTzLocalizedTimeZone::TTzFrequentlyUsedZone)i;
       
   256 
       
   257 		// Find out what the time zone Id of the cached zone is
       
   258 		CTzLocalizedTimeZoneRecord* timeZoneRecord = iTzSession.LocalizationReadFrequentlyUsedZoneL(freqUsedZone);
       
   259 		TInt timeZoneId = timeZoneRecord->Id();
       
   260 		delete timeZoneRecord;
       
   261 
       
   262 		// Update the time zone
       
   263 		CTzLocalizedTimeZone* timeZone = GetLocalizedTimeZoneL(timeZoneId, EFalse);
       
   264 		CleanupStack::PushL(timeZone);
       
   265 
       
   266 
       
   267 		// Does the cached city still exist in this time zone?
       
   268 
       
   269 		// Get all the cities in this cached zone
       
   270 		CTzLocalizedCityArray* citiesInTimeZone = GetCitiesL(*timeZone);
       
   271 		CleanupStack::PushL(citiesInTimeZone);
       
   272 
       
   273 		TIdentityRelation<CTzLocalizedCity> identity(NTzLocalSortAndFind::FindCityByName);
       
   274 
       
   275 		// search for the city that was used to set this cached zone
       
   276 		// in the previous language (it might be a user defined city or
       
   277 		// it might have the same name in the new language)
       
   278 		CTzLocalizedCityRecord* cityRecord = iTzSession.LocalizationReadCachedTimeZoneCityL(freqUsedZone);
       
   279 		CleanupStack::PushL(cityRecord);
       
   280 		CTzLocalizedCity* city = CreateCityL(*cityRecord);
       
   281 		CleanupStack::PopAndDestroy(cityRecord);
       
   282 		CleanupStack::PushL(city);
       
   283 		TInt index = citiesInTimeZone->Find(city,identity);
       
   284         if (index == KErrNotFound)
       
   285             {
       
   286             // if city with this name can't be found, use the city with the same index in this time zone group
       
   287             if (city->CityIndex() >= 0 && city->CityIndex() < citiesInTimeZone->Count())
       
   288                 {
       
   289                 index = city->CityIndex();
       
   290                 }
       
   291             }
       
   292 		CleanupStack::PopAndDestroy(city);
       
   293 		city = NULL;
       
   294 
       
   295 		if(index != KErrNotFound)
       
   296 		// city still exists in the new language
       
   297 			{
       
   298 			// Point city to array member.
       
   299 			// This ensures all city info is valid
       
   300 			city = &(citiesInTimeZone->At(index));
       
   301 			// we're taking ownership of this element, so remove it
       
   302 			// from the array
       
   303 			citiesInTimeZone->Remove(index);
       
   304 			}
       
   305 		else
       
   306 		// city not found - use the default city for the zone instead
       
   307 			{
       
   308 			city = ReadDefaultCityL(timeZone->TimeZoneId(), EFalse);
       
   309 			}
       
   310 
       
   311 		CleanupStack::PopAndDestroy(citiesInTimeZone);
       
   312 
       
   313 		CleanupStack::PushL(city);
       
   314 		cachedCities->AppendL(city);
       
   315 		CleanupStack::Pop(city);
       
   316 		frequentlyUsedZones->AppendL(timeZone);
       
   317 		CleanupStack::Pop(timeZone);
       
   318 		}
       
   319 
       
   320 	WriteAllFrequentlyUsedZonesL(*frequentlyUsedZones,*cachedCities);
       
   321 	CleanupStack::PopAndDestroy(cachedCities);
       
   322 	CleanupStack::PopAndDestroy(frequentlyUsedZones);
       
   323 	}
       
   324 
       
   325 /**
       
   326 Get the localized default time zone for the given frequently used time zone.
       
   327 The default time zone for each of the possible frequently used time zones may be
       
   328 specified in the TZ Server repository or in the TZ Localization resource file.
       
   329 Check the possible sources in this order.
       
   330 
       
   331 @param aFreqUsedZone The frequently used time zone for which the localized
       
   332 default time zone is required.
       
   333 
       
   334 @return The localized default time zone for the given frequently used time zone.
       
   335 */
       
   336 CTzLocalizedTimeZone* CTzLocalizer::GetFrequentlyUsedDefaultZoneL(CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFreqUsedZone)
       
   337 	{
       
   338 	// Assume that we will not find the key in the repository or that we do find
       
   339 	// the key but it has no value.  If either of these scenarios is true then
       
   340 	// we will use the time zone identifier recorded in the resource file for
       
   341 	// the default time zone.
       
   342 	TBool readFreqUsedZoneFromRscFile = ETrue;
       
   343 	
       
   344 	TUint32 defaultTimeZoneKey = GetFrequentlyUsedDefaultZoneCenRepKeyL(aFreqUsedZone);
       
   345 	TInt defaultTimeZoneId = 0;
       
   346 
       
   347 	CRepository* tzRepository = CRepository::NewL(NTzUpdate::KPropertyCategory);
       
   348 	CleanupStack::PushL(tzRepository);
       
   349 	TInt err = tzRepository->Get(defaultTimeZoneKey, defaultTimeZoneId);
       
   350 	CleanupStack::PopAndDestroy(tzRepository);
       
   351 	
       
   352 	CTzLocalizedTimeZone* defaultTimeZone = 0;
       
   353 	
       
   354 	// The key may not exist in the repository so this is not an error
       
   355 	// condition.
       
   356 	if(err != KErrNotFound)
       
   357 		{
       
   358 		User::LeaveIfError(err);
       
   359 
       
   360 		// The key exists - check that it has a value.
       
   361 		if(defaultTimeZoneId != 0)
       
   362 			{
       
   363 			readFreqUsedZoneFromRscFile = EFalse;
       
   364 			defaultTimeZone = iStaticDataReader->ReadTimeZoneL(defaultTimeZoneId);
       
   365 			}
       
   366 		}
       
   367 
       
   368 	if(readFreqUsedZoneFromRscFile)
       
   369 		{
       
   370 		defaultTimeZone = iStaticDataReader->ReadFrequentlyUsedZoneL(aFreqUsedZone);
       
   371 		}
       
   372 
       
   373 	return defaultTimeZone;
       
   374 	}
       
   375 
       
   376 /**
       
   377 Get the TZ Server's CenRep repository key for the given frequently used zone.
       
   378 
       
   379 @param aFreqUsedZone The frequently used time zone for which the TZ Server's
       
   380 CenRep repository key is required.
       
   381 
       
   382 @return The TZ Server's CenRep repository key for the given frequently used
       
   383 zone.
       
   384 */
       
   385 TUint32 CTzLocalizer::GetFrequentlyUsedDefaultZoneCenRepKeyL(CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFreqUsedZone)
       
   386 	{
       
   387 	// These key values are copied from those defined in tzconfigagent.h.  We
       
   388 	// want to keep the key values private - this is one way to do it.
       
   389 	const TUint32 KDefaultHomeTimeZoneKey = 0x3UL;
       
   390 	const TUint32 KDefaultInterestTimeZoneKey = 0x4UL;
       
   391 	const TUint32 KDefaultRecent1TimeZoneKey = 0x5UL;
       
   392 	const TUint32 KDefaultRecent2TimeZoneKey = 0x6UL;
       
   393 
       
   394 	TUint32 key = 0;
       
   395 
       
   396 	switch(aFreqUsedZone)
       
   397 	    {
       
   398 	    case CTzLocalizedTimeZone::EHomeZone:
       
   399 	    	{
       
   400 	    	key = KDefaultHomeTimeZoneKey;
       
   401 	        }
       
   402 	    break;
       
   403 
       
   404 	    case CTzLocalizedTimeZone::EInterestZone:
       
   405 	    	{
       
   406 	    	key = KDefaultInterestTimeZoneKey;
       
   407 	        }
       
   408 	    break;
       
   409 
       
   410 	    case CTzLocalizedTimeZone::ERecentZone1:
       
   411 	    	{
       
   412 	    	key = KDefaultRecent1TimeZoneKey;
       
   413 	        }
       
   414 	    break;
       
   415 
       
   416 	    case CTzLocalizedTimeZone::ERecentZone2:
       
   417 	    	{
       
   418 	    	key = KDefaultRecent2TimeZoneKey;
       
   419 	        }
       
   420 	    break;
       
   421 	    
       
   422 	    default:
       
   423 	    	{
       
   424 	    	User::Leave(KErrArgument);
       
   425 	    	}
       
   426 	    }
       
   427 
       
   428 	return key;
       
   429     }
       
   430 
       
   431 /**
       
   432 Gets the localized time zone that matches the time zone ID specified.
       
   433 The calling function takes ownership of the returned localized time zone.
       
   434 @param aTimeZoneId A positive time zone ID of the localized time zone to return.
       
   435 @return The localized time zone.
       
   436 */
       
   437 EXPORT_C CTzLocalizedTimeZone* CTzLocalizer::GetLocalizedTimeZoneL(TInt aTimeZoneId) const
       
   438 	{
       
   439 	return GetLocalizedTimeZoneL(aTimeZoneId, ETrue);
       
   440 	}
       
   441 
       
   442 /**
       
   443 Gets the localized time zone that aCity is a member of.
       
   444 The calling function takes ownership of the returned localized time zone.
       
   445 @param aCity Any city in the time zone to return.
       
   446 @return The localized time zone.
       
   447 */
       
   448 EXPORT_C CTzLocalizedTimeZone* CTzLocalizer::GetLocalizedTimeZoneL(const CTzLocalizedCity& aCity) const
       
   449 	{
       
   450 	if(IsOperateOnUserDbL(aCity.TzLocalizedId().TimeZoneId(), ETrue))
       
   451 		{
       
   452 		return iUserDataReader->ReadTimeZoneL(aCity.TzLocalizedId());
       
   453 		}
       
   454 	else
       
   455 		{
       
   456 		return iStaticDataReader->ReadTimeZoneL(aCity.TzLocalizedId());
       
   457 		}
       
   458 	}
       
   459 
       
   460 /**
       
   461 Gets an array of all available localizable time zones, sorted according to aSortOrder.
       
   462 The calling function takes ownership of the returned array.
       
   463 @param aSortOrder Specifies the sort order of the returned array.
       
   464 @return Array of all available localizable time zones.
       
   465 */
       
   466 EXPORT_C CTzLocalizedTimeZoneArray* CTzLocalizer::GetAllTimeZonesL(const TTzSortOrder aSortOrder)
       
   467 	{
       
   468 	CTzLocalizedTimeZoneArray* allTimeZones = CTzLocalizedTimeZoneArray::NewLC();
       
   469 	if(iDataSource&ETzDataSourceSystem)
       
   470 		{
       
   471 		iStaticDataReader->ReadAllTimeZonesL(*allTimeZones);
       
   472 		}
       
   473 	//User time zones will be appended
       
   474 	if (iDataSource&ETzDataSourceUser)
       
   475 		{
       
   476 		iUserDataReader->ReadAllTimeZonesL(*allTimeZones);
       
   477 		}
       
   478 
       
   479 	if ((aSortOrder == ETzUTCAscending) || (aSortOrder == ETzUTCDescending))
       
   480 		{
       
   481 		PrepareForUTCSortL(*allTimeZones);
       
   482 		}
       
   483 
       
   484 	if (aSortOrder != ETzUnsorted)
       
   485 		{
       
   486 		TLinearOrder<CTzLocalizedTimeZone> sortOrder(TimeZoneSortOrderL(aSortOrder));
       
   487 		allTimeZones->Sort(sortOrder);
       
   488 		}
       
   489 
       
   490 	CleanupStack::Pop(allTimeZones);
       
   491 
       
   492 	return allTimeZones;
       
   493 	}
       
   494 
       
   495 /**
       
   496 Sets the time zone in the time zone server to be that of the
       
   497 supplied time zone id.  The current cached zone is also updated.
       
   498 @param aTimeZoneId A positive time zone ID of the new time zone.
       
   499 */
       
   500 EXPORT_C void CTzLocalizer::SetTimeZoneL(TInt aTimeZoneId)
       
   501 	{
       
   502 	SetFrequentlyUsedZoneL(aTimeZoneId, CTzLocalizedTimeZone::ECurrentZone);
       
   503 	}
       
   504 
       
   505 /**
       
   506 Gets the default city for the specified time zone.
       
   507 The calling function takes ownership of the returned city.
       
   508 @param aTimeZoneId A positive time zone ID of the default city to return.
       
   509 @return The default city for the specified time zone.
       
   510 */
       
   511 EXPORT_C CTzLocalizedCity* CTzLocalizer::GetDefaultCityL(TInt aTimeZoneId) const
       
   512 	{
       
   513 	return ReadDefaultCityL(aTimeZoneId, ETrue);
       
   514 	}
       
   515 
       
   516 /**
       
   517 Gets the default city for the time zone the specified city is a member of.
       
   518 The calling function takes ownership of the returned city.
       
   519 @param aCity Any city in the required time zone.
       
   520 @return The default city.
       
   521 */
       
   522 EXPORT_C CTzLocalizedCity* CTzLocalizer::GetDefaultCityL(const CTzLocalizedCity& aCity) const
       
   523 	{
       
   524 	return ReadDefaultCityL(aCity.TzLocalizedId().TimeZoneId(), ETrue);
       
   525 	}
       
   526 
       
   527 /**
       
   528 Gets the default city for the specified time zone.
       
   529 The calling function takes ownership of the returned city.
       
   530 @param aTimeZone A time zone.
       
   531 @return The default city for the specified time zone.
       
   532 */
       
   533 EXPORT_C CTzLocalizedCity* CTzLocalizer::GetDefaultCityL(const CTzLocalizedTimeZone& aTimeZone) const
       
   534 	{
       
   535 	return ReadDefaultCityL(aTimeZone.TzLocalizedId().TimeZoneId(), ETrue);
       
   536 	}
       
   537 
       
   538 /**
       
   539 Returns all cities defined in the static and persisted data.
       
   540 The calling function takes ownership of the returned array.
       
   541 @param aSortOrder Specifies the order in which the returned array will be sorted.
       
   542 It can have one of the following values: ETzUnsorted, ETzUTCAscending, ETzUTCDescending,
       
   543 ETzAlphaNameAscending, or ETzAlphaNameDescending.
       
   544 @return Pointer to the array of cities.
       
   545 */
       
   546 EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesL(const TTzSortOrder aSortOrder)
       
   547 	{
       
   548 	//Create an empty city array and retrieve all cities
       
   549 	CTzLocalizedCityArray* cities = CTzLocalizedCityArray::NewLC();
       
   550 	if(iDataSource&ETzDataSourceSystem)
       
   551 		{
       
   552 		iStaticDataReader->ReadCitiesL(*cities);
       
   553 		}
       
   554 	if(iDataSource&ETzDataSourceUser)
       
   555 		{//Cities stored in the user tz database will be appended.
       
   556 		iUserDataReader->ReadCitiesL(*cities);
       
   557 		}
       
   558 	RPointerArray<CTzLocalizedCityRecord> cityRecords;
       
   559 	CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray, &cityRecords));
       
   560 	iTzSession.LocalizationReadCitiesL(cityRecords);
       
   561 	PopulateCityArrayL(cityRecords, *cities);
       
   562 	CleanupStack::PopAndDestroy();	// cityRecords
       
   563 
       
   564 	if ((aSortOrder == ETzUTCAscending) || (aSortOrder == ETzUTCDescending))
       
   565 		{
       
   566 		//get utc offset for each city if required
       
   567 		PrepareForUTCSortL(*cities);
       
   568 		}
       
   569 
       
   570 	if (aSortOrder != ETzUnsorted)
       
   571 		{
       
   572 		TLinearOrder<CTzLocalizedCity> sortOrder(CitySortOrderL(aSortOrder));
       
   573 		cities->Sort(sortOrder);
       
   574 		}
       
   575 
       
   576 	CleanupStack::Pop(cities);
       
   577 	return cities;
       
   578 	}
       
   579 
       
   580 /**
       
   581 Gets all the cities defined in the static and persisted data that belong
       
   582 to the time zone identified by aTimeZoneId.
       
   583 The calling function takes ownership of the returned array.
       
   584 @param aTimeZoneId A positive time zone ID that identifies the time zone of
       
   585 the cities to return.
       
   586 @param aSortOrder Defines the order in which the returned array will be sorted.
       
   587 It can have one of the following values: ETzUnsorted, ETzAlphaNameAscending,
       
   588 ETzAlphaNameDescending.
       
   589 @leave KErrArgument An invalid sort order is specified.
       
   590 @return A pointer to the array of cities.
       
   591 */
       
   592 EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesL(TInt aTimeZoneId, const TTzSortOrder aSortOrder)
       
   593 	{
       
   594 	CTzLocalizedCityArray* cities = CTzLocalizedCityArray::NewLC();
       
   595 	ReadCitiesL(*cities, aTimeZoneId, ETrue);
       
   596 
       
   597 	RPointerArray<CTzLocalizedCityRecord> cityRecords;
       
   598 	CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray, &cityRecords));
       
   599 	iTzSession.LocalizationReadCitiesL(cityRecords, aTimeZoneId);
       
   600 	PopulateCityArrayL(cityRecords, *cities);
       
   601 	CleanupStack::PopAndDestroy();	// cityRecords
       
   602 
       
   603 	//Only sort alphabetically if requested.
       
   604 	//We have all cities in a time zone, so there is no need to sort by UTC offset
       
   605 	if ((aSortOrder == ETzAlphaNameAscending) || (aSortOrder == ETzAlphaNameDescending))
       
   606 		{
       
   607 		TLinearOrder<CTzLocalizedCity> sortOrder(CitySortOrderL(aSortOrder));
       
   608 		cities->Sort(sortOrder);
       
   609 		}
       
   610 	else if(aSortOrder != ETzUnsorted)
       
   611 		{
       
   612 		User::Leave(KErrArgument);
       
   613 		}
       
   614 
       
   615 	CleanupStack::Pop(cities);
       
   616 
       
   617 	return cities;
       
   618 	}
       
   619 
       
   620 /**
       
   621 Gets all the cities defined in the static and persisted data that belong to
       
   622 the same time zone as aCity.
       
   623 The calling function takes ownership of the returned array.
       
   624 @param aCity Any city in the desired time zone.
       
   625 @param aSortOrder Specifies the order in which the returned array will be sorted.
       
   626 @return A pointer to the array of cities.
       
   627 */
       
   628 EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesL(const CTzLocalizedCity& aCity,const TTzSortOrder aSortOrder)
       
   629 	{
       
   630 	CTzLocalizedCityArray* cities = CTzLocalizedCityArray::NewLC();
       
   631 	GetCitiesL(*cities,aCity.TzLocalizedId(),ETrue,aSortOrder);
       
   632 	CleanupStack::Pop(cities);
       
   633 	return cities;
       
   634 	}
       
   635 
       
   636 /**
       
   637 Gets all the cities defined in the static and persisted data that belong to
       
   638 aTimeZone.
       
   639 The calling function takes ownership of the array.
       
   640 @param aTimeZone The required time zone
       
   641 @param aSortOrder Specifies the order in which the returned array will be sorted
       
   642 @return A pointer to the array of cities.
       
   643 */
       
   644 EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesL(const CTzLocalizedTimeZone& aTimeZone, const TTzSortOrder aSortOrder)
       
   645 	{
       
   646 	CTzLocalizedCityArray* cities = CTzLocalizedCityArray::NewLC();
       
   647 	GetCitiesL(*cities,aTimeZone.TzLocalizedId(),ETrue,aSortOrder);
       
   648 	CleanupStack::Pop(cities);
       
   649 	return cities;
       
   650 	}
       
   651 
       
   652 /**
       
   653 Adds to the specified city array all cities defined in the static and persisted
       
   654 data that are members of the time zone referenced by aLocalizedId.
       
   655 @param The array of cities to add the cities to.
       
   656 @param aLocalizedId A TzLocalizedId identifying a time zone
       
   657 @param aSortOrder Specifies the order in which the returned array will be
       
   658 sorted. CTzLocalizedCityArray can take the following sort orders:
       
   659 ETzUnsorted, ETzAlphaNameAscending,	ETzAlphaNameDescending.
       
   660 @leave KErrArgument An invalid sort order is asked for.
       
   661 */
       
   662 void CTzLocalizer::GetCitiesL(CTzLocalizedCityArray& aCities, const TTzLocalizedId& aLocalizedId,
       
   663 		TBool aUseDataSource, const TTzSortOrder aSortOrder)
       
   664 	{
       
   665 	ReadCitiesL(aCities, aLocalizedId.TimeZoneId(), aUseDataSource);
       
   666 
       
   667 	RPointerArray<CTzLocalizedCityRecord> cityRecords;
       
   668 	CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray, &cityRecords));
       
   669 	iTzSession.LocalizationReadCitiesL(cityRecords, aLocalizedId.TimeZoneId());
       
   670 	PopulateCityArrayL(cityRecords, aCities);
       
   671 	CleanupStack::PopAndDestroy();	// cityRecords
       
   672 
       
   673 	//Only sort alphabetically if requested.
       
   674 	//We have all cities in a time zone, so there is no need to sort by UTC offset
       
   675 	if ((aSortOrder == ETzAlphaNameAscending) || (aSortOrder == ETzAlphaNameDescending))
       
   676 		{
       
   677 		TLinearOrder<CTzLocalizedCity> sortOrder(CitySortOrderL(aSortOrder));
       
   678 		aCities.Sort(sortOrder);
       
   679 		}
       
   680 	else if(aSortOrder != ETzUnsorted)
       
   681 		{
       
   682 		User::Leave(KErrArgument);
       
   683 		}
       
   684 	}
       
   685 
       
   686 /**
       
   687 Creates a user defined city, specifying the time zone and
       
   688 optionally the group to which it belongs.
       
   689 @param aTimeZoneId A positive time zone ID of the city to add.
       
   690 @param aCityName The name of the city to add.
       
   691 @param aGroupId The ID of the city group to add the city to. Zero if the city doesn't
       
   692 belong to a group. Currently supports up to 255 groups
       
   693 @return The newly created city. The calling function takes ownership.
       
   694 @leave KErrAlreadyExists The specified city already exists in the time zone.
       
   695 @leave KErrNotFound aTimeZoneId or aGroupId is not found.
       
   696 @leave KErrArgument aGroupId is invalid
       
   697 */
       
   698 EXPORT_C CTzLocalizedCity* CTzLocalizer::AddCityL(TInt aTimeZoneId,const TDesC& aCityName, TInt aGroupId)
       
   699 	{
       
   700 	//Check that aGroupId is a valid TUint8 and leave if not.
       
   701 	//Group number > 255 is not supported
       
   702 	__ASSERT_ALWAYS(aGroupId >= 0 && aGroupId <256 , User::Leave(KErrArgument));
       
   703 
       
   704 	// Check that the group exists - this code will leave with
       
   705 	// KErrNotFound if the group does not exist.
       
   706 	// Do not need to check when the gtoup ID is zero as this specifies a groupless city
       
   707 	if(aGroupId != 0)
       
   708 		{
       
   709 		CTzLocalizedCityGroup* group = GetCityGroupL(aGroupId);
       
   710 		delete group;
       
   711 		}
       
   712 
       
   713 	//Check that the city doesn't exist in this time zone
       
   714 	CTzLocalizedCityArray* staticCityArray = CTzLocalizedCityArray::NewLC();
       
   715 	ReadCitiesL(*staticCityArray, aTimeZoneId, EFalse);
       
   716 
       
   717 	TInt count = staticCityArray->Count();
       
   718 	for (TInt x = 0; x < count; ++x)
       
   719 		{
       
   720 		CTzLocalizedCity& city = staticCityArray->At(x);
       
   721 		if (aCityName == city.Name())
       
   722 			{
       
   723 			User::Leave(KErrAlreadyExists);
       
   724 			}
       
   725 		}
       
   726 	// Copy the TzLocalizedID (timezoneID/resourceId pair) for these cities to
       
   727 	// put in the new city
       
   728 	TTzLocalizedId localizedId(staticCityArray->At(0).TzLocalizedId());
       
   729 	CleanupStack::PopAndDestroy(staticCityArray);
       
   730 
       
   731 	//City doesn't exist - we can try and add it
       
   732 	CTzLocalizedCity* newCity = CTzLocalizedCity::NewLC(aCityName,localizedId,(TUint8)aGroupId);
       
   733 
       
   734 	//WriteCityL checks to see if a city with the same Time Zone ID
       
   735 	//is already in the persisted cities, while adding the city.
       
   736 	iTzSession.LocalizationWriteCityL(newCity->Name(), (TInt)newCity->TimeZoneId(), newCity->GroupId(),
       
   737 			newCity->TzLocalizedId().ResourceId());
       
   738 	CleanupStack::Pop(newCity);
       
   739 	return newCity;
       
   740 	}
       
   741 
       
   742 /**
       
   743 Removes a city from the user defined city collection.
       
   744 The calling function loses ownership of aCity.
       
   745 @param aCity The city to remove.
       
   746 */
       
   747 EXPORT_C void CTzLocalizer::RemoveCityL(CTzLocalizedCity* aCity)
       
   748 	{
       
   749 	if(aCity)
       
   750 		{
       
   751 		CleanupStack::PushL(aCity);
       
   752 		iTzSession.LocalizationDeleteCityL(aCity->Name(), aCity->TimeZoneId());
       
   753 		CleanupStack::PopAndDestroy(aCity);
       
   754 		}
       
   755 	else
       
   756 		{
       
   757 		User::Leave(KErrArgument);
       
   758 		}
       
   759 	}
       
   760 
       
   761 /**
       
   762 Gets a list of all the existing city groups.
       
   763 The calling function takes ownership of the returned array.
       
   764 @param aSortOrder Specifies the order in which the returned array will be
       
   765 sorted. Possible values are ETzAlphaNameAscending or ETzAlphaNameDescending.
       
   766 @return Array of all existing city groups.
       
   767 */
       
   768 EXPORT_C CTzLocalizedCityGroupArray* CTzLocalizer::GetAllCityGroupsL(const TTzSortOrder aSortOrder) const
       
   769 	{
       
   770 	CTzLocalizedCityGroupArray* cityGroups = CTzLocalizedCityGroupArray::NewLC();
       
   771 	if(iDataSource&ETzDataSourceSystem)
       
   772 		{
       
   773 		iStaticDataReader->ReadAllGroupsL(*cityGroups);
       
   774 		}
       
   775 	if(iDataSource&ETzDataSourceUser)
       
   776 		{
       
   777 		iUserDataReader->ReadAllGroupsL(*cityGroups);
       
   778 		}
       
   779 
       
   780 	if (aSortOrder == ETzAlphaNameAscending)
       
   781 		{
       
   782 		TLinearOrder<CTzLocalizedCityGroup> order(NTzLocalSortAndFind::SortCityGroupNameAscending);
       
   783 		cityGroups->Sort(order);
       
   784 		}
       
   785 	else if (aSortOrder == ETzAlphaNameDescending)
       
   786 		{
       
   787 		TLinearOrder<CTzLocalizedCityGroup> order(NTzLocalSortAndFind::SortCityGroupNameDescending);
       
   788 		cityGroups->Sort(order);
       
   789 		}
       
   790 	CleanupStack::Pop(cityGroups);
       
   791 	return cityGroups;
       
   792 	}
       
   793 
       
   794 /**
       
   795 Gets the city group with the specified ID.
       
   796 The calling function takes ownership of the returned CTzLocalizedCityGroup.
       
   797 @param aGroupId The ID of the city group to get.
       
   798 @return The matching city group.
       
   799 @leave KErrArgument aGroupId is invalid
       
   800 */
       
   801 EXPORT_C CTzLocalizedCityGroup* CTzLocalizer::GetCityGroupL(TInt aGroupId) const
       
   802 	{
       
   803 	//Check that aGroupId is a valid TUint8 and leave if not.
       
   804 	//Group number > 255 is not supported
       
   805 	__ASSERT_ALWAYS(aGroupId >= 0 && aGroupId <256 , User::Leave(KErrArgument));
       
   806 	return iStaticDataReader->ReadGroupL((TUint8)aGroupId);
       
   807 	}
       
   808 
       
   809 /**
       
   810 Gets the city group to which the specified city belongs.
       
   811 The calling function takes ownership of the returned CTzLocalizedCityGroup.
       
   812 @param aCity Any city in the required city group.
       
   813 @return The city group.
       
   814 */
       
   815 EXPORT_C CTzLocalizedCityGroup* CTzLocalizer::GetCityGroupL(const CTzLocalizedCity& aCity) const
       
   816 	{
       
   817 	return iStaticDataReader->ReadGroupL(aCity.GroupId());
       
   818 	}
       
   819 
       
   820 /**
       
   821 Returns all cities defined in the static and persisted data that are members
       
   822 of the group with the specified group ID.
       
   823 The calling function takes ownership of the array.
       
   824 @param aGroupId The group ID.
       
   825 @param aSortOrder Specifies the order in which the returned array will be sorted.
       
   826 The following sort orders are supported: ETzUnsorted, ETzUTCAscending, ETzUTCDescending,
       
   827 ETzAlphaNameAscending, ETzAlphaNameDescending.
       
   828 @return Pointer to the array of cities.
       
   829 @leave KErrArgument aGroupId is invalid
       
   830 */
       
   831 EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesInGroupL(TInt aGroupId,const TTzSortOrder aSortOrder)
       
   832 	{
       
   833 	//Check that aGroupId is a valid TUint8 and leave if not.
       
   834 	//Group number > 255 is not supported
       
   835 	__ASSERT_ALWAYS(aGroupId >= 0 && aGroupId <256 , User::Leave(KErrArgument));
       
   836 
       
   837 	CTzLocalizedCityArray* cities = CTzLocalizedCityArray::NewLC();
       
   838 
       
   839 	if(iDataSource&ETzDataSourceSystem)
       
   840 		{
       
   841 		iStaticDataReader->ReadCitiesInGroupL(*cities,(TUint8)aGroupId);
       
   842 		}
       
   843 	if(aGroupId == KTzCityNotInGroupId && iDataSource&ETzDataSourceUser)
       
   844 		{//All user time zone are groupless
       
   845 		iUserDataReader->ReadCitiesInGroupL(*cities, KTzCityNotInGroupId);
       
   846 		}
       
   847 
       
   848 	RPointerArray<CTzLocalizedCityRecord> cityRecords;
       
   849 	CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray, &cityRecords));
       
   850 	iTzSession.LocalizationReadCitiesInGroupL(cityRecords, (TUint8)aGroupId);
       
   851 	PopulateCityArrayL(cityRecords, *cities);
       
   852 	CleanupStack::PopAndDestroy();	// cityRecords
       
   853 
       
   854 	if ((aSortOrder == ETzUTCAscending) || (aSortOrder == ETzUTCDescending))
       
   855 		{
       
   856 		PrepareForUTCSortL(*cities);
       
   857 		}
       
   858 
       
   859 	if (aSortOrder != ETzUnsorted)
       
   860 		{
       
   861 		TLinearOrder<CTzLocalizedCity> sortOrder(CitySortOrderL(aSortOrder));
       
   862 		cities->Sort(sortOrder);
       
   863 		}
       
   864 	CleanupStack::Pop(cities);
       
   865 	return cities;
       
   866 	}
       
   867 
       
   868 /**
       
   869 Returns all cities defined in the static and persisted data that are members
       
   870 of the same group as the specified city.
       
   871 The calling function takes ownership of the array.
       
   872 @param aCity Any city in the desired city group.
       
   873 @param aSortOrder Specifies the order in which the returned array will be sorted.
       
   874 The following sort orders are supported: ETzUnsorted, ETzUTCAscending, ETzUTCDescending,
       
   875 ETzAlphaNameAscending, ETzAlphaNameDescending.
       
   876 @return Pointer to an array of cities.
       
   877 */
       
   878 EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesInGroupL(const CTzLocalizedCity& aCity,const TTzSortOrder aSortOrder)
       
   879 	{
       
   880 	return GetCitiesInGroupL(aCity.GroupId(),aSortOrder);
       
   881 	}
       
   882 
       
   883 /**
       
   884 Returns all cities defined in the static and persisted data that are members
       
   885 of the specified city group.
       
   886 The calling function takes ownership of the array.
       
   887 @param aCityGroup The city group of interest.
       
   888 @param aSortOrder Specifies the order in which the returned array will be sorted.
       
   889 The following sort orders are supported: ETzUnsorted, ETzUTCAscending,
       
   890 ETzUTCDescending, ETzAlphaNameAscending, ETzAlphaNameDescending.
       
   891 @return Pointer to an array of cities.
       
   892 */
       
   893 EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesInGroupL(const CTzLocalizedCityGroup& aCityGroup,const TTzSortOrder aSortOrder)
       
   894 	{
       
   895 	return GetCitiesInGroupL(aCityGroup.Id(),aSortOrder);
       
   896 	}
       
   897 
       
   898 /**
       
   899 Gets the cached time zone identified by aFrequentlyUsedZone.
       
   900 The calling function takes ownership of the returned zone.
       
   901 When retrieving the current zone (CTzLocalizedTimeZone::ECurrentZone), the time zone
       
   902 server is queried to make sure that the system's current time zone has not been updated
       
   903 since the current zone was cached.
       
   904 If the system's time zone has been updated, the new localised zone is stored in the database.
       
   905 @param aFrequentlyUsedZone Identifies the cached zone to return.
       
   906 @return The cached zone.
       
   907 */
       
   908 EXPORT_C CTzLocalizedTimeZone* CTzLocalizer::GetFrequentlyUsedZoneL(const CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFrequentlyUsedZone)
       
   909 	{
       
   910 	CTzLocalizedTimeZone* timeZone;
       
   911 
       
   912 	if (aFrequentlyUsedZone == CTzLocalizedTimeZone::ECurrentZone)
       
   913 		{
       
   914 		//Get cached current zone
       
   915 		CTzLocalizedTimeZoneRecord* frequentlyUsedZoneRecord = iTzSession.LocalizationReadFrequentlyUsedZoneL(aFrequentlyUsedZone);
       
   916 		CleanupStack::PushL(frequentlyUsedZoneRecord);
       
   917 		CTzLocalizedTimeZone* frequentlyUsedZone = CreateTimeZoneL(*frequentlyUsedZoneRecord);
       
   918 		CleanupStack::PopAndDestroy(frequentlyUsedZoneRecord);
       
   919 		CleanupStack::PushL(frequentlyUsedZone);
       
   920 
       
   921 		TInt currentTimeZoneId = GetTimeZoneIdFromTzServerL();
       
   922 		if (frequentlyUsedZone->TimeZoneId() != currentTimeZoneId)
       
   923 			{
       
   924 			//Current timezone has changed.  Set the current zone in the cache and return it
       
   925 			CTzLocalizedTimeZone* currentZone = GetLocalizedTimeZoneL(currentTimeZoneId, EFalse);
       
   926 			CleanupStack::PushL(currentZone);
       
   927 			timeZone = currentZone;
       
   928 
       
   929 			CTzLocalizedCity* city = ReadDefaultCityL(timeZone->TimeZoneId(), EFalse);
       
   930 			CleanupStack::PushL(city);
       
   931 			SetFrequentlyUsedZoneL(*timeZone, *city, CTzLocalizedTimeZone::ECurrentZone);
       
   932 	        CleanupStack::PopAndDestroy(city);
       
   933 
       
   934 			CleanupStack::Pop(currentZone);
       
   935 			CleanupStack::PopAndDestroy(frequentlyUsedZone);
       
   936 			frequentlyUsedZone = NULL;
       
   937 			}
       
   938 		else
       
   939 			{
       
   940 			//Return the cached zone.
       
   941 			timeZone = frequentlyUsedZone;
       
   942 			CleanupStack::Pop(frequentlyUsedZone);
       
   943 			frequentlyUsedZone = NULL;
       
   944 			}
       
   945 		}
       
   946 
       
   947 	else
       
   948 		{
       
   949 		CTzLocalizedTimeZoneRecord* timeZoneRecord = iTzSession.LocalizationReadFrequentlyUsedZoneL(aFrequentlyUsedZone);
       
   950 		CleanupStack::PushL(timeZoneRecord);
       
   951 		timeZone = CreateTimeZoneL(*timeZoneRecord);
       
   952 		CleanupStack::PopAndDestroy(timeZoneRecord);
       
   953 		}
       
   954 
       
   955 	return timeZone;
       
   956 	}
       
   957 
       
   958 /**
       
   959 Retrieves the integer time zone ID of the current time zone from the time zone
       
   960 server (app-services/Tz).
       
   961 @return The integer time zone ID according to the time zone server.
       
   962 */
       
   963 TInt CTzLocalizer::GetTimeZoneIdFromTzServerL()
       
   964 	{
       
   965 	// Get current time zone using the current CTzId from the time zone server
       
   966 	CTzId* currentCTzId = iTzSession.GetTimeZoneIdL();
       
   967 	CleanupStack::PushL(currentCTzId);
       
   968 
       
   969 	TUint timeZoneIdInt = currentCTzId->TimeZoneNumericID();
       
   970 
       
   971 	CleanupStack::PopAndDestroy(currentCTzId);
       
   972 
       
   973 	// Is the time zone ID the unknown/invalid ID?
       
   974 	// This is temporary measure that is required until PREQ 234' TzServer
       
   975 	// changes are introduced
       
   976 	const TUint32 KUnknownTZId = 0x0ffffff0;
       
   977 	if((TUint32)timeZoneIdInt == KUnknownTZId)
       
   978 		{
       
   979 		// Return the ID of the DEFAULT home zone instead
       
   980 		CTzLocalizedTimeZone* homeZone = iStaticDataReader->ReadFrequentlyUsedZoneL(CTzLocalizedTimeZone::EHomeZone);
       
   981 		CleanupStack::PushL(homeZone);
       
   982 		timeZoneIdInt = homeZone->TimeZoneId();
       
   983 		CleanupStack::PopAndDestroy(homeZone);
       
   984 		}
       
   985 
       
   986 	return timeZoneIdInt;
       
   987 	}
       
   988 
       
   989 /**
       
   990 Gets the city that was used to set the specified cached time zone.
       
   991 The calling function takes ownership of the returned city.
       
   992 If a city was not used to set the cached zone, the default
       
   993 city for the zone is returned.
       
   994 @param aFrequentlyUsedZone Indicates one of the five cached zones.
       
   995 @return The city used to set the cached zone.
       
   996 */
       
   997 EXPORT_C CTzLocalizedCity* CTzLocalizer::GetFrequentlyUsedZoneCityL(const CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFrequentlyUsedZone)
       
   998 	{
       
   999 	CTzLocalizedCityRecord* cityRecord = iTzSession.LocalizationReadCachedTimeZoneCityL(aFrequentlyUsedZone);
       
  1000 	CleanupStack::PushL(cityRecord);
       
  1001 	CTzLocalizedCity* city = CreateCityL(*cityRecord);
       
  1002 	CleanupStack::PopAndDestroy(cityRecord);
       
  1003 
       
  1004 	// check that the city contains valid information
       
  1005 	if(city->TimeZoneId() == 0)
       
  1006 	// if not, get of the default cached zone's default city from the static reader
       
  1007 		{
       
  1008 		delete city;
       
  1009 		city = NULL;
       
  1010 
       
  1011 		if(aFrequentlyUsedZone != CTzLocalizedTimeZone::ECurrentZone)
       
  1012 			{
       
  1013 			city = iStaticDataReader->ReadCachedTimeZoneCityL(aFrequentlyUsedZone);
       
  1014 			}
       
  1015 		else
       
  1016 			{
       
  1017 			// use GetFrequentlyUsedZoneL(), because it deals with the current zone correctly
       
  1018 			CTzLocalizedTimeZone* defaultFrequentlyUsedZone = GetFrequentlyUsedZoneL(aFrequentlyUsedZone);
       
  1019 			CleanupStack::PushL(defaultFrequentlyUsedZone);
       
  1020 			// then get the city
       
  1021 			city = ReadDefaultCityL(defaultFrequentlyUsedZone->TimeZoneId(), EFalse);
       
  1022 			CleanupStack::PopAndDestroy(defaultFrequentlyUsedZone);
       
  1023 			}
       
  1024 		}
       
  1025 	else
       
  1026 		{
       
  1027 		if(aFrequentlyUsedZone == CTzLocalizedTimeZone::ECurrentZone)
       
  1028 			{
       
  1029 			CleanupStack::PushL(city);
       
  1030 			CTzLocalizedTimeZone* timeZone = GetLocalizedTimeZoneL(*city, EFalse);
       
  1031 			TUint16 tzId = timeZone->TimeZoneId();
       
  1032 			delete timeZone;
       
  1033 			CTzLocalizedTimeZone* currentTimeZone = GetFrequentlyUsedZoneL(CTzLocalizedTimeZone::ECurrentZone);
       
  1034 			TUint16 currentTzId = currentTimeZone->TimeZoneId();
       
  1035 			delete currentTimeZone;
       
  1036 			if (tzId != currentTzId)
       
  1037 				{
       
  1038 				CleanupStack::PopAndDestroy(city);
       
  1039 				city = NULL;
       
  1040 				city = ReadDefaultCityL(currentTzId, EFalse);
       
  1041 				}
       
  1042 			else
       
  1043 				{
       
  1044 				CleanupStack::Pop(city);
       
  1045 				}
       
  1046 			}
       
  1047 
       
  1048 		}
       
  1049 
       
  1050 	return city;
       
  1051 	}
       
  1052 
       
  1053 /**
       
  1054 Sets the ID of the specified cached time zone.
       
  1055 @param aTimeZoneId A positive time zone ID to assign to aFrequentlyUsedZone. Must not
       
  1056 be zero or the function leaves with KErrArgument.
       
  1057 @param aFrequentlyUsedZone Identifies the cached zone whose ID will be set. This must be
       
  1058 either CTzLocalizedTimeZone::ECurrentZone, CTzLocalizedTimeZone::EHomeZone or
       
  1059 CTzLocalizedTimeZone::EInterestZone, or the function leaves with KErrArgument.
       
  1060 N.B. When the current zone is set, the time zone of the device is altered.
       
  1061 */
       
  1062 EXPORT_C void CTzLocalizer::SetFrequentlyUsedZoneL(TInt aTimeZoneId,const CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFrequentlyUsedZone)
       
  1063 	{
       
  1064 	// The time zone ID must be a non-zero number to be valid
       
  1065 	__ASSERT_ALWAYS(aTimeZoneId > 0, User::Leave(KErrArgument));
       
  1066 	CTzLocalizedTimeZone* aTimeZone = GetLocalizedTimeZoneL(aTimeZoneId, EFalse);
       
  1067 	CleanupStack::PushL(aTimeZone);
       
  1068 	SetFrequentlyUsedZoneL(*aTimeZone,aFrequentlyUsedZone);
       
  1069 	CleanupStack::PopAndDestroy(aTimeZone);
       
  1070 	}
       
  1071 
       
  1072 /**
       
  1073 Sets the value of the specified cached time zone.
       
  1074 @param aTimeZone The value to assign to aFrequentlyUsedZone. It must have an ID greater
       
  1075 than zero or the function leaves with KErrArgument.
       
  1076 @param aFrequentlyUsedZone Identifies the cached zone whose ID will be set. This must be
       
  1077 either CTzLocalizedTimeZone::ECurrentZone, CTzLocalizedTimeZone::EHomeZone or
       
  1078 CTzLocalizedTimeZone::EInterestZone, or the function leaves with KErrArgument.
       
  1079 N.B. When the current zone is set, the time zone of the device is altered.
       
  1080 */
       
  1081 EXPORT_C void CTzLocalizer::SetFrequentlyUsedZoneL(const CTzLocalizedTimeZone& aTimeZone, const CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFrequentlyUsedZone)
       
  1082 	{
       
  1083 	// The time zone ID must be a non-zero number to be valid
       
  1084 	__ASSERT_ALWAYS(aTimeZone.TimeZoneId() > 0, User::Leave(KErrArgument));
       
  1085 	CTzLocalizedCity* city = ReadDefaultCityL(aTimeZone.TimeZoneId(), EFalse);
       
  1086 	CleanupStack::PushL(city);
       
  1087 	// Update the time zone server, if the current zone is being updated
       
  1088 	if(aFrequentlyUsedZone == CTzLocalizedTimeZone::ECurrentZone)
       
  1089 		{
       
  1090 		DoSetTimeZoneL(aTimeZone.TimeZoneId());
       
  1091 		}
       
  1092 	else if(aFrequentlyUsedZone == CTzLocalizedTimeZone::EHomeZone)
       
  1093 		{
       
  1094 		ChangeHomeTimeZoneL(aTimeZone.TimeZoneId());
       
  1095 		}
       
  1096 	SetFrequentlyUsedZoneL(aTimeZone, *city, aFrequentlyUsedZone);
       
  1097     CleanupStack::PopAndDestroy(city);
       
  1098 	}
       
  1099 
       
  1100 /**
       
  1101 Sets the value of the specified cached zone to be the zone which aCity
       
  1102 is located in.
       
  1103 Setting a cached zone by city also stores the city used to select the time zone.
       
  1104 @param aCity Any city in the time zone to set. It must have a time zone ID greater
       
  1105 than zero or the function leaves with KErrArgument.
       
  1106 @param aFrequentlyUsedZone Indicates which of the cached zones to set. This must be
       
  1107 either CTzLocalizedTimeZone::ECurrentZone, CTzLocalizedTimeZone::EHomeZone or
       
  1108 CTzLocalizedTimeZone::EInterestZone, or the function leaves with KErrArgument.
       
  1109 N.B. When the current zone is set, the time zone of the device is altered.
       
  1110 */
       
  1111 EXPORT_C void CTzLocalizer::SetFrequentlyUsedZoneL(const CTzLocalizedCity& aCity,const CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFrequentlyUsedZone)
       
  1112 	{
       
  1113 	// The time zone ID must be a non-zero number to be valid
       
  1114 	__ASSERT_ALWAYS(aCity.TimeZoneId() > 0, User::Leave(KErrArgument));
       
  1115 	CTzLocalizedTimeZone* timeZone = GetLocalizedTimeZoneL(aCity, EFalse);
       
  1116 	CleanupStack::PushL(timeZone);
       
  1117 	// Update the time zone server, if the current zone is being updated
       
  1118 	if(aFrequentlyUsedZone == CTzLocalizedTimeZone::ECurrentZone)
       
  1119 		{
       
  1120 		DoSetTimeZoneL(aCity.TimeZoneId());
       
  1121 		}
       
  1122 	else if(aFrequentlyUsedZone == CTzLocalizedTimeZone::EHomeZone)
       
  1123 		{
       
  1124 		ChangeHomeTimeZoneL(timeZone->TimeZoneId());
       
  1125 		}
       
  1126 	SetFrequentlyUsedZoneL(*timeZone, aCity, aFrequentlyUsedZone);
       
  1127 	CleanupStack::PopAndDestroy(timeZone);
       
  1128 	}
       
  1129 
       
  1130 void CTzLocalizer::ChangeHomeTimeZoneL(TInt aNewId)
       
  1131 	{
       
  1132 	NTzUpdate::TTimeZoneChange change;
       
  1133 	change.iNewTimeZoneId = aNewId;
       
  1134 	CTzLocalizedTimeZoneRecord* oldTz = iTzSession.LocalizationReadFrequentlyUsedZoneL(CTzLocalizedTimeZone::EHomeZone);
       
  1135 	change.iOldTimeZoneId = oldTz->Id();
       
  1136 	delete oldTz; // don't need to put on cleanup stack because previous line can't leave
       
  1137 
       
  1138 	RTz tz;
       
  1139 	User::LeaveIfError(tz.Connect());
       
  1140 	CleanupClosePushL(tz);
       
  1141 	tz.NotifyHomeTimeZoneChangedL(change);
       
  1142 	CleanupStack::PopAndDestroy(&tz);
       
  1143 	}
       
  1144 
       
  1145 /**
       
  1146 Set the time zone in the time zone server to be that of the
       
  1147 supplied time zone id
       
  1148 @param aTimeZoneId The time zone id of the new time zone.
       
  1149 @internalTechnology
       
  1150 */
       
  1151 void CTzLocalizer::DoSetTimeZoneL(TInt aTimeZoneId)
       
  1152 	{
       
  1153 	// Create a new CTzId with the new time zone ID in it
       
  1154 	CTzId* newCTzId = CTzId::NewL(aTimeZoneId);
       
  1155 	CleanupStack::PushL(newCTzId);
       
  1156 
       
  1157 	//Connect to time zone server
       
  1158 	RTz tz;
       
  1159 	User::LeaveIfError(tz.Connect());
       
  1160 	CleanupClosePushL(tz);
       
  1161 
       
  1162 	tz.SetTimeZoneL(*newCTzId);
       
  1163 
       
  1164 	CleanupStack::PopAndDestroy(); //tz
       
  1165 	CleanupStack::PopAndDestroy(newCTzId);
       
  1166 	}
       
  1167 
       
  1168 /**
       
  1169 Prepares a CTzLocalizedTimeZoneArray or CTzLocalizedCityArray for sorting by UTC offset.
       
  1170 All array elements which have not already had the UTC offset set will retrieve the
       
  1171 correct offset from App-Services/Tz.
       
  1172 @param aArray
       
  1173 @internalTechnology
       
  1174 */
       
  1175 template <class T>
       
  1176 void CTzLocalizer::PrepareForUTCSortL(T& aArray)
       
  1177 	{
       
  1178 	//Prepare an array of timezone IDs to give to the time zone server
       
  1179 	RArray<TInt> timeZoneIds;
       
  1180 	CleanupClosePushL(timeZoneIds);
       
  1181 	TInt i;
       
  1182 	TInt count = aArray.Count();
       
  1183 	for(i=0; i<count; ++i)
       
  1184 		{
       
  1185 		timeZoneIds.AppendL(aArray.At(i).TimeZoneId());
       
  1186 		}
       
  1187 
       
  1188 	//Prepare an array of UTC Offsets for the timezone server to fill
       
  1189 	RArray<TInt> utcOffsets;
       
  1190 	CleanupClosePushL(utcOffsets);
       
  1191 
       
  1192 	//Connect to Time Zone Server
       
  1193 	RTz tz;
       
  1194 	User::LeaveIfError(tz.Connect());
       
  1195 	CleanupClosePushL(tz);
       
  1196 
       
  1197 	// Pass the arrays to tz - the time zone server will populate the array
       
  1198 	// of UTC Offsets based using the array of Time Zone IDs
       
  1199 	tz.GetOffsetsForTimeZoneIdsL(timeZoneIds, utcOffsets);
       
  1200 
       
  1201 	//Finished with Time Zone Server
       
  1202 	CleanupStack::PopAndDestroy(); //tz
       
  1203 
       
  1204 	// copy the utc offsets from one array to the other
       
  1205 	for(i=0; i<count; ++i)
       
  1206 		{
       
  1207 		aArray.At(i).SetUTCOffset(utcOffsets[i]);
       
  1208 		}
       
  1209 
       
  1210 	//Finished with arrays, so close them
       
  1211 	CleanupStack::PopAndDestroy(2);	// utcOffsets, timeZoneIds
       
  1212 	}
       
  1213 
       
  1214 /**
       
  1215 Searches for a city with the specified name. If a time Zone ID is also specified, then
       
  1216 the search only covers cities in that time zone. Otherwise, all time zones are searched.
       
  1217 The first matching city is returned.
       
  1218 @param aCityName Name of the city to search for.
       
  1219 @param aTimeZoneId (Optional) A positive time zone ID of the city to search for.
       
  1220 Specify zero to omit.
       
  1221 @return If successful, a pointer to a CTzLocalizedCity. The calling function
       
  1222 takes ownership of the returned pointer. If the search string is not found,
       
  1223 NULL is returned.
       
  1224 @leave KErrNotFound The specified time zone ID does not exist.
       
  1225 */
       
  1226 EXPORT_C CTzLocalizedCity* CTzLocalizer::FindCityByNameL(const TDesC& aCityName, const TInt aTimeZoneId)
       
  1227 	{
       
  1228 	CTzLocalizedCity* foundCity;
       
  1229 	//Create a dummy city for the search
       
  1230 	CTzLocalizedCity* aCity = CTzLocalizedCity::NewLC(aCityName,TTzLocalizedId((TUint16)aTimeZoneId,0),0);
       
  1231 
       
  1232 	CTzLocalizedCityArray* citiesToSearch = NULL;
       
  1233 
       
  1234 	if(aTimeZoneId > 0)
       
  1235 	// A non-zero Time Zone ID has been supplied, so search through the cities within that Time Zone.
       
  1236 		{
       
  1237 		citiesToSearch = GetCitiesL(aTimeZoneId);
       
  1238 		}
       
  1239 	else
       
  1240 	// Search through all cities
       
  1241 		{
       
  1242 		citiesToSearch= GetCitiesL();
       
  1243 		}
       
  1244 
       
  1245 	TIdentityRelation<CTzLocalizedCity> identity(NTzLocalSortAndFind::FindCityByName);
       
  1246 
       
  1247 	TInt index = citiesToSearch->Find(aCity,identity);
       
  1248 
       
  1249 	if (index != KErrNotFound)
       
  1250 		{
       
  1251 		foundCity = &(citiesToSearch->At(index));
       
  1252 		// ownership is transferred to calling function
       
  1253 		// we don't want this pointer deleted when the array is
       
  1254 		citiesToSearch->Remove(index);
       
  1255 		}
       
  1256 	else
       
  1257 		{
       
  1258 		foundCity = NULL;
       
  1259 		}
       
  1260 
       
  1261 	CleanupStack::PopAndDestroy(aCity);
       
  1262 
       
  1263 	delete citiesToSearch;
       
  1264 	citiesToSearch = NULL;
       
  1265 
       
  1266 	return foundCity;
       
  1267 	}
       
  1268 /**
       
  1269 Searches for a time zone with the specified name.
       
  1270 All text fields of the time zone are searched.
       
  1271 @param aTimeZoneName the name of the time zone to search for.
       
  1272 @return If successful, a pointer to a CTzLocalizedTimeZone.
       
  1273 The calling function takes ownership of the returned pointer.
       
  1274 If the search string is not found, NULL is returned.
       
  1275 */
       
  1276 EXPORT_C CTzLocalizedTimeZone* CTzLocalizer::FindTimeZoneByNameL(const TDesC& aTimeZoneName)
       
  1277 	{
       
  1278 	CTzLocalizedTimeZone* foundTimeZone;
       
  1279 	//Create a dummy time zone for the search
       
  1280 	TTzLocalizedId id(0, 0);
       
  1281 	CTzLocalizedTimeZone* timeZone = CTzLocalizedTimeZone::NewLC(id,aTimeZoneName,aTimeZoneName,aTimeZoneName,aTimeZoneName);
       
  1282 	//Get all the time zones
       
  1283 	CTzLocalizedTimeZoneArray* allTimeZones = GetAllTimeZonesL();
       
  1284 
       
  1285 	TIdentityRelation<CTzLocalizedTimeZone> identity(NTzLocalSortAndFind::FindTimeZoneByName);
       
  1286 
       
  1287 	TInt index = allTimeZones->Find(timeZone,identity);
       
  1288 
       
  1289 	if (index != KErrNotFound)
       
  1290 		{
       
  1291 		foundTimeZone = &(allTimeZones->At(index));
       
  1292 		allTimeZones->Remove(index);
       
  1293 		}
       
  1294 	else
       
  1295 		{
       
  1296 		foundTimeZone = NULL;
       
  1297 		}
       
  1298 
       
  1299 	CleanupStack::PopAndDestroy(timeZone);
       
  1300 
       
  1301 	delete allTimeZones;
       
  1302 	allTimeZones = NULL;
       
  1303 
       
  1304 	return foundTimeZone;
       
  1305 	}
       
  1306 
       
  1307 /**
       
  1308 Searches for a city group with the specified name.
       
  1309 @param aCityGroupName The name of the city group to search for.
       
  1310 @return If successful, a pointer to a CTzLocalizedCityGroup.
       
  1311 The calling function takes ownership of the returned pointer.
       
  1312 If the search string is not found, NULL is returned.
       
  1313 */
       
  1314 EXPORT_C CTzLocalizedCityGroup* CTzLocalizer::FindCityGroupByNameL(const TDesC& aCityGroupName)
       
  1315 	{
       
  1316 	CTzLocalizedCityGroup* foundCityGroup;
       
  1317 	//Create a dummy city group for the search
       
  1318 	CTzLocalizedCityGroup* aCityGroup = CTzLocalizedCityGroup::NewLC(aCityGroupName,0);
       
  1319 	//Get all the city groups
       
  1320 	CTzLocalizedCityGroupArray* allCityGroups = GetAllCityGroupsL();
       
  1321 
       
  1322 	TIdentityRelation<CTzLocalizedCityGroup> identity(NTzLocalSortAndFind::FindCityGroupByName);
       
  1323 
       
  1324 	TInt index = allCityGroups->Find(aCityGroup,identity);
       
  1325 
       
  1326 	if (index != KErrNotFound)
       
  1327 		{
       
  1328 		foundCityGroup = &(allCityGroups->At(index));
       
  1329 		allCityGroups->Remove(index);
       
  1330 		}
       
  1331 	else
       
  1332 		{
       
  1333 		foundCityGroup = NULL;
       
  1334 		}
       
  1335 
       
  1336 	CleanupStack::PopAndDestroy(aCityGroup);
       
  1337 
       
  1338 	delete allCityGroups;
       
  1339 	allCityGroups = NULL;
       
  1340 
       
  1341 	return foundCityGroup;
       
  1342 	}
       
  1343 
       
  1344 /**
       
  1345 Tests whether the language of the loaded static data is still correct. If it
       
  1346 is not, the static data is reloaded.
       
  1347 Method could leave while creating a data reader.
       
  1348 @return ETrue if the system language (as returned by User::Language()) has changed,
       
  1349 EFalse if it has not.
       
  1350 @see User::Language()
       
  1351 */
       
  1352 EXPORT_C TBool CTzLocalizer::CheckLanguage()
       
  1353 	{
       
  1354 	TBool languageChange = (iLanguage != User::Language());
       
  1355 
       
  1356 	if(languageChange)
       
  1357 	// the language has changed - reload the static data and repopulate the
       
  1358 	// cached zones database
       
  1359 		{
       
  1360 		iLanguage = User::Language();
       
  1361 		delete iStaticDataReader;
       
  1362 		iStaticDataReader = 0;
       
  1363 		iStaticDataReader = CTzLocalizationResourceReader::NewL(); // Method could leave while creating a data reader
       
  1364 		UpdateFrequentlyUsedZonesL();
       
  1365 		}
       
  1366 
       
  1367 	return languageChange;
       
  1368 	}
       
  1369 
       
  1370 /**
       
  1371 Returns all cities defined in the static and persisted data that have
       
  1372 the specified UTC offset.
       
  1373 The calling function takes ownership of the array.
       
  1374 @param aUTCOffsetInMinutes The offset in minutes.
       
  1375 @param aSortOrder Specifies the order in which the returned array will be sorted.
       
  1376 Only ETzUnsorted, ETzAlphaNameAscending and ETzAlphaNameDescending will have any effect,
       
  1377 as all elements in the returned array will have the same UTC offset.
       
  1378 @return Pointer to the array of cities.
       
  1379 */
       
  1380 EXPORT_C CTzLocalizedCityArray* CTzLocalizer::GetCitiesWithUTCOffsetL(TInt aUTCOffsetInMinutes, const TTzSortOrder aSortOrder)
       
  1381 	{
       
  1382 	//Fetch all the cities sorted by UTC offset
       
  1383 	CTzLocalizedCityArray* allCities = GetCitiesL(ETzUTCAscending);
       
  1384 	TInt count = allCities->Count();
       
  1385 
       
  1386 	CTzLocalizedCity* city;
       
  1387 	for (TInt x = count-1; x >= 0; --x)
       
  1388 		{
       
  1389 		city = &(allCities->At(x));
       
  1390 		if (city->UTCOffset() != aUTCOffsetInMinutes)
       
  1391 			{
       
  1392 			allCities->Remove(x);
       
  1393 			delete city;
       
  1394 			}
       
  1395 		}
       
  1396 
       
  1397 	//Only sort the city array alphabetically if requested
       
  1398 	if ((aSortOrder == ETzAlphaNameAscending) | (aSortOrder == ETzAlphaNameDescending))
       
  1399 		{
       
  1400 		TLinearOrder<CTzLocalizedCity> sortOrder(CitySortOrderL(aSortOrder));
       
  1401 		allCities->Sort(sortOrder);
       
  1402 		}
       
  1403 
       
  1404 	return allCities;
       
  1405 	}
       
  1406 /**
       
  1407 Returns all the time zones defined in the static data that have
       
  1408 the specified UTC offset.
       
  1409 The calling function takes ownership of the array.
       
  1410 @param aUTCOffsetInMinutes The UTC offset in minutes.
       
  1411 @param aSortOrder Specifies the order in which the returned array will be sorted.
       
  1412 Sort orders ETzUTCAscending and ETzUTCDescending will not have any effect
       
  1413 as all elements in the returned array will have the same UTC offset.
       
  1414 @return Pointer to the array of time zones.
       
  1415 */
       
  1416 EXPORT_C CTzLocalizedTimeZoneArray* CTzLocalizer::GetTimeZonesWithUTCOffsetL(TInt aUTCOffsetInMinutes, const TTzSortOrder aSortOrder)
       
  1417 	{
       
  1418 	//Fetch all the time zones sorted by UTC offset
       
  1419 	CTzLocalizedTimeZoneArray* allTimeZones = GetAllTimeZonesL(ETzUTCAscending);
       
  1420 	TInt count = allTimeZones->Count();
       
  1421 
       
  1422 	CTzLocalizedTimeZone* timeZone;
       
  1423 	for (TInt x = count-1; x >= 0; --x)
       
  1424 		{
       
  1425 		timeZone = &(allTimeZones->At(x));
       
  1426 		if (timeZone->UTCOffset() != aUTCOffsetInMinutes)
       
  1427 			{
       
  1428 			allTimeZones->Remove(x);
       
  1429 			delete timeZone;
       
  1430 			}
       
  1431 		}
       
  1432 
       
  1433 	//Only sort the time zone array alphabetically if requested
       
  1434 	if ((aSortOrder != ETzAlphaNameAscending) && (aSortOrder > ETzUTCDescending))
       
  1435 		{
       
  1436 		TLinearOrder<CTzLocalizedTimeZone> sortOrder(TimeZoneSortOrderL(aSortOrder));
       
  1437 		allTimeZones->Sort(sortOrder);
       
  1438 		}
       
  1439 	return allTimeZones;
       
  1440 	}
       
  1441 /**
       
  1442 Gets the correct TLinearOrder to sort by.
       
  1443 @param aSortOrder
       
  1444 @return the TLinearOrder to sort by
       
  1445 @internalTechnology
       
  1446 */
       
  1447 TLinearOrder<CTzLocalizedCity> CTzLocalizer::CitySortOrderL(const TTzSortOrder aSortOrder)
       
  1448 	{
       
  1449 
       
  1450 	TLinearOrder<CTzLocalizedCity> sortOrder(NTzLocalSortAndFind::SortCityUTCAscending);
       
  1451 
       
  1452 	switch (aSortOrder)
       
  1453 		{
       
  1454 		case ETzUTCAscending:
       
  1455 			{
       
  1456 			//Sort order already set
       
  1457 			}
       
  1458 		break;
       
  1459 
       
  1460 		case ETzUTCDescending:
       
  1461 			{
       
  1462 			sortOrder = TLinearOrder<CTzLocalizedCity>(NTzLocalSortAndFind::SortCityUTCDescending);
       
  1463 			}
       
  1464 		break;
       
  1465 
       
  1466 		case ETzAlphaNameAscending:
       
  1467 			{
       
  1468 			sortOrder = TLinearOrder<CTzLocalizedCity>(NTzLocalSortAndFind::SortCityNameAscending);
       
  1469 			}
       
  1470 		break;
       
  1471 
       
  1472 		case ETzAlphaNameDescending:
       
  1473 			{
       
  1474 			sortOrder = TLinearOrder<CTzLocalizedCity>(NTzLocalSortAndFind::SortCityNameDescending);
       
  1475 			}
       
  1476 		break;
       
  1477 
       
  1478 		case ETzAlphaStandardNameAscending:		//FALL THROUGH - these aren't supported
       
  1479 		case ETzAlphaDaylightNameAscending:
       
  1480 		case ETzAlphaShortStandardNameAscending:
       
  1481 		case ETzAlphaShortDaylightNameAscending:
       
  1482 		case ETzAlphaStandardNameDescending:
       
  1483 		case ETzAlphaDaylightNameDescending:
       
  1484 		case ETzAlphaShortStandardNameDescending:
       
  1485 		case ETzAlphaShortDaylightNameDescending:
       
  1486 		default:
       
  1487 			{
       
  1488 			User::Leave(KErrArgument);
       
  1489 			}
       
  1490 		}
       
  1491 	return sortOrder;
       
  1492 	}
       
  1493 /**
       
  1494 Gets the correct TLinearOrder to sort by
       
  1495 @param aSortOrder
       
  1496 @return the TLinearOrder to sort by
       
  1497 @internalTechnology
       
  1498 */
       
  1499 TLinearOrder<CTzLocalizedTimeZone> CTzLocalizer::TimeZoneSortOrderL(const TTzSortOrder aSortOrder)
       
  1500 	{
       
  1501 	TLinearOrder<CTzLocalizedTimeZone> sortOrder(NTzLocalSortAndFind::SortUTCAscending);
       
  1502 
       
  1503 	switch (aSortOrder)
       
  1504 		{
       
  1505 		case ETzUTCAscending:
       
  1506 			{
       
  1507 			// Sort order already set
       
  1508 			}
       
  1509 		break;
       
  1510 
       
  1511 		case ETzUTCDescending:
       
  1512 			{
       
  1513 			sortOrder = TLinearOrder<CTzLocalizedTimeZone>(NTzLocalSortAndFind::SortUTCDescending);
       
  1514 			}
       
  1515 		break;
       
  1516 
       
  1517 		case ETzAlphaNameAscending:			//Standard Name
       
  1518 		case ETzAlphaStandardNameAscending:
       
  1519 			{
       
  1520 			sortOrder = TLinearOrder<CTzLocalizedTimeZone>(NTzLocalSortAndFind::SortAlphaStdNameAscending);
       
  1521 			}
       
  1522 		break;
       
  1523 
       
  1524 		case ETzAlphaDaylightNameAscending:
       
  1525 			{
       
  1526 			sortOrder = TLinearOrder<CTzLocalizedTimeZone>(NTzLocalSortAndFind::SortAlphaDSTNameAscending);
       
  1527 			}
       
  1528 		break;
       
  1529 
       
  1530 		case ETzAlphaShortStandardNameAscending:
       
  1531 			{
       
  1532 			sortOrder = TLinearOrder<CTzLocalizedTimeZone>(NTzLocalSortAndFind::SortAlphaShortStdNameAscending);
       
  1533 			}
       
  1534 		break;
       
  1535 
       
  1536 		case ETzAlphaShortDaylightNameAscending:
       
  1537 			{
       
  1538 			sortOrder = TLinearOrder<CTzLocalizedTimeZone>(NTzLocalSortAndFind::SortAlphaShortDSTNameAscending);
       
  1539 			}
       
  1540 		break;
       
  1541 
       
  1542 		case ETzAlphaNameDescending:		//Standard Name
       
  1543 		case ETzAlphaStandardNameDescending:
       
  1544 			{
       
  1545 			sortOrder = TLinearOrder<CTzLocalizedTimeZone>(NTzLocalSortAndFind::SortAlphaStdNameDescending);
       
  1546 			}
       
  1547 		break;
       
  1548 
       
  1549 		case ETzAlphaDaylightNameDescending:
       
  1550 			{
       
  1551 			sortOrder = TLinearOrder<CTzLocalizedTimeZone>(NTzLocalSortAndFind::SortAlphaDSTNameDescending);
       
  1552 			}
       
  1553 		break;
       
  1554 
       
  1555 		case ETzAlphaShortStandardNameDescending:
       
  1556 			{
       
  1557 			sortOrder = TLinearOrder<CTzLocalizedTimeZone>(NTzLocalSortAndFind::SortAlphaShortStdNameDescending);
       
  1558 			}
       
  1559 		break;
       
  1560 
       
  1561 		case ETzAlphaShortDaylightNameDescending:
       
  1562 			{
       
  1563 			sortOrder = TLinearOrder<CTzLocalizedTimeZone>(NTzLocalSortAndFind::SortAlphaShortDSTNameDescending);
       
  1564 			}
       
  1565 		break;
       
  1566 
       
  1567 		default:
       
  1568 			{
       
  1569 			User::Leave(KErrArgument);
       
  1570 			}
       
  1571 		}
       
  1572 	return sortOrder;
       
  1573 	}
       
  1574 
       
  1575 /* Find the city matching the name defined in aLocalizedCity and set its city index to aLocalizedCity
       
  1576 @param aLocalizedCity A CTzLocalizedCity object
       
  1577 @param aDataSource A data source flag
       
  1578 @return Return ETrue if the city has been found, otherwise EFalse.
       
  1579  */
       
  1580 TBool CTzLocalizer::FindCityAndSetCityIndexL(CTzLocalizedCity& aLocalizedCity, TTzLocalizerDataSource aDataSource)
       
  1581 	{
       
  1582 	TBool hasFound = EFalse;
       
  1583     CTzLocalizedCityArray* citiesInDb = CTzLocalizedCityArray::NewLC();
       
  1584     if(aDataSource == ETzDataSourceSystem)
       
  1585     	{
       
  1586     	iStaticDataReader->ReadCitiesL(*citiesInDb);
       
  1587     	}
       
  1588     else
       
  1589     	{
       
  1590     	iUserDataReader->ReadCitiesL(*citiesInDb);
       
  1591     	}
       
  1592 
       
  1593     TInt KCityCount = citiesInDb->Count();
       
  1594     for (TInt i = 0; i < KCityCount; ++i)
       
  1595         {
       
  1596         if (citiesInDb->At(i).Name() == aLocalizedCity.Name())
       
  1597             {
       
  1598             aLocalizedCity.SetCityIndex(citiesInDb->At(i).CityIndex());
       
  1599             hasFound = ETrue;
       
  1600             break;
       
  1601             }
       
  1602         }
       
  1603     CleanupStack::PopAndDestroy(citiesInDb);
       
  1604     return hasFound;
       
  1605 	}
       
  1606 
       
  1607 TBool CTzLocalizer::IsOperateOnUserDbL(TInt aTimeZoneId, TBool aUseDataSource) const
       
  1608 	{
       
  1609 	TBool userDbOperation = EFalse;
       
  1610 	if (iDataSource&ETzDataSourceUser || !aUseDataSource)
       
  1611 		{
       
  1612 		CTzId* tzid = CTzId::NewL(aTimeZoneId);
       
  1613 		userDbOperation = tzid->IsUserTzId();
       
  1614 		delete tzid;
       
  1615 		}
       
  1616 	return userDbOperation;
       
  1617 	}
       
  1618 
       
  1619 void CTzLocalizer::ReadCitiesL(CTzLocalizedCityArray& aCityArray, TInt aTimeZoneId, TBool aUseDataSource) const
       
  1620 	{
       
  1621 	if (IsOperateOnUserDbL(aTimeZoneId, aUseDataSource))
       
  1622 		{
       
  1623 		iUserDataReader->ReadCitiesL(aCityArray, aTimeZoneId);
       
  1624 		}
       
  1625 	else if (iDataSource&ETzDataSourceSystem)
       
  1626 		{
       
  1627 		iStaticDataReader->ReadCitiesL(aCityArray, aTimeZoneId);
       
  1628 		}
       
  1629 	}
       
  1630 
       
  1631 CTzLocalizedCity* CTzLocalizer::ReadDefaultCityL(TInt aTimeZoneId, TBool aUseDataSource) const
       
  1632 	{
       
  1633 	if (IsOperateOnUserDbL(aTimeZoneId, aUseDataSource))
       
  1634 		{
       
  1635 		return iUserDataReader->ReadDefaultCityL(aTimeZoneId);
       
  1636 		}
       
  1637 	else if(iDataSource&ETzDataSourceSystem)
       
  1638 		{
       
  1639 		return iStaticDataReader->ReadDefaultCityL(aTimeZoneId);
       
  1640 		}
       
  1641 	return NULL;
       
  1642 	}
       
  1643 
       
  1644 /**
       
  1645 Sets all the cached zones and their associated cities to be those that are
       
  1646 supplied.
       
  1647 @param aTimeZones Array of time zones to be written.
       
  1648 @param aCities Array of cities to be written.
       
  1649 @internalTechnology
       
  1650 */
       
  1651 void CTzLocalizer::WriteAllFrequentlyUsedZonesL(const CTzLocalizedTimeZoneArray& aTimeZones, const CTzLocalizedCityArray& aCities)
       
  1652 	{
       
  1653 	// Ensure that the numbers of items in the arrays are the expected amount
       
  1654 	__ASSERT_ALWAYS(aTimeZones.Count() == CTzLocalizedTimeZone::ECachedTimeZones &&
       
  1655 					aCities.Count() == CTzLocalizedTimeZone::ECachedTimeZones, User::Leave(KErrArgument));
       
  1656 
       
  1657 	RPointerArray<CTzLocalizedTimeZoneRecord> timeZones;
       
  1658 	CleanupStack::PushL(TCleanupItem(CleanupTimeZonePointerArray,&timeZones));
       
  1659 	TInt i = 0;
       
  1660 	TInt end = aTimeZones.Count();
       
  1661 	timeZones.ReserveL(end);
       
  1662 	while (i < end)
       
  1663 		{
       
  1664 		CTzLocalizedTimeZoneRecord* newTimeZone = CreateTimeZoneRecordL(aTimeZones.At(i));
       
  1665 		timeZones.Append(newTimeZone);
       
  1666 		++i;
       
  1667 		}
       
  1668 
       
  1669 	RPointerArray<CTzLocalizedCityRecord> cities;
       
  1670 	CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray,&cities));
       
  1671 	i = 0;
       
  1672 	end = aCities.Count();
       
  1673 	cities.ReserveL(end);
       
  1674 	while (i < end)
       
  1675 		{
       
  1676 		CTzLocalizedCityRecord* newCity = CreateCityRecordL(aCities.At(i));
       
  1677 		cities.Append(newCity);
       
  1678 		++i;
       
  1679 		}
       
  1680 
       
  1681 	iTzSession.LocalizationWriteAllFrequentlyUsedZonesL(timeZones, cities);
       
  1682 
       
  1683 	CleanupStack::PopAndDestroy();	// cities
       
  1684 	CleanupStack::PopAndDestroy();	// timeZones
       
  1685 	}
       
  1686 
       
  1687 void CTzLocalizer::SetFrequentlyUsedZoneL(const CTzLocalizedTimeZone& aTimeZone, const CTzLocalizedCity& aCity,
       
  1688 		const CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFrequentlyUsedZone)
       
  1689 	{
       
  1690 	CTzLocalizedTimeZoneRecord* timeZoneRecord = CreateTimeZoneRecordLC(aTimeZone);
       
  1691     CTzLocalizedCityRecord* cityRecord = CreateCityRecordLC(aCity);
       
  1692     iTzSession.LocalizationWriteFrequentlyUsedZoneL(*timeZoneRecord, *cityRecord, aFrequentlyUsedZone);
       
  1693     CleanupStack::PopAndDestroy(cityRecord);
       
  1694     CleanupStack::PopAndDestroy(timeZoneRecord);
       
  1695 	}
       
  1696 
       
  1697 CTzLocalizedTimeZone* CTzLocalizer::GetLocalizedTimeZoneL(TInt aTimeZoneId, TBool aUseDataSource) const
       
  1698 	{
       
  1699 	if (IsOperateOnUserDbL(aTimeZoneId, aUseDataSource))
       
  1700 		{
       
  1701 		return iUserDataReader->ReadTimeZoneL(aTimeZoneId);
       
  1702 		}
       
  1703 	else
       
  1704 		{
       
  1705 		return iStaticDataReader->ReadTimeZoneL(aTimeZoneId);
       
  1706 		}
       
  1707 	}
       
  1708 
       
  1709 CTzLocalizedTimeZone* CTzLocalizer::GetLocalizedTimeZoneL(const CTzLocalizedCity& aCity, TBool aUseDataSource) const
       
  1710 	{
       
  1711 	if(IsOperateOnUserDbL(aCity.TzLocalizedId().TimeZoneId(), aUseDataSource))
       
  1712 		{
       
  1713 		return iUserDataReader->ReadTimeZoneL(aCity.TzLocalizedId());
       
  1714 		}
       
  1715 	else
       
  1716 		{
       
  1717 		return iStaticDataReader->ReadTimeZoneL(aCity.TzLocalizedId());
       
  1718 		}
       
  1719 	}
       
  1720 
       
  1721 void CTzLocalizer::PopulateCityArrayL(const RPointerArray<CTzLocalizedCityRecord>& aCityRecords,
       
  1722 		CTzLocalizedCityArray& aCities)
       
  1723 	{
       
  1724 	TInt i = 0;
       
  1725 	TInt end = aCityRecords.Count();
       
  1726 	aCities.ReserveL(aCities.Count() + end);
       
  1727 	while (i < end)
       
  1728 		{
       
  1729 		CTzLocalizedCityRecord* record = aCityRecords[i];
       
  1730 		TTzLocalizedId id(record->TzId(), record->TzResourceId());
       
  1731 		CTzLocalizedCity* city = CTzLocalizedCity::NewL(record->Name(), id, record->GroupId());
       
  1732 		city->SetCityIndex(record->Index());
       
  1733 		aCities.AppendL(city);	// Won't leave since we have reserved the necessary space
       
  1734 		++i;
       
  1735 		}
       
  1736 	}
       
  1737 
       
  1738 CTzLocalizedTimeZoneRecord* CTzLocalizer::CreateTimeZoneRecordL(const CTzLocalizedTimeZone& aTimeZone)
       
  1739 	{
       
  1740 	return CTzLocalizedTimeZoneRecord::NewL(aTimeZone.TimeZoneId(), aTimeZone.StandardName(),
       
  1741 		aTimeZone.DaylightName(), aTimeZone.ShortStandardName(), aTimeZone.ShortDaylightName(),
       
  1742 		aTimeZone.TzLocalizedId().ResourceId());
       
  1743 	}
       
  1744 
       
  1745 CTzLocalizedTimeZoneRecord* CTzLocalizer::CreateTimeZoneRecordLC(const CTzLocalizedTimeZone& aTimeZone)
       
  1746 	{
       
  1747 	return CTzLocalizedTimeZoneRecord::NewLC(aTimeZone.TimeZoneId(), aTimeZone.StandardName(),
       
  1748 		aTimeZone.DaylightName(), aTimeZone.ShortStandardName(), aTimeZone.ShortDaylightName(),
       
  1749 		aTimeZone.TzLocalizedId().ResourceId());
       
  1750 	}
       
  1751 
       
  1752 CTzLocalizedCityRecord* CTzLocalizer::CreateCityRecordL(const CTzLocalizedCity& aCity)
       
  1753 	{
       
  1754 	return CTzLocalizedCityRecord::NewL(aCity.Name(), aCity.GroupId(), aCity.CityIndex(),
       
  1755 		aCity.TimeZoneId(), aCity.TzLocalizedId().ResourceId());
       
  1756 	}
       
  1757 
       
  1758 CTzLocalizedCityRecord* CTzLocalizer::CreateCityRecordLC(const CTzLocalizedCity& aCity)
       
  1759 	{
       
  1760 	return CTzLocalizedCityRecord::NewLC(aCity.Name(), aCity.GroupId(), aCity.CityIndex(),
       
  1761 		aCity.TimeZoneId(), aCity.TzLocalizedId().ResourceId());
       
  1762 	}
       
  1763 
       
  1764 CTzLocalizedTimeZone* CTzLocalizer::CreateTimeZoneL(const CTzLocalizedTimeZoneRecord& aTimeZoneRecord)
       
  1765 	{
       
  1766 	TTzLocalizedId id(aTimeZoneRecord.Id(), aTimeZoneRecord.ResourceId());
       
  1767 	return CTzLocalizedTimeZone::NewL(id, aTimeZoneRecord.StandardName(),
       
  1768 		aTimeZoneRecord.DaylightName(),	aTimeZoneRecord.ShortStandardName(),
       
  1769 		aTimeZoneRecord.ShortDaylightName());
       
  1770 	}
       
  1771 
       
  1772 CTzLocalizedCity* CTzLocalizer::CreateCityL(const CTzLocalizedCityRecord& aCityRecord)
       
  1773 	{
       
  1774 	TTzLocalizedId tzId(aCityRecord.TzId(), aCityRecord.TzResourceId());
       
  1775 	CTzLocalizedCity* city = CTzLocalizedCity::NewL(aCityRecord.Name(), tzId, aCityRecord.GroupId());
       
  1776 	city->SetCityIndex(aCityRecord.Index());
       
  1777 	return city;
       
  1778 	}
       
  1779 
       
  1780 void CTzLocalizer::CleanupTimeZonePointerArray(TAny* aArray)
       
  1781 	{
       
  1782 	RPointerArray<CTzLocalizedTimeZoneRecord>* array = static_cast<RPointerArray<CTzLocalizedTimeZoneRecord>* >(aArray);
       
  1783 	if (array)
       
  1784 		{
       
  1785 		array->ResetAndDestroy();
       
  1786 		array->Close();
       
  1787 		}
       
  1788 	}
       
  1789 
       
  1790 void CTzLocalizer::CleanupCityPointerArray(TAny* aArray)
       
  1791 	{
       
  1792 	RPointerArray<CTzLocalizedCityRecord>* array = static_cast<RPointerArray<CTzLocalizedCityRecord>* >(aArray);
       
  1793 	if (array)
       
  1794 		{
       
  1795 		array->ResetAndDestroy();
       
  1796 		array->Close();
       
  1797 		}
       
  1798 	}