/*
* Copyright (c) 2007 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 : FreestyleEmailUi message details view implementation
*  Version     : %version: e003sa37#48 %
*
*/



// SYSTEM INCLUDES
#include "emailtrace.h"
#include <AknUtils.h>
#include <gulicon.h>
#include <freestyleemailui.mbg>
#include <FreestyleEmailUi.rsg>
#include <StringLoader.h>
#include <AknBidiTextUtils.h>
#include <akntitle.h>
// <cmail> SF
#include <alf/alfdecklayout.h>
#include <alf/alfcontrolgroup.h>
#include <alf/alfframebrush.h>
#include <alf/alfevent.h>
// </cmail>
#include <featmgr.h>
//</cmail>

//<cmail>
#include "cfsmailmessage.h"
#include "cfsmailclient.h"
//</cmail>

#include "FSEmailBuildFlags.h"
//<cmail>
#include "cfsccontactactionmenu.h"
#include "mfsccontactactionmenumodel.h"
//</cmail>

//<cmail>
#include "fstreelist.h"
#include "fstreevisualizerbase.h"
#include "fstreeplainonelinenodedata.h"
#include "fstreeplainonelinenodevisualizer.h"
#include "fstreeplainonelineitemdata.h"
#include "fstreeplainonelineitemvisualizer.h"
#include "fstreeplaintwolineitemdata.h"
#include "fstreeplaintwolineitemvisualizer.h"
#include <csxhelp/cmail.hlp.hrh>
#include "AknWaitDialog.h"
// </cmail>

// INTERNAL INCLUDES
#include "FreestyleEmailUiAppui.h"
#include "FreestyleEmailUiMsgDetailsControl.h"
#include "FreestyleEmailUiMsgDetailsModel.h"
#include "FreestyleEmailUiMsgDetailsVisualiser.h"
#include "FreestyleEmailUi.hrh"
#include "FreestyleEmailUiLayoutHandler.h"
#include "FreestyleEmailUiTextureManager.h"
#include "FreestyleEmailUiUtilities.h"
#include "FreestyleEmailUiShortcutBinding.h"
#include "FreestyleEmailUiContactHandler.h"
#include "FSDelayedLoader.h"


CFSEmailUiMsgDetailsVisualiser* CFSEmailUiMsgDetailsVisualiser::NewL( CAlfEnv& aEnv,
                                                 CAlfControlGroup& aControlGroup,
                                                 CFreestyleEmailUiAppUi& aAppUi )
    {
    FUNC_LOG;
    CFSEmailUiMsgDetailsVisualiser* self = CFSEmailUiMsgDetailsVisualiser::NewLC(aEnv, aControlGroup, aAppUi );
    CleanupStack::Pop(self);
    return self;
    }

CFSEmailUiMsgDetailsVisualiser* CFSEmailUiMsgDetailsVisualiser::NewLC( CAlfEnv& aEnv,
                                                 CAlfControlGroup& aControlGroup,
                                                 CFreestyleEmailUiAppUi& aAppUi )
{
    FUNC_LOG;
    CFSEmailUiMsgDetailsVisualiser* self = new (ELeave) CFSEmailUiMsgDetailsVisualiser( aEnv, aAppUi, aControlGroup );
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
}

void CFSEmailUiMsgDetailsVisualiser::ConstructL()
	{
    FUNC_LOG;

    BaseConstructL( R_FSEMAILUI_MAIL_DETAILS_VIEW );

    iFirstStartCompleted = EFalse;    
	iFetchingMessageStructure = EFalse;
	iAsyncProcessComplete = ETrue;
	iWaitDialog = NULL;
	}

// CFSEmailUiMsgDetailsVisualiser::DoFirstStartL()
// Purpose of this function is to do first start only when msg details is
// really needed to be shown. Implemented to make app startuo faster.
void CFSEmailUiMsgDetailsVisualiser::DoFirstStartL()
    {
    FUNC_LOG;
    iControl = CFSEmailUiMsgDetailsControl::NewL( iEnv, *this );
    iModel = new (ELeave) CFSEmailUiMsgDetailsModel();

    UpdateListSizeAttributes();
     
    iParentLayout = CAlfDeckLayout::AddNewL( *iControl );
    iParentLayout->SetFlags( EAlfVisualFlagLayoutUpdateNotification );
    iParentLayout->SetRect( iScreenRect );
    
    iTreeVisualizer = CFsTreeVisualizerBase::NewL(iControl, *iParentLayout);
    iTreeVisualizer->SetItemExpansionDelay( iAppUi.LayoutHandler()->ListItemExpansionDelay() );
    iTreeVisualizer->SetScrollTime( iAppUi.LayoutHandler()->ListScrollingTime() );
    iTreeVisualizer->SetFadeInEffectTime( iAppUi.LayoutHandler()->ListFadeInEffectTime() );
    iTreeVisualizer->SetFadeOutEffectTime( iAppUi.LayoutHandler()->ListFadeOutEffectTime() );
    
    iTreeList = CFsTreeList::NewL( *iTreeVisualizer, iEnv );
    iTreeList->HideListL();
    iTreeList->SetLoopingType( EFsTreeListLoopingJumpToFirstLast );
    iTreeList->SetScrollbarVisibilityL( EFsScrollbarAuto );
    iTreeList->SetIndentationL( 0 );

    //<cmail> Compared to S60 3.2.3 in S60 5.0 Alf offers the key events in
    // opposite order.
    ControlGroup().AppendL( iControl );
    ControlGroup().AppendL( iTreeList->TreeControl() ); 
    //</cmail>
    
    // <cmail> Touch
    iTreeList->AddObserverL(*this);
    //</cmail>
    
    // Set page up and page down keys
    iTreeVisualizer->AddCustomPageUpKey( EStdKeyPageUp );
    iTreeVisualizer->AddCustomPageDownKey( EStdKeyPageDown );
    iTreeVisualizer->SetItemsAlwaysExtendedL( ETrue );

    iAppUi.LayoutHandler()->SetListMarqueeBehaviour( iTreeList );
    
    iFirstStartCompleted = ETrue;
    }

CFSEmailUiMsgDetailsVisualiser::CFSEmailUiMsgDetailsVisualiser( CAlfEnv& aEnv, CFreestyleEmailUiAppUi& aAppUi, CAlfControlGroup& aControlGroup  )
  : CFsEmailUiViewBase(aControlGroup, aAppUi),
    iEnv(aEnv),
    iFirstViewActivation( ETrue ),
    iExpandCollapseMode( EExpandAll ),
    // <cmail> video call
    iVideoCall( EFalse )
    // </cmail>
	{
    FUNC_LOG;
	}
	
CFSEmailUiMsgDetailsVisualiser::~CFSEmailUiMsgDetailsVisualiser()
	{
    FUNC_LOG;
	delete iModel;
	iModel = NULL;

	delete iPreviousTitleText;
	iPreviousTitleText = NULL;

	delete iViewedMsg;
	iViewedMsg = NULL;
	
	delete iNoDisplayNameAvailableText;
	iNoDisplayNameAvailableText = NULL;
	
	delete iNoEmailAddressAvailableText;
	iNoEmailAddressAvailableText = NULL;
	
	delete iTreeList;
	iTreeList = NULL;
	
	iNodeIds.Close();
	}

TUid CFSEmailUiMsgDetailsVisualiser::Id() const
	{
    FUNC_LOG;
	return MsgDetailsViewId;
	}			   

// <cmail> Toolbar
/*void CFSEmailUiMsgDetailsVisualiser::DoActivateL(const TVwsViewId& aPrevViewId,
                     TUid aCustomMessageId,
                     const TDesC8& aCustomMessage)*/
void CFSEmailUiMsgDetailsVisualiser::ChildDoActivateL(
    const TVwsViewId& aPrevViewId, TUid aCustomMessageId, 
        const TDesC8& aCustomMessage)
