// EIKDIALG.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//
 
#include <eikdialg.h>
#include <eikdialg.hrh>
#include <eikmover.h>
#include <eikcapc.h>
#include <eikcapca.h>
#include <eikcmbut.h>
#include <eiklabel.h>
#include <eikdialg.pan>
#include <barsread.h>
#include <eikenv.h>
#include <eikbtpan.h>
#include <eikpgsel.h>
#include <eikon.rsg>
#include <eikcolor.h>

const TInt KCapCHorzEdgeSpacing=8;


GLDEF_C void Panic(TEikDialogPanic aPanic)
	{
	User::Panic(_L("EIKON-DIALOG"),aPanic);
	}

enum
    { // follow on from values in EIKDIALG.HRH
    EEikDialogFlagIsWaiting	=0x10000,
    EEikDialogFlagSleeping	=0x20000,
	EEikDialogFlagBroughtForward=0x40000
    };

EXPORT_C CEikDialog::CEikDialog()
    {
	__DECLARE_NAME(_S("CEikDialog"));
	iBorder=TEikBorder(TEikBorder::EThickDeepRaisedWithOutline);
#if defined (__DEBUG__)
	RDebug::ProfileReset(PROFILE_POINT_EIKON_DIALOG_LOAD,1);
	RDebug::ProfileStart(PROFILE_POINT_EIKON_DIALOG_LOAD);
#endif
    }

EXPORT_C CEikDialog::~CEikDialog()
    {
	if (iDialogFlags&EEikDialogFlagBroughtForward)
		iEikonEnv->BringForwards(EFalse);
    delete(iTitleBar);
	if (iPageSelector)
		delete iPageSelector; // one of the pages owns iLines
	else
		delete iLines;
	iLines=NULL; // prevent CEikForm dtor trying to delete iLines again
	delete(iButtonPanel);
	if (!(iDialogFlags&EEikDialogFlagModeless))
	    iEikonEnv->RemoveFromStack(this);
    if (iDialogFlags&EEikDialogFlagIsWaiting)
        CActiveScheduler::Stop();
    }

void CEikDialog::DynamicConstructL()
	{
    PreLayoutDynInitL();
    SetSizeAndPositionL(MinimumSize());
    PostLayoutDynInitL();
	}

EXPORT_C void CEikDialog::PrepareLC(TInt aResourceId)
    {
    CleanupStack::PushL(this);
	BaseConstructL();
    StaticConstructL(aResourceId);
    }

EXPORT_C TInt CEikDialog::ExecuteLD(TInt aResourceId)
    {
	PrepareLC(aResourceId);
	return(RunLD());
    }

void CEikDialog::BaseConstructL()
	{
    CreateWindowL();
	iEikonEnv->AddWindowShadow(this);
	EnableDragEvents();
	Window().SetPointerGrab(ETrue);
    iContext=this;
    iBrushStyle=CGraphicsContext::ESolidBrush;
	iBrushColor=iEikonEnv->ControlColor(EEikColorDialogBackground,*this);
    Window().SetBackgroundColor(iEikonEnv->ControlColor(EEikColorDialogBackground,*this));
	}

void CEikDialog::StaticConstructL(TInt aResourceId)
    {
    TResourceReader reader;
    iCoeEnv->CreateResourceReaderLC(reader,aResourceId);
    ConstructFromResourceL(reader);
	CleanupStack::PopAndDestroy();
    }

EXPORT_C void CEikDialog::ConstructSleepingDialogL(TInt aResourceId)
	{
	CommonConstructSleepingDialog(aResourceId);
    iEikonEnv->AddSleepingDialogToStackL(this);
	}

EXPORT_C void CEikDialog::ConstructSleepingAlertDialogL(TInt aResourceId)
	{
 	CommonConstructSleepingDialog(aResourceId);
	iEikonEnv->AddSleepingAlertDialogToStackL(this);
	}

void CEikDialog::CommonConstructSleepingDialog(TInt aResourceId)
	//
	// code common to both ConstructSleepingDialogL & ConstructSleepingAlertDialogL
	//
	{
	BaseConstructL();
	StaticConstructL(aResourceId);
	MakeVisible(EFalse);
	iDialogFlags|=EEikDialogFlagSleeping;
	}

TInt CEikDialog::WaitAsRequired()
    {
    TInt exitConfirmed=0;
#if defined (__DEBUG__)
	RDebug::ProfileEnd(PROFILE_POINT_EIKON_DIALOG_LOAD);
	TProfile profile;
	RDebug::ProfileResult(&profile,PROFILE_POINT_EIKON_DIALOG_LOAD,1);
	TBuf<60> tmp;
	tmp.Format(_L("Time to load dialog: %d milliseconds"),profile.iTime/1000);
	iEikonEnv->VerboseInfoMsg(tmp);
#endif
    if (iDialogFlags&EEikDialogFlagWait)
        {
	    iExitConfirmed=(&exitConfirmed);
        iDialogFlags|=EEikDialogFlagIsWaiting;
        CActiveScheduler::Start();
        }
    return(exitConfirmed);
    }

