// TCLOCK.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <e32keys.h>
#include <basched.h>
#include <barsread.h>
#include <coecntrl.h>
#include <eikdef.h>
#include <eikenv.h>
#include <eikappui.h>
#include <eikdialg.h>
#include <eikcmds.hrh>
#include <eikclock.h>
#include <eikclock.hrh>
#include <eikapp.h>
#include <eikdoc.h>
#include <eikon.rsg>
#include <tclock.rsg>
#include "tclock.hrh"

enum TTClockPanic
	{
	ETClockPanicBadBrushStyle,
	ETClockPanicBadCommand,
	ETClockPanicClockNotOwnedByThisContainer,
	ETClockPanicClocksHaveAlreadyBeenCreated,
	};

LOCAL_C void Panic(TTClockPanic aPanic)
	{
	User::Panic(_L("TClock"), aPanic);
	}

//
// CTstForeignClock
//

class CTstForeignClock : public CEikClock
	{
public:
	CTstForeignClock(TTimeIntervalSeconds aUniversalTimeOffset, TDaylightSavingZone aDaylightSavingZone);
private:
	virtual void ConstructClockL(CEikLocaleConformantClock& aClock);
private:
	TTimeIntervalSeconds iUniversalTimeOffset;
	TDaylightSavingZone iDaylightSavingZone;
	};

CTstForeignClock::CTstForeignClock(TTimeIntervalSeconds aUniversalTimeOffset, TDaylightSavingZone aDaylightSavingZone)
	:iUniversalTimeOffset(aUniversalTimeOffset),
	 iDaylightSavingZone(aDaylightSavingZone)
	{
	__DECLARE_NAME(_S("CTstForeignClock"));
	}

void CTstForeignClock::ConstructClockL(CEikLocaleConformantClock& aClock)
	{
	aClock.ConstructL(iUniversalTimeOffset, iDaylightSavingZone);
	}

//
// CTstLocaleDialog
//

class CTstLocaleDialog : public CEikDialog
	{
public:
	CTstLocaleDialog(TLocale* aLocale);
private: // framework
	virtual void PreLayoutDynInitL();
	virtual TBool OkToExitL(TInt aKeycode);
private:
	TLocale* iLocale;
	};

CTstLocaleDialog::CTstLocaleDialog(TLocale* aLocale)
	:iLocale(aLocale)
	{
	__DECLARE_NAME(_S("CTstLocaleDialog"));
	}

void CTstLocaleDialog::PreLayoutDynInitL()
	{
	SetCharEditor(ETClockControlIdLocaleDialogTimeSeparator1, iLocale->TimeSeparator(1));
	SetCharEditor(ETClockControlIdLocaleDialogTimeSeparator2, iLocale->TimeSeparator(2));
	SetChoiceListCurrentItem(ETClockControlIdLocaleDialogAmPmSpaceBetween, iLocale->AmPmSpaceBetween());
	SetChoiceListCurrentItem(ETClockControlIdLocaleDialogAmPmSymbolPosition, iLocale->AmPmSymbolPosition());
	SetChoiceListCurrentItem(ETClockControlIdLocaleDialogTimeFormat, iLocale->TimeFormat());
	SetChoiceListCurrentItem(ETClockControlIdLocaleDialogClockFormat, iLocale->ClockFormat());
	}

#pragma warning( disable : 4710 )	// function not expanded

TBool CTstLocaleDialog::OkToExitL(TInt)
	{
	iLocale->SetTimeSeparator(CharEditor(ETClockControlIdLocaleDialogTimeSeparator1), 1);
	iLocale->SetTimeSeparator(CharEditor(ETClockControlIdLocaleDialogTimeSeparator2), 2);
	iLocale->SetAmPmSpaceBetween(ChoiceListCurrentItem(ETClockControlIdLocaleDialogAmPmSpaceBetween));
	iLocale->SetAmPmSymbolPosition((TLocalePos)ChoiceListCurrentItem(ETClockControlIdLocaleDialogAmPmSymbolPosition));
	iLocale->SetTimeFormat((TTimeFormat)ChoiceListCurrentItem(ETClockControlIdLocaleDialogTimeFormat));
	iLocale->SetClockFormat((TClockFormat)ChoiceListCurrentItem(ETClockControlIdLocaleDialogClockFormat));
	return ETrue;
	}