// </cmail> Toolbar
	{
    FUNC_LOG;
	if ( !iFirstStartCompleted )
	    {
	    DoFirstStartL();
	    }
	
	UpdateListSizeAttributes();
    iParentLayout->SetRect( iScreenRect );

	if ( aCustomMessageId == KStartMsgDetailsReturnToPrevious )
	    {
	    // Fisrt handle special case where we are returning to msg details view,
	    // so we don't need to recreate list contents, just refresh the view
	    if ( iViewedMsg ) // Safety check
	        {
	        // Set title bar text to "Message/Meeting details"
	        ChangeTitleBarTextL( ETrue );

	        // Hide list and switch this view as active
	        iTreeList->HideListL();

	        // Then just refresh the list as in dynamic variant switch,
	        // because screen orientation might have changed
            HandleDynamicVariantSwitchL( EScreenLayoutChanged );
	        }
	    }
	else
		{
		// This is the "normal" case, so we need to recreate the list contents
		
		// Store previous view ID
		iPreviousViewUid = aPrevViewId.iViewUid;

		TMsgDetailsActivationData subView;
		TPckgBuf<TMsgDetailsActivationData> viewData( subView );
		viewData.Copy( aCustomMessage );
		subView = viewData();

		delete iViewedMsg;
		iViewedMsg = NULL;

		iViewedMsg = iAppUi.GetMailClient()->GetMessageByUidL( subView.iMailBoxId, subView.iFolderId, subView.iMessageId, EFSMsgDataEnvelope  );
		CFSMailBox* mailBox = iAppUi.GetMailClient()->GetMailBoxByUidL( subView.iMailBoxId );
	    CleanupStack::PushL( mailBox );    
	    if ( mailBox && TFsEmailUiUtility::IsRemoteLookupSupported( *mailBox ) )
	        {
	        iRCLSupported = ETrue;       
	        } 
	    else
	        {
	        iRCLSupported = EFalse;
	        }
	    CleanupStack::PopAndDestroy( mailBox );		

		if( iFirstViewActivation )
			{
			iTreeVisualizer->SetMenuIcon( iAppUi.FsTextureManager()->TextureByIndex( EListControlMenuIcon ) );		
		    //<cmail> S60 skin support
		    //iTreeVisualizer->SetBackgroundTextureL( iAppUi.FsTextureManager()->TextureByIndex( EBackgroundTextureMailList ) );
		    //</cmail>

		  	CAlfBrush* selectorBrush = iAppUi.FsTextureManager()->ListSelectorBrushL();
			iTreeVisualizer->SetSelectorPropertiesL( selectorBrush, 1.0, CFsTreeVisualizerBase::EFsSelectorMoveSmoothly );
	  
		    iFirstViewActivation = EFalse;
			}

	    if ( iViewedMsg ) // Safety check
	        {
			//<cmail> 
			// The code below fetches the mail structure in order to have access to all detail needed. 
			// IMAP - hasStructure should be always True
			// POP  - it is False if the message has not been read yet so the code below
			//        should fetch the message structure
			iAsyncProcessComplete = ETrue;
			TBool hasStructure = TFsEmailUiUtility::IsMessageStructureKnown( *iViewedMsg );			 
			if (!hasStructure)
				{
				iWaitDialog = new (ELeave) CAknWaitDialog((REINTERPRET_CAST(CEikDialog**,&iWaitDialog)), EFalse);
				iWaitDialog->SetCallback(this);
				iWaitDialog->ExecuteLD(R_FSE_FETCHING_WAIT_DIALOG);

				iDialogNotDismissed = ETrue;
				iAsyncProcessComplete = EFalse;
				StartFetchingMessageStructureL(iViewedMsg);
				}
			//</cmail>
	        // Set title bar text to "Message/Meeting details"
	        ChangeTitleBarTextL( ETrue );

	        iTreeList->HideListL();

            // By default we expand all nodes, if parameters doesn't state
            // something else
            iExpandCollapseMode = EExpandAll;
            if ( aCustomMessageId == KStartMsgDetailsToTo )
                {
                iExpandCollapseMode = ECollapseAllExceptTo;
                }
            else if ( aCustomMessageId == KStartMsgDetailsToCc )
                {
                iExpandCollapseMode = ECollapseAllExceptCc;
                }
            else if ( aCustomMessageId == KStartMsgDetailsToBcc )
                {
                iExpandCollapseMode = ECollapseAllExceptBcc;
                }
            
            iParentLayout->SetRect( iScreenRect );
            ClearMsgDetailsModelL();        
            
			//<cmail> 
			// IMAP - hasStructure is True so the view can be updated. 
			// POP - if hasStructure is False then the message strucure is being fetched. Wait for responce that will be received in 
			//       observer method RequestResponseL( ... )
			if ( hasStructure )
				{
            UpdateMsgDetailsModelL();
            iTreeList->ShowListL();
	        }
			//</cmail>
	        }
		}
	// <cmail> Touch
	iTreeList->SetFocusedL(ETrue);
	// </cmail>
	}

void CFSEmailUiMsgDetailsVisualiser::ChildDoDeactivate()
	{
    FUNC_LOG;
	//<cmail> 
	CancelFetching();
	//</cmail>
    if ( !iAppUi.AppUiExitOngoing() )
        {
        if ( iTreeList->IsFocused() )
            {
            TRAP_IGNORE( { 
                iTreeList->SetFocusedL(EFalse);
                iTreeList->SetFocusedItemL(KFsTreeNoneID);
                } );
            }
        iTreeVisualizer->NotifyControlVisibilityChange( EFalse );
        }
	}

void CFSEmailUiMsgDetailsVisualiser::PrepareForExit()
    {
    delete iViewedMsg;
    iViewedMsg = NULL;
    }


void CFSEmailUiMsgDetailsVisualiser::ChangeTitleBarTextL( TBool aViewStarted )
	{
    FUNC_LOG;
	if ( iFirstStartCompleted ) // Safety
	    {
		if ( aViewStarted )
			{
			// Store previous application title text
			delete iPreviousTitleText;
			iPreviousTitleText = NULL;
			iPreviousTitleText = iAppUi.TitlePaneTextL().AllocL();
			
			HBufC* titleText = NULL;
			if( iViewedMsg->IsFlagSet( EFSMsgFlag_CalendarMsg ) )
				{
				titleText = StringLoader::LoadLC( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_MEETING_HEADING );
				}
			else
				{
				titleText = StringLoader::LoadLC( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_HEADING );
				}

			iAppUi.SetTitlePaneTextL( *titleText );

			CleanupStack::PopAndDestroy( titleText ); 
			}
		else
			{
			if ( iPreviousTitleText )
				{
				iAppUi.SetTitlePaneTextL( *iPreviousTitleText ); // Set application title text back			
				}
			}
		}
	}

void CFSEmailUiMsgDetailsVisualiser::LaunchActionMenuL()
	{
    FUNC_LOG;
    CFSEmailUiActionMenu::RemoveAllL();

    RFsEActionMenuIdList itemList;
    itemList.AppendL(FsEActionMenuCall);
    // <cmail> video call
    itemList.AppendL( FsEActionMenuCallVideo );
    // </cmail>
    itemList.AppendL(FsEActionMenuCreateMessage);
    itemList.AppendL(FsEActionMenuContactDetails);
    itemList.AppendL(FsEActionMenuAddToContacts);
    if ( iRCLSupported )
        {
        itemList.AppendL(FsEActionMenuRemoteLookup);
        }     
    CFSEmailUiActionMenu::AddCustomItemsL( itemList );
    itemList.Close();
    
    // <cmail> Touch	
    TActionMenuCustomItemId itemId = CFSEmailUiActionMenu::ExecuteL( EFscCustom, 0, this );
    // </cmail>
	
   	HandleActionMenuCommandL( itemId );
	}

void CFSEmailUiMsgDetailsVisualiser::HandleActionMenuCommandL( TActionMenuCustomItemId itemId )
	{
    FUNC_LOG;
	switch( itemId )
		{
		case FsEActionMenuCall:
			{
			CallToFocusedItemL();
			}
			break;
        // <cmail> video call
        case FsEActionMenuCallVideo: // Video Call
            {
            iVideoCall = ETrue;
            CallToFocusedItemL();
            }
            break;
        // </cmail>
		case FsEActionMenuCreateMessage:
			{
			CreateMessageToFocusedItemL();
			}
			break;

		case FsEActionMenuContactDetails:
			{
			ShowContactDetailsForFocusedItemL();
			}
			break;

		case FsEActionMenuAddToContacts:
			{
			AddFocusedItemToContactsL();
			}
			break;

		case FsEActionMenuRemoteLookup:
			{
			LaunchRemoteLookupForFocusedItemL();
			}
			break;
		}
	}


// -----------------------------------------------------------------------------
// CFSEmailUiMsgDetailsVisualiser::GetEmailAddressForFocusedItem
// Returns email address of the focused list item. NULL returned if not found.
// -----------------------------------------------------------------------------
CFSMailAddress* CFSEmailUiMsgDetailsVisualiser::GetEmailAddressForFocusedItem() const
	{
    FUNC_LOG;
	CFSMailAddress* foundEmailAddress = NULL;
	CFSEmailUiMsgDetailsItem* item = iModel->ItemByListId( iTreeList->FocusedItem() );
	if( item )
		{
		foundEmailAddress = item->iMailAddress;
		}
	return foundEmailAddress;
	}

// -----------------------------------------------------------------------------
// CFSEmailUiMsgDetailsVisualiser::GetEmailAddressForFocusedItem
// Returns email address of the focused list item. NULL returned if not found.
// -----------------------------------------------------------------------------
TDesC* CFSEmailUiMsgDetailsVisualiser::GetEmailAddressForFocusedItemAsTDes() const
	{
    FUNC_LOG;
	TDesC* foundEmailAddress = NULL;
	CFSMailAddress* address = GetEmailAddressForFocusedItem();
	if( address )
		{
		foundEmailAddress = &address->GetEmailAddress();
		}
	return foundEmailAddress;
	}