EXPORT_C TInt CEikDialog::RouseSleepingDialog()
	{ // none of following ...L calls to Leave
	if (IsVisible())
		ExitSleepingDialog(); // eg for rousing an already roused Alert dialog
	ResetLineMinimumSizes();
	DynamicConstructL();
	iEikonEnv->BringForwards(ETrue); // before the call to EnableBackup()
	iDialogFlags|=EEikDialogFlagBroughtForward;
	DrawableWindow()->SetOrdinalPosition(0);
	if (~iDialogFlags&EEikDialogFlagNoBackup)
		DrawableWindow()->EnableBackup();
	MakeVisible(ETrue);
	iEikonEnv->RouseSleepingDialog(this,ETrue);
	if (iCoeEnv->LastEvent().Type()==EEventPointer)
		ClaimPointerGrab(ETrue); // send pointer up to any dragged component
    ActivateL();
    SetInitialCurrentLine();
    return(WaitAsRequired());
	}

EXPORT_C void CEikDialog::ExitSleepingDialog()
	{
	MakeVisible(EFalse);
	iEikonEnv->RouseSleepingDialog(this,EFalse);
	if (iDialogFlags&EEikDialogFlagBroughtForward)
		{
		iEikonEnv->BringForwards(EFalse);
		iDialogFlags&=(~EEikDialogFlagBroughtForward);
		}
    if (iDialogFlags&EEikDialogFlagIsWaiting)
        {
		CActiveScheduler::Stop();
		iDialogFlags&=(~EEikDialogFlagIsWaiting);
		}
	}

void CEikDialog::ResetLineMinimumSizes()
	{
	iLines->ResetMinimumSizes(); // !! what about MP dialogs?
	}

EXPORT_C void CEikDialog::ConstructFromResourceL(TResourceReader& aReader)
    {
    iDialogFlags=aReader.ReadInt16();
	CreateTitleBarL();
	iTitleBar->ConstructFromResourceL(aReader);
	CreatePageSelectorL(aReader.ReadInt32());
    CreateButtonsL(aReader.ReadInt32());
	CCoeControl* container=this;
	TInt resourceId=0;
	TResourceReader* reader=(&aReader);
	if (!iPageSelector)
	    iLines=new(ELeave) CEikCapCArray(1); // granularity
	else
		{
		iLines=iPageSelector->StartConstructPageL(0,container,resourceId);
		if (resourceId)
			{
			TResourceReader indirectReader;
			iCoeEnv->CreateResourceReaderLC(indirectReader,resourceId);
			reader=(&indirectReader);
			}
		}
	ConstructPageFromResourceL(iLines,*reader,container);
	if (resourceId)
		CleanupStack::PopAndDestroy();
	ConstructRemainingPagesL();
	}

void CEikDialog::ConstructRemainingPagesL()
	{
	if (!iPageSelector)
		return;
	TInt pageIndex=0;
	FOREVER
		{
		CCoeControl* container=this;
		TInt resourceId;
		CEikCapCArray* lines=iPageSelector->StartConstructPageL(++pageIndex,container,resourceId);
		if (!lines)
			return; // passed the last page
		if (!resourceId)
			continue; // loading deferred
		TResourceReader reader;
		iCoeEnv->CreateResourceReaderLC(reader,resourceId);
		ConstructPageFromResourceL(lines,reader,container);
		CleanupStack::PopAndDestroy();
		}
	}

void CEikDialog::ConstructPageFromResourceL(CEikCapCArray* aLines,TResourceReader& aReader,CCoeControl* aContainer)
	{
    const TInt lineCount=aReader.ReadInt16();
	if (lineCount==EEikDlgMainPageIndirect)
		{
		TInt indirectRid=aReader.ReadInt32();
		if (!indirectRid)
			return;
	    TResourceReader indirectReader;
	    iCoeEnv->CreateResourceReaderLC(indirectReader,indirectRid);
		ConstructPageFromResourceL(aLines,indirectReader,aContainer);
		CleanupStack::PopAndDestroy();
		return;
		}
	if (iDialogFlags&EEikDialogFlagDensePacking)
		aLines->SetDensePacking(ETrue);
    CEikCaptionedControl* line=NULL;
    aLines->AppendL(line,lineCount); // reserve space for all the lines
	CCoeControl* previous=NULL;
    for (TInt ii=0; ii<lineCount; ++ii)
        {
        line=new(ELeave) CEikCaptionedControl;
		line->CopyControlContextFrom(this);
		aLines->At(ii)=line;
        TInt controlType=aReader.ReadInt16();
		TResourceReader* reader=(&aReader);
		TInt indirectRid=0;
		if (controlType==EEikDlgItemIndirect)
			{
			indirectRid=aReader.ReadInt32();
		    TResourceReader indirectReader;
		    iCoeEnv->CreateResourceReaderLC(indirectReader,indirectRid);
        	controlType=indirectReader.ReadInt16();
			reader=(&indirectReader);
			}
		ConstructByTypeL(controlType,line,aContainer);
		line->iControl->SetNeighbor(previous);
		previous=line->iControl;
        line->ConstructFromResourceL(*reader);
		if (indirectRid)
			CleanupStack::PopAndDestroy();
		CheckNonFocusingState(line->iControl);
        }
    }