#pragma warning( default : 4710 )	// function not expanded

//
// CTstClockFormatDialog
//

class CTstClockFormatDialog : public CEikDialog
	{
public:
	CTstClockFormatDialog(TClockFormat* aFormat);
private: // framework
	virtual void PreLayoutDynInitL();
	virtual TBool OkToExitL(TInt aKeycode);
private:
	TClockFormat* iFormat;
	};

CTstClockFormatDialog::CTstClockFormatDialog(TClockFormat* aFormat)
	:iFormat(aFormat)
	{
	__DECLARE_NAME(_S("CTstClockFormatDialog"));
	}

void CTstClockFormatDialog::PreLayoutDynInitL()
	{
	SetChoiceListCurrentItem(ETClockControlIdClockFormatDialogFormat, *iFormat);
	}

TBool CTstClockFormatDialog::OkToExitL(TInt)
	{
	*iFormat=(TClockFormat)ChoiceListCurrentItem(ETClockControlIdClockFormatDialogFormat);
	return ETrue;
	}

//
// CTstTimeZoneDialog
//

class CTstTimeZoneDialog : public CEikDialog
	{
public:
	CTstTimeZoneDialog(TTimeIntervalSeconds* aUniversalTimeOffset, TDaylightSavingZone* aDaylightSavingZone);
private: // framework
	virtual void PreLayoutDynInitL();
	virtual TBool OkToExitL(TInt aKeycode);
private:
	TTimeIntervalSeconds *iUniversalTimeOffset;
	TDaylightSavingZone *iDaylightSavingZone;
	};

CTstTimeZoneDialog::CTstTimeZoneDialog(TTimeIntervalSeconds* aUniversalTimeOffset, TDaylightSavingZone* aDaylightSavingZone)
	:iUniversalTimeOffset(aUniversalTimeOffset),
	 iDaylightSavingZone(aDaylightSavingZone)
	{
	__DECLARE_NAME(_S("CTstTimeZoneDialog"));
	}

void CTstTimeZoneDialog::PreLayoutDynInitL()
	{
	SetTimeOffsetEditorValue(ETClockControlIdTimeZoneDialogUniversalTimeOffset, *iUniversalTimeOffset);
	SetChoiceListCurrentItem(ETClockControlIdTimeZoneDialogDaylightSavingZone, *iDaylightSavingZone);
	}

TBool CTstTimeZoneDialog::OkToExitL(TInt)
	{
	*iUniversalTimeOffset=TimeOffsetEditorValue(ETClockControlIdTimeZoneDialogUniversalTimeOffset);
	TInt daylightSavingZone=ChoiceListCurrentItem(ETClockControlIdTimeZoneDialogDaylightSavingZone);
	*iDaylightSavingZone=(TDaylightSavingZone)(daylightSavingZone? 1<<(daylightSavingZone-1): 0);
	return ETrue;
	}

//
// CTstDaylightSavingDialog
//

class CTstDaylightSavingDialog : public CEikDialog
	{
public:
	CTstDaylightSavingDialog(TUint* aDaylightSaving);
private: // framework
	virtual void PreLayoutDynInitL();
	virtual TBool OkToExitL(TInt aKeycode);
private:
	TUint* iDaylightSaving;
	};

CTstDaylightSavingDialog::CTstDaylightSavingDialog(TUint* aDaylightSaving)
	:iDaylightSaving(aDaylightSaving)
	{
	__DECLARE_NAME(_S("CTstDaylightSavingDialog"));
	}

void CTstDaylightSavingDialog::PreLayoutDynInitL()
	{
	SetCheckBoxState(ETClockControlIdDaylightSavingDialogHomeDaylightSaving, (*iDaylightSaving&EDstHome)? CEikButtonBase::ESet: CEikButtonBase::EClear);
	SetCheckBoxState(ETClockControlIdDaylightSavingDialogEuropeanDaylightSaving, (*iDaylightSaving&EDstEuropean)? CEikButtonBase::ESet: CEikButtonBase::EClear);
	SetCheckBoxState(ETClockControlIdDaylightSavingDialogNorthernDaylightSaving, (*iDaylightSaving&EDstNorthern)? CEikButtonBase::ESet: CEikButtonBase::EClear);
	SetCheckBoxState(ETClockControlIdDaylightSavingDialogSouthernDaylightSaving, (*iDaylightSaving&EDstSouthern)? CEikButtonBase::ESet: CEikButtonBase::EClear);
	}