// -----------------------------------------------------------------------------
// CFSEmailUiMsgDetailsVisualiser::SendEmailToFocusedItemL
// 
// Open composer and set the focused item as recipient, if valid email address
// is available. Return ETrue if valid email address was found, EFalse if not.
// -----------------------------------------------------------------------------
TBool CFSEmailUiMsgDetailsVisualiser::SendEmailToFocusedItemL() const
	{
    FUNC_LOG;
	TBool addrFound = EFalse;
	CFSMailAddress* address = GetEmailAddressForFocusedItem();
	if( address )
		{
		iAppUi.LaunchEditorL( address );
		addrFound = ETrue;
		}
	return addrFound;	
	}
	
// -----------------------------------------------------------------------------
// CFSEmailUiMsgDetailsVisualiser::CallToFocusedItemL
// -----------------------------------------------------------------------------
void CFSEmailUiMsgDetailsVisualiser::CallToFocusedItemL()
	{
    FUNC_LOG;
	TDesC* email = GetEmailAddressForFocusedItemAsTDes();
	if( email )
		{
		CFSMailClient* mailClient =	iAppUi.GetMailClient();
		CFSMailBox* mailBox = mailClient->GetMailBoxByUidL( iViewedMsg->GetMailBoxId() );
	   	CleanupStack::PushL( mailBox );

        // <cmail> video call
        if ( iVideoCall )
            {
            iVideoCall = EFalse;
            CFsDelayedLoader::InstanceL()->GetContactHandlerL()->SetVideoCall( ETrue );
            }
        // </cmail>
	   	
	   	CFsDelayedLoader::InstanceL()->GetContactHandlerL()->FindAndCallToContactByEmailL( *email, 
	   			 iAppUi.GetActiveMailbox(), this, EFalse );

	   	CleanupStack::PopAndDestroy( mailBox );
		}
	}

// -----------------------------------------------------------------------------
// CFSEmailUiMsgDetailsVisualiser::CreateMessageToFocusedItemL
// -----------------------------------------------------------------------------
void CFSEmailUiMsgDetailsVisualiser::CreateMessageToFocusedItemL() const
	{
    FUNC_LOG;
	TDesC* email = GetEmailAddressForFocusedItemAsTDes();
	if( email )
		{
		CFsDelayedLoader::InstanceL()->GetContactHandlerL()->FindAndCreateMsgToContactByEmailL( *email, iAppUi.GetActiveMailbox() );
		}
	}

// -----------------------------------------------------------------------------
// CFSEmailUiMsgDetailsVisualiser::LaunchRemoteLookupForFocusedItemL
// -----------------------------------------------------------------------------
void CFSEmailUiMsgDetailsVisualiser::LaunchRemoteLookupForFocusedItemL() const
	{
    FUNC_LOG;
	CFSEmailUiMsgDetailsItem* item = iModel->ItemByListId( iTreeList->FocusedItem() );
	if( !item )
		{
		return;
		}
	CFSMailAddress* address = item->iMailAddress;
	if( !address )
		{
		return;
		}
	TDesC* queryString = &address->GetEmailAddress();
	if( !queryString )
		{
		queryString = &address->GetDisplayName();
		if( !queryString )
			{
			return;
			}
		}

	// this method assumes that remote lookup is available with current plugin.
	CFSMailClient* mailClient =	iAppUi.GetMailClient();
	CFSMailBox* mailBox = mailClient->GetMailBoxByUidL( iViewedMsg->GetMailBoxId() );
   	CleanupStack::PushL( mailBox );
   	
	CFsDelayedLoader::InstanceL()->GetContactHandlerL()->LaunchRemoteLookupWithQueryL( *mailBox, *queryString );

   	CleanupStack::PopAndDestroy( mailBox );
	}

// -----------------------------------------------------------------------------
// CFSEmailUiMsgDetailsVisualiser::AddFocusedItemToContactsL
// -----------------------------------------------------------------------------
void CFSEmailUiMsgDetailsVisualiser::AddFocusedItemToContactsL() const
	{
    FUNC_LOG;
	TDesC* email = GetEmailAddressForFocusedItemAsTDes();
	if( email )
		{
		TAddToContactsType aType;
		//Query to "update existing" or "Create new" --> EFALSE = user choosed "cancel"
		if ( CFsDelayedLoader::InstanceL()->GetContactHandlerL()->AddtoContactsQueryL( aType ) )
			{
			CFsDelayedLoader::InstanceL()->GetContactHandlerL()->AddToContactL( 
					*email, EContactUpdateEmail, aType );		
			}						
		}										
	}

// -----------------------------------------------------------------------------
// CFSEmailUiMsgDetailsVisualiser::ShowContactDetailsForFocusedItemL
// -----------------------------------------------------------------------------
void CFSEmailUiMsgDetailsVisualiser::ShowContactDetailsForFocusedItemL() const
	{
    FUNC_LOG;
	TDesC* email = GetEmailAddressForFocusedItemAsTDes();
	if( email )
		{
		CFsDelayedLoader::InstanceL()->GetContactHandlerL()->ShowContactDetailsL( 
					*email, EContactUpdateEmail, NULL );
		}
	}

// -----------------------------------------------------------------------------
// CFSEmailUiMsgDetailsVisualiser::CopyFocusedItemToClipboardL
// -----------------------------------------------------------------------------
void CFSEmailUiMsgDetailsVisualiser::CopyFocusedItemToClipboardL() const
	{
    FUNC_LOG;
	CFSEmailUiMsgDetailsItem* item = iModel->ItemByListId( iTreeList->FocusedItem() );
	if (item)
	    {
    	CFSMailAddress* address = item->iMailAddress;
    	TDesC* text = item->iText;
    	if ( address )
    	    {
        	TDesC* clipBoardText = &address->GetEmailAddress();
        	if( !clipBoardText ||
        		(clipBoardText && clipBoardText->Length() == 0) )
        		{
        		clipBoardText = &address->GetDisplayName();
        		if( !clipBoardText )
        			{
        			return;
        			}
        		}
	       	TFsEmailUiUtility::CopyToClipboardL( *clipBoardText );
    	    }
    	else if( text )
    		{
	       	TFsEmailUiUtility::CopyToClipboardL( *text );
    		}
	    }		
	}

// -----------------------------------------------------------------------------
// Action menu is available for items that has iMailAddress set in model.
// -----------------------------------------------------------------------------
TBool CFSEmailUiMsgDetailsVisualiser::HasFocusedItemActionMenu() const
	{
    FUNC_LOG;
	CFSEmailUiMsgDetailsItem* item = iModel->ItemByListId( iTreeList->FocusedItem() );
	if( item && item->iMailAddress )
		{
		const TDesC* displayName = &item->iMailAddress->GetDisplayName();
		const TDesC* emailAddress = &item->iMailAddress->GetEmailAddress();

		if ( (displayName && displayName->Length()) ||
		     (emailAddress && emailAddress->Length()) )
		    {
		    return ETrue;
		    }
		}
	return EFalse;
	}

void CFSEmailUiMsgDetailsVisualiser::SetMskL()
    {
    FUNC_LOG;
    if ( iFirstStartCompleted ) // Safety
        {
        TFsTreeItemId curId = iTreeList->FocusedItem(); 

        if ( iTreeList->IsNode( curId ) )
            {
            if ( iTreeList->IsExpanded( curId ) )
                {
                ChangeMskCommandL( R_FSE_QTN_MSK_COLLAPSE );
                } 
            else  
                {
                ChangeMskCommandL( R_FSE_QTN_MSK_EXPAND );
                }
            }
        else // non-node item
            {
            if( GetEmailAddressForFocusedItem() )
                {
                ChangeMskCommandL( R_FSE_QTN_MSK_COMPOSE );
                }
            else
                {
                ChangeMskCommandL( R_FSE_QTN_MSK_EMPTY );
                }
            }        
        }
    }

TBool CFSEmailUiMsgDetailsVisualiser::OfferEventL(const TAlfEvent& aEvent)
    {
    FUNC_LOG;
    TBool result = EFalse;
    SetMskL();
    if ( aEvent.IsKeyEvent() && aEvent.Code() == EEventKey )
        {
        TInt scanCode = aEvent.KeyEvent().iScanCode;
        // Swap right and left controls in mirrored layout
        if ( AknLayoutUtils::LayoutMirrored() )
            {
            if (scanCode == EStdKeyRightArrow) scanCode = EStdKeyLeftArrow;
            else if (scanCode == EStdKeyLeftArrow ) scanCode = EStdKeyRightArrow;
            }
        
        switch ( scanCode )
            {
            case EStdKeyDevice3:	// CENTER CLICK
            case EStdKeyEnter:		// ENTER
            	{
            	// Send email to focused item. Set the event as consumed if
            	// valid email address was found and composer was opened with
            	// that email address as recipent. If email address was not
            	// found, offer the event to list by not consuming it.
            	result = SendEmailToFocusedItemL();
            	}
            	break;
				
            case EStdKeyYes:
            	{
				CallToFocusedItemL();
            	result = ETrue;
            	}
            	break;
            
	        case EStdKeyRightArrow:
            	{
            	// Show action toolbar if the item has action menu.
            	if( HasFocusedItemActionMenu() )
            		{
            		LaunchActionMenuL();
            		result = ETrue;
            		}
            	else
            		{
            		result = EFalse;
            		}
            	}
				break;
			
			default:
			    // Check keyboard shortcuts.
	       	    TInt shortcutCommand = 
	       	        iAppUi.ShortcutBinding().CommandForShortcutKey( aEvent.KeyEvent(),
	       	                                                         CFSEmailUiShortcutBinding::EContextMailDetails );
	       	    if ( shortcutCommand != KErrNotFound )
	       	        {
       	            HandleCommandL( shortcutCommand );
	       	        result = ETrue;
       	            }
				break;
            }
        }
    else if (aEvent.IsPointerEvent())
        {
        result = iTreeList->TreeControl()->OfferEventL(aEvent);
        }

	return result;
    }