void CEikDialog::CheckNonFocusingState(CCoeControl* aControl)
	{ // static
	if (!aControl->OwnsWindow())
		aControl->SetNonFocusing();
	}

void CEikDialog::CreatePageSelectorL(TInt aResourceId)
	{
	if (!aResourceId)
		return;
	iPageSelector = new(ELeave) CEikPageSelector;
	iPageSelector->SetContainerWindowL(*this);
    iPageSelector->CopyControlContextFrom(this);
	iPageSelector->SetObserver(this);
	TResourceReader reader;
    iCoeEnv->CreateResourceReaderLC(reader,aResourceId);
	iPageSelector->ConstructFromResourceL(reader);
	CleanupStack::PopAndDestroy();
	}

void CEikDialog::CreateButtonsL(TInt aResourceId)
    {
	if (!aResourceId)
		return;
	iButtonPanel=new(ELeave) CEikButtonPanel;
	iButtonPanel->SetContainerWindowL(*this);
	iButtonPanel->SetObserver(this);
    iButtonPanel->CopyControlContextFrom(this);
	if (! (iDialogFlags&EEikDialogFlagButtonsRight))
		iButtonPanel->SetHorizontal();
    TResourceReader reader;
    iCoeEnv->CreateResourceReaderLC(reader,aResourceId);
	iButtonPanel->ConstructFromResourceL(reader);
	CleanupStack::PopAndDestroy();
    }

EXPORT_C void CEikDialog::PreLayoutDynInitL()
    {
    }

EXPORT_C void CEikDialog::PostLayoutDynInitL()
    {
    }

EXPORT_C void CEikDialog::SetSizeAndPositionL(const TSize& aSize)
    {
    SetCornerAndSizeL(EHCenterVCenter,aSize);
    }

EXPORT_C TSize CEikDialog::MinimumSize()
    {
    TSize size=iPageSelector ? iPageSelector->MinimumPageSize() : iLines->MinimumSize();
    const TSize titleSize= (iDialogFlags&EEikDialogFlagNoTitleBar) ? TSize(0,0) 
																   : iTitleBar->MinimumSize();
	if (iDialogFlags&EEikDialogFlagFillScreen)	// minimum size should be called first.//buttonpanel minsize gets called by sizechanged()
		return iEikonEnv->ScreenDevice()->SizeInPixels();
	if (iButtonPanel)
		{
		const TSize butPnlSize = iButtonPanel->MinimumSize();
		const TSize pgSelSize = iPageSelector ? iPageSelector->MinimumSize() : TSize(0,0);
		size.iHeight+=pgSelSize.iHeight;
		if (pgSelSize.iWidth>size.iWidth)
			size.iWidth=pgSelSize.iWidth;
		if (iDialogFlags&EEikDialogFlagButtonsRight)
			{
			size.iWidth+=butPnlSize.iWidth;
			if (butPnlSize.iHeight>size.iHeight)
				size.iHeight=butPnlSize.iHeight;
			}
    	else	// by default, buttons are laid out along the bottom
			{
			if (butPnlSize.iWidth>size.iWidth)
				size.iWidth=butPnlSize.iWidth;
			size.iHeight+=butPnlSize.iHeight;
			}
		}
	size.iHeight+=titleSize.iHeight;
	if (titleSize.iWidth>size.iWidth)
		size.iWidth=titleSize.iWidth;
    size += iBorder.SizeDelta();
    return size;
    }