TBool CTstDaylightSavingDialog::OkToExitL(TInt)
	{
	if (CheckBoxState(ETClockControlIdDaylightSavingDialogHomeDaylightSaving)==CEikButtonBase::ESet)
		*iDaylightSaving|=EDstHome;
	else
		*iDaylightSaving&=~EDstHome;
	if (CheckBoxState(ETClockControlIdDaylightSavingDialogEuropeanDaylightSaving)==CEikButtonBase::ESet)
		*iDaylightSaving|=EDstEuropean;
	else
		*iDaylightSaving&=~EDstEuropean;
	if (CheckBoxState(ETClockControlIdDaylightSavingDialogNorthernDaylightSaving)==CEikButtonBase::ESet)
		*iDaylightSaving|=EDstNorthern;
	else
		*iDaylightSaving&=~EDstNorthern;
	if (CheckBoxState(ETClockControlIdDaylightSavingDialogSouthernDaylightSaving)==CEikButtonBase::ESet)
		*iDaylightSaving|=EDstSouthern;
	else
		*iDaylightSaving&=~EDstSouthern;
	return ETrue;
	}

//
// CTstTimeAndDateDialog
//

class CTstTimeAndDateDialog : public CEikDialog
	{
public:
	CTstTimeAndDateDialog(TTime* aTimeAndDate);
private: // framework
	void PreLayoutDynInitL();
	TBool OkToExitL(TInt aKeycode);
private:
	TTime* iTimeAndDate;
	};

CTstTimeAndDateDialog::CTstTimeAndDateDialog(TTime* aTimeAndDate)
	:iTimeAndDate(aTimeAndDate)
	{
	__DECLARE_NAME(_S("CTstTimeAndDateDialog"));
	}

void CTstTimeAndDateDialog::PreLayoutDynInitL()
	{
	SetTTimeEditorValue(ETClockControlIdTimeAndDateDialogTimeAndDate, *iTimeAndDate);
	}

TBool CTstTimeAndDateDialog::OkToExitL(TInt)
	{
	*iTimeAndDate=TTimeEditorValue(ETClockControlIdTimeAndDateDialogTimeAndDate);
	return ETrue;
	}

//
// CTstContainer
//

class CTstContainer : public CCoeControl, public MCoeControlContext, public MEikClockContainer
	{
public:
	CTstContainer();
	void ConstructL(const TRect& aRect);
	virtual ~CTstContainer();
	void HandleCommandL(TInt aCommand);
private:
	// framework
	virtual void MakeVisible(TBool aVisible);
	virtual void ActivateL();
	virtual void HandlePointerEventL(const TPointerEvent& aPointerEvent);
	virtual void SizeChangedL();
	virtual void PositionChanged();
	virtual TInt CountComponentControls() const;
	virtual CCoeControl* ComponentControl(TInt aIndex) const;
	virtual void Draw(const TRect& aRect) const;
	virtual void PrepareContext(CWindowGc& aGc) const;
	virtual TBool ClockIsVisible(const CEikLocaleConformantClock& aClock) const;
	virtual void GetClockPositionAndSize(TPoint& aPosition, TSize& aSize, const CEikLocaleConformantClock& aClock, const TSize& aMinimumSize);
	virtual void DrawClockDeferred(const TRect& aRect) const;
	// other functions
	void CreateClocksL(TBool aForeign);
	void CreateSpecialClocks();
private:
	enum {ESpacing=3};
private:
	TInt iNumClocks;
	CEikClock** iClocks;
	TInt iNumForeignClocks;
	CEikClock** iForeignClocks;
	CEikLocaleConformantClock* iClockIgnoringLocaleTimeZoneButConformingToFormat;
	CEikLocaleConformantClock* iClockIgnoringLocaleTimeZoneAndFormat;
	TPoint iOffsetToCenterOfClockIgnoringLocaleTimeZoneButConformingToFormat;
	TPoint iOffsetToCenterOfClockIgnoringLocaleTimeZoneAndFormat;
	CGraphicsContext::TBrushStyle iBrushStyle;
	};