// ---------------------------------------------------------------------------
// From MFSEmailUiContactHandlerObserver
// The ownership of the CLS items in the contacts array is transferred to the
// observer, and they must be deleted by the observer.
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::OperationCompleteL(
    TContactHandlerCmd /*aCmd*/, const RPointerArray<CFSEmailUiClsItem>& /*aContacts*/ )
    {
    FUNC_LOG;
    }

// ---------------------------------------------------------------------------
// From MFSEmailUiContactHandlerObserver
// Handles error in contact handler operation.
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::OperationErrorL( TContactHandlerCmd /*aCmd*/,
    TInt /*aError*/ )
    {
    FUNC_LOG;
    }

void CFSEmailUiMsgDetailsVisualiser::DynInitMenuPaneL(TInt aResourceId, CEikMenuPane* aMenuPane)
	{
    FUNC_LOG;
	   
    if ( aResourceId == R_FSEMAILUI_MAILDETAILS_MENUPANE )
        {
        if ( FeatureManager::FeatureSupported( KFeatureIdFfCmailIntegration ) )
    	   {
    	   // remove help support in pf5250
    	   aMenuPane->SetItemDimmed( EFsEmailUiCmdHelp, ETrue);      
    	   }
        
        // Hide "actions" option if currently focused item doesn't have action menu
       	aMenuPane->SetItemDimmed( EFsEmailUiCmdMailActions, !HasFocusedItemActionMenu() );
        // Hide "copy to clipboard" option if there is nothing to copy on the focused row
    	CFSEmailUiMsgDetailsItem* item = iModel->ItemByListId( iTreeList->FocusedItem() );
    	if ( !item )
    	    {
        	aMenuPane->SetItemDimmed( EFsEmailUiCmdActionsCopyToClipboard, ETrue );
            }
        aMenuPane->SetItemDimmed( EFsEmailUiCmdActionsCollapseAll, AllNodesCollapsed() );
        aMenuPane->SetItemDimmed( EFsEmailUiCmdActionsExpandAll, AllNodesExpanded() );
        }
    
    if ( aResourceId == R_FSEMAILUI_MAILDETAILS_SUBMENU_ACTIONS )
        {
        TInt pos( 0 );
        if ( !iRCLSupported && aMenuPane->MenuItemExists( EFsEmailUiCmdActionsRemoteLookup ,pos) )
            {
            aMenuPane->SetItemDimmed( EFsEmailUiCmdActionsRemoteLookup, ETrue );
            }
        }
    
    // Add shortcut hints
	iAppUi.ShortcutBinding().AppendShortcutHintsL( *aMenuPane, 
	                           CFSEmailUiShortcutBinding::EContextMailDetails );
	}

void CFSEmailUiMsgDetailsVisualiser::HandleCommandL( TInt aCommand )
    {
    FUNC_LOG;
    switch(aCommand)
        {
        case EAknSoftkeyBack:
        	{
            if ( !iAppUi.ViewSwitchingOngoing() )
				{
				ChangeTitleBarTextL( EFalse );
	  	       	iAppUi.ReturnToPreviousViewL();
				}
     	 	}
        	break;
        	
        case EFsEmailUiCmdActionsCopyToClipboard:
		    {
		    CopyFocusedItemToClipboardL();
	        }
	        break;
        case EFsEmailUiCmdCollapse:
			{
            TFsTreeItemId focId1 = iTreeList->FocusedItem();
            iTreeList->CollapseNodeL(focId1);
            ChangeMskCommandL( R_FSE_QTN_MSK_EXPAND);
            }
            break;
            
        case EFsEmailUiCmdExpand:
			{
            TFsTreeItemId focId2 = iTreeList->FocusedItem();
            iTreeList->ExpandNodeL(focId2);
            ChangeMskCommandL( R_FSE_QTN_MSK_COLLAPSE);
			}
            break;
		// Options menu commands
        case EFsEmailUiCmdActionsCollapseAll:
		    {
        	TFsTreeItemId prevId = iTreeList->FocusedItem();
        	prevId = GetRootParent( prevId );
	    	iTreeVisualizer->CollapseAllL();
    	    if ( prevId != KFsTreeRootID && prevId != KFsTreeNoneID )
    	    	{
		        iTreeVisualizer->SetFocusedItemL( prevId );
    	    	}
	        }
	        break;

        case EFsEmailUiCmdActionsExpandAll:
		    {
        	TFsTreeItemId prevId = iTreeList->FocusedItem();	
		   	iTreeVisualizer->ExpandAllL();
    	    if ( prevId != KFsTreeRootID && prevId != KFsTreeNoneID )
    	    	{
		        iTreeVisualizer->SetFocusedItemL( prevId );
    	    	}
	        }
	        break;

        case EFsEmailUiCmdActionsCall:
		    {
		    CallToFocusedItemL();
	        }
	        break;
        // <cmail> video call
        case EFsEmailUiCmdActionsCallVideo:
            {
            iVideoCall = ETrue;
            CallToFocusedItemL();
            }
            break;
        // </cmail>
        case EFsEmailUiCmdActionsCreateMessage:
		    {
		    CreateMessageToFocusedItemL();
	        }
	        break;

        case EFsEmailUiCmdComposeTo:
            {
            SendEmailToFocusedItemL();
            }
            break;
            
        case EFsEmailUiCmdActionsContactDetails:
		    {
		    ShowContactDetailsForFocusedItemL();
	        }
	        break;

        case EFsEmailUiCmdActionsAddContact:
		    {
		    AddFocusedItemToContactsL();
	        }
	        break;

        case EFsEmailUiCmdActionsRemoteLookup:
		    {
		    LaunchRemoteLookupForFocusedItemL();
	        }
	        break;

        case EFsEmailUiCmdHelp:
		    {
        	TFsEmailUiUtility::LaunchHelpL( KFSE_HLP_LAUNCHER_GRID );
	        }
	        break;

        case EFsEmailUiCmdExit:
		    {
		    //<cmail>
		    iTreeList->SetFocusedL(EFalse);
		    //</cmail>
		    iAppUi.Exit();
	        }
	        break;
        
        case EFsEmailUiCmdActionsCollapseExpandAllToggle:
            {
            ShortcutCollapseExpandAllToggleL();
            }
            break;
        
        case EFsEmailUiCmdGoToTop:
            {
            GoToTopL();
            }
            break;
            
        case EFsEmailUiCmdGoToBottom:
            {
            GoToBottomL();
            }
            break;
            
        case EFsEmailUiCmdPageUp:
            {
            TKeyEvent simEvent = { EKeyPageUp, EStdKeyPageUp, 0, 0 };
            iCoeEnv->SimulateKeyEventL( simEvent, EEventKey );
            }
            break;
            
        case EFsEmailUiCmdPageDown:
            {
            TKeyEvent simEvent = { EKeyPageDown, EStdKeyPageDown, 0, 0 };
            iCoeEnv->SimulateKeyEventL( simEvent, EEventKey );
            }
            break;

        default:
        	break;
        }
    }


void CFSEmailUiMsgDetailsVisualiser::ClearMsgDetailsModelL()
	{
    FUNC_LOG;
	iTreeList->RemoveAllL();
	iModel->RemoveAll();

	iNodeIds.Reset();
	iToNodeId = iCcNodeId = iBccNodeId = KFsTreeNoneID;
	}

void CFSEmailUiMsgDetailsVisualiser::UpdateMsgDetailsModelL()
    {
    FUNC_LOG;
    // If there are lots of items under some node, then the list drawing
    // might become very slow because of scroll bar updating. So we deny
    // the list refresh during the construction. List refresh is still
    // allowed in case of node insert, as there aren't that many nodes,
    // and it will keep the scroll bar roughly in the map.
    iAllowListRefreshInInsert = ETrue;
    iExpandAndHighlightNextNode = EFalse;

	// Append lines to the model
	AppendFromLinesL();
	AppendSubjectLinesL();
	
	if( iExpandCollapseMode == ECollapseAllExceptTo )
	    {
	    iExpandAndHighlightNextNode = ETrue;
	    }
	AppendToLinesL();

	if( iExpandCollapseMode == ECollapseAllExceptCc )
        {
        iExpandAndHighlightNextNode = ETrue;
        }
	AppendCcLinesL();

	if( iExpandCollapseMode == ECollapseAllExceptBcc )
        {
        iExpandAndHighlightNextNode = ETrue;
        }
	AppendBccLinesL();
	AppendSizeLinesL();
	AppendSentLinesL();	
	AppendPriorityLinesL();
    // Allow list (scroll bar) refresh for last item(s)
    //iAllowListRefreshInInsert = ETrue;
	AppendMessageTypeLinesL();
  	}

