/*
* Copyright (c) 2002-2005 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

// AknDialog.cpp
//
// Copyright (c) 2001 Symbian Ltd.  All rights reserved.
//

#include <AknDialog.h>
#include <eikmenub.h>
#include <eikenv.h>
#include <aknappui.h>
#include "aknenv.h"
#include <eikcapc.h>
#include <eikdialogext.h>
#include <avkon.hrh>
#include <avkon.rsg>
#include <aknsoundsystem.h>
#include "aknitemactionmenuregister.h"

#include <AknsDrawUtils.h>
#include <AknsFrameBackgroundControlContext.h>
#include "AknUtils.h"

#include <skinlayout.cdl.h>
using namespace SkinLayout;



class CAknDialogAttributes: public CBase
	{
public:
	~CAknDialogAttributes()
		{
		delete iBgContext;
		delete iBrushAndPenContext;
		}
public: // data
	TInt iAknDialogFlags;
	CAknsFrameBackgroundControlContext* iBgContext;	
    CCoeBrushAndPenContext* iBrushAndPenContext;
	TRect iOuterRect;
	TRect iInnerRect;
	TBool iNeedsUpdate;
	};

/**
 * Constructor 
 */
EXPORT_C CAknDialog::CAknDialog() 
	{
	}


/**
 * Creates a menu using a menu resource.
 * A menu resource MUST be specified - this function will Panic otherwise.  If a menu is not required use CEikDialog!
 */
EXPORT_C void CAknDialog::ConstructL(TInt aMenuTitleResourceId)
	{
    if ( !iAttributes ) 
        {
		AttributesL();        
		}
	
	CreateMenuBarL(aMenuTitleResourceId);
	
	iAttributes->iAknDialogFlags &= ~EAknDialogFlagNotConstructed;
	}

/**
 *
 */
EXPORT_C CAknDialog::~CAknDialog() 
	{
    AknItemActionMenuRegister::RemoveConstructingMenuBarOwner( this );

    if ( iCoeEnv->AppUi() && iAttributes )
		if (iAttributes->iAknDialogFlags&EAknDialogFlagDefaultSounds) // return original sound stack
			{
			iAvkonAppUiBase->KeySounds()->PopContext();
			}

	if (iMenuBar) 
		{
		if ( iAttributes )
			{
			iAttributes->iAknDialogFlags |= EAknDialogFlagDialogDeleted;
			}
		HideMenu();
		iEikonEnv->EikAppUi()->RemoveFromStack(iMenuBar);
		delete iMenuBar;
		}
	delete iAttributes;
	}

EXPORT_C void CAknDialog::PrepareLC(TInt aResourceId)
	{ 
	if (!iMenuBar)
		{
		// PrepareLC has to keep ownership of "this".
		CleanupStack::PushL(this);	
		CreateMenuBarL(R_AVKON_DIALOG_EMPTY_MENUBAR); // empty menu bar
		CleanupStack::Pop(this);
		}
	CEikDialog::PrepareLC(aResourceId);
	}

EXPORT_C TInt CAknDialog::RunLD()
	{
	return CEikDialog::RunLD();
	}

/**
 * Swap the Application menu with the Form's menu before displaying
 *
 */
EXPORT_C TInt CAknDialog::ExecuteLD(TInt aResourceId) 
	{
    if ( iCoeEnv->AppUi() ) // Enable default tones while dialog / form is on screen
        {
        CleanupStack::PushL(this);
		if (!iAttributes)
			{
			AttributesL();
			iAttributes->iAknDialogFlags |= EAknDialogFlagNotConstructed; // Way to indicate to SetEmphasis that other members are  not accessible
			}

        iAvkonAppUiBase->KeySounds()->PushContextL(R_AVKON_DEFAULT_SKEY_LIST);
        iAttributes->iAknDialogFlags |= EAknDialogFlagDefaultSounds;
        CleanupStack::Pop();
        }

	return ( CEikDialog::ExecuteLD(aResourceId) );	
    }

/**
 *From MEikMenuObserver
 * (called when menu is cancelled)
 * Called also from destructor ( EAknDialogFlagDialogDeleted is set)
 */