CTstContainer::CTstContainer()
	:iBrushStyle(CGraphicsContext::ESolidBrush)
	{
	__DECLARE_NAME(_S("CTstContainer"));
	}

void CTstContainer::ConstructL(const TRect& aRect)
	{
	CreateWindowL();
	SetControlContext(this);
	Window().SetShadowDisabled(ETrue);
	Window().SetBackgroundColor(TRgb(170, 170, 170));
	CreateClocksL(EFalse);
	CreateClocksL(ETrue);
	CreateSpecialClocks();
	SetRectL(aRect);
	ActivateL();
	}

CTstContainer::~CTstContainer()
	{
	if (iClocks)
		{
		for (TInt i=0; i<iNumClocks; ++i)
			delete iClocks[i];
		delete [] iClocks;
		}
	if (iForeignClocks)
		{
		for (TInt i=0; i<iNumForeignClocks; ++i)
			delete iForeignClocks[i];
		delete [] iForeignClocks;
		}
	delete iClockIgnoringLocaleTimeZoneButConformingToFormat;
	delete iClockIgnoringLocaleTimeZoneAndFormat;
	}

void CTstContainer::HandleCommandL(TInt aCommand)
	{
	switch (aCommand)
		{
	case ETClockCmdChangeBackground:
		switch (iBrushStyle)
			{
		case CGraphicsContext::ESolidBrush:
			iBrushStyle=CGraphicsContext::EPatternedBrush;
			break;
		case CGraphicsContext::EPatternedBrush:
			iBrushStyle=CGraphicsContext::ESolidBrush;
			break;
		default:
			Panic(ETClockPanicBadBrushStyle);
			break;
			}
		DrawNow();
		break;
	case ETClockCmdLocaleDialog:
		{
		TLocale locale;
		CEikDialog* dialog=new(ELeave) CTstLocaleDialog(&locale);
		if (dialog->ExecuteLD(R_TCLOCK_LOCALE_DIALOG))
			locale.Set();
		}
		break;
	case ETClockCmdClockFormatDialog:
		{
		TClockFormat format=iClockIgnoringLocaleTimeZoneAndFormat->Format();
		CEikDialog* dialog=new(ELeave) CTstClockFormatDialog(&format);
		if (dialog->ExecuteLD(R_TCLOCK_CLOCK_FORMAT_DIALOG))
			iClockIgnoringLocaleTimeZoneAndFormat->ChangeFormatL(format);
		}
		break;
	case ETClockCmdHomeTimeZoneDialog:
		{
		TLocale locale;
		TTimeIntervalSeconds universalTimeOffset=locale.UniversalTimeOffset();
		TDaylightSavingZone daylightSavingZone=locale.HomeDaylightSavingZone();
		CEikDialog* dialog=new(ELeave) CTstTimeZoneDialog(&universalTimeOffset, &daylightSavingZone);
		if (dialog->ExecuteLD(R_TCLOCK_HOME_TIME_ZONE_DIALOG))
			{
			locale.SetUniversalTimeOffset(universalTimeOffset);
			locale.SetHomeDaylightSavingZone(daylightSavingZone);
			locale.Set();
			}
		}
		break;
	case ETClockCmdForeignTimeZoneDialog:
		{
		TTimeIntervalSeconds universalTimeOffset;
		TDaylightSavingZone daylightSavingZone;
		iClockIgnoringLocaleTimeZoneButConformingToFormat->GetUniversalTimeOffsetAndDaylightSavingZone(universalTimeOffset, daylightSavingZone);
		CEikDialog* dialog=new(ELeave) CTstTimeZoneDialog(&universalTimeOffset, &daylightSavingZone);
		if (dialog->ExecuteLD(R_TCLOCK_FOREIGN_TIME_ZONE_DIALOG))
			{
			iClockIgnoringLocaleTimeZoneButConformingToFormat->ChangeUniversalTimeOffsetAndDaylightSavingZone(universalTimeOffset, daylightSavingZone);
			iClockIgnoringLocaleTimeZoneAndFormat->ChangeUniversalTimeOffsetAndDaylightSavingZone(universalTimeOffset, daylightSavingZone);
			}
		}
		break;
	case ETClockCmdDaylightSavingDialog:
		{
		TLocale locale;
		TUint daylightSaving=locale.DaylightSaving();
		CEikDialog* dialog=new(ELeave) CTstDaylightSavingDialog(&daylightSaving);
		if (dialog->ExecuteLD(R_TCLOCK_DAYLIGHT_SAVING_DIALOG))
			{
			locale.SetDaylightSaving(daylightSaving);
			locale.Set();
			}
		}
		break;
	case ETClockCmdHomeTimeAndDateDialog:
		{
		TTime homeTimeAndDate;
		homeTimeAndDate.HomeTime();
		CEikDialog* dialog=new(ELeave) CTstTimeAndDateDialog(&homeTimeAndDate);
		if (dialog->ExecuteLD(R_TCLOCK_HOME_TIME_AND_DATE_DIALOG))
			User::SetHomeTime(homeTimeAndDate);
		}
		break;
	case ETClockCmdShowCurrentTime:
		{
		TInt notUsed;
		TTime time;
		time.HomeTime();
		TBuf<128> buffer=_L("");
		TBuf<64> tempBuffer=_L("");
		TRAP(notUsed, time.FormatL(tempBuffer, _L("Home: %-B%J%:1%T%:2%S%+B")));
		buffer.Append(tempBuffer);
		tempBuffer=_L("");
		buffer.Append(_L(" - "));
		time.UniversalTime();
		TRAP(notUsed, time.FormatL(tempBuffer, _L("Universal: %-B%J%:1%T%:2%S%+B")));
		buffer.Append(tempBuffer);
		tempBuffer=_L("");
		iEikonEnv->InfoMsg(buffer);
		}
		break;
	case ETClockCmdToggleVisibility:
		MakeVisible(!IsVisible());
		break;
	case EEikCmdExit:
		CBaActiveScheduler::Exit();
		break;
	default:
		Panic(ETClockPanicBadCommand);
		break;
		}
	}