void CFSEmailUiMsgDetailsVisualiser::CreateOneLinePlainItemLC2( const TDesC& aItemDataBuff,
                                                       		    CFsTreePlainOneLineItemData* &aItemData,
                                                       		    CFsTreePlainOneLineItemVisualizer* &aItemVisualizer )
	{
    FUNC_LOG;
    aItemData = CFsTreePlainOneLineItemData::NewL();
    CleanupStack::PushL( aItemData );
    aItemData->SetDataL( aItemDataBuff );
    
    aItemVisualizer = CFsTreePlainOneLineItemVisualizer::NewL(*iTreeList->TreeControl());
    CleanupStack::PushL( aItemVisualizer );
	aItemVisualizer->SetExtendable( EFalse ); // One line items are obviously not extendable
	aItemVisualizer->SetLayoutHints( CFsTreeItemVisualizerBase::EFolderLayout );

    SetItemVisualizerCommonProperties( *aItemVisualizer );
	}

void CFSEmailUiMsgDetailsVisualiser::CreateTwoLinePlainItemLC2( const TDesC& aPrimaryDataBuff,
															    const TDesC& aSecondaryDataBuff,
															    CFsTreePlainTwoLineItemData* &aItemData,
															    CFsTreePlainTwoLineItemVisualizer* &aItemVisualizer )
	{
    FUNC_LOG;
    aItemData = CFsTreePlainTwoLineItemData::NewL();
    CleanupStack::PushL( aItemData );
    aItemData->SetDataL( aPrimaryDataBuff );
	aItemData->SetSecondaryDataL( aSecondaryDataBuff );

    aItemVisualizer = CFsTreePlainTwoLineItemVisualizer::NewL(*iTreeList->TreeControl());
    CleanupStack::PushL( aItemVisualizer );
	aItemVisualizer->SetExtendable( ETrue ); // All two line items are extendable
	aItemVisualizer->SetMenu( NULL );
	aItemVisualizer->SetLayoutHints( CFsTreeItemVisualizerBase::EFolderLayout );

    SetItemVisualizerCommonProperties( *aItemVisualizer );
	}

void CFSEmailUiMsgDetailsVisualiser::SetItemVisualizerCommonProperties( MFsTreeItemVisualizer& aItemVisualizer )
	{
    FUNC_LOG;
    aItemVisualizer.SetSize(TSize(iScreenRect.Width(), iAppUi.LayoutHandler()->OneLineListItemHeight()));
	aItemVisualizer.SetExtendedSize(TSize(iScreenRect.Width(), iAppUi.LayoutHandler()->TwoLineListItemHeight()));

  	// Set correct skin text colors for the list items  
   	TRgb focusedColor = iAppUi.LayoutHandler()->ListFocusedStateTextSkinColor();
   	TRgb normalColor = iAppUi.LayoutHandler()->ListNormalStateTextSkinColor();
    aItemVisualizer.SetFocusedStateTextColor( focusedColor );
    aItemVisualizer.SetNormalStateTextColor( normalColor );	
	}

void CFSEmailUiMsgDetailsVisualiser::CreatePlainNodeLC2( const TDesC& aItemDataBuff,
                                                         CFsTreePlainOneLineNodeData* &aItemData,
                                                         CFsTreePlainOneLineNodeVisualizer* &aNodeVisualizer )
	{
    FUNC_LOG;
    aItemData = CFsTreePlainOneLineNodeData::NewL();
    CleanupStack::PushL( aItemData );
    
    aItemData->SetDataL( aItemDataBuff );
	aItemData->SetIconExpanded( iAppUi.FsTextureManager()->TextureByIndex( EListTextureNodeExpanded ) );
    aItemData->SetIconCollapsed( iAppUi.FsTextureManager()->TextureByIndex( EListTextureNodeCollapsed ) );
    
    aNodeVisualizer = CFsTreePlainOneLineNodeVisualizer::NewL(*iTreeList->TreeControl());
    CleanupStack::PushL( aNodeVisualizer );
    
    SetNodeVisualizerProperties( *aNodeVisualizer );
    
    // Gradient background for headings    
    CAlfBrush *titleDividerBgBrush = iAppUi.FsTextureManager()->TitleDividerBgBrushL();
    aNodeVisualizer->SetBackgroundBrush( titleDividerBgBrush );
	}

void CFSEmailUiMsgDetailsVisualiser::SetNodeVisualizerProperties( MFsTreeItemVisualizer& aNodeVisualizer )
	{
    FUNC_LOG;
    aNodeVisualizer.SetSize(TSize(iScreenRect.Width(), iListNodeHeight));

  	// Set correct skin text colors for the list items  
   	TRgb focusedColor = iAppUi.LayoutHandler()->ListFocusedStateTextSkinColor();
   	TRgb normalColor = iAppUi.LayoutHandler()->ListNodeTextColor();
    aNodeVisualizer.SetFocusedStateTextColor( focusedColor );
    aNodeVisualizer.SetNormalStateTextColor( normalColor );
	
	// Set font size
	aNodeVisualizer.SetFontHeight( iAppUi.LayoutHandler()->ListItemFontHeightInTwips() );		
	// Set node bolded	
	aNodeVisualizer.SetTextBold( ETrue );
	
	// Temporary fix for EASV-7GJFVD
	//aNodeVisualizer.SetBackgroundColorL( iAppUi.LayoutHandler()->ListNodeBackgroundColor() );
		
	}

TFsTreeItemId CFSEmailUiMsgDetailsVisualiser::AppendHeadingToListL( TInt aResourceId )
	{
    FUNC_LOG;
    CFsTreePlainOneLineNodeData* plainNodeData;
    CFsTreePlainOneLineNodeVisualizer* plainNodeVisualizer;

 	HBufC* headingText = StringLoader::LoadLC( aResourceId );

	CreatePlainNodeLC2( *headingText, plainNodeData, plainNodeVisualizer );
	
    TFsTreeItemId nodeId = iTreeList->InsertNodeL( *plainNodeData, *plainNodeVisualizer, KFsTreeRootID);
    CleanupStack::Pop( 2 ); // plainNodeData & plainNodeVisualizer

    // Set the node expanded/collapsed according to the member variables
    if( nodeId != KFsTreeNoneID ) // Safety check
        {
        if( iExpandCollapseMode == EExpandAll )
            {
            // The "normal" case, expand all and keep the first one highlighted
            iTreeList->ExpandNodeL( nodeId );
            }
        else if( iExpandAndHighlightNextNode )
            {
            // View opened to To, Cc or Bcc field and we just added the
            // corresponding node, so expand and focus it
            iTreeList->ExpandNodeL( nodeId );
            iTreeVisualizer->SetFocusedItemL( nodeId );
            }
        else
            {
            // View opened to To, Cc or Bcc field but we added some other
            // node, so collapse it
            iTreeList->CollapseNodeL( nodeId );
            }
        }
    // Reset the node expanding and highlighting flag
    iExpandAndHighlightNextNode = EFalse;
    
   	CleanupStack::PopAndDestroy(headingText);

   	return nodeId;
	}

TFsTreeItemId CFSEmailUiMsgDetailsVisualiser::AppendOneLineItemToListL( const TDesC& aItemData, TFsTreeItemId aParentNode )
	{
    FUNC_LOG;
    CFsTreePlainOneLineItemData* plainItemData;
    CFsTreePlainOneLineItemVisualizer* plainItemVisualizer;

    CreateOneLinePlainItemLC2( aItemData, plainItemData, plainItemVisualizer );

    TFsTreeItemId itemId = iTreeList->InsertItemL( *plainItemData, *plainItemVisualizer, aParentNode, KErrNotFound, iAllowListRefreshInInsert );
    CleanupStack::Pop( 2 ); // plainItemData & plainItemVisualizer

    return itemId;
	}

TFsTreeItemId CFSEmailUiMsgDetailsVisualiser::AppendTwoLineItemToListL( const TDesC& aPrimaryDataBuff,
															  			const TDesC& aSecondaryDataBuff,
															  			TFsTreeItemId aParentNode,
															  			TBool aItemHasActionMenu /*= EFalse*/ )
	{
    FUNC_LOG;
    CFsTreePlainTwoLineItemData* plainItemData;
    CFsTreePlainTwoLineItemVisualizer* plainItemVisualizer;

    CreateTwoLinePlainItemLC2( aPrimaryDataBuff, aSecondaryDataBuff, plainItemData, plainItemVisualizer );
    
    if ( aItemHasActionMenu )
        {
        plainItemVisualizer->SetFlags( plainItemVisualizer->Flags() | KFsTreeListItemHasMenu );
        }
   
    plainItemVisualizer->SetFlags(plainItemVisualizer->Flags() & ~KFsTreeListItemManagedLayout);  
  
    TFsTreeItemId itemId = iTreeList->InsertItemL( *plainItemData, *plainItemVisualizer, aParentNode, KErrNotFound, iAllowListRefreshInInsert );
    CleanupStack::Pop( 2 ); // plainItemData & plainItemVisualizer

    return itemId;
	}