EXPORT_C void CEikDialog::SizeChangedL()
    {
    TRect rect=iBorder.InnerRect(Rect());
	if (iTitleBar)
		iTitleBar->SetTitleLeftMargin(KCapCHorzEdgeSpacing);
	const TInt bottomY=rect.iBr.iY;
	if (!(iDialogFlags&EEikDialogFlagNoTitleBar))
		{
		rect.iBr.iY=rect.iTl.iY+iTitleBar->MinimumSize().iHeight;
		iTitleBar->SetRectL(rect);
		rect.iTl.iY=rect.iBr.iY;
		rect.iBr.iY=bottomY;
		}
	if (!iButtonPanel)
		{
		if (iPageSelector)
			{
			rect.iBr.iY = rect.iTl.iY + iPageSelector->MinimumSize().iHeight;
			iPageSelector->SetRectL(TRect(rect.iTl, iPageSelector->MinimumSize()));
			rect.iBr.iY = bottomY;
			}
		SetLinesRectL(rect);
		return;
		}
	TRect tmp=rect;
	TSize butSize=iButtonPanel->MinimumSize();
	TSize pgSelSize = iPageSelector ? iPageSelector->MinimumSize() : TSize(0,0);
	if (iDialogFlags & EEikDialogFlagButtonsRight)
		{
		tmp.iBr.iX-=butSize.iWidth;
		if (iPageSelector)
			{
			iPageSelector->SetRectL(TRect(tmp.iTl, pgSelSize));
			}
		SetLinesRectL(TRect(tmp.iTl+TPoint(0, pgSelSize.iHeight), tmp.iBr));
		tmp.iTl.iX=tmp.iBr.iX;
		tmp.iBr.iX=rect.iBr.iX;
		iButtonPanel->SetRectL(tmp);
		}
    else
		{
		if (iPageSelector)
			{
			tmp.iBr.iY = tmp.iTl.iY+pgSelSize.iHeight;
			iPageSelector->SetRectL(TRect(tmp.iTl, pgSelSize));
			tmp.iTl.iY = tmp.iBr.iY;
			tmp.iBr.iY=bottomY;
			}
		tmp.iBr.iY-=butSize.iHeight;
		SetLinesRectL(tmp);
		tmp.iTl.iY=tmp.iBr.iY;
		tmp.iBr.iY=rect.iBr.iY;
		iButtonPanel->SetRectL(tmp);
		}
    }

void CEikDialog::SetLinesRectL(const TRect& aRect)
	{
	if (iPageSelector)
		iPageSelector->SetPagesRectL(aRect);
	else
		iLines->SetRectL(aRect);
	}

EXPORT_C TInt CEikDialog::LineIndexFromId(TInt aControlId,CEikCapCArray*& aArray) const
    {
	if (!iPageSelector)
		return CEikForm::LineIndexFromId(aControlId,aArray);
	TInt ii=0;
	CEikCapCArray* lines;
	TInt index=KErrNotFound;
	while (iPageSelector->GetNextPage(ii++,lines))
		{
		if (!lines)
			continue;
		index=lines->LineIndexFromId(aControlId);
		if (index<0)
			continue;
		aArray=lines;
		break;
		}
	return(index);
    }

void CEikDialog::HandlePageChangeL()
	{
	if (iCurrentLine >= 0)
		{
		PrepareForFocusTransitionL();
		ChangeFocusTo(-1);
		}
	iLines=iPageSelector->SwapPageDetails(iCurrentLine);
	PageChangedL(iPageSelector->CurrentPageControlId());
	}

TInt CEikDialog::IdFromLineNumber(TInt aLineNumber) const
	{
	return((*iLines)[aLineNumber]->iId);
	}

TInt CEikDialog::FindButtonId(CCoeControl* aControl) const
	{
	return(iButtonPanel? iButtonPanel->ButtonId(aControl): 0);
	}

EXPORT_C CEikMover* CEikDialog::Title() const
	{
	return(iTitleBar);
	}

EXPORT_C void CEikDialog::SetTitleL(const TDesC& aText)
    {
	iTitleBar->SetTextL(aText);
    }

EXPORT_C void CEikDialog::SetTitleL(TInt aResourceId)
    {
    TBuf<80> tmp;
    iCoeEnv->ReadResource(tmp,aResourceId);
    SetTitleL(tmp);
    }

EXPORT_C void CEikDialog::SetLineDimmedNow(TInt aControlId,TBool aDimmed)
    {
    CEikCaptionedControl* line=Line(aControlId);
	CCoeControl* control=line->iControl;
	if (!control->IsDimmed() == !aDimmed)
		return;
	control->SetDimmed(aDimmed);
    line->CheckDimmedDisplayState();
    control->DrawNow();
    }

EXPORT_C void CEikDialog::SetLineNonFocusing(TInt aControlId)
	{
    CEikCaptionedControl* line=Line(aControlId);
	line->SetNonFocusing();
	line->iControl->SetNonFocusing();
	}

EXPORT_C void CEikDialog::MakeLineVisible(TInt aControlId,TBool aVisible)
    {
    CEikCaptionedControl* line=Line(aControlId);
	CCoeControl* control=line->iControl;
	if (control->IsVisible()==aVisible)
		return;
    control->MakeVisible(aVisible);
    line->CheckDimmedDisplayState();
    }