void CTstContainer::MakeVisible(TBool aVisible)
	{
	CCoeControl::MakeVisible(aVisible);
	iClockIgnoringLocaleTimeZoneButConformingToFormat->SetVisible(aVisible);
	iClockIgnoringLocaleTimeZoneAndFormat->SetVisible(aVisible);
	}

void CTstContainer::ActivateL()
	{
	CCoeControl::ActivateL();
	iClockIgnoringLocaleTimeZoneButConformingToFormat->SetVisible(IsVisible());
	iClockIgnoringLocaleTimeZoneAndFormat->SetVisible(IsVisible());
	}

void CTstContainer::HandlePointerEventL(const TPointerEvent& aPointerEvent)
	{
	CCoeControl::HandlePointerEventL(aPointerEvent);
	if ((GrabbingComponent()==NULL) && (aPointerEvent.iType==TPointerEvent::EButton1Down) && iClockIgnoringLocaleTimeZoneAndFormat->Rect().Contains(aPointerEvent.iPosition))
		iClockIgnoringLocaleTimeZoneAndFormat->ChangeFormatL((iClockIgnoringLocaleTimeZoneAndFormat->Format()==EClockDigital)? EClockAnalog: EClockDigital);
	}

void CTstContainer::SizeChangedL()
	{
	TPoint position(ESpacing, ESpacing);
	TSize size;
	TInt maxClockHeight=0;
	TInt maxAnyClockWidth=0;
	TInt i;
	for (i=0; i<iNumClocks; ++i)
		{
		size=iClocks[i]->MinimumSize();
		if (maxClockHeight<size.iHeight)
			maxClockHeight=size.iHeight;
		if (maxAnyClockWidth<size.iWidth)
			maxAnyClockWidth=size.iWidth;
		iClocks[i]->SetExtentL(position, size);
		position.iX+=size.iWidth+ESpacing;
		}
	position.iX=ESpacing;
	position.iY+=maxClockHeight+ESpacing;
	TInt maxForeignClockHeight=0;
	for (i=0; i<iNumForeignClocks; ++i)
		{
		size=iForeignClocks[i]->MinimumSize();
		if (maxForeignClockHeight<size.iHeight)
			maxForeignClockHeight=size.iHeight;
		if (maxAnyClockWidth<size.iWidth)
			maxAnyClockWidth=size.iWidth;
		iForeignClocks[i]->SetExtentL(position, size);
		position.iX+=size.iWidth+ESpacing;
		}
	position.iX=ESpacing+(maxAnyClockWidth/2);
	position.iY+=maxForeignClockHeight+ESpacing+(Max(maxClockHeight, maxForeignClockHeight)/2);
	iOffsetToCenterOfClockIgnoringLocaleTimeZoneButConformingToFormat=position;
	position.iX+=maxAnyClockWidth+ESpacing;
	iOffsetToCenterOfClockIgnoringLocaleTimeZoneAndFormat=position;
	GetClockPositionAndSize(position, size, *iClockIgnoringLocaleTimeZoneButConformingToFormat, iClockIgnoringLocaleTimeZoneButConformingToFormat->MinimumSize());
	iClockIgnoringLocaleTimeZoneButConformingToFormat->SetPositionAndSize(position, size);
	GetClockPositionAndSize(position, size, *iClockIgnoringLocaleTimeZoneAndFormat, iClockIgnoringLocaleTimeZoneAndFormat->MinimumSize());
	iClockIgnoringLocaleTimeZoneAndFormat->SetPositionAndSize(position, size);
	}