TFsTreeItemId CFSEmailUiMsgDetailsVisualiser::AppendDateTimeItemToListL( const TDesC& aPrimaryDataBuff,
															  			 const TDesC& aSecondaryDataBuff,
															  			 const TDesC& aDateTimeDataBuff,
															  			 TFsTreeItemId aParentNode )
	{
    FUNC_LOG;
    CFsTreePlainTwoLineItemData* plainItemData;
    CFsTreePlainTwoLineItemVisualizer* plainItemVisualizer;

    CreateTwoLinePlainItemLC2( aPrimaryDataBuff, aSecondaryDataBuff, plainItemData, plainItemVisualizer );

	plainItemData->SetDateTimeDataL( aDateTimeDataBuff );
	plainItemVisualizer->SetExtendable( EFalse );
    
	TFsTreeItemId itemId = iTreeList->InsertItemL( *plainItemData, *plainItemVisualizer, aParentNode, KErrNotFound, iAllowListRefreshInInsert );
    CleanupStack::Pop( 2 ); // plainItemData & plainItemVisualizer

    return itemId;
	}

TBool CFSEmailUiMsgDetailsVisualiser::GetDisplayNameAndEmailAddressL( CFSMailAddress* aAddressData, TDesC* &aDisplayName, TDesC* &aEmailAddress )
	{
    FUNC_LOG;
 	aDisplayName = &aAddressData->GetDisplayName();
 	aEmailAddress = &aAddressData->GetEmailAddress();
 	TInt notFoundCount(0);
 	
 	// If display name is not set, then the plugins seem to set it to be same
 	// as email address. So there's no safe way to know wheter the display name
 	// is set or not. Best quess is that if display name is the same as email
 	// address, then there are no display name available.
 	if ( !aDisplayName || ( aDisplayName->Length() == 0 ) || ( *aDisplayName == *aEmailAddress ) )
		{
		// Internal variable used to store the text to avoid problems with ownership handling
		if( !iNoDisplayNameAvailableText )
			{
			iNoDisplayNameAvailableText = StringLoader::LoadL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_NO_DISPLAY_NAME );
			}
	
		aDisplayName = iNoDisplayNameAvailableText;
		notFoundCount++;
		}
 	if ( !aEmailAddress || ( aEmailAddress->Length() == 0 ) )
		{
		// Internal variable used to store the text to avoid problems with ownership handling
		if( !iNoEmailAddressAvailableText )
			{
			iNoEmailAddressAvailableText = StringLoader::LoadL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_NO_EMAIL_ADDRESS );
			}

		aEmailAddress = iNoEmailAddressAvailableText;
		notFoundCount++;
		}

	// If both display name and email address are empty, return EFalse
	if( notFoundCount > 1 )
		{
		return EFalse;
		}
	else
		{
		return ETrue;
		}
	}

void CFSEmailUiMsgDetailsVisualiser::AppendFromLinesL()
	{
    FUNC_LOG;
	TFsTreeItemId nodeId;
	if( iViewedMsg->IsFlagSet( EFSMsgFlag_CalendarMsg ) )
		{
		nodeId = AppendHeadingToListL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_ORGANIZER );
		}
	else
		{
	 	nodeId = AppendHeadingToListL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_FROM );
		}
 	iNodeIds.Append( nodeId );

 	CFSMailAddress* fromAddress = iViewedMsg->GetSender();
	// If CFSMailAddress not available, show "No sender info available"
 	if( fromAddress == NULL )
 		{
	 	HBufC* noSender = StringLoader::LoadLC( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_NO_SENDER_INFO_AVAILABLE );
		AppendOneLineItemToListL( *noSender, nodeId );
		CleanupStack::PopAndDestroy( noSender );
 		}
 	else
 		{
		TDesC* displayName( NULL );
		TDesC* emailAddress( NULL );
		if( GetDisplayNameAndEmailAddressL( fromAddress, displayName, emailAddress ) )
			{
			TFsTreeItemId itemId = AppendTwoLineItemToListL( *displayName, *emailAddress, nodeId, ETrue );
			iModel->AppendL( itemId, fromAddress );
			}
		else
			{
		 	HBufC* noSender = StringLoader::LoadLC( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_NO_SENDER_INFO_AVAILABLE );
			AppendOneLineItemToListL( *noSender, nodeId );
			CleanupStack::PopAndDestroy( noSender );
			}
 		}
	}

void CFSEmailUiMsgDetailsVisualiser::AppendSubjectLinesL()
	{
    FUNC_LOG;
 	TFsTreeItemId nodeId = AppendHeadingToListL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_SUBJECT );
 	iNodeIds.Append( nodeId );

	TDesC* subject = &iViewedMsg->GetSubject();
	if ( subject == NULL || subject->Length() <= 0 )
		{
	 	HBufC* noSubject = StringLoader::LoadLC( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_NO_SUBJECT );
		AppendOneLineItemToListL( *noSubject, nodeId );
		CleanupStack::PopAndDestroy( noSubject );
		}
	else
		{
		HBufC* subjectText = TFsEmailUiUtility::CreateSubjectTextLC( iViewedMsg );
		TFsTreeItemId itemId = AppendOneLineItemToListL( *subjectText, nodeId );
		CleanupStack::PopAndDestroy( subjectText );
		iModel->AppendL( itemId, subject );
		}
	}

// Duplicate code in AppendToLinesL/AppendCcLinesL/AppendBccLinesL, create
// one generic function that can be used from all of these functions
void CFSEmailUiMsgDetailsVisualiser::AppendToLinesL()
	{
    FUNC_LOG;
	if( iViewedMsg->IsFlagSet( EFSMsgFlag_CalendarMsg ) )
		{
		iToNodeId = AppendHeadingToListL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_REQUIRED );
		}
	else
		{
	 	iToNodeId = AppendHeadingToListL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_TO );
		}
 	iNodeIds.Append( iToNodeId );
 
 	RPointerArray<CFSMailAddress>& toArray = iViewedMsg->GetToRecipients();
	TInt toArrayCount = toArray.Count(); 
	if ( toArrayCount )
		{
		for ( TInt i=0 ; i<toArrayCount ; i++ )
			{
		  	CFSMailAddress* toAddress = toArray[i];
		  	if( toAddress )
		  		{
			 	TDesC* displayName( NULL );
			 	TDesC* emailAddress( NULL );
				TBool toNameFound = GetDisplayNameAndEmailAddressL( toAddress, displayName, emailAddress );

				TFsTreeItemId itemId = AppendTwoLineItemToListL( *displayName, *emailAddress, iToNodeId, toNameFound );
				iModel->AppendL( itemId, toAddress );
		  		}
			}		
		}		
	else
		{
		//Laske To- ja Cc-vastaanottajat yhteensä ja näytä tämä vain jos kumpiakaan ei ole yhtään
	 	HBufC* noToText = StringLoader::LoadLC( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_NO_VISIBLE_RECIPIENTS );
		AppendOneLineItemToListL( *noToText, iToNodeId );
		CleanupStack::PopAndDestroy( noToText );
		}
	}

void CFSEmailUiMsgDetailsVisualiser::AppendCcLinesL()
	{
    FUNC_LOG;
 	RPointerArray<CFSMailAddress>& ccArray = iViewedMsg->GetCCRecipients();
	TInt ccArrayCount = ccArray.Count(); 

	if ( ccArrayCount )
		{
		if( iViewedMsg->IsFlagSet( EFSMsgFlag_CalendarMsg ) )
			{
			iCcNodeId = AppendHeadingToListL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_OPTIONAL );
			}
		else
			{
		 	iCcNodeId = AppendHeadingToListL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_CC );
			}
	 	iNodeIds.Append( iCcNodeId );
	 	
		for ( TInt i=0 ; i<ccArrayCount ; i++ )
			{
		  	CFSMailAddress* ccAddress = ccArray[i];
		  	if( ccAddress )
		  		{
			 	TDesC* displayName( NULL );
			 	TDesC* emailAddress( NULL );
				TBool ccNameFound = GetDisplayNameAndEmailAddressL( ccAddress, displayName, emailAddress );

				TFsTreeItemId itemId = AppendTwoLineItemToListL( *displayName, *emailAddress, iCcNodeId, ccNameFound );
				iModel->AppendL( itemId, ccAddress );
		  		}
			}
		}
	}