EXPORT_C void CAknDialog::SetEmphasis(CCoeControl* aMenuControl,TBool aEmphasis)
	{
	if (!iAttributes 
		|| iAttributes->iAknDialogFlags & EAknDialogFlagNotConstructed
		|| iAttributes->iAknDialogFlags & EAknDialogFlagDialogDeleted)
		return;

	CEikAppUi* appUi = iEikonEnv->EikAppUi();
	appUi->RemoveFromStack(aMenuControl);
    // Remove focus from aMenuControl because AppUi's RemoveFromStack won't do
    // that.
    aMenuControl->SetFocus( EFalse );
	TRAP_IGNORE(appUi->AddToStackL(aMenuControl, aEmphasis ? ECoeStackPriorityDialog : ECoeStackPriorityMenu));
	appUi->UpdateStackedControlFlags(this, aEmphasis ? ECoeStackFlagRefusesFocus : 0, ECoeStackFlagRefusesFocus);
	appUi->UpdateStackedControlFlags(aMenuControl, aEmphasis ? 0 : ECoeStackFlagRefusesFocus, ECoeStackFlagRefusesFocus);
	appUi->HandleStackChanged();
	}

/**
 * This function intialiases the items on the menu.  It's used to disable and enable menu items and may be
 * over ridden to add new ones.
 * NOTE that it might be called with the 'wrong' ResourceId so it must do a check and not assume.
 *
 */
EXPORT_C void CAknDialog::DynInitMenuPaneL(TInt /*aResourceId*/, CEikMenuPane* /*aMenuPane*/) 
	{
	}

/**
 *From MEikCommandObserver
 */
EXPORT_C void CAknDialog::ProcessCommandL(TInt /* aCommandId */)
	{
	HideMenu();
	}


/**
 * From CCoeControl
 *
 * If MMC is supported always process user input (MMC PIN requester does not seem
 * to have focus when it pops up)
 */
EXPORT_C TKeyResponse CAknDialog::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType) 
	{
	if (IsFocused() ||
		(aType == EEventKey && aKeyEvent.iCode == EKeyEscape)
		)
		return (CEikDialog::OfferKeyEventL(aKeyEvent, aType));
	else
		return EKeyWasNotConsumed;
	}



/**
 *
 * From CEikDialog - If there is an Options key then pops up menu, otherwise exits.  Override this if necessary.
 */
EXPORT_C TBool CAknDialog::OkToExitL(TInt aButtonId) 
	{
	TBool retVal;

	if (iMenuBar)
		HideMenu();
	
	if (aButtonId == EAknSoftkeyOptions)
		{
		DisplayMenuL();
		retVal = EFalse;
		}
	else 
		{
		retVal = ETrue;
		}

	if (aButtonId == EAknSoftkeyMark || aButtonId == EAknSoftkeyUnmark)
		{
		retVal = EFalse;
		}

	return retVal;
	}


/**
 * 
 */
EXPORT_C void CAknDialog::DisplayMenuL() 
	{
    if (iMenuBar)
        {
        iMenuBar->TryDisplayMenuBarL();
        }
	}

/**
 * 
 */
EXPORT_C void CAknDialog::HideMenu() 
	{
	iMenuBar->StopDisplayingMenuBar();
	}

EXPORT_C void CAknDialog::FocusChanged(TDrawNow aDrawNow)
	{
	if (!iAttributes || iAttributes->iAknDialogFlags & EAknDialogFlagDialogDeleted)
		return;
	TInt controlID = IdOfFocusControl();
	if (controlID)
		Line(controlID)->SetFocus(IsFocused(), aDrawNow);			
	}

/**
 * 
 */
EXPORT_C TBool CAknDialog::MenuShowing() const
	{
	return iMenuBar->IsDisplayed();
	}


EXPORT_C void CAknDialog::Reserved_MtsmPosition()
	{
	}

EXPORT_C void CAknDialog::Reserved_MtsmObject()
	{
	}

EXPORT_C void CAknDialog::HandlePointerEventL(const TPointerEvent& aPointerEvent)
    {
    CEikDialog::HandlePointerEventL(aPointerEvent);
    }   

EXPORT_C void* CAknDialog::ExtensionInterface( TUid /*aInterface*/ ) 
    { 
    return NULL;
    }

void CAknDialog::CreateMenuBarL(TInt aMenuTitleResourceId)
	{
	if (iMenuBar)
		{
		// just replace the content if it doesn't already exist
		iMenuBar->TitleArray()->ResetAndDestroy();
		iMenuBar->SetMenuTitleResourceId(aMenuTitleResourceId);
		}
	else
		{
		CEikMenuBar* newMenuBar = new (ELeave) CEikMenuBar();
		CleanupStack::PushL(newMenuBar);
		newMenuBar->ConstructL(this, NULL, aMenuTitleResourceId);
		iEikonEnv->EikAppUi()->AddToStackL(newMenuBar,ECoeStackPriorityMenu,ECoeStackFlagRefusesFocus);
		iMenuBar=newMenuBar;
		CleanupStack::Pop(); // now owned by this Dialog.
		}

    AknItemActionMenuRegister::SetConstructingMenuBarOwnerL( this );
	}