void CTstContainer::PositionChanged()
	{
	TPoint position;
	TSize size;
	GetClockPositionAndSize(position, size, *iClockIgnoringLocaleTimeZoneButConformingToFormat, iClockIgnoringLocaleTimeZoneButConformingToFormat->MinimumSize());
	iClockIgnoringLocaleTimeZoneButConformingToFormat->SetPosition(position);
	GetClockPositionAndSize(position, size, *iClockIgnoringLocaleTimeZoneAndFormat, iClockIgnoringLocaleTimeZoneAndFormat->MinimumSize());
	iClockIgnoringLocaleTimeZoneAndFormat->SetPosition(position);
	}

TInt CTstContainer::CountComponentControls() const
	{
	return iNumClocks+iNumForeignClocks;
	}

CCoeControl* CTstContainer::ComponentControl(TInt aIndex) const
	{
	return (aIndex<iNumClocks)? iClocks[aIndex]: iForeignClocks[aIndex-iNumClocks];
	}

void CTstContainer::Draw(const TRect&) const
	{
	CWindowGc& gc=SystemGc();
	gc.SetPenStyle(CGraphicsContext::ENullPen);
	gc.DrawRect(Rect());
	gc.SetPenStyle(CGraphicsContext::ESolidPen);
	iClockIgnoringLocaleTimeZoneButConformingToFormat->Draw(gc);
	iClockIgnoringLocaleTimeZoneAndFormat->Draw(gc);
	}

void CTstContainer::PrepareContext(CWindowGc& aGc) const
	{
	if (iBrushStyle==CGraphicsContext::EPatternedBrush)
		iEikonEnv->SetTexturedBrush(aGc);
	else
		{
		aGc.SetBrushStyle(iBrushStyle);
		aGc.SetBrushColor(TRgb(170, 170, 170));
		}
	}

TBool CTstContainer::ClockIsVisible(const CEikLocaleConformantClock&) const
	{
	return IsActivated();
	}

void CTstContainer::GetClockPositionAndSize(TPoint& aPosition, TSize& aSize, const CEikLocaleConformantClock& aClock, const TSize& aMinimumSize)
	{
	TPoint center=iPosition;
	if (&aClock==iClockIgnoringLocaleTimeZoneButConformingToFormat)
		center+=iOffsetToCenterOfClockIgnoringLocaleTimeZoneButConformingToFormat;
	else if (&aClock==iClockIgnoringLocaleTimeZoneAndFormat)
		center+=iOffsetToCenterOfClockIgnoringLocaleTimeZoneAndFormat;
	else
		Panic(ETClockPanicClockNotOwnedByThisContainer);
	aPosition=center-TPoint(aMinimumSize.iWidth/2, aMinimumSize.iHeight/2);
	aSize=aMinimumSize;
	}

void CTstContainer::DrawClockDeferred(const TRect& aRect) const
	{ // !! why is this routine needed - it certainly won't work in the backed up case
	if (IsBackedUp())
		BackedUpWindow().UpdateScreen();
	else
		Window().Invalidate(aRect);
	}