void CFSEmailUiMsgDetailsVisualiser::AppendBccLinesL()
	{
    FUNC_LOG;
	// Get message's parent folder
	TFSMailMsgId folderId = iViewedMsg->GetFolderId();
	TFSMailMsgId mailboxId = iViewedMsg->GetMailBoxId();
	CFSMailFolder* folder = iAppUi.GetMailClient()->GetFolderByUidL( mailboxId, folderId );
	
	// Show bcc field only if message's parent folder is some outgoing folder,
	// so basically outbox, drafts or sent items.
	TBool showBcc( EFalse );
	if( folder )
		{
		TInt folderType = folder->GetFolderType();

		switch( folderType )
			{
			case EFSOutbox:
			case EFSDraftsFolder:
			case EFSSentFolder:
				{
				showBcc = ETrue;
				}
				break;

			case EFSInbox:
			case EFSDeleted:
			default:
				break;
			}
		}
	delete folder; 
	
	if( showBcc )
		{
	 	RPointerArray<CFSMailAddress>& bccArray = iViewedMsg->GetBCCRecipients();
		TInt bccArrayCount = bccArray.Count(); 

		if ( bccArrayCount )
			{
		 	iBccNodeId = AppendHeadingToListL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_BCC );
		 	iNodeIds.Append( iBccNodeId );
		 	
			for ( TInt i=0 ; i<bccArrayCount ; i++ )
				{
			  	CFSMailAddress* bccAddress = bccArray[i];
			  	if( bccAddress )
			  		{
				 	TDesC* displayName( NULL );
				 	TDesC* emailAddress( NULL );
					TBool bccNameFound = GetDisplayNameAndEmailAddressL( bccAddress, displayName, emailAddress );

					TFsTreeItemId itemId = AppendTwoLineItemToListL( *displayName, *emailAddress, iBccNodeId, bccNameFound );
					iModel->AppendL( itemId, bccAddress );
			  		}
				}
			}
		}
	}

void CFSEmailUiMsgDetailsVisualiser::AppendSizeLinesL()
	{
    FUNC_LOG;
 	TFsTreeItemId nodeId = AppendHeadingToListL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_SIZE_HEADER );
 	iNodeIds.Append( nodeId );
 	
 	// Gets the full content size (in bytes)
    TUint msgSize = iViewedMsg->ContentSize();

    HBufC* sizeText = TFsEmailUiUtility::CreateSizeDescLC( msgSize, ETrue );

	AppendOneLineItemToListL( *sizeText, nodeId );
	CleanupStack::PopAndDestroy( sizeText );
	}

void CFSEmailUiMsgDetailsVisualiser::AppendSentLinesL()
	{
    FUNC_LOG;
 	TFsTreeItemId nodeId = AppendHeadingToListL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_SENT );
 	iNodeIds.Append( nodeId );

 	HBufC* dateFromMsg = TFsEmailUiUtility::DateTextFromMsgLC( iViewedMsg );
	HBufC* dateText = StringLoader::LoadLC( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_DATE_U, *dateFromMsg );
 	
	AppendOneLineItemToListL( *dateText, nodeId );
		
	CleanupStack::PopAndDestroy( dateText );
 	CleanupStack::PopAndDestroy( dateFromMsg );
	
	//////////////////////////
 	HBufC* timeFromMsg = TFsEmailUiUtility::TimeTextFromMsgLC( iViewedMsg );
	HBufC* timeText = StringLoader::LoadLC( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_TIME_U, *timeFromMsg );
 	
	AppendOneLineItemToListL( *timeText, nodeId );
	
	CleanupStack::PopAndDestroy( timeText );
 	CleanupStack::PopAndDestroy( timeFromMsg );
	}

void CFSEmailUiMsgDetailsVisualiser::AppendPriorityLinesL()
	{
    FUNC_LOG;
 	TFsTreeItemId nodeId = AppendHeadingToListL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_PRIORITY );
 	iNodeIds.Append( nodeId );
 	
 	HBufC* priorityText( NULL );
	if ( iViewedMsg->IsFlagSet( EFSMsgFlag_Important ) )
		{
		priorityText = StringLoader::LoadL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_PRIORITY_HIGH );			
		}
	else if ( iViewedMsg->IsFlagSet( EFSMsgFlag_Low ) )
		{
		priorityText = StringLoader::LoadL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_PRIORITY_LOW );				
		}
	else
		{
		priorityText = StringLoader::LoadL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_PRIORITY_NORMAL );					
		}

	CleanupStack::PushL( priorityText );
	AppendOneLineItemToListL( *priorityText, nodeId );
	CleanupStack::PopAndDestroy( priorityText );
	}

void CFSEmailUiMsgDetailsVisualiser::AppendMessageTypeLinesL()
	{
    FUNC_LOG;
 	TFsTreeItemId nodeId = AppendHeadingToListL( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_MSG_TYPE );
 	iNodeIds.Append( nodeId );
 	
 	HBufC* msgType;
	if( iViewedMsg->IsFlagSet( EFSMsgFlag_CalendarMsg ) )
		{
		msgType = StringLoader::LoadLC( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_MSG_TYPE_MEETING );
		}
	else
		{
		msgType = StringLoader::LoadLC( R_FREESTYLE_EMAIL_UI_MSG_DETAILS_MSG_TYPE_EMAIL );
		}
		
	AppendOneLineItemToListL( *msgType, nodeId );
	CleanupStack::PopAndDestroy( msgType );
	}

void CFSEmailUiMsgDetailsVisualiser::HandleDynamicVariantSwitchL( CFsEmailUiViewBase::TDynamicSwitchType /*aType*/ )
	{
    FUNC_LOG;
    if ( iFirstStartCompleted ) // Safety
        {
        iTreeList->HideListL();        
        UpdateListSizeAttributes();
        iParentLayout->SetRect( iScreenRect );
        for ( TInt i = 0; i < iNodeIds.Count(); i++ )
            {
            MFsTreeItemVisualizer& vis = iTreeList->ItemVisualizer( iNodeIds[i] );
            SetNodeVisualizerProperties( vis );           
            SetChildVisualizersProperties( iNodeIds[i] );
            }
        iTreeList->ShowListL();        
        }
	}

// ---------------------------------------------------------------------------
// Sets tree item visualizer properties for all the childs of the given node
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::SetChildVisualizersProperties( TFsTreeItemId aNodeId )
	{
    FUNC_LOG;
	TUint childrenCount = iTreeList->CountChildren( aNodeId );
	for( TInt i = 0; i < childrenCount; ++i )
		{
		TFsTreeItemId childId = iTreeList->Child( aNodeId, i );
    	MFsTreeItemVisualizer& vis = iTreeList->ItemVisualizer( childId );
	    SetItemVisualizerCommonProperties( vis );
		}
	}

// ---------------------------------------------------------------------------
// Update list size members variables
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::UpdateListSizeAttributes()
	{
    FUNC_LOG;
    if ( iFirstStartCompleted ) // Safety
        {
        AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EMainPane, iScreenRect );
        iScreenRect.SetRect( 0, 0, iScreenRect.Width(), iScreenRect.Height() );


        iListNodeHeight = iAppUi.LayoutHandler()->OneLineListNodeHeight();        
        }
	}

// ---------------------------------------------------------------------------
// Collapse nodes except the specified one (used when starting the list in 
// specific loaction)
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::CollapseNodesExceptL( TFsTreeItemId aExcludedNode )
	{
    FUNC_LOG;
	for( TInt i = 0; i < iNodeIds.Count(); i++ )
		{
		if( iNodeIds[i] != aExcludedNode )
			{
			iTreeList->CollapseNodeL( iNodeIds[i] );
			}
		}
	}

// ---------------------------------------------------------------------------
// If there is one or more expanded nodes, collapses all nodes.
// Otherwise expands all nodes.
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::ShortcutCollapseExpandAllToggleL()
    {
    FUNC_LOG;
    TBool collapseAllNodes( EFalse );
    for( TInt i=0 ; i<iNodeIds.Count() ; i++ )
        {
        if( iTreeList->IsExpanded( iNodeIds[i] ) )
            {
            collapseAllNodes = ETrue;
            break;
            }	
        }

    if( collapseAllNodes )
        {
        HandleCommandL( EFsEmailUiCmdActionsCollapseAll );
        }
    else
        {
        HandleCommandL( EFsEmailUiCmdActionsExpandAll );
        }
    }

// ---------------------------------------------------------------------------
// Moves the focus to the topmost item
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::GoToTopL()
    {
    FUNC_LOG;
    if ( iNodeIds.Count() )
        {
        TFsTreeItemId topId = iNodeIds[0];
        iTreeVisualizer->SetFocusedItemL( topId );            
        }
    }

// ---------------------------------------------------------------------------
// Moves the focus to the bottommost item
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::GoToBottomL()
    {
    FUNC_LOG;
    if ( iNodeIds.Count() )
        {
        TFsTreeItemId bottomId = iNodeIds[ iNodeIds.Count()-1 ];
        TInt childCount = iTreeList->CountChildren(bottomId);
        if ( childCount && iTreeList->IsExpanded(bottomId) )
            {
            // Focus the last child of the bottom node if the node is expanded.
            bottomId = iTreeList->Child( bottomId, childCount-1 );
            }
        iTreeVisualizer->SetFocusedItemL( bottomId );            
        }
    }