EXPORT_C void CEikDialog::MakeWholeLineVisible(TInt aControlId,TBool aVisible)
    {
    CEikCaptionedControl* line=Line(aControlId);
	if (line->IsVisible()==aVisible)
		return;
	CCoeControl* control=line->iControl;
    if (line->iCaption)
		line->iCaption->MakeVisible(aVisible);
	if (line->iTrailer)
		line->iTrailer->MakeVisible(aVisible);
    control->MakeVisible(aVisible);
	line->MakeVisible(aVisible);
    }

EXPORT_C void CEikDialog::DeleteLine(TInt aControlId)
	{
	CEikCapCArray* array;
	TInt index=LineIndexFromId(aControlId,array);
	if (index<0)
		Panic(EEikDialogPanicNoSuchControl);
	array->DeleteLine(index);
	}

EXPORT_C void CEikDialog::InsertLineL(TInt aIndex,TInt aResourceId,TInt aPageId)
	{
	CEikCapCArray* lines=iLines;
	CCoeControl* container=this;
	if (aPageId)
		lines=iPageSelector->InfoFromPageId(aPageId,container);
    CEikCaptionedControl* line=new(ELeave) CEikCaptionedControl;
	CleanupStack::PushL(line);
	lines->InsertL(aIndex,line);
	CleanupStack::Pop();
	TResourceReader reader;
    iCoeEnv->CreateResourceReaderLC(reader,aResourceId);
    const TInt controlType=reader.ReadInt16();
	ConstructByTypeL(controlType,line,container);
    line->ConstructFromResourceL(reader);
	CleanupStack::PopAndDestroy();
	CheckNonFocusingState(line->iControl);
	}

EXPORT_C void CEikDialog::SetPageDensePacking(TInt aPageId,TBool aDensePacking)
	{
	CEikCapCArray* lines=iLines;
	CCoeControl* container;
	if (iPageSelector)
		lines=iPageSelector->InfoFromPageId(aPageId,container);
	lines->SetDensePacking(aDensePacking);
	}

void CEikDialog::CreateTitleBarL()
	{
	iTitleBar=new(ELeave) CEikMover;
    iTitleBar->SetContainerWindowL(*this);
	if (iDialogFlags&EEikDialogFlagNoDrag)
		return;
	iTitleBar->SetActive(ETrue);
	}

EXPORT_C void CEikDialog::ConstructAutoDialogLC(TInt aFlags,TInt aButtonsId)
	{
    CleanupStack::PushL(this);
	BaseConstructL();
	iDialogFlags=aFlags;
	CreateTitleBarL();
	iLines=new(ELeave) CEikCapCArray (4);
	if (iDialogFlags & EEikDialogFlagDensePacking)
		iLines->SetDensePacking(ETrue);
	CreateButtonsL(aButtonsId);
	}

EXPORT_C void CEikDialog::SetButtonPanel(CEikButtonPanel* aButtonPanel)
	{
    if (! (iDialogFlags&EEikDialogFlagButtonsRight))
		aButtonPanel->SetHorizontal();
	iButtonPanel = aButtonPanel;  // dialog takes ownership
	}

EXPORT_C CEikButtonPanel* CEikDialog::ButtonPanel()
	{
	return iButtonPanel;
	}	

EXPORT_C CEikPageSelector* CEikDialog::PageSelector()
	{
	return iPageSelector;
	}

EXPORT_C void CEikDialog::DeclareItemAuto(TInt aControlId,TInt aControlType,TAny* aReturnValue)
	{
	CEikCaptionedControl* line=Line(aControlId);
	if (line->iControlType!=aControlType)
		Panic(EEikDialogPanicWrongAutoType);
	line->iReturnValue=aReturnValue;
	}

EXPORT_C TInt CEikDialog::RunLD()
	{
	DynamicConstructL();
	if (!(iDialogFlags&EEikDialogFlagModeless))
	    iEikonEnv->AddDialogLikeControlToStackL(this);
	iEikonEnv->BringForwards(ETrue); // before call to EnableBackup()
	iDialogFlags|=EEikDialogFlagBroughtForward;
	if (~iDialogFlags&EEikDialogFlagNoBackup)
		DrawableWindow()->EnableBackup();
    ActivateL();
    SetInitialCurrentLine();
    CleanupStack::Pop();
    return(WaitAsRequired());
	}

EXPORT_C void CEikDialog::Draw(const TRect& /*aRect*/) const
    {
	TRect rect=Rect();
	CGraphicsContext& gc=SystemGc();
	iBorder.Draw(gc,rect);
	TRect innerRect=iBorder.InnerRect(rect);
	gc.SetPenStyle(CGraphicsContext::ENullPen);
    gc.DrawRect(innerRect);
    }