void CTstContainer::CreateClocksL(TBool aForeign)
	{
	CEikClock**& clocks=aForeign? iForeignClocks: iClocks;
	TInt& numClocks=aForeign? iNumForeignClocks: iNumClocks;
	__ASSERT_ALWAYS(clocks==NULL, Panic(ETClockPanicClocksHaveAlreadyBeenCreated));
	TResourceReader resourceReader;
	iCoeEnv->CreateResourceReaderLC(resourceReader, R_TCLOCK_CLOCKS); // also pushes on to CleanupStack
	numClocks=resourceReader.ReadUint8();
	clocks=new(ELeave) CEikClock*[numClocks];
	TInt i;
	for (i=0; i<numClocks; ++i)
		clocks[i]=NULL;
	for (i=0; i<numClocks; ++i)
		{
		clocks[i]=aForeign? new(ELeave) CTstForeignClock(-5*3600, EDstNorthern): new(ELeave) CEikClock; // New York time, or else home time
		clocks[i]->SetContainerWindowL(*this);
		clocks[i]->ConstructFromResourceL(resourceReader);
		}
	CleanupStack::PopAndDestroy();
	}

void CTstContainer::CreateSpecialClocks()
	{
	RAnimDll& animDll=iEikonEnv->ClockDllL();
	RWindowBase& window=Window();
	iClockIgnoringLocaleTimeZoneButConformingToFormat=new(ELeave) CEikResourceConstructedClock(*this, animDll, window, EEikLocaleConformantClockTypeChangesFormatAccordingToLocale,
																					EFalse, *iCoeEnv, R_TCLOCK_DIGITAL_CLOCK_TEST_TEXT_FORMAT, R_EIK_ANALOG_CLOCK);
	iClockIgnoringLocaleTimeZoneButConformingToFormat->ConstructL(2*3600, EDstEuropean);
	iClockIgnoringLocaleTimeZoneAndFormat=new(ELeave) CEikResourceConstructedClock(*this, animDll, window, EEikLocaleConformantClockTypeDigital,
																					EFalse, *iCoeEnv, R_TCLOCK_DIGITAL_CLOCK, R_EIK_ANALOG_CLOCK);
	iClockIgnoringLocaleTimeZoneAndFormat->ConstructL(2*3600, EDstEuropean);
	}

//
// CTstAppUi
//

class CTstAppUi : public CEikAppUi
	{
public:
	void ConstructL();
	virtual ~CTstAppUi();
private: // framework
	virtual void HandleCommandL(TInt aCommand);
private:
	CTstContainer* iContainer;
	};

void CTstAppUi::ConstructL()
	{
	BaseConstructL();
	CreateHotKeyControlL(R_TCLOCK_HOTKEYS);
	iContainer=new(ELeave) CTstContainer;
	iContainer->ConstructL(ClientRect());
	AddToStackL(iContainer);
	}

CTstAppUi::~CTstAppUi()
	{
	delete iContainer;
	}

void CTstAppUi::HandleCommandL(TInt aCommand)
	{
	iContainer->HandleCommandL(aCommand);
	}

//
// CTstDocument
//

class CTstDocument : public CEikDocument
	{
public:
	CTstDocument(CEikApplication& aApp): CEikDocument(aApp) { }
private: // from CApaDocument
	CEikAppUi* CreateAppUiL();
	};

CEikAppUi* CTstDocument::CreateAppUiL()
	{
    return(new(ELeave) CTstAppUi);
	}

//
// CTstApplication
//

class CTstApplication : public CEikApplication
	{
private: // from CApaApplication
	CApaDocument* CreateDocumentL();
	TUid AppDllUid() const;
	};

const TUid KUidTstApp={234};

TUid CTstApplication::AppDllUid() const
	{
	return(KUidTstApp);
	}

CApaDocument* CTstApplication::CreateDocumentL()
	{
	return(new(ELeave) CTstDocument(*this));
	}

//
// EXPORTed functions
//

EXPORT_C CApaApplication* NewApplication()
	{
	return(new CTstApplication);
	}

GLDEF_C TInt E32Dll(TDllReason)
	{
	return(KErrNone);
	}
