/*
* Copyright (c) 2002 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: 
*     Abstract base class for recent views
*
*/


// INCLUDE FILES

// System includes
#include <eikmenub.h>
#include <AknQueryDialog.h>
#include <aknnotewrappers.h> 
#include <baclipb.h>
#include <StringLoader.h> 
#include <CMessageData.h>
#include <sendui.h> 
#include <SendUiConsts.h>
#include <TSendingCapabilities.h>
#include <sendnorm.rsg>
#include <Logs.rsg>
#include <AiwCommon.hrh>                //KAiwCmdCall
#include <AiwPoCParameters.h>           //TAiwPocParameterData
#include <aknViewAppUi.h>
#include <AiwServiceHandler.h>
#include <AiwGenericParam.h>
#include <StringLoader.h>
#include <aknnotewrappers.h>
#include <AknGlobalNote.h>
#include <AknGlobalConfirmationQuery.h>
#include <MGFetch.h>
#include <AiwContactSelectionDataTypes.h>
#include <AiwContactAssignDataTypes.h>

// Virtual Phonebook
#include <RVPbkContactFieldDefaultPriorities.h>
#include <VPbkFieldType.hrh>
#include <TVPbkContactStoreUriPtr.h>
#include <CVPbkContactStoreUriArray.h>
#include <MVPbkContactStoreList.h>
#include <CVPbkContactManager.h>
#include <CVPbkFieldTypeSelector.h>
#include <CVPbkContactLinkArray.h>
#include <VPbkContactStoreUris.h>
#include <VPbkContactViewFilterBuilder.h>
//------------------------

#include "CLogsRecentListView.h"
#include "CLogsRecentListControlContainer.h"
#include "CLogsEngine.h"
#include "MLogsEventGetter.h"
#include "MLogsClearLog.h"
#include "MLogsStateHolder.h"
#include "MLogsSharedData.h"
#include "CLogsAppUi.h"
#include "LogsUID.h"
#include "CLogsViewGlobals.h"
#include "MLogsExtensionFactory.h"
#include "MLogsViewExtension.h"
#include "MLogsSystemAgent.h"
#include "MLogsUiControlExtension.h"
#include "LogsConstants.hrh"
#include "CLogsPrependQuery.h"

#include "LogsDebug.h"
#include "LogsTraces.h"

// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES  

// CONSTANTS

// Panic string
_LIT( KStmRecentView, "StmRecentView" );

// MACROS


// LOCAL CONSTANTS AND MACROS

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// ================= MEMBER FUNCTIONS =======================

// ----------------------------------------------------------------------------
// CLogsRecentListView::NewL
// ----------------------------------------------------------------------------
//
CLogsRecentListView* CLogsRecentListView::NewL( TLogsModel aModel )
    {
    CLogsRecentListView* self = new ( ELeave ) CLogsRecentListView( aModel );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );  // self
    return self;
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::CLogsRecentListView
// ----------------------------------------------------------------------------
//
CLogsRecentListView::CLogsRecentListView( TLogsModel aModel ) :
    iState( EStateUndefined ),
    iViewExtension( NULL ),
    iEventListCurrentNoChange( KErrNotFound ) //iEventListCurrentNoChange switched off
    {
    iModel = aModel;
    }
    