//
// UpdateBgContext is done here because we dont want to create huge icons 
// always when dialog is launched. The icon is anyway used only when
// queries are used, so deferring its creation to MopSupplyObject;
// this saves considerable amount of time and memory for non-popup
// dialogs. SetFrameRects renders the qsn_fr_popup, so deferring that call.
//
static void UpdateBgContext(CAknDialogAttributes &aAttrs)
	{
	if (aAttrs.iNeedsUpdate)
		{
		TRect outerRect = aAttrs.iOuterRect;
		TRect innerRect = aAttrs.iInnerRect;
		aAttrs.iBgContext->SetFrameRects( outerRect, innerRect );
		aAttrs.iNeedsUpdate = EFalse;
		}
	}

EXPORT_C TTypeUid::Ptr CAknDialog::MopSupplyObject(TTypeUid aId)
	{	
	// Must test on the type of dialog before supplying an object
	if ( Extension() ) { 
	    if ( aId.iUid == MAknsControlContext::ETypeId && 
		    Extension()->LayoutCategory() == CEikDialogExtension::EPopupLayout )
			    {
		    if (!iAttributes)
			    {
			    TRAPD( err, AttributesL() );
			    if ( err )
				    {
				    delete iAttributes;
				    iAttributes = 0;
				    return CEikDialog::MopSupplyObject(aId);
				    }
			    else
				    {
				    iAttributes->iAknDialogFlags |= EAknDialogFlagNotConstructed; // Way to indicate to SetEmphasis that other members are  not accessible
				    }
			    }
			UpdateBgContext(*iAttributes);
		    return MAknsControlContext::SupplyMopObject(aId, iAttributes->iBgContext );
		    }
        }
	if (aId.iUid == CEikMenuBar::ETypeId)
		return aId.MakePtr(iMenuBar);
	else
		return CEikDialog::MopSupplyObject(aId);
	}

EXPORT_C void CAknDialog::Draw(const TRect& aRect) const
	{

		CEikDialog::Draw(aRect); // Frame drawing done in eikdialog
	}
	
EXPORT_C void CAknDialog::SizeChanged()
	{
	if (iAttributes)
		{
		TRect windowRect = Rect();
	
		TAknLayoutRect topLeft;
        topLeft.LayoutRect(windowRect, Popup_windows_skin_placing__frame_general__Line_2());

		TAknLayoutRect bottomRight;
        bottomRight.LayoutRect(windowRect, Popup_windows_skin_placing__frame_general__Line_5());

		TRect outerRect = TRect(topLeft.Rect().iTl, bottomRight.Rect().iBr);
		TRect innerRect = TRect(topLeft.Rect().iBr, bottomRight.Rect().iTl);

		iAttributes->iOuterRect = outerRect;
		iAttributes->iInnerRect = innerRect;
		iAttributes->iNeedsUpdate = ETrue;
		iAttributes->iBgContext->SetParentPos( PositionRelativeToScreen() );
		}
	CEikDialog::SizeChanged();
	}

EXPORT_C void CAknDialog::CEikDialog_Reserved_1()
	{
	}
	
EXPORT_C void CAknDialog::CEikDialog_Reserved_2()
	{
	}

EXPORT_C void CAknDialog::CAknDialog_Reserved()
	{
	}

CAknDialogAttributes* CAknDialog::AttributesL()
	{
	if ( !iAttributes )
		{
		iAttributes = new (ELeave) CAknDialogAttributes();
        
		TRect windowRect = Rect();
	
		TAknLayoutRect topLeft;
        topLeft.LayoutRect(windowRect, Popup_windows_skin_placing__frame_general__Line_2());

		TAknLayoutRect bottomRight;
		bottomRight.LayoutRect(windowRect, ELayoutEmpty, 169, ELayoutEmpty, ELayoutEmpty, 2, 7,7);
        bottomRight.LayoutRect(windowRect, Popup_windows_skin_placing__frame_general__Line_5());

        TRect outerRect = TRect(topLeft.Rect().iTl, bottomRight.Rect().iBr);
		TRect innerRect = TRect(topLeft.Rect().iBr, bottomRight.Rect().iTl);

		iAttributes->iBgContext = CAknsFrameBackgroundControlContext::NewL(
				KAknsIIDQsnFrPopup, outerRect, innerRect, ETrue );


		if ( &Window() )
			iAttributes->iBgContext->SetParentPos( PositionRelativeToScreen() );
		}
	
	return iAttributes; 
	}

// end of CAknDialog