TKeyResponse CEikDialog::TryAnimateButtonAndExitL(TInt aKeycode)
	{
	TInt buttonId=EEikBidCancel;
	switch (aKeycode)
		{
	case EKeyEnter:
		buttonId=EEikBidOk;
		break;
	case EKeySpace:
		buttonId=EEikBidSpace;
		break;
	case EKeyTab:
		buttonId=EEikBidTab;
		break;
	case EKeyBackspace:
		buttonId=EEikBidDelete;
		break;
		}
	CEikCommandButtonBase* button=(iButtonPanel? iButtonPanel->ButtonById(buttonId) : NULL);
	if (button)
		{
		if (button->IsDimmed() || !button->IsVisible())
			return EKeyWasNotConsumed;
		button->Animate();
		}
	if (button || buttonId==EEikBidCancel || (buttonId==EEikBidOk && iButtonPanel==NULL))
		{
		TryExitL(buttonId);
		return EKeyWasConsumed;
		}
	return EKeyWasNotConsumed;
	}

EXPORT_C void CEikDialog::PrepareForFocusTransitionL()
    {
    if (iCurrentLine < 0) 
		{
		if (iPageSelector)
			iPageSelector->PrepareForFocusLossL();
		else
			return;
		}
	else
		(*iLines)[iCurrentLine]->iControl->PrepareForFocusLossL();
    }

EXPORT_C TKeyResponse CEikDialog::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
    {
    if (aType!=EEventKey)
        return(EKeyWasConsumed);
	TInt code=aKeyEvent.iCode;
	TInt foldedCode=TCharF(code);
	TInt topmostFocusableLineIndex = -1;
	TInt bottommostFocusableLineIndex = -1;
	const TUint modifiers = aKeyEvent.iModifiers;
	if (iDialogFlags&EEikDialogFlagAllKeysToButtons)
		{
		if (ButtonsConsumedKeyL(foldedCode))
			return(EKeyWasConsumed);
		}
	else if ((modifiers & EAllStdModifiers) == EModifierCtrl)
        {
		if (ButtonsConsumedKeyL(foldedCode))
			return(EKeyWasConsumed);
        }
	TKeyResponse response;
    switch (code)
        {
    case EKeyEnter:
		if ((iCurrentLine>=0 && (*iLines)[iCurrentLine]->TakesEnterKey()) ||
			(modifiers&EModifierCtrl && !(modifiers&EModifierPureKeycode)))
			goto KeyToFocus; // else fall through
    case EKeyEscape:
		if (modifiers&EModifierShift)
			goto KeyToFocus;
		if (!(modifiers&EModifierCtrl) || modifiers&EModifierPureKeycode)
			TryAnimateButtonAndExitL(code);
        break;
	case EKeyTab:
		if (iPageSelector && aKeyEvent.iModifiers&EModifierCtrl)
			{
			response = iPageSelector->OfferKeyEventL(aKeyEvent, aType);
			if (response==EKeyWasConsumed)
				break;
			}
		// drop through
	case EKeySpace:
	case EKeyBackspace:
		if (TryAnimateButtonAndExitL(code)==EKeyWasConsumed)
			break;
		goto KeyToFocus;
	case EKeyLeftArrow:
	case EKeyRightArrow:
		if (iPageSelector && iPageSelector->IsFocused())
			{
			response = iPageSelector->OfferKeyEventL(aKeyEvent, aType);
			if (response == EKeyWasNotConsumed)
				goto KeyToFocus;
			}
		else
            goto KeyToFocus;
		break;
    case EKeyDownArrow:
		if (iPageSelector && iPageSelector->IsFocused())
			{
			topmostFocusableLineIndex = TopmostFocusableLineIndex();
			if (topmostFocusableLineIndex >= 0)
				{
    			PrepareForFocusTransitionL();
    			ChangeFocusTo(topmostFocusableLineIndex);
				}
			return(EKeyWasConsumed);
			}
		if (iCurrentLine >= 0)
			{
			response = (*iLines)[iCurrentLine]->iControl->OfferKeyEventL(aKeyEvent,aType);
			if (response == EKeyWasConsumed)
				return(EKeyWasConsumed);
			}
		if (iPageSelector && (iCurrentLine==BottommostFocusableLineIndex()) && (iCurrentLine >= 0))
			{
			if (!(iPageSelector->IsFocused()))
				{
    			PrepareForFocusTransitionL();
				ChangeFocusTo(-1);	
				}
			return(EKeyWasConsumed);
			}
		if (!RotateFocusByL(+1))
			goto KeyToFocus;
        break;
    case EKeyUpArrow:
		if (iPageSelector && iPageSelector->IsFocused())
			{
			bottommostFocusableLineIndex = BottommostFocusableLineIndex();
			if (bottommostFocusableLineIndex >= 0)
				{
    			PrepareForFocusTransitionL();
    			ChangeFocusTo(bottommostFocusableLineIndex);
				}
			return(EKeyWasConsumed);
			}
		if (iCurrentLine >= 0)
			{
			response = (*iLines)[iCurrentLine]->iControl->OfferKeyEventL(aKeyEvent,aType);
			if (response == EKeyWasConsumed)
				return(EKeyWasConsumed);
			}
		if ((iPageSelector && iCurrentLine==TopmostFocusableLineIndex()) && (iCurrentLine >= 0))
			{
			if (!(iPageSelector->IsFocused()))
				{
    			PrepareForFocusTransitionL();
				ChangeFocusTo(-1);	
				}
			return(EKeyWasConsumed);
			}
        if (!RotateFocusByL(-1))
            goto KeyToFocus;
        break;
    default:
    KeyToFocus:
		// the following code should be moved after the focused control's OfferKeyEventL once controls 
		// only consume key events they really use
		const TInt count=iLines->Count();
		for (TInt ii=0;ii<count;ii++)
			{
			if ((*iLines)[ii]->OfferHotKeys() &&
				(*iLines)[ii]->iControl->OfferKeyEventL(aKeyEvent,aType)==EKeyWasConsumed)
				return EKeyWasConsumed;
			}
		//
        if (iCurrentLine>=0)
            (*iLines)[iCurrentLine]->iControl->OfferKeyEventL(aKeyEvent,aType);
        }
    return(EKeyWasConsumed);
    }