// ----------------------------------------------------------------------------
// CLogsRecentListView::~CLogsRecentListView
// ----------------------------------------------------------------------------
//
CLogsRecentListView::~CLogsRecentListView()
    {
    delete iExitCbaButton;
    delete iBackCbaButton;
    iCoeEnv->RemoveForegroundObserver( *this );
    
    Release( iViewExtension );
    Release( iViewGlobal );
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::ConstructL
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::ConstructL()
    {
    BaseConstructL( R_STM_COMMON_VIEW );
    iCoeEnv->AddForegroundObserverL( *this );
    iExitCbaButton = iCoeEnv->AllocReadResourceL( R_STM_EXIT_CBA_BUTTON );
    iBackCbaButton = iCoeEnv->AllocReadResourceL( R_STM_BACK_CBA_BUTTON );
    iViewGlobal = CLogsViewGlobals::InstanceL();
    
// Safwish VoIP changes  >>>
    if ( !iViewExtension )
        {
        CPbkContactEngine* nullContactEngine = NULL;
        iViewExtension = iViewGlobal->ExtensionFactoryL().
                CreateLogsViewExtensionL( *nullContactEngine, this );        
                
        iViewExtension->SetSendUi( *LogsAppUi()->SendUiL() ); 
        iViewExtension->SetSendUiText( SendUiTextL() );                 
        }
// <<<  Safwish VoIP changes
    }
    
// ----------------------------------------------------------------------------
// CLogsRecentListView::LogsCurrentRecentViewId
// ----------------------------------------------------------------------------
//
TLogsViewIds CLogsRecentListView::LogsCurrentRecentViewId() const
    {
    switch( iModel )
        {
        case ELogsReceivedModel:
            return EStmReceivedListViewId;
        case ELogsDialledModel:
            return EStmDialledListViewId;
        case ELogsMissedModel:
            return EStmMissedListViewId;
        default:
            User::Panic( KStmRecentView, KErrUnknown );
            return ELogsDummyViewId; // just to compile without error
            //break;
        }
    }


// ----------------------------------------------------------------------------
// CLogsRecentListView::Id
// ----------------------------------------------------------------------------
//
TUid CLogsRecentListView::Id() const
    {
    return TUid::Uid( LogsCurrentRecentViewId() );
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::RecentListType
// ----------------------------------------------------------------------------
//
TLogsModel CLogsRecentListView::RecentListType() const
    {
    return iModel;
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::ProcessKeyEventL
//
// Called by base control container when a key press happens. 
// ----------------------------------------------------------------------------
//
TBool CLogsRecentListView::ProcessKeyEventL( 
    const TKeyEvent& aKeyEvent,
    TEventCode aType )
    {
    if( MenuBar()->ItemSpecificCommandsEnabled() && aType == EEventKey )
        {
        if( aKeyEvent.iCode == EKeyBackspace ) 
            {
            HandleCommandL( ELogsCmdMenuDelete );
            return ETrue;
            }
        }
        
    const MLogsEventGetter* event( CurrentEvent() );
    
    //FIXME (CLogsRecentListView and CLogsEventListView): 
    //The below is needed only because we get key event before the actual row
    //is changed in the listbox. If/when listbox observer for changed row focus
    //is available, remove code below and get correct event index from observer.
    SetEventListCurrent(iContainer->ListBox()->CurrentItemIndex());

    if( aType == EEventKey && EventListCurrent() != KErrNotFound ) 
        {
        TInt count( CurrentModel()->Count() );
        switch (aKeyEvent.iScanCode)
            {
            case EStdKeyUpArrow:
                //Set iEventListCurrent + jump to previous or last event depending on position in list
                iEventListCurrent > 0 ? event = CurrentModel()->At( --iEventListCurrent ) :
                                        event = CurrentModel()->At( iEventListCurrent = count - 1 );
                break;

            case EStdKeyDownArrow:
                //Set iEventListCurrent + jump to next or first event depending on position in list                
                iEventListCurrent < count - 1 ? event = CurrentModel()->At( ++iEventListCurrent ) :
                                                event = CurrentModel()->At( iEventListCurrent = 0 );
                break;                
            }
        } 
		 
        
    return CLogsBaseView::ProcessKeyEventEventL( aKeyEvent,aType, event );
    }
    
// ----------------------------------------------------------------------------
// CLogsRecentListView::ProcessPointerEventL
//
// Handler for pointer events, when the current focused item is tapped
// ----------------------------------------------------------------------------
// 
void CLogsRecentListView::ProcessPointerEventL( TInt /* aIndex */ )
	{
    // Open the context sensitive menu   
	ProcessCommandL( EAknSoftkeyContextOptions );      	
	}

// ----------------------------------------------------------------------------
// CLogsRecentListView::HandleCommandL
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::HandleCommandL( TInt aCommandId )
    {
    TRACE_ENTRY_POINT;

// Safwish VoIP changes  >>>
    //1. Process first the commands that may be in range interested by PECLogs exension
    if ( iViewExtension->HandleCommandL( aCommandId ) )
        {
        return;
        }
// <<<  Safwish VoIP changes

    //2. Was not a command in range intended for extension. Continue processing.
    const MLogsEventGetter* event = CurrentEvent();
                        
    switch( aCommandId )
        {
        case ELogsCmdMenuDeleteAll:
            CmdClearRecentListL();
            break;

        case ELogsCmdMenuDelete:
            CmdDeleteEventL();
            break;

        case ELogsCmdHandleMSK:
            {
            // If single click or press MSK for a log event,
            // it will request directly by AiwSrvCmd.
            aCommandId = ELogsCmdSingleTapCall;
            } // Fall through
            
        default:
            {
            CLogsBaseView::HandleCommandEventL( aCommandId, event );
            }
        } 
   
    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::ChangeTitlePaneTextToDefaultL
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::ChangeTitlePaneTextToDefaultL()
    {       
    iContainer->SetTitlePaneTextToDefaultL( LogsAppUi()->ActiveViewId() );
    } 

// ----------------------------------------------------------------------------
// CLogsRecentListView::ProcessCommandL
//
// Called from FW when e.g. cba pressed 
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::ProcessCommandL( TInt aCommand )
    {
    TRACE_ENTRY_POINT;
           
    if (LogsAppUi()->ActiveViewId() != LogsCurrentRecentViewId() || !iContainer )
        {
        LOGS_DEBUG_PRINT(LOGS_DEBUG_STRING
                ( "CLogsRecentListView::ProcessCommandL - view already deactivated! return " ));  
        return;
        }
    
    if (aCommand == EAknSoftkeyOptions)
        {
        // If options menu is opened call SetRefreshMenuOnUpdate which records the current event id
        // which can then be used to make a decision on wether options menu needs to be refreshed
        // when reading is finished.
        SetRefreshMenuOnUpdate( CurrentEvent() );
        }
    
    CLogsBaseView::ProcessCommandL( aCommand );
        
    TRACE_EXIT_POINT;
    }
    
// ----------------------------------------------------------------------------
// CLogsRecentListView::DynInitMenuPaneL
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::DynInitMenuPaneL( 
    TInt aResourceId, 
    CEikMenuPane* aMenuPane )
    {
    //Get event. Note that event may NOT yet be available if asynch request(s) are not completed. 
    const MLogsEventGetter*  event = CurrentEvent(); //returns NULL if no data yet available
    CLogsBaseView::DynInitMenuPaneEventL( aResourceId, aMenuPane, event );    
    
// Sawfish VoIP changes  >>>
    iViewExtension->DynInitMenuPaneL( aResourceId, aMenuPane, event );
// <<<  Sawfish VoIP changes    

    }


// ----------------------------------------------------------------------------
// CLogsRecentListView::HandleClientRectChange
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::HandleClientRectChange()
    {
    if (iContainer)
    	{
    	iContainer->SetRect( ClientRect() );  
    	}
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::DrawComponents
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::DrawComponents()
    {
    if (iContainer)
        {
        iContainer->DrawNow();
        }
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::ViewDeactivated
//
// This is called by framework when really losing foreground but not when losing foreground to some note etc.
// Also called by framework when switching views inside application.
// So DoDeactivate is not always called when ViewDeactivated is called.
//
// Note: there is no guarenteed order of which is called first ViewDeactivated or HandleLosingForeground
//
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::ViewDeactivated()
    {
    // When view is deactivated due to losing foreground we reset the list here in advance so there won't be 
    // flickering of the old list. Since view server introduced redraw storing the HandleGainingForeground
    // comes too late and the old list will flicker before it is reseted. 
    // We'll skip this when Phonebook update pending - the list is going to be updated later.
    //
    // If we would do this in HandleLosingForeground, then the list would be emptied when for example when
    // active applications list, global note etc. is shown.
    //
    if (CurrentModel() && iContainer && ( iFocusChangeControl != ELogsNoChange_PbkUpdPending ) )
        {
		
		// EJZO-7RJB3V
        if (IgnoreViewDeactivatedOperation())
            {
            CAknView::ViewDeactivated();
            return;
            }

        if (iFocusChangeControl != ELogsOkToChange)
            {
            StoreEvenListCurrentFocus();
            }
         
        // Reset array and set dirty which means refresh requested, 
        // will call StateChangedL with state EStateArrayReseted and update the listbox.
        CurrentModel()->DoDeactivate( MLogsModel::ESkipClearing,
                                      MLogsModel::EResetOnlyArrayWithDirty );
     
        // On gaining foreground, do a clean read of events
        iResetAndRefreshOnGainingForeground = MLogsModel::EResetAndRefresh;
        }       
    
    CAknView::ViewDeactivated();
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::DoActivateL
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::DoActivateL(
    const TVwsViewId& aPrevViewId,
    TUid aCustomMessageId,
    const TDesC8& aCustomMessage )
    {
    TRACE_ENTRY_POINT;
       
    CLogsBaseView::DoActivateL( aPrevViewId, aCustomMessageId, aCustomMessage );    

    //To prevent first time flicker of context menu if no ctx mnu will be displayed
    Cba()->MakeCommandVisible( EAknSoftkeyContextOptions, EFalse );
    
    iFocusChangeControl = ELogsOkToChange;           
    iEventListCurrentNoChange = KErrNotFound;
    
    LogsAppUi()->SetCurrentViewId( Id() );
    
    //To avoid possible flicker, change the cba text to 'Exit' when going to background
    //but don't draw it. Sometimes CAknView::ConstructMenuAndCbaL might draw the cba
    //when we are going to background and activating dialled calls view. It is safer 
    //to have the cba thus set as 'Exit'
    if( aCustomMessageId.iUid == ELogsViewActivationBackground && 
        LogsAppUi()->ExecutionMode() == ELogsInBackground_ExitOrEndPressed )
        {
        ChangeCba2ToExitL( ELogsDontDraw );     
        }
    else if ( LogsAppUi()->ProvideOnlyRecentViews())                   
        {  
        LogsAppUi()->SetPreviousAppUid( aPrevViewId.iAppUid );
        LogsAppUi()->SetPreviousViewId( aPrevViewId.iViewUid );
        Engine()->DeleteConfig();           //Logs settings
        ChangeCba2ToExitL( ELogsDrawNow );                //We must not be able to back to other Logs views, just exit
        }
    else  
        {
        ChangeCba2ToBackL();
        }
   

    Engine()->CreateModelL( iModel );       //Creates model only if not yet exists

    //Create the control container. 
    if( !iContainer )
        {
        iContainer = CLogsRecentListControlContainer::NewL( this, ClientRect() );
        AppUi()->AddToViewStackL( *this,iContainer );  
        }
    iContainer->ListBox()->SetListBoxObserver( this );

    //External launch has been done already, so come here
    if ( ! LogsAppUi()->ProvideOnlyRecentViews() )
        {
        LogsAppUi()->SetPreviousAppUid( TUid::Uid( KLogsAppUID3 ) );
        LogsAppUi()->SetPreviousViewId( aPrevViewId.iViewUid );
        }

    //Update item selection. Set always focus to top. If previous focus is to be retained, comment below two rows out
    SetEventListCurrent(0);
    SetEventListTop(0);
    
    CurrentModel()->SetObserver( this );
    
    if( aCustomMessageId.iUid == ELogsViewActivationBackground && 
        LogsAppUi()->ExecutionMode() == ELogsInBackground_ExitOrEndPressed )
        {
        // We have activated this view because we are hiding Logs into background (faking exit) 
        // so this view is waiting when Logs is again foregrounded.    
        //
        // With MLogsModel::ECloseDBConnectionAndResetArray the connection to the database is
        // closed and event array will be deleted. Calls StateChangedL with state EStateArrayReseted 
        // which will update the listbox to empty state.
        CurrentModel()->DoDeactivate( MLogsModel::ENormalOperation,
                                      MLogsModel::ECloseDBConnectionAndResetArray );

        // Now we can enable bring-to-foreground on view activation:
        AppUi()->SetCustomControl(0); 
        AppUi()->HideInBackground(); 
        // When coming back to foreground, do a clean read of events
        iResetAndRefreshOnGainingForeground = MLogsModel::EResetAndRefresh; 
        }
    else
        {
        // Just to make sure the inputblocker is not on
        RemoveInputBlocker();
        CurrentModel()->DoActivateL( MLogsModel::EResetAndRefresh );
        
        // By default on gaining foreground, just refresh the list. So when active applications list, 
        // keylock or some note (like when plugin in the charger) is shown the list doesn't flicker. 
        // When view is deactivated this is set to MLogsModel::EResetAndRefresh.
        iResetAndRefreshOnGainingForeground = MLogsModel::ERefresh; 
        }
    
    
    if( CurrentModel()->Count() )
          {
          iContainer->ListBox()->SetTopItemIndex( EventListTop() );
          if( EventListCurrent() < 0 )
              {
              SetEventListCurrent(0);
              }
          iContainer->ListBox()->SetCurrentItemIndex( EventListCurrent() );
          }
     
    ClearMissedCallNotificationsL();     //Clear cenrep new missed calls counter + notifications (however, possible missed 
                                         //list duplicate counters need to be cleared separately).  
     
    TRACE_EXIT_POINT;    
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::ReadingFinished
// ----------------------------------------------------------------------------
//
TBool CLogsRecentListView::ReadingFinished()
    {
    TBool finished = ( iState != EStateActive       && iState != EStateUndefined  &&  
                       iState != EStateInitializing && iState != EStateSemiFinished &&
                       iState != EStateInterrupted );  
                                          
    return finished;
    }   
    
// ----------------------------------------------------------------------------
// CLogsRecentListView::IgnoreViewDeactivatedOperation
// ----------------------------------------------------------------------------
//  
TBool CLogsRecentListView::IgnoreViewDeactivatedOperation()
    {
    TBool ret = EFalse;
    if (iIgnoreViewDeactivatedHandling)
        {
	      // no guarenteed order of which is called first ViewDeactivated or HandleLosingForeground,
	      // so add the iSemiFinishViewDeactivatedOperation flag
        if (iSemiFinishViewDeactivatedOperation)
            {
            iIgnoreViewDeactivatedHandling = EFalse;
            iSemiFinishViewDeactivatedOperation = EFalse;
            }
        else
            {
            iSemiFinishViewDeactivatedOperation = ETrue;
            }
                
        ret = ETrue;
        }
        
    return ret;   
	}
	  
// ----------------------------------------------------------------------------
// CLogsRecentListView::DoDeactivate
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::DoDeactivate()
    {
    TRACE_ENTRY_POINT;
        
    CLogsBaseView::DoDeactivate(); 
                         
    if( iContainer )
        {
        SetEventListCurrent(iContainer->ListBox()->CurrentItemIndex());
        SetEventListTop(iContainer->ListBox()->TopItemIndex());
        AppUi()->RemoveFromViewStack( *this, iContainer );
        delete iContainer;
        iContainer = NULL;
        }

     if( iModel == ELogsMissedModel )
        {
        // Below we test for reading finshed to prevent unnecessary clearing of duplicate counters, 
        // new missed call icons and missed call notification and the "x missed calls" text 
        // in the Call register view. 
        //
        // This would otherwise be done when user reopens Logs by 
        // green key or from appshell after first leaving Missed calls view to background. 
        //
        // (Missed calls view will first receive HandleGainingForeground followed by an 
        // immediate DoDeactivate )
        //
        // FIXME: This fix is not 100% sure cause it might happen rarely that the reading has time to 
        // finish before framework activates the actual view that was opened (and calls DoDeactivate for 
        // missed calls view). No better solution found yet though. 
        //
        if ( ReadingFinished() )
            {
            LOGS_DEBUG_PRINT(LOGS_DEBUG_STRING
                    ( "CLogsRecentListView::DoDeactivate - ReadingFinished" ));  
            ClearMissedCallNotifications();   //Clear cenrep new missed calls counter + notifications          
            CurrentModel()->DoDeactivate( MLogsModel::ENormalOperation,
                                          MLogsModel::ECloseDBConnection );//ETrue: disconnect from db. This helps for EMSH-6JDFBV but
                                              //reduces user's perceived performance for other views
                                              //(seems to keep clearing of missed duplicates process alive
                                              // so no need for EFalse here as it would increase probability of 
                                              // EMSH-6JDFBV occurring again   
                                    
            }
                              
        else
            {
            LOGS_DEBUG_PRINT(LOGS_DEBUG_STRING
                    ( "CLogsRecentListView::DoDeactivate - Reading interrupted" )); 
            CurrentModel()->DoDeactivate( MLogsModel::ESkipClearing,
                                          MLogsModel::ECloseDBConnection );
            }    
        }
    else
        {
        CurrentModel()->DoDeactivate( MLogsModel::ENormalOperation,
                                      MLogsModel::ECloseDBConnection );//ETrue: disconnect from db. This helps for EMSH-6JDFBV but
                                              //reduces user's perceived performance for other views
                                              //EFalse: don't disconnect from db. This keeps read data cached in Logs.
        }
        
    //To prevent second time flicker of context menu if ctx mnu was was displayed
    //but will not later be displayed
    Cba()->MakeCommandVisible( EAknSoftkeyContextOptions, EFalse );
    
    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::CmdClearRecentListL
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::CmdClearRecentListL()
    {
    if( CurrentModel()->Count() )
        {
        TInt resId( 0 );

        CAknQueryDialog* queryDlg = CAknQueryDialog::NewL();
                
        switch( iModel )
            {
            case ELogsMissedModel:
                resId = R_CLEAR_MISSED_LIST_CONFIRMATION_QUERY;
                break;

            case ELogsReceivedModel:
                resId = R_CLEAR_RECEIVED_LIST_CONFIRMATION_QUERY;
                break;

            case ELogsDialledModel:
                resId = R_CLEAR_DIALLED_LIST_CONFIRMATION_QUERY;
                break;

            default:
                User::Panic( KStmRecentView, KErrUnknown );
                break;
            }
          
        if( queryDlg->ExecuteLD( resId ) )
            {
            Engine()->ClearLogsL()->ClearModelL( iModel );
            SetEventListTop(0);
            SetEventListCurrent(0);
                
            SetInputBlockerL();
            } 
        }
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::CmdDeleteEventL
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::CmdDeleteEventL()
    {
    if( CurrentModel()->Count() && iContainer->ListBox()->CurrentItemIndex() != KErrNotFound )    
        {
        CAknQueryDialog* queryDlg = CAknQueryDialog::NewL();
        SetEventListTop(iContainer->ListBox()->TopItemIndex());
        SetEventListCurrent(iContainer->ListBox()->CurrentItemIndex());

        TLogId id = CurrentModel()->At( EventListCurrent() )->LogId();
        
        if( queryDlg->ExecuteLD( R_DELETE_CONFIRMATION_QUERY ) )
            {
            iEventListCurrentNoChange = iContainer->ListBox()->CurrentItemIndex(); 
            Engine()->ClearLogsL()->DeleteEventL( id ); //Delete the event from LogDb. Event from view gets 
                                                        //removed when the view data is reread from db.
            iFocusChangeControl = ELogsNoChange;        //Prevent focus moving to top when list is reread 
            } 
        }
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::ChangeCba2ToExitL
// ----------------------------------------------------------------------------
//
TBool CLogsRecentListView::ChangeCba2ToExitL( TLogsDrawNow aDrawNow )
    {
    //We must attempt to change CBA only if we have correct view in the foreground
    if( LogsAppUi()->ActiveViewId() != LogsCurrentRecentViewId() )
        {
        return EFalse; //There is some other view already active, so we don't have 
        }              // our own cba's present
 
    TInt pos = Cba()->PositionById( EAknSoftkeyBack );   
         
    if( pos > 0 )
        {
        Cba()->SetCommandL( pos, 
                            ELogsCmdMenuExit, 
                            iExitCbaButton->Des() );
                            
        if (aDrawNow == ELogsDrawNow)
            {
            Cba()->DrawNow();  
            }
            
        return ETrue;
        }
        
    return EFalse;
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::ChangeCba2ToBackL
// ----------------------------------------------------------------------------
//
TBool CLogsRecentListView::ChangeCba2ToBackL()
    {
    if( LogsAppUi()->ActiveViewId() != LogsCurrentRecentViewId() )
        {
        return EFalse; //There is some other view already active, so we don't have our own cba's present
        }              // (e.g. FSW can be brought to foreground already)
        
    TInt pos = Cba()->PositionById( ELogsCmdMenuExit ); 
           
    if( pos > 0 )
        {
        Cba()->SetCommandL( pos, 
                            EAknSoftkeyBack, 
                            iBackCbaButton->Des() );
        Cba()->DrawNow();//Needed when this view already been open and cba changed in other view
        
        return ETrue;
        }
        
    return EFalse;
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::HandleGainingForeground
//
// This function is called once for each already constructed Recent View when 
// Logs is gaining foreground. No matter if a view is deactivated (i.e. is also 
// called for view(s) not actually gaining foreground but just have been constructed)
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::HandleGainingForeground()
    {   
    TRACE_ENTRY_POINT;  
         
    CLogsBaseView::HandleGainingForeground();

    //Process cba if this view is already open and then just brought to foreground
    //in ProvideOnlyRecentViews mode
    if( LogsAppUi()->ProvideOnlyRecentViews() )    
        {
        TRAPD( err, ChangeCba2ToExitL( ELogsDrawNow ) );  
        if( err ) 
            {
            iCoeEnv->HandleError( err );
            }
        
        // Always reset focus to the top of the list, when Logs is opened by a send key 
        // press from idle    
        if (LogsAppUi()->LogsOpenedWithSendKey() && LogsCurrentRecentViewId() == EStmDialledListViewId)
            {
            iFocusChangeControl = ELogsOkToChange;
            iEventListCurrentNoChange = KErrNotFound;
            LogsAppUi()->SetLogsOpenedWithSendKey(EFalse); // reset the send key checking 
            LOGS_DEBUG_PRINT(LOGS_DEBUG_STRING
                ( "CLogsRecentListView::HandleGainingForeground - LogsOpenedWithSendKey: reset focus" ));  
            }       
        }

    //Activate current view's model that we deactivated in HandleLosingForeground().
    //No need to check if already active, DoActivateL() handles this.
    if( LogsAppUi()->ActiveViewId() == LogsCurrentRecentViewId() && iContainer )  //Only if this object corresponds 
                                                                    //to current view.
        {
        MLogsModel* model = CurrentModel();
        
        //ELogsNoChange is special case here, i.e contact just added to pbk: skip activating to avoid unwanted UI-focus change.
        //We don't know in hw which is finished first, reading of entries because of gaining of foreground (EMSH-6JDFBV) here or 
        //re-reading of entries because change observed in db, or will the first db-read have enough time to finish before.
        if( model )  
            {
            if( iFocusChangeControl != ELogsNoChange_PbkUpdPending) 
                {
                 //If menu is shown, we need to close it as focus is lost
                if (MenuBar()->IsDisplayed())
                    {
                    MenuBar()->StopDisplayingMenuBar();
                    }
                
                SetEventListCurrent( KErrNotFound );//just to make sure that UI does not try to read anything from eventarray                
                TRAPD( err, model->DoActivateL( iResetAndRefreshOnGainingForeground ) );  
                if( err ) 
                    {
                    iCoeEnv->HandleError( err );
                    }
                
                // By default on gaining foreground, just refresh the list. So when active applications list, 
                // keylock or some note (like when plugin in the charger) is shown the list doesn't flicker. 
                // When view is deactivated this is set to MLogsModel::EResetAndRefresh.
                iResetAndRefreshOnGainingForeground = MLogsModel::ERefresh;
                }
            else
                {
                // Change ELogsNoChange_PbkUpdPending to ELogsNoChange now so there is no need to 
                // differentiate those in StateChangedL
                iFocusChangeControl = ELogsNoChange;
                }
            }
        
        RemoveInputBlocker(); //just in case
        }                            
    TRACE_EXIT_POINT; 
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::StoreEvenListCurrentFocus()
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::StoreEvenListCurrentFocus()
    {
    //
    // Check that not called from deactivated recent list view that also gets 
    // a notification of losin foreground.
    if (!iContainer || LogsAppUi()->ActiveViewId() != LogsCurrentRecentViewId())
        {
        return;
        }
     
    // Store the current focused item. Sometimes foreground can be regained for only very briefly and 
    // event reading is not finished so skip those situations. 
    // Also there is no guarantees which is called fist, HandleLosingForeground
    // or ViewDeactivated so don't change when list is already deleted.
    //
    if( (iContainer->ListBox()->CurrentItemIndex() != KErrNotFound) && ReadingFinished() )
        {
        SetEventListCurrent(iContainer->ListBox()->CurrentItemIndex());
        
        // Switch on iEventListCurrentNoChange: store the current item index to 
        // keep it over effects of loss and gain of foreground.
        iEventListCurrentNoChange = EventListCurrent(); 
        SetEventListTop(iContainer->ListBox()->TopItemIndex());
        }
    //
    // If the list has no focus and iEventListCurrentNoChange is not set, let the focus go 
    // to the top of the list when events are reread.
    else if ( ( iContainer->ListBox()->CurrentItemIndex() == KErrNotFound ) &&
              ( iEventListCurrentNoChange == KErrNotFound ) )
        {
        iFocusChangeControl = ELogsOkToChange;
        }
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::HandleLosingForeground
//
// This function is called once for each type of already constructed recent view (e.g.when fast swapping 
// window is brought to foreground).
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::HandleLosingForeground()
    {
    TRACE_ENTRY_POINT;
    CLogsBaseView::HandleLosingForeground(); 
    
    TBool finished = ReadingFinished();     
    TLogsViewIds currView = LogsCurrentRecentViewId();      
    
    
    if ( iContainer && ( LogsAppUi()->ActiveViewId() == currView )) 
        {
        // EJZO-7RJB3V
        if (IgnoreViewDeactivatedOperation())
            {
            TRACE_EXIT_POINT;
            return; 
            }
           
        // If we are losing foreground in the middle of event reading, force empty text to the view.
        // This happens for example when keys are locked EYSN-6X5DYS
        if (!finished)
            {
            // Does not have effect if list is not empty
            iContainer->ForceEmptyTextListBox();
            }
        //
        // If focus is to be kept (iFocusChangeControl is ELogsNoChange or 
        // ELogsNoChange_PbkUpdPending) store the current focused item
       if ( iFocusChangeControl != ELogsOkToChange  )   
            {
            StoreEvenListCurrentFocus();
            }
        }
    
    // The below is additional code for tuning performance consumption. It can be removed when no need 
    // for this is found as the code below does not affect functionality.
    // For performance consumption reasons (EMSH-6JDFBV) we need to deactivate the 
    // current view when we lose foreground. However, this needs to be done only for 
    // missed calls view as other views should not be affected by this. However we do it for dialled calls in order 
    // to prevent old wrong entry staying a while in top of list when redialing from dialled list. 
    //
    // Update: apply the same for Received calls view. This is needed to to avoid inconsistency 
    // between the views, like in EYSN-6X5DYS  
    //
    if( ( LogsAppUi()->ActiveViewId() == currView ) &&  //Only if this object corresponds to current view.
        ( currView == EStmMissedListViewId  || 
          currView == EStmDialledListViewId ||
          currView == EStmReceivedListViewId ) ) 
        {                                               
        MLogsModel* model = CurrentModel();
        if( model )
            {
            // End key pressed in missed calls view: sent to background before the Dialled calls view 
            // is activated while in background. so need to clear duplicates now since the reader is deleted
            // and they cannot be cleared in DoDeactivate anymore
            if( LogsAppUi()->ExecutionMode() == ELogsInBackground_ExitOrEndPressed && currView == EStmMissedListViewId )
                {
                 LOGS_DEBUG_PRINT(LOGS_DEBUG_STRING
                    ( "CLogsRecentListView::HandleLosingForeground - clear duplicates" ));      
                model->DoDeactivate( MLogsModel::ENormalOperation, 
                                     MLogsModel::ECloseDBConnection );    //EFalse: don't disconnect from db 
                }
            else    
                {
                LOGS_DEBUG_PRINT(LOGS_DEBUG_STRING
                    ( "CLogsRecentListView::HandleLosingForeground - skip clearing" )); 
                //Other loss of foreground (call or AppKey). We'll not touch duplicate counters
                model->DoDeactivate( MLogsModel::ESkipClearing, //Don't update db (for missed view)
                                     MLogsModel::ECloseDBConnection );    //ETrue: disconnect from db in order to immediately to stop
                                                 //EFalse: don't disconnect from db                                     
                }
            }
        }
    
    TRACE_EXIT_POINT;
    }
 
// ----------------------------------------------------------------------------
// CLogsRecentListView::StateChangedL
//
// CLogsModel informs it has changed event array, e.g. added entry to array or reseted the array etc.
// This function is called as many times as there is new/changed row in the event array. 
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::StateChangedL( MLogsStateHolder* aHolder )
    {
    TRACE_ENTRY_POINT;
    
    if( !aHolder )
         {
         return;  
         }
         
     iState = aHolder->State();
    
    // When check contact link finished, call base method to check if need to 
    // refresh menu.
     if( iState == EStateCheckContactLinkFinished )
         {
         CLogsBaseView::StateChangedL(aHolder);
         return;
         }
    
    //Call Update() when related items available to show changes immediately plus when reading is finished. 
    const TInt KNbrShownEntries = 8;
    
    iState = aHolder->State();
    LOGS_DEBUG_PRINT(LOGS_DEBUG_STRING
        ( "CLogsRecentListView::StateChangedL - iState:%d  iFocusChangeControl:%d viewid:%d"), 
          iState, iFocusChangeControl, LogsCurrentRecentViewId() );  
        
    // If there was some error reading events - most likely KErrNoMemory, 
    // display information to user and close Logs 
    if( iState == EStateError )
    	{
    	iCoeEnv->HandleError(KErrNoMemory);
	    LogsAppUi()->CmdExit();
    	}
    
    //A. If reader deleted (EMSH-6JDFBV), stop all processing.
    if( iState == EStateReaderDeletedOrStopped )
        { 
        return;
        }
    // Special case, array is reseted so update the list to empty state. This prevents flicker
    // of the old list when regaining foreground
    else if ( iState == EStateArrayReseted )
        {
        if( iContainer )
            {
            iContainer->UpdateL();
            }
        return;
        }
              
    //B. Continue to show contents quickly and without flicker when enough events available
    if( iContainer )
        {
        //1. Check are we finished and set scroll bars
        TInt count( iContainer->ListBox()->Model()->NumberOfItems() );  //Current count of items CLogsModel has read into item array
        TBool finished = ReadingFinished();  
        CEikScrollBarFrame* sbFrame = iContainer->ListBox()->ScrollBarFrame();    

        if( finished || iState == EStateSemiFinished) //To avoid scroll bar flicker don't show scroll bar until completely finished
            {
            sbFrame->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff, CEikScrollBarFrame::EOn );  
            }
        else if (count == 0)
            {
            sbFrame->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff, CEikScrollBarFrame::EOff ); 
            }
        
        //2. Update listbox when sufficiently events available
        if( finished || iState == EStateSemiFinished)
            {
            iContainer->UpdateL();      //Calls HandleItemAdditionL (plus sets Empty text if needed)    
            // Fetch data for extension
            iContainer->ControlExtension()->HandleAdditionalData( 
                *CurrentModel(), 
                *iContainer->ListBox() );
            ClearMissedCallNotificationsL();
            // When event reading is finished, remove inputblocker
            RemoveInputBlocker();
            }        
        // If focus is not retained, refresh the UI when a screenful of events is read
        else if( iFocusChangeControl == ELogsOkToChange && count == KNbrShownEntries ) 
            {
            iContainer->UpdateL();
            }
   
        //3. Control focus changes in the list during the read of events
        
        //Set focus once when ok to change     
        if ( iFocusChangeControl == ELogsOkToChange ) 
            {
            if( iState == EStateFinished || iState == EStateSemiFinished )
                {            
                //Reset iEventListCurrentNoChange and iFocusChangeControl
                iEventListCurrentNoChange = KErrNotFound; 
                iFocusChangeControl =  ELogsNoChange;
                }
            
            if( count &&  //at least one entry from previous read to this view
               ( iState == EStateUndefined || iState == EStateInitializing )) //we're about start reread        
                {
                SetEventListCurrent(0); 
                iContainer->ListBox()->SetCurrentItemIndex( EventListCurrent() );
                }                
            }
  
        else
            //No focus change when entry saved to phonebook, deleted or list updated twice.
            {
            if( (iState == EStateFinished && LogsCurrentRecentViewId() != EStmMissedListViewId ) || iState == EStateSemiFinished)
                {
                //If e.g. foreground regained, use iEventListCurrentNoChange if switched on
                if( iEventListCurrentNoChange != KErrNotFound &&    //iEventListCurrentNoChange is switched on.
                    ( EventListCurrent() == KErrNotFound ||
                      EventListCurrent() == 0) )     //No iEventListCurrent available.
                    {
                    SetEventListCurrent(iEventListCurrentNoChange);  //Use iEventListCurrentNoChange
                    }
             
                if( count > 0 ) 
                    {
                    //If now less rows than current item before, or if no current selection (e.g last
                    //row was deleted), try to set focus to last available item. Otherwise try to use 
                    //iEventListCurrent.
                    if( count <= EventListCurrent() || EventListCurrent() < 0 ) 
                        {
                        iContainer->ListBox()->SetCurrentItemIndex( count - 1 );
                        }
                    else if( count > EventListCurrent() )
                        {
                        iContainer->ListBox()->SetCurrentItemIndex( EventListCurrent() );
                        // if event list top is sensible, adjust the window back to what it was
                        if ((EventListTop() >= 0) && (EventListTop() < count) )
                            {
                            iContainer->ListBox()->SetTopItemIndex(EventListTop());
                            }
                        }
                    }
                
                iFocusChangeControl =  ELogsNoChange;
                SetEventListCurrent( iContainer->ListBox()->CurrentItemIndex() );                    
                }
            }
        
                //When reading twice (EMSH-6JDFBV), prevent setting focus again for second phase read. 
        if( iState == EStateSemiFinished ) 
            {
            iFocusChangeControl = ELogsNoChange; 
            }
        
        //4. Set MSK state
        if( iState == EStateFinished || iState == EStateSemiFinished )         
            {
            Cba()->MakeCommandVisible( 
                EAknSoftkeyContextOptions, 
                IsOkToShowContextMenu( CurrentEvent() ));
            }

        //5. To improve user's perceived responsiviness we probably now have a good moment to perform 
        //some time consuming operations if not yet already done
        if( count == KNbrShownEntries ) //if( iState == EStateFinished )
            {
            ConstructDelayedL( ETrue );   //EFalse: perform immediately, ETrue: perform using idle time                                
            }
        
        //6. When starting reading, call UpdateL so the informative text 
        // "Retrieving data" can be shown instead just the empty screen.    
        if (count == 0 && iState == EStateInitializing )
            {
            iContainer->UpdateL();  
            }
      
        //7. Just in case the menu was open before reading events, handle the possible menu refresh now 
        if (finished)
            {
            HandleMenuRefreshL(CurrentEvent());
            }
        
        }
        
    TRACE_EXIT_POINT;    
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::ExtStateChangedL
// ----------------------------------------------------------------------------
//
void CLogsRecentListView::ExtStateChangedL()
    {
    if( iContainer )
        {
        iContainer->UpdateL();
        }
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::State
// ----------------------------------------------------------------------------
//
TLogsState CLogsRecentListView::State() const
    {
    return iState;  
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::CurrentEvent
//
// Returns event relating current selection of listbox or NULL
// ----------------------------------------------------------------------------
//
const MLogsEventGetter* CLogsRecentListView::CurrentEvent()
    {
    TRACE_ENTRY_POINT;
    //KErrNotFound if no current selection in listbox:
    if (iContainer && iContainer->ListBox())
        {
        SetEventListCurrent(iContainer->ListBox()->CurrentItemIndex());
        }
    else
        {
        TRACE_EXIT_POINT;
        return NULL;
        }
    
    //Return null if no current selection or no suitable event available 
    if( CurrentModel() && CurrentModel()->Count() > 0 && EventListCurrent() >= 0  )    
        {
        TRACE_EXIT_POINT;
        return CurrentModel()->At( EventListCurrent() );    
        }
    else
        {
        TRACE_EXIT_POINT;
        return NULL;
        }
    }

// ----------------------------------------------------------------------------
// CLogsRecentListView::HandleNotifyL
//
// Handle AIW-notifications (from asynch ExecuteCmdL call)
// ----------------------------------------------------------------------------
//
TInt CLogsRecentListView::HandleNotifyL(
    TInt aCmdId, 
    TInt aEventId,
    CAiwGenericParamList& aEventParamList,
    const CAiwGenericParamList& aInParamList )
    {
    TInt result = CLogsBaseView::HandleNotifyL( aCmdId, aEventId, aEventParamList, aInParamList );        
    return result;    
    }


//  End of File  