// ---------------------------------------------------------------------------
// Recursive function to get the root parent of given item
// ---------------------------------------------------------------------------
//
TFsTreeItemId CFSEmailUiMsgDetailsVisualiser::GetRootParent( const TFsTreeItemId aItemId ) const
	{
    FUNC_LOG;
	TFsTreeItemId parentId = iTreeList->Parent( aItemId );
	// If current item's parent is KFsTreeRootID, return its id
	if( parentId == KFsTreeRootID || parentId == KFsTreeNoneID )
		{
		return aItemId;
		}
	else
		{
		// Get the root parent recursively
		return GetRootParent( parentId );
		}
	}


// ---------------------------------------------------------------------------
// Tells if all expandable nodes are collapsed
// ---------------------------------------------------------------------------
//
TBool CFSEmailUiMsgDetailsVisualiser::AllNodesCollapsed() const
    {
    FUNC_LOG;
    TFsTreeItemId itemId = KFsTreeNoneID;
    TInt count = iTreeList->CountChildren(KFsTreeRootID);
	
	// If top level is collapsed, then everything is collapsed. There's no need
	// to crawl any deeper in the tree hierarchy.
	for ( TInt i=0 ; i<count ; ++i )
	    {
	    itemId = iTreeList->Child( KFsTreeRootID, i );
	    if ( iTreeList->IsNode(itemId) &&
	         iTreeList->IsExpanded(itemId) )
	        {
	        return EFalse;
	        }
	    }
	
	return ETrue;
    }

// ---------------------------------------------------------------------------
// Tells if all expandable nodes are expanded
// ---------------------------------------------------------------------------
//
TBool CFSEmailUiMsgDetailsVisualiser::AllNodesExpanded( TFsTreeItemId aParentNodeId ) const
    {
    FUNC_LOG;
    // We must crawl through the whole tree to see, if there are any collapsed nodes
    // at any level. We do this with recursive depth-first-search.
    
    TFsTreeItemId itemId = KFsTreeNoneID;
    TInt count = iTreeList->CountChildren(aParentNodeId);
    
    for ( TInt i=0 ; i<count ; ++i )
        {
        itemId = iTreeList->Child( aParentNodeId, i );
        if ( iTreeList->IsNode(itemId) )
            {
            if ( !iTreeList->IsExpanded(itemId) ||
                 !AllNodesExpanded(itemId) )
                {
                return EFalse;
                }
            }
        }
	
	return ETrue;
    }

// <cmail> Touch
// ---------------------------------------------------------------------------
// Process a treelist event
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::TreeListEventL( const TFsTreeListEvent aEvent, 
                                    const TFsTreeItemId /*aId*/,
                                    const TPoint& /*aPoint*/ )
    {
    switch (aEvent)
        {
        case EFsTreeListItemTouchAction:
            {
            if (TFsTreeItemId focId1 = iTreeList->FocusedItem())
                {
                if (iTreeList->IsNode(focId1))
                    {
                    if (iTreeList->IsExpanded(focId1))
                        {
                        HandleCommandL(EFsEmailUiCmdCollapse);
                        }
                    else
                        {
                        HandleCommandL(EFsEmailUiCmdExpand);
                        }
                    }
                else
                    {
                    SendEmailToFocusedItemL();
                    }
                }
            break;
            }
        case EFsTreeListItemTouchLongTap:
            {
            // Show action toolbar if the item has action menu.
            if( HasFocusedItemActionMenu() )
                {
                LaunchActionMenuL();
                }
            break;
            }
        case EFsTreeListItemWillGetFocused:
            {
            SetMskL(); 
            break;
            }
        }
    }


TPoint CFSEmailUiMsgDetailsVisualiser::ActionMenuPosition()
    {
    TAlfRealRect focusRect;
    TFsTreeItemId listItemId = iTreeList->FocusedItem();
    iTreeList->GetItemDisplayRectTarget(listItemId, focusRect);
    return focusRect.iTl;
    }
// </cmail>

void CFSEmailUiMsgDetailsVisualiser::GetParentLayoutsL( RPointerArray<CAlfVisual>& aLayoutArray ) const
    {
    aLayoutArray.AppendL( iParentLayout );
    }

// <cmail> 
// ---------------------------------------------------------------------------
// Fetching the Message Structure. It is necessary for POP protocol in order to read recipients
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::StartFetchingMessageStructureL(
		CFSMailMessage* aMsg)
	{
	FUNC_LOG;
	TFSMailMsgId currentMailboxId = aMsg->GetMailBoxId();
	TFSMailMsgId currentMessageFolderId = aMsg->GetFolderId();
	CFSMailFolder* currentFolder = iAppUi.GetMailClient()->GetFolderByUidL(
			currentMailboxId, currentMessageFolderId);
	CleanupStack::PushL(currentFolder);
	RArray<TFSMailMsgId> messageIds;
	CleanupClosePushL(messageIds);
	messageIds.Append(aMsg->GetMessageId());
	// Fetch the message structure
	iCurrentStructureFetchRequestId = currentFolder->FetchMessagesL(messageIds,
			EFSMsgDataStructure, *this);
	iFetchingMessageStructure = ETrue;
	CleanupStack::PopAndDestroy(&messageIds);
	CleanupStack::PopAndDestroy(currentFolder);
	}
// </cmail>

// <cmail> 
// ---------------------------------------------------------------------------
// MFSMailRequestObserver interface implementation
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::RequestResponseL(TFSProgress aEvent,
		TInt aRequestId)
	{
	FUNC_LOG;
	if (aRequestId == iCurrentStructureFetchRequestId && iFetchingMessageStructure)
		{
		if (aEvent.iError != KErrNone || aEvent.iProgressStatus == TFSProgress::EFSStatus_RequestCancelled)
			{
			iAsyncProcessComplete = ETrue;
			iFetchingMessageStructure = EFalse;
			}
		else if (aEvent.iProgressStatus == TFSProgress::EFSStatus_RequestComplete)
			{
			iAsyncProcessComplete = ETrue;
			iFetchingMessageStructure = EFalse;

			// get message again, there might be new information
			if (iViewedMsg)
				{
				TFSMailMsgId mailboxId = iViewedMsg->GetMailBoxId();
				TFSMailMsgId folderId = iViewedMsg->GetFolderId();
				TFSMailMsgId messageId = iViewedMsg->GetMessageId();
				UpdateMessagePtrL(mailboxId, folderId, messageId);
				}
			}
		}	
    //<cmail>
    if (iAsyncProcessComplete && iWaitDialog && iDialogNotDismissed)
		{
		iWaitDialog->ProcessFinishedL(); // deletes the dialog
		}
    //</cmail>
	
	if (iViewedMsg) //safety check
		{
		UpdateMsgDetailsModelL();
		iTreeList->ShowListL();
		iTreeList->SetFocusedL(ETrue);
		}
	}
// </cmail>

// <cmail> 
// ---------------------------------------------------------------------------
// Update our message pointer and saves its status
// ---------------------------------------------------------------------------
// 
void CFSEmailUiMsgDetailsVisualiser::UpdateMessagePtrL(
		TFSMailMsgId aNewMailboxId, TFSMailMsgId aNewFolderId,
		TFSMailMsgId aNewMessageId)
	{
	FUNC_LOG;
	if (iViewedMsg)
		{

		delete iViewedMsg;
		iViewedMsg = NULL;
		}

	// it should contain all data now (including recipients)
	iViewedMsg = iAppUi.GetMailClient()->GetMessageByUidL(aNewMailboxId,
			aNewFolderId, aNewMessageId, EFSMsgDataEnvelope);

	if (iViewedMsg)
		{
		// Save read status
		iViewedMsg->SaveMessageL();
		}
	}
// </cmail>

// <cmail> 
// ---------------------------------------------------------------------------
// Cancel fetching of the message structure 
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::CancelFetching()
	{
	FUNC_LOG;

	if (iFetchingMessageStructure)
		{
		TRAP_IGNORE( iAppUi.GetMailClient()->CancelL( iCurrentStructureFetchRequestId ) );
		iFetchingMessageStructure = EFalse;
		}
	iAsyncProcessComplete = ETrue;
	if (iWaitDialog && iDialogNotDismissed)
		{
		TRAP_IGNORE(iWaitDialog->ProcessFinishedL()); // deletes the dialog
		iWaitDialog = NULL;
		}
	//</cmail>
	}
// </cmail>

// <cmail> 
// ---------------------------------------------------------------------------
// MProgressDialogCallback interface implementation
// ---------------------------------------------------------------------------
//
void CFSEmailUiMsgDetailsVisualiser::DialogDismissedL( TInt aButtonId)
	{
    FUNC_LOG;
    iDialogNotDismissed = EFalse;
	if( aButtonId == EAknSoftkeyCancel )
		{
		CancelFetching();
		}
	
	}
// </cmail>