EXPORT_C void CEikDialog::TryExitL(TInt aButtonId)
    {
	if (iDialogFlags&EEikDialogFlagNoUserExit)
		return;
    if (aButtonId!=EEikBidCancel)
        PrepareForFocusTransitionL();
    else if (!(iDialogFlags&EEikDialogFlagNotifyEsc))
		goto finished;
	if (!OkToExitL(aButtonId))
        return;
	if (aButtonId!=EEikBidCancel)
		GetAutoValues();
finished:
    if (iExitConfirmed)
        *iExitConfirmed=(aButtonId==EEikBidCancel? 0: aButtonId);
	if (iDialogFlags&EEikDialogFlagSleeping)
		ExitSleepingDialog();
	else
	    delete(this);
    }

TInt CEikDialog::TopmostFocusableLineIndex() const
	{
	TInt lineIndex = 0;
	TInt lastLineIndex = iLines->Count() - 1;
	while (lineIndex <= lastLineIndex)
		{
		CEikCaptionedControl* line = (*iLines)[lineIndex];
		if (line->IsNonFocusing() || line->IsDimmed() || !(line->IsVisible()))
			++lineIndex;
		else
			break;
		}
	if (lineIndex > lastLineIndex)
		return(-1);
	else
		return(lineIndex);
	}

TInt CEikDialog::BottommostFocusableLineIndex() const
	{
	TInt lineIndex = iLines->Count() - 1;
	while (lineIndex >= 0)
		{
		CEikCaptionedControl* line = (*iLines)[lineIndex];
		if (line->IsNonFocusing() || line->IsDimmed() || !(line->IsVisible()))
			--lineIndex;
		else
			break;
		}
	return(lineIndex);
	}

void CEikDialog::GetAutoValues()
	{
	if (!iPageSelector)
		{
		GetAutoValuesFromPage(iLines);
		return;
		}
	TInt ii=0;
	CEikCapCArray* lines;
	while (iPageSelector->GetNextPage(ii++,lines))
		{
		if (lines)
			GetAutoValuesFromPage(lines);
		}
	}

TBool CEikDialog::ButtonsConsumedKeyL(TInt aCode)
	{
	if (!iButtonPanel)
		return(EFalse);
	TInt buttonId;
	CEikCommandButtonBase* button=iButtonPanel->ButtonForKey(aCode,buttonId);
	if (!button)
		return(EFalse);
	if (button->IsDimmed())
		{
		HandleInteractionRefused(buttonId);
		return(EFalse);
		}
	if (!button->IsVisible())
		return(EFalse);
	button->Animate();
	TryExitL(buttonId);
    return(ETrue);
	}

EXPORT_C void CEikDialog::TryChangeFocusToL(TInt aControlId)
    {
    PrepareForFocusTransitionL();
	CEikCapCArray* array;
	TInt index=LineIndexFromId(aControlId,array);
	if (index<0)
		Panic(EEikDialogPanicNoSuchControl);
	if (index==iCurrentLine && array==iLines)
		return;
	ShowFocus(EFalse);
	if (array!=iLines)
		{
		iPageSelector->ChangePageL(array,-1);
		iLines=array;
		PageChangedL(iPageSelector->CurrentPageControlId());
		}
	iCurrentLine=index;
	ShowFocus(ETrue);
    }

EXPORT_C TInt CEikDialog::CountComponentControls() const
    {
	TInt count = (iButtonPanel? 2: 1); // includes the title bar
	if (iPageSelector)
		count++;
	else
		count+=iLines->Count();
	return(count);
    }

EXPORT_C CCoeControl* CEikDialog::ComponentControl(TInt aIndex) const
    {
    if (!aIndex)
        return(iTitleBar);
	if (iPageSelector)
		{
		if (aIndex==1)
			return(iPageSelector);
		}
	else
		{
		TInt lineCount = iLines->Count();
		if (aIndex<=lineCount)
			return((*iLines)[--aIndex]);
		}
	return(iButtonPanel);
    }

EXPORT_C void CEikDialog::ShowFocus(TBool aFocus)
	{
	if (iCurrentLine>=0)
	    (*iLines)[iCurrentLine]->SetCurrent(aFocus);
	else if (iPageSelector)
		iPageSelector->SetFocus(aFocus, EDrawNow);
	}
  
EXPORT_C void CEikDialog::HandleControlEventL(CCoeControl* aControl,TCoeEvent aEventType)
    {
    switch (aEventType)
        {
    case EEventPrepareFocusTransition:
        PrepareForFocusTransitionL();
        break;
    case EEventRequestFocus:
	    ChangeFocusTo(FindLineIndex(aControl));
        break;
    case EEventStateChanged:
		{
		if (aControl==iPageSelector)
			{
			HandlePageChangeL();
			return;
			}
		TInt lineNumber=FindLineIndex(aControl);
		if (lineNumber>=0)
	        HandleControlStateChangeL(IdFromLineNumber(lineNumber));
		else
			{
			TInt buttonId=FindButtonId(aControl);
			TryExitL(buttonId);
			}
		}
        break;
    case EEventInteractionRefused:
		{
		TInt id=0;
		if (aControl==iPageSelector)
			id=iPageSelector->IdOfUnavailableSelectedPage();
		else
			{
			TInt lineNumber=FindLineIndex(aControl);
			if (lineNumber>=0)
				id=IdFromLineNumber(lineNumber);
			else
				id=FindButtonId(aControl);
			}
	    HandleInteractionRefused(id);
		}
        break;
    default:
        break;
        }
    }

EXPORT_C void CEikDialog::SetInitialCurrentLine()
    {
    const TInt count=iLines->Count();
    TInt ii=-1;
    while (++ii<count)
        {
        CEikCaptionedControl* line=(*iLines)[ii];
		if (line->IsNonFocusing() || line->IsDimmed() || !(line->IsVisible()))
            continue;
        ChangeFocusTo(ii);
        break;
        }
	if (ii==count)	// i.e. no focusable line was found
		{
		iCurrentLine=-1;
		if (iPageSelector)
			iPageSelector->SetFocus(ETrue,EDrawNow);
		}
    }

EXPORT_C TBool CEikDialog::OkToExitL(TInt /*aButtonId*/)
    {
    return(ETrue);
    }

EXPORT_C void CEikDialog::HandleControlStateChangeL(TInt /*aControlId*/)
    {
    }

EXPORT_C void CEikDialog::HandleInteractionRefused(TInt aControlId)
    {
	iEikonEnv->InfoMsg(aControlId? R_EIK_TBUF_NOT_AVAILABLE: R_EIK_TBUF_PAGE_NOT_AVAILABLE);
    }

EXPORT_C void CEikDialog::AdjustAllIdsOnPage(TInt aPageId,TInt aControlIdDelta)
	{
	CCoeControl* unused;
	CEikCapCArray* lines=iPageSelector->InfoFromPageId(aPageId,unused);
	lines->AdjustAllIds(aControlIdDelta);
	}

EXPORT_C void CEikDialog::MakePanelButtonVisible(TInt aButtonId,TBool aVisible)
	{
	ButtonPanel()->MakeButtonVisible(aButtonId,aVisible);
	}

EXPORT_C void CEikDialog::PageChangedL(TInt /*aControlId*/)
	{
	}

EXPORT_C void CEikDialog::SwitchLineLatency(TInt aBecomesLatent,TInt aNoLongerLatent)
	{
	CEikCaptionedControl* becomesLatent=Line(aBecomesLatent);
	CEikCaptionedControl* noLongerLatent=Line(aNoLongerLatent);
#if defined(_DEBUG)
	if (becomesLatent->IsLatent() || !noLongerLatent->IsLatent())
		Panic(EEikDialogPanicWrongLatencySwitch);
#endif
	becomesLatent->SetLatent(ETrue);
	noLongerLatent->SetLatent(EFalse);
	noLongerLatent->CheckDimmedDisplayState();
	}

EXPORT_C void CEikDialog::SetPageDimmedNow(TInt aPageId,TBool aDimmed)
	{
	iPageSelector->SetPageDimmed(aPageId,aDimmed);
	}

EXPORT_C void CEikDialog::Reserved_1()
	{}
EXPORT_C void CEikDialog::Reserved_2()
	{}
EXPORT_C void CEikDialog::Reserved_3()
	{}
EXPORT_C void CEikDialog::Reserved_4()
	{}
