/*
* Copyright (c) 2005-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:  Phonebook 2 names list control.
*
*/


// INCLUDE FILES
#include "CPbk2NamesListControl.h"

// Phonebook 2
#include "CPbk2NamesListStateFactory.h"
#include "CPbk2ContactViewListBox.h"
#include "CPbk2ThumbnailLoader.h"
#include "cpbk2filteredviewstack.h"
#include "MPbk2NamesListState.h"
#include "MPbk2ControlObserver.h"
#include "MPbk2UiControlEventSender.h"
#include <CPbk2ControlContainer.h>
#include <CPbk2ViewState.h>
#include <Pbk2UIControls.hrh>
#include <MPbk2Command.h>
#include <MPbk2ContactUiControlExtension.h>
#include <pbk2contactuicontroldoublelistboxextension.h>
#include <MPbk2UIExtensionFactory.h>
#include <CPbk2UIExtensionManager.h>
#include "MPbk2FilteredViewStack.h"
#include "cpbk2predictiveviewstack.h"
#include <Pbk2Commands.hrh>
#include <Pbk2InternalUID.h>
#include "CPbk2PredictiveSearchFilter.h"
#include "cpbk2contactviewdoublelistbox.h"
#include <CPbk2ThumbnailManager.h>
#include <Pbk2CommonUi.rsg>
#include <Pbk2UIControls.rsg>
#include "CPbk2AppUi.h"

// Virtual Phonebook
#include <MVPbkContactViewBase.h>
#include <MVPbkViewContact.h>
#include <MVPbkContactLink.h>
#include <CVPbkContactLinkArray.h>

// System includes
#include <barsread.h>
#include <aknsfld.h>
#include <AknPriv.hrh>
#include <featmgr.h>
#include <AknWaitDialog.h>

// Debugging headers
#include <Pbk2Debug.h>


/// Unnamed namespace for local definitions
namespace {

/**
 * Handles errors.
 *
 * @param aErrorCode    Error code.
 */
void HandleError( TInt aErrorCode )
    {
    if ( aErrorCode != KErrNone )
        {
        // Display standard error message
        CEikonEnv::Static()->HandleError( aErrorCode );
        }
    }

#ifdef _DEBUG
enum TPanicCode
    {
    EPanicLogic_ComponentControl = 1,
    };

void Panic(TPanicCode aReason)
    {
    _LIT(KPanicText, "CPbk2NamesListControl");
    User::Panic(KPanicText, aReason);
    }
#endif // _DEBUG

} /// namespace

/**
 * A helper class for sending control events.
 */
NONSHARABLE_CLASS( CPbk2UiControlEventSender ) : public CBase,
                                                public MPbk2UiControlEventSender
    {
    public: // Construction and destruction

        /**
         * Creates a new instance of this class.
         *
         * @param aControl      Control.
         * @param aObservers    Observers.
         * @return  A new instance of this class.
         */
        static CPbk2UiControlEventSender* NewL(
                CPbk2NamesListControl& aControl,
                RPointerArray<MPbk2ControlObserver>& aObservers );

        /**
         * Destructor.
         */
       ~CPbk2UiControlEventSender();

    public: /// From MPbk2UiControlEventSender
        TBool SendEventToObserversL(
                const TPbk2ControlEvent& aEvent );
        void Reset();

    private: // Implementation
        CPbk2UiControlEventSender(
                CPbk2NamesListControl& aControl,
                RPointerArray<MPbk2ControlObserver>& aObservers );
        void ConstructL();
        TBool SendEvent(
                const TPbk2ControlEvent& aEvent );

    private: // Data
        /// Ref: Control
        CPbk2NamesListControl& iControl;
        /// Ref: Observers
        RPointerArray<MPbk2ControlObserver>& iObservers;
        /// Own: Indicates has the ready event been sent
        TBool iReadyEventSend;
    };

/**
 * A helper class for hiding inheritance of MPbk2FilteredViewStackObserver
 * from CPbk2NamesListControl.
 */
class CPbk2FilteredViewStackObserver  : public CBase,
                                                      public MPbk2FilteredViewStackObserver
    {
    public: /// Typedefs
        typedef void( CPbk2NamesListControl::* TopViewChangedFuncPtr )
            ( MVPbkContactViewBase& aOldView );
        typedef void( CPbk2NamesListControl::* ViewStackErrorFuncPtr )
            ( TInt aError );
        typedef void( CPbk2NamesListControl::* ContactAddedToBaseViewFuncPtr )
            ( MVPbkContactViewBase& aBaseView,
              TInt aIndex, const MVPbkContactLink& aContactLink );
        typedef void( CPbk2NamesListControl::* TopViewUpdatedFuncPtr )();
        typedef void( CPbk2NamesListControl::* BaseViewChangedFuncPtr )();

    public: // Construction and destruction

        /**
         * Creates a new instance of this class.
         *
         * @param aControl                          Control.
         * @param aViewStack                        View stack.
         * @param aTopViewChangedFuncPtr            Top view changed function pointer.
         * @param aTopViewUpdatedFuncPtr            Top view updated function pointer.
         * @param aBaseViewChangedFuncPtr           Base view changed function pointer.
         * @param aViewStackErrorFuncPtr            View stack error function pointer.
         * @param aContactAddedToBaseViewFuncPtr    Contact added to base view function pointer.
         * @return  A new instance of this class.
         */
        static CPbk2FilteredViewStackObserver* NewL(
                CPbk2NamesListControl& aControl,
                TopViewChangedFuncPtr aTopViewChangedFuncPtr,
                TopViewUpdatedFuncPtr aTopViewUpdatedFuncPtr,
                BaseViewChangedFuncPtr aBaseViewChangedFuncPtr,
                ViewStackErrorFuncPtr aViewStackErrorFuncPtr,
                ContactAddedToBaseViewFuncPtr aContactAddedToBaseViewFuncPtr );

        /**
         * Destructor.
         */
       ~CPbk2FilteredViewStackObserver();

    private: // From MPbk2FilteredViewStackObserver
        void TopViewChangedL(
                MVPbkContactViewBase& aOldView );
        void TopViewUpdatedL();
        void BaseViewChangedL();
        void ViewStackError(
                    TInt aError );
        void ContactAddedToBaseView(
                    MVPbkContactViewBase& aBaseView,
                    TInt aIndex,
                    const MVPbkContactLink& aContactLink );

    private: // Implementation
        CPbk2FilteredViewStackObserver(
                CPbk2NamesListControl& aControl,
                TopViewChangedFuncPtr aTopViewChangedFuncPtr,
                TopViewUpdatedFuncPtr aTopViewUpdatedFuncPtr,
                BaseViewChangedFuncPtr aBaseViewChangedFuncPtr,
                ViewStackErrorFuncPtr aViewStackErrorFuncPtr,
                ContactAddedToBaseViewFuncPtr aContactAddedToBaseViewFuncPtr );
        void ConstructL();

    private: // Data
        /// Ref: Control
        CPbk2NamesListControl& iControl;
        /// Ref: Top view changed function pointer
        TopViewChangedFuncPtr iTopViewChangedFuncPtr;
        /// Ref: Top view updated function pointer
        TopViewUpdatedFuncPtr iTopViewUpdatedFuncPtr;
        /// Ref: Base view changed function pointer
        BaseViewChangedFuncPtr iBaseViewChangedFuncPtr;
        /// Ref: View stack error function pointer
        ViewStackErrorFuncPtr iViewStackErrorFuncPtr;
        /// Ref: Contact added to base view function pointer
        ContactAddedToBaseViewFuncPtr iContactAddedToBaseViewFuncPtr;
    };

/**
 * An observer for list box selections. Sends control events
 * when the list box enters to or from the selection mode.
 */
NONSHARABLE_CLASS( CPbk2ListBoxSelectionObserver ) :  public CBase,
                                                        private MListBoxSelectionObserver
    {
    public: // Interface

        /**
         * Creates a new instance of this class.
         *
         * @param aListBox      The list box that is observed.
         * @param aEventSender  An event sender for sending control
         *                      events.
         * @return  A new instance of this class.
         */
        static CPbk2ListBoxSelectionObserver* NewL(
                CPbk2NamesListControl& aControl,
                CEikListBox& aListBox,
                MPbk2UiControlEventSender& aEventSender );

        /**
         * Destructor
         */
        ~CPbk2ListBoxSelectionObserver();

    private: /// From MListBoxSelectionObserver
        void SelectionModeChanged(
                CEikListBox* aListBox,
                TBool aSelectionModeEnabled );

    private: // Implementation
        CPbk2ListBoxSelectionObserver(
                CPbk2NamesListControl& aControl,
                CEikListBox& aListBox,
                MPbk2UiControlEventSender& aEventSender );
        void ConstructL();

    private: // Data
        /// Ref: Control
        CPbk2NamesListControl& iControl;
        /// Ref: List box
        CEikListBox& iListBox;
        /// Ref: Event sender
        MPbk2UiControlEventSender& iEventSender;
    };


/**
 * Background Task Handler.
 */
NONSHARABLE_CLASS(CPbk2NamesListControlBgTask) : public CActive
    {

    public:
        CPbk2NamesListControlBgTask( CPbk2NamesListControl& aControl );
        ~CPbk2NamesListControlBgTask();

        void AddEvent( CPbk2NamesListControl::TPbk2NamesListBgEvents aEvent );
        void ClearAllEvents();
        void RemoveEvent( CPbk2NamesListControl::TPbk2NamesListBgEvents aEvent );

    private: // From CActive
        void DoCancel();
        void RunL();
        TInt RunError(TInt aError);

    private:
        //Owns
        RArray <CPbk2NamesListControl::TPbk2NamesListBgEvents> iEventQueue;

        //doesnt Own
        CPbk2NamesListControl& iControl;
    };

/**
 * A helper class for mass update cases.
 */
NONSHARABLE_CLASS( CPbk2HandleMassUpdate ) : public CBase
    {
    public: // Construction and destruction
        /**
         * Creates new instance of this class.
         * @return new instance of this class.
         */
        static CPbk2HandleMassUpdate* NewL(CEikListBox& iListBox);

        /**
         * Destructor.
         */
       ~CPbk2HandleMassUpdate();

    public:
        /**
         * Call this function after each update event.
         * @return  ETrue if this event is part of a mass update.
         */
       TBool MassUpdateCheckThis();

        /**
         * Call this function to check if mass update process is ongoing.
         * @return  ETrue if mass update process is ongoing.
         */
       TBool MassUpdateDetected();
       
       /**
        * Call this function to skip the showing of blocking progress note.
		* When done MassUpdateSkipProgressNote( EFalse ) must be called to reset.
        */
      void MassUpdateSkipProgressNote( TBool aSkip );       

    private:
        CPbk2HandleMassUpdate(CEikListBox& iListBox);
        void ConstructL();
        TBool HandleMassUpdateCheckL();
        void HandleMassUpdateBurstL(
            const TTimeIntervalMicroSeconds aFromFirst, 
            const TInt64 aDeltaMax64);        
        void HandleMassUpdateResetCounters();
        void HandleMassUpdateDone();
        static TInt HandleMassUpdateTimerCallBack(TAny* aAny);

    private:
		CEikListBox& iListBox;
        TBool iHandleMassUpdateDetected;
        TTime iHandleMassUpdateFirst;
        TTime iHandleMassUpdatePrev;
        TInt  iHandleMassUpdateCount;
        TBool iHandleMassUpdateSkipDialog;        
        CPeriodic* iHandleMassUpdateTimer;
		CAknWaitDialog*  iHandleMassUpdateDialog;
    };

// --------------------------------------------------------------------------
// CPbk2UiControlEventSender::CPbk2UiControlEventSender
// --------------------------------------------------------------------------
//
CPbk2UiControlEventSender::CPbk2UiControlEventSender
        ( CPbk2NamesListControl& aControl,
          RPointerArray<MPbk2ControlObserver>& aObservers ) :
            iControl( aControl ),
            iObservers( aObservers )
    {
    }

// --------------------------------------------------------------------------
// CPbk2UiControlEventSender::NewL
// --------------------------------------------------------------------------
//
CPbk2UiControlEventSender* CPbk2UiControlEventSender::NewL(
        CPbk2NamesListControl& aControl,
        RPointerArray<MPbk2ControlObserver>& aObservers )
    {
    CPbk2UiControlEventSender* self =
        new ( ELeave ) CPbk2UiControlEventSender( aControl, aObservers );
    return self;
    }

// --------------------------------------------------------------------------
// CPbk2UiControlEventSender::~CPbk2UiControlEventSender
// --------------------------------------------------------------------------
//
CPbk2UiControlEventSender::~CPbk2UiControlEventSender()
    {
    }

// --------------------------------------------------------------------------
// CPbk2UiControlEventSender::SendEventToObserversL
// Sends control observer events in reverse order to disable the possibility
// of crash if aObserver is changed during the loop.
// --------------------------------------------------------------------------
//
TBool CPbk2UiControlEventSender::SendEventToObserversL(
        const TPbk2ControlEvent& aEvent )
    {
    // Loop backwards in case some observer destroys itself in the
    // event handler
    TBool okToSendEvent( SendEvent( aEvent ) );
    for ( TInt i = iObservers.Count() - 1; i >= 0 && okToSendEvent; --i )
        {
        iObservers[i]->HandleControlEventL( iControl, aEvent );
        }

    return okToSendEvent;
    }

// --------------------------------------------------------------------------
// CPbk2UiControlEventSender::Reset
// Resets event sender
// --------------------------------------------------------------------------
//
void CPbk2UiControlEventSender::Reset()
    {
    iReadyEventSend = EFalse;
    }

// --------------------------------------------------------------------------
// CPbk2UiControlEventSender::SendEvent
// Makes sure that ready event is send only ones and reset the status
// if control goes unavailable
// --------------------------------------------------------------------------
//
TBool CPbk2UiControlEventSender::SendEvent
        ( const TPbk2ControlEvent& aEvent )
    {
    TBool ret( ETrue );
    if ( aEvent.iEventType == TPbk2ControlEvent::EUnavailable )
        {
        iReadyEventSend = EFalse;
        }
    else if ( aEvent.iEventType == TPbk2ControlEvent::EReady )
        {
        if ( iReadyEventSend )
            {
            ret = EFalse;
            }
        else
            {
            iReadyEventSend = ETrue;
            }
        }
    return ret;
    }

// --------------------------------------------------------------------------
// CPbk2FilteredViewStackObserver::CPbk2FilteredViewStackObserver
// --------------------------------------------------------------------------
//
CPbk2FilteredViewStackObserver::CPbk2FilteredViewStackObserver(
        CPbk2NamesListControl& aControl,
        TopViewChangedFuncPtr aTopViewChangedFuncPtr,
        TopViewUpdatedFuncPtr aTopViewUpdatedFuncPtr,
        BaseViewChangedFuncPtr aBaseViewChangedFuncPtr,
        ViewStackErrorFuncPtr aViewStackErrorFuncPtr,
        ContactAddedToBaseViewFuncPtr aContactAddedToBaseViewFuncPtr ) :
            iControl( aControl ),
            iTopViewChangedFuncPtr( aTopViewChangedFuncPtr ),
            iTopViewUpdatedFuncPtr( aTopViewUpdatedFuncPtr ),
            iBaseViewChangedFuncPtr( aBaseViewChangedFuncPtr ),
            iViewStackErrorFuncPtr( aViewStackErrorFuncPtr ),
            iContactAddedToBaseViewFuncPtr( aContactAddedToBaseViewFuncPtr )
    {
    }

// --------------------------------------------------------------------------
// CPbk2FilteredViewStackObserver::NewL
// --------------------------------------------------------------------------
//
CPbk2FilteredViewStackObserver* CPbk2FilteredViewStackObserver::NewL(
        CPbk2NamesListControl& aControl,
        TopViewChangedFuncPtr aTopViewChangedFuncPtr,
        TopViewUpdatedFuncPtr aTopViewUpdatedFuncPtr,
        BaseViewChangedFuncPtr aBaseViewChangedFuncPtr,
        ViewStackErrorFuncPtr aViewStackErrorFuncPtr,
        ContactAddedToBaseViewFuncPtr aContactAddedToBaseViewFuncPtr )
    {
    CPbk2FilteredViewStackObserver* self =
        new ( ELeave ) CPbk2FilteredViewStackObserver( aControl,
            aTopViewChangedFuncPtr,
            aTopViewUpdatedFuncPtr,
            aBaseViewChangedFuncPtr,
            aViewStackErrorFuncPtr,
            aContactAddedToBaseViewFuncPtr );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// --------------------------------------------------------------------------
// CPbk2FilteredViewStackObserver::ConstructL
// --------------------------------------------------------------------------
//
void CPbk2FilteredViewStackObserver::ConstructL()
    {
    }

// --------------------------------------------------------------------------
// CPbk2FilteredViewStackObserver::~CPbk2FilteredViewStackObserver
// --------------------------------------------------------------------------
//
CPbk2FilteredViewStackObserver::~CPbk2FilteredViewStackObserver()
    {
    }

// --------------------------------------------------------------------------
// CPbk2FilteredViewStackObserver::TopViewChangedL
// --------------------------------------------------------------------------
//
void CPbk2FilteredViewStackObserver::TopViewChangedL(
        MVPbkContactViewBase& aOldView )
    {
    ( iControl.*iTopViewChangedFuncPtr )( aOldView );
    }

// --------------------------------------------------------------------------
// CPbk2FilteredViewStackObserver::TopViewUpdatedL
// --------------------------------------------------------------------------
//
void CPbk2FilteredViewStackObserver::TopViewUpdatedL()
    {
    ( iControl.*iTopViewUpdatedFuncPtr )();
    }

// --------------------------------------------------------------------------
// CPbk2FilteredViewStackObserver::BaseViewChangedL
// --------------------------------------------------------------------------
//
void CPbk2FilteredViewStackObserver::BaseViewChangedL()
    {
    ( iControl.*iBaseViewChangedFuncPtr )();
    }

// --------------------------------------------------------------------------
// CPbk2FilteredViewStackObserver::ViewStackError
// --------------------------------------------------------------------------
//
void CPbk2FilteredViewStackObserver::ViewStackError( TInt aError )
    {
    ( iControl.*iViewStackErrorFuncPtr )( aError );
    }

// --------------------------------------------------------------------------
// CPbk2FilteredViewStackObserver::ContactAddedToBaseView
// --------------------------------------------------------------------------
//
void CPbk2FilteredViewStackObserver::ContactAddedToBaseView(
        MVPbkContactViewBase& aBaseView, TInt aIndex,
        const MVPbkContactLink& aContactLink )
    {
    ( iControl.*iContactAddedToBaseViewFuncPtr )( aBaseView,
         aIndex, aContactLink );
    }

// --------------------------------------------------------------------------
// CPbk2ListBoxSelectionObserver::CPbk2ListBoxSelectionObserver
// --------------------------------------------------------------------------
//
CPbk2ListBoxSelectionObserver::CPbk2ListBoxSelectionObserver(
        CPbk2NamesListControl& aControl, CEikListBox& aListBox,
        MPbk2UiControlEventSender& aEventSender )
        :   iControl( aControl ),
            iListBox( aListBox ),
            iEventSender( aEventSender )
    {
    }

// --------------------------------------------------------------------------
// CPbk2ListBoxSelectionObserver::ConstructL
// --------------------------------------------------------------------------
//
void CPbk2ListBoxSelectionObserver::ConstructL()
    {
    iListBox.AddSelectionObserverL( this );
    }

// --------------------------------------------------------------------------
// CPbk2ListBoxSelectionObserver::NewL
// --------------------------------------------------------------------------
//
CPbk2ListBoxSelectionObserver* CPbk2ListBoxSelectionObserver::NewL(
        CPbk2NamesListControl& aControl,
        CEikListBox& aListBox,
        MPbk2UiControlEventSender& aEventSender )
    {
    CPbk2ListBoxSelectionObserver* self =
        new( ELeave ) CPbk2ListBoxSelectionObserver( aControl, aListBox,
            aEventSender );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// --------------------------------------------------------------------------
// CPbk2ListBoxSelectionObserver::~CPbk2ListBoxSelectionObserver
// --------------------------------------------------------------------------
//
CPbk2ListBoxSelectionObserver::~CPbk2ListBoxSelectionObserver()
    {
    iListBox.RemoveSelectionObserver( this );
    }

// --------------------------------------------------------------------------
// CPbk2ListBoxSelectionObserver::SelectionModeChanged
// --------------------------------------------------------------------------
//
void CPbk2ListBoxSelectionObserver::SelectionModeChanged(
        CEikListBox* aListBox, TBool aSelectionModeEnabled )
    {
    if ( &iListBox == aListBox )
        {
        TPbk2ControlEvent event(
            TPbk2ControlEvent::EControlEntersSelectionMode );
        if ( !aSelectionModeEnabled )
            {
            event.iEventType =
                TPbk2ControlEvent::EControlLeavesSelectionMode;
            }
        TRAPD( res, iEventSender.SendEventToObserversL( event ) );
        HandleError( res );
        if ( res != KErrNone )
            {
            iControl.Reset();
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2HandleMassUpdate::NewL
// --------------------------------------------------------------------------
//
CPbk2HandleMassUpdate* CPbk2HandleMassUpdate::NewL(CEikListBox& aListBox)
    {
    CPbk2HandleMassUpdate* self =
        new( ELeave ) CPbk2HandleMassUpdate(aListBox);
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// --------------------------------------------------------------------------
// CPbk2HandleMassUpdate::~CPbk2HandleMassUpdate
// --------------------------------------------------------------------------
//
CPbk2HandleMassUpdate::~CPbk2HandleMassUpdate()
    {
    delete iHandleMassUpdateDialog;
    delete iHandleMassUpdateTimer;
    }

// --------------------------------------------------------------------------
// CPbk2HandleMassUpdate::CPbk2HandleMassUpdate
// --------------------------------------------------------------------------
//
CPbk2HandleMassUpdate::CPbk2HandleMassUpdate(CEikListBox& aListBox) :
    iListBox(aListBox)
    {
    }

// --------------------------------------------------------------------------
// CPbk2HandleMassUpdate::ConstructL
// --------------------------------------------------------------------------
//
void CPbk2HandleMassUpdate::ConstructL()
    {
    iHandleMassUpdateTimer = CPeriodic::NewL( CActive::EPriorityIdle );
    }

// --------------------------------------------------------------------------
// CPbk2HandleMassUpdate::HandleMassUpdateCheckThis
//
// Functionality to detect mass updates done to contact database and to prevent
// e.g nameslist flickering when constant updates are happening in background
// when pc sync etc is adding hundreds of contacts in line
// --------------------------------------------------------------------------
//
TBool CPbk2HandleMassUpdate::MassUpdateCheckThis()
    {
    TBool ret(EFalse);
    const TInt KNbrUpdBeforeMassCheck(5);
    iHandleMassUpdateTimer->Cancel();

    if( iHandleMassUpdateCount > KNbrUpdBeforeMassCheck )
        {
        //candidates to be checked are they continual of a mass update
        TRAP_IGNORE(ret = HandleMassUpdateCheckL());
        }
    else if( iHandleMassUpdateCount > 0 )
        {
        //Subsequent updates that are handled normally even if
        // they would be first ones in a mass update burst
        iHandleMassUpdateCount++;
        iHandleMassUpdatePrev.UniversalTime();
        }
    else
        {
        //very first update, reset time & counter
        HandleMassUpdateResetCounters();
        }
    return ret;
    }

// --------------------------------------------------------------------------
// CPbk2HandleMassUpdate::MassUpdateDetected
// --------------------------------------------------------------------------
//
TBool CPbk2HandleMassUpdate::MassUpdateDetected()
    {
	return iHandleMassUpdateDetected;
	}

// --------------------------------------------------------------------------
// CPbk2HandleMassUpdate::MassUpdateSkipProgressNote
// --------------------------------------------------------------------------
//
void CPbk2HandleMassUpdate::MassUpdateSkipProgressNote( TBool aSkip )
    {
    iHandleMassUpdateSkipDialog = aSkip;
    HandleMassUpdateResetCounters();        
    }

// --------------------------------------------------------------------------
// CPbk2HandleMassUpdate::HandleMassUpdateCheckL
// --------------------------------------------------------------------------
//
TBool CPbk2HandleMassUpdate::HandleMassUpdateCheckL()
    {
    //KDeltaAverage time per update to be considered as mass
    //update. One occasional update can take KDeltaMax time as long as
    //average time not exeeded (therefore timeout for the very first updates in
    //practice is also KDeltaAverage).
    const TInt64 KDeltaAverage(2000000);
    const TInt64 KDeltaMax(KDeltaAverage * 2);
    const TTimeIntervalMicroSeconds KMaxPrev(KDeltaMax);
    TBool ret(EFalse);

    TTime now;
    now.UniversalTime();
    TTimeIntervalMicroSeconds fromFirst = 
            now.MicroSecondsFrom(iHandleMassUpdateFirst);
    TTimeIntervalMicroSeconds fromPrev = 
            now.MicroSecondsFrom(iHandleMassUpdatePrev);
    TTimeIntervalMicroSeconds maxCumu(KDeltaAverage * iHandleMassUpdateCount);

    if( fromFirst < maxCumu && fromPrev < KMaxPrev )
        {
        //mass update burst ongoing
        HandleMassUpdateBurstL(fromFirst, KDeltaMax);    
        ret = ETrue;    
        }
    else if(iHandleMassUpdateDetected)
        {
        //mass update burst ended
        HandleMassUpdateDone();
        ret = ETrue;
        }
    else
        {
        //just normal update so reset counters
        HandleMassUpdateResetCounters();
        }
    return ret;
    }

// --------------------------------------------------------------------------
// CPbk2HandleMassUpdate::HandleMassUpdateBurstL
// --------------------------------------------------------------------------
//
void CPbk2HandleMassUpdate::HandleMassUpdateBurstL(
    const TTimeIntervalMicroSeconds aFromFirst,
    const TInt64 aDeltaMax64)
    {
    const TInt64 KMinWaitBeforeBlockUi(1500000);    
    const TTimeIntervalMicroSeconds KWait(KMinWaitBeforeBlockUi);    
    
    //mass update burst ongoing, nameslist behaviour can be altered
    iHandleMassUpdateDetected=ETrue;
    iHandleMassUpdateCount++;
    iHandleMassUpdatePrev.UniversalTime();
    iListBox.UpdateScrollBarsL();

    if( !iHandleMassUpdateDialog && 
        !iHandleMassUpdateSkipDialog && 
        aFromFirst > KWait)        
        {
        //mass update burst ongoing, ok also to block ui
        iHandleMassUpdateDialog = new(ELeave) CAknWaitDialog
            (reinterpret_cast<CEikDialog**>(&iHandleMassUpdateDialog), EFalse);
        iHandleMassUpdateDialog->SetTone(CAknNoteDialog::ENoTone);
        iHandleMassUpdateDialog->ExecuteLD(R_QTN_GEN_NOTE_SYNCHRONIZING_PROGRESS);
        //ExecuteLD above handles validity of pointer iHandleMassUpdateDialog plus
        //cleanupstack
        }
    else if( iHandleMassUpdateDialog && iHandleMassUpdateSkipDialog)
        {
        //burst ongoing but do not not block ui
        TRAP_IGNORE(iHandleMassUpdateDialog->ProcessFinishedL());
        delete iHandleMassUpdateDialog;
        iHandleMassUpdateDialog = NULL;        
        }

    TCallBack callback(HandleMassUpdateTimerCallBack, this);
    TTimeIntervalMicroSeconds32 delta32(aDeltaMax64);
    iHandleMassUpdateTimer->Start( delta32, delta32, callback );
    }

// ----------------------------------------------------------------------------
// CPbk2HandleMassUpdate::HandleMassUpdateResetCounters
// ----------------------------------------------------------------------------
//
void CPbk2HandleMassUpdate::HandleMassUpdateResetCounters()
    {
    iHandleMassUpdateCount = 1;  //set as first candidate for next burst
    iHandleMassUpdateFirst.UniversalTime();
    iHandleMassUpdatePrev=iHandleMassUpdateFirst;
    }

// ----------------------------------------------------------------------------
// CPbk2HandleMassUpdate::HandleMassUpdateTimerCallBack
// ----------------------------------------------------------------------------
//
TInt CPbk2HandleMassUpdate::HandleMassUpdateTimerCallBack(TAny* aAny)
    {
    CPbk2HandleMassUpdate* self = static_cast<CPbk2HandleMassUpdate*>( aAny );
    self->iHandleMassUpdateTimer->Cancel();
    self->HandleMassUpdateDone();
    return KErrNone;
    }

// ----------------------------------------------------------------------------
// CPbk2HandleMassUpdate::HandleMassUpdateDone
// ----------------------------------------------------------------------------
//
void CPbk2HandleMassUpdate::HandleMassUpdateDone()
    {
    if( iHandleMassUpdateDialog )
        {
        TRAP_IGNORE(iHandleMassUpdateDialog->ProcessFinishedL());
        //The below 2 lines just in case... ProcessFinishedL already took care of these
        delete iHandleMassUpdateDialog;
        iHandleMassUpdateDialog = NULL;
        }

    iHandleMassUpdateDetected = EFalse;
    HandleMassUpdateResetCounters();
    iListBox.SetCurrentItemIndex(0);
    iListBox.SetTopItemIndex(0);

    //Update the items of listbox in NameListView
    iListBox.DrawDeferred();
    }

///////////////////////// End of helper classes /////////////////////////////


// --------------------------------------------------------------------------
// CPbk2NamesListControl::CPbk2NamesListControl
// --------------------------------------------------------------------------
//
EXPORT_C CPbk2NamesListControl::CPbk2NamesListControl
            (const CCoeControl* aContainer,
            CVPbkContactManager& aManager,
            MVPbkContactViewBase& aView,
            MPbk2ContactNameFormatter& aNameFormatter,
            CPbk2StorePropertyArray& aStoreProperties) :
                iContactManager( aManager ),
                iBaseView( &aView ),
                iContainer( aContainer ),
                iNameFormatter( aNameFormatter ),
                iStoreProperties( aStoreProperties ),
                iAllowPointerEvents( ETrue ),
                iOpeningCca( EFalse )
    {
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::CPbk2NamesListControl
// --------------------------------------------------------------------------
//
CPbk2NamesListControl::CPbk2NamesListControl
            (const CCoeControl* aContainer,
            CVPbkContactManager& aManager,
            MVPbkContactViewBase& aView,
            MPbk2ContactNameFormatter& aNameFormatter,
            CPbk2StorePropertyArray& aStoreProperties,
            CPbk2ThumbnailManager* aThumbManager) :
                iContactManager( aManager ),
                iBaseView( &aView ),
                iContainer( aContainer ),
                iNameFormatter( aNameFormatter ),
                iStoreProperties( aStoreProperties ),
                iAllowPointerEvents( ETrue ),                
                iThumbManager( aThumbManager ),
                iOpeningCca( EFalse )
    {
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::~CPbk2NamesListControl
// --------------------------------------------------------------------------
//
CPbk2NamesListControl::~CPbk2NamesListControl()
    {
    ClearMarkedContactsInfo();

    if (iBgTask)
        {
        delete iBgTask;
        iBgTask = NULL;
        }

    if ( iViewStack && iStackObserver )
        {
        iViewStack->RemoveStackObserver( *iStackObserver );
        }

    if( iThumbManager )
        {
        TRAP_IGNORE( iThumbManager->SetContactViewL( NULL ) );
        iThumbManager->RemoveObserver();
        }

    if (iCommand)
        {
        // inform the command that the control is deleted
        iCommand->ResetUiControl(*this);
        }
    iObservers.Reset();
    iCommandItems.ResetAndDestroy();
	delete iCheckMassUpdate;
    delete iListBoxSelectionObserver;
    delete iStateFactory;
    delete iListBox;
    delete iFindBox;
    delete iThumbnailLoader;
    delete iEventSender;
    delete iStackObserver;
    delete iUiExtension;
    delete iViewStack;
    delete iSearchFilter;
    if( iOwnThumbManager )
        {
        delete iThumbManager;
        }
    if (iOwnBaseView)
        {
        delete iBaseView;
        }
    if(iFeatureManagerInitilized)
        {
        FeatureManager::UnInitializeLib();
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::NewL
// --------------------------------------------------------------------------
//
EXPORT_C CPbk2NamesListControl* CPbk2NamesListControl::NewL(
            TInt aResourceId,
            const CCoeControl* aContainer,
            CVPbkContactManager& aManager,
            MVPbkContactViewBase& aView,
            MPbk2ContactNameFormatter& aNameFormatter,
            CPbk2StorePropertyArray& aStoreProperties )
    {
    CPbk2NamesListControl* self = new (ELeave) CPbk2NamesListControl(
            aContainer, aManager, aView, aNameFormatter, aStoreProperties );
    CleanupStack::PushL(self);
    self->ConstructL( aResourceId);
    CleanupStack::Pop(self);
    return self;
    }


// --------------------------------------------------------------------------
// CPbk2NamesListControl::NewL
// --------------------------------------------------------------------------
//
EXPORT_C CPbk2NamesListControl* CPbk2NamesListControl::NewL(
               TInt aResourceId,
               const CCoeControl* aContainer,
               CVPbkContactManager& aManager,
               MVPbkContactViewBase& aView,
               MPbk2ContactNameFormatter& aNameFormatter,
               CPbk2StorePropertyArray& aStoreProperties,
               CPbk2ThumbnailManager* aThumbManager )
    {
    CPbk2NamesListControl* self = new (ELeave) CPbk2NamesListControl(
            aContainer, aManager, aView, aNameFormatter, aStoreProperties, aThumbManager );
    CleanupStack::PushL(self);
    self->ConstructL( aResourceId);
    CleanupStack::Pop(self);
    return self;
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ConstructL
//
// Note that NewL (and hence ConstructL) will not be called when custom control  
// constructed. Instead public constructor and ConstructFromResourceL are 
// called (happens when ServerApp launches custom fetch dialog)
// --------------------------------------------------------------------------
//
inline void CPbk2NamesListControl::ConstructL(
    TInt aResourceId)
    {
    if (!iContainer)
        {
        User::Leave(KErrGeneral);
        }

    // First set container
    SetContainerWindowL(*iContainer);

    TResourceReader resReader;
    CCoeEnv::Static()->CreateResourceReaderLC(resReader, aResourceId);
    ConstructFromResourceL(resReader);
    CleanupStack::PopAndDestroy(); // resReader
    FeatureManager::InitializeLibL();
    iFeatureManagerInitilized = ETrue;
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ConstructFromResourceL
// --------------------------------------------------------------------------
//
inline void CPbk2NamesListControl::ConstructFromResourceL
        ( TResourceReader& aReader )
    {
    iSearchFilter = CPbk2PredictiveSearchFilter::NewL();

    if(FeatureManager::FeatureSupported(KFeatureIdFfContactsPredictiveSearch))

        {
        iViewStack = CPbk2PredictiveViewStack::NewL( *iBaseView, *iSearchFilter,
                                iNameFormatter  );
        }
    else
        {
        iViewStack = CPbk2FilteredViewStack::NewL( *iBaseView );
        }

    iViewStack->AddObserverL( *this );

    iStackObserver = CPbk2FilteredViewStackObserver::NewL
        ( *this,
          &CPbk2NamesListControl::HandleTopViewChangedL,
          &CPbk2NamesListControl::HandleTopViewUpdatedL,
          &CPbk2NamesListControl::HandleBaseViewChangedL,
          &CPbk2NamesListControl::HandleViewStackError,
          &CPbk2NamesListControl::HandleContactAddedToBaseView );
    iEventSender = CPbk2UiControlEventSender::NewL( *this, iObservers );
    iViewStack->AddStackObserverL( *iStackObserver );


    CPbk2UIExtensionManager* extManager =
        CPbk2UIExtensionManager::InstanceL();
    extManager->PushL();

    iUiExtension = extManager->FactoryL()->CreatePbk2UiControlExtensionL
        ( iContactManager );

    CleanupStack::PopAndDestroy(); // extManager

    // peek listbox type from resource
    TInt flags = aReader.ReadInt32();
    aReader.Rewind( sizeof( TInt32 ) );

    // Create the listbox and its model
    if( flags & KPbk2ContactViewListControlDoubleRow )
        {
        if( !iThumbManager )
            {
            iThumbManager = CPbk2ThumbnailManager::NewL( iContactManager );
            iOwnThumbManager = ETrue;
            }

        iDoubleListBox = CPbk2ContactViewDoubleListBox::NewL
            ( *this, aReader, iContactManager,
            *iViewStack, iNameFormatter, iStoreProperties,
            iUiExtension, *iSearchFilter, *iThumbManager );

        iThumbManager->SetObserver( *iDoubleListBox );
        iThumbManager->SetContactViewL( iViewStack );

        iListBox = iDoubleListBox;
        }
    else
        {
        iListBox = CPbk2ContactViewListBox::NewL
            ( *this, aReader, iContactManager,
            *iViewStack, iNameFormatter, iStoreProperties,
            iUiExtension, *iSearchFilter );

        if( iThumbManager )
            {
            iThumbManager->RemoveObserver();
            }
        iDoubleListBox = NULL;
        }

    iListBox->SetObserver( this );
    iListBox->SetScrollEventObserver( this );
    iListBox->SetListBoxObserver(this);
    iUiExtension->SetContactUiControlUpdate( this );
    // set command item updater
    TAny* ext = iUiExtension->ContactUiControlExtensionExtension(
        TUid::Uid( KPbk2ContactUiControlExtensionExtensionUID ) );
    if( ext )
        {
        static_cast<MPbk2ContactUiControlDoubleListboxExtension*>(ext)->
            SetCommandItemUpdater( this );
        }

    if ( iListBox->Flags() & KPbk2ContactViewListControlFindBox )
        {
        // Create a find box
        if ( iSearchFilter->IsPredictiveActivated() )
            {
            iFindBox = CAknSearchField::NewL
            (*this, CAknSearchField::ESearch, NULL, KSearchFieldLength);
            }
        else
            {
            iFindBox = CAknSearchField::NewL
                        (*this, CAknSearchField::EAdaptiveSearch, NULL, KSearchFieldLength);
            }

        iSearchFilter->SetAknSearchFieldL( iFindBox );

        iFindBox->MakeVisible( EFalse );
        iFindBox->SetObserver( this );
        iFindBox->AddAdaptiveSearchTextObserverL( this );
        }

    // If list box supports selection then construct an observer that
    // handles the event sending when the selection mode changes.
    if ( iListBox->IsSelectionListBox() )
        {
        iListBoxSelectionObserver = CPbk2ListBoxSelectionObserver::NewL(
            *this, *iListBox, *iEventSender );
        }

    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPbk2NamesListControl::ConstructL find box created"));

    // Instantiate the state factory
    iStateFactory = CPbk2NamesListStateFactory::NewL( *this, *iListBox,
        *iViewStack, iFindBox, *iThumbnailLoader, *iEventSender,
        iNameFormatter, iCommandItems, *iSearchFilter );

    // Create the initial state
    iCurrentState = &iStateFactory->ActivateStartupStateL( iCurrentState );

    iBgTask = new (ELeave) CPbk2NamesListControlBgTask( *this );
    iCheckMassUpdate = CPbk2HandleMassUpdate::NewL(*iListBox); //iListbox created above    
    
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPbk2NamesListControl::ConstructFromResourceL end"));
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::AddObserverL
// --------------------------------------------------------------------------
//
EXPORT_C void CPbk2NamesListControl::AddObserverL
        ( MPbk2ControlObserver& aObserver )
    {
    User::LeaveIfError(iObservers.Append(&aObserver));
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::RemoveObserver
// --------------------------------------------------------------------------
//
EXPORT_C void CPbk2NamesListControl::RemoveObserver
        ( MPbk2ControlObserver& aObserver )
    {
    const TInt index = iObservers.Find(&aObserver);
    if (index >= 0)
        {
        iObservers.Remove(index);
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::Reset
// --------------------------------------------------------------------------
//
EXPORT_C void CPbk2NamesListControl::Reset()
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING("CPbk2NamesListControl::Reset(0x%x) - IN"),
        this );

    // Unmark all contacts and reset the toolbar so that the Call button
    // won't be dimmed
    TRAP_IGNORE( ProcessCommandL( EAknUnmarkAll ) );
    // Reset find box
    TRAP_IGNORE( ResetFindL() );
    // Destroy all the filtered views from the stack
    iViewStack->Reset();
    // Refresh observer to get the view state
    iViewStack->RemoveObserver( *this );
    // Shouldn't leave because the observer was first removed.
    // The control updates its state when the asynchronous Virtual Phonebook
    // view event arrives.
    TRAP_IGNORE( iViewStack->AddObserverL( *this ) );

    const TInt firstContactIndex = 0;
    // Best effort: try to reset the focus.
    TRAP_IGNORE( iCurrentState->SetFocusedContactIndexL( firstContactIndex ) );
    //scroll listbox into beginning (ignore focus that may be below promotion items)
    iListBox->SetTopItemIndex(firstContactIndex);

    // Switch to the background state. This enables the next state to avtivate fully (ActivateStateL()) once phonebook
    // comes from the background.
    TRAP_IGNORE( iCurrentState = &iStateFactory->ActivateHiddenStateL( iCurrentState ); );

    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING("CPbk2NamesListControl::Reset() - OUT"));
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SetViewL
// --------------------------------------------------------------------------
//
EXPORT_C void CPbk2NamesListControl::SetViewL( MVPbkContactViewBase& aView )
    {
    // Control will receive a view event asynchronously from the stack
    iViewStack->SetNewBaseViewL( aView );

    if (iOwnBaseView)
        {
        delete iBaseView;
        iBaseView = NULL;
        }

    iBaseView = &aView;
    iOwnBaseView = EFalse;

    iEventSender->Reset();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::GiveViewL
// --------------------------------------------------------------------------
//
EXPORT_C void CPbk2NamesListControl::GiveViewL( MVPbkContactViewBase* aView )
    {
    SetViewL( *aView );
    iOwnBaseView = ETrue;
    }

EXPORT_C void CPbk2NamesListControl::AllowPointerEvents( TBool aAllow )
    {
    iAllowPointerEvents = aAllow;
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SetCurrentGroupLinkL
// --------------------------------------------------------------------------
//
EXPORT_C void CPbk2NamesListControl::SetCurrentGroupLinkL( MVPbkContactLink* aGroupLinktoSet)
    {
    // This is used only when predictive search is enabled
    if(FeatureManager::FeatureSupported(KFeatureIdFfContactsPredictiveSearch))
        {
        static_cast<CPbk2PredictiveViewStack*> (iViewStack)->SetCurrentGroupLinkL(aGroupLinktoSet);
        }
    return;
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::MassUpdateSkipProgressNote
// --------------------------------------------------------------------------
//
EXPORT_C void CPbk2NamesListControl::MassUpdateSkipProgressNote( TBool aSkip )
    {
    iCheckMassUpdate->MassUpdateSkipProgressNote( aSkip ); 
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::View
// --------------------------------------------------------------------------
//
MVPbkContactViewBase& CPbk2NamesListControl::View()
    {
    return *iViewStack;
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::MakeVisible
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::MakeVisible(TBool aVisible)
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING(
        "CPbk2NamesListControl::MakeVisible(0x%x,%d)"),
        this, aVisible);

    CCoeControl::MakeVisible(aVisible);
    iCurrentState->MakeComponentsVisible(aVisible);
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ActivateL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::ActivateL()
    {
    // First, call base class implementation
    CCoeControl::ActivateL();
    // Then do own initialization
    iCurrentState->ActivateL();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::OfferKeyEventL
// --------------------------------------------------------------------------
//
TKeyResponse CPbk2NamesListControl::OfferKeyEventL
        ( const TKeyEvent& aKeyEvent, TEventCode aType )
    {
    if(FeatureManager::FeatureSupported(KFeatureIdFfContactsPredictiveSearch))
        {
        if( iCurrentState->NamesListState() == EStateReady ||
            iCurrentState->NamesListState() == EStateFiltered )
            {
            iSearchFilter->FilterL( aKeyEvent, aType, iFindBox );
            }
        }

    TKeyResponse result = iSearchFilter->OfferKeyEventL( aKeyEvent, aType );

    if ( result == EKeyWasNotConsumed )
        {
        result = iCurrentState->OfferKeyEventL( aKeyEvent, aType );
        }

    // Ignore Send Key up and down events to prevent Dialer appearance
    // on top of Phonebook application.
    if ( result == EKeyWasNotConsumed && iListBox->NumberOfItems() != 0 )
        {
        if ( ( aType == EEventKeyDown || aType == EEventKeyUp )
            && aKeyEvent.iScanCode == EStdKeyYes )
            {
            result = EKeyWasConsumed;
            }
        }

    return result;
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::CountComponentControls
// --------------------------------------------------------------------------
//
TInt CPbk2NamesListControl::CountComponentControls() const
    {
    return iCurrentState->CountComponentControls();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ComponentControl
// --------------------------------------------------------------------------
//
CCoeControl* CPbk2NamesListControl::ComponentControl(TInt aIndex) const
    {
    // This is not forwarded to the states because these controls are
    // always existing. It does not matter what is the state.
    switch (aIndex)
        {
        case 0:
            {
            return iListBox;
            }
        case 1:
            {
            return iFindBox;
            }
        default:
            {
            // Illegal state
            __ASSERT_DEBUG( EFalse, Panic( EPanicLogic_ComponentControl ) );
            return NULL;
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::FocusChanged
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::FocusChanged( TDrawNow aDrawNow )
    {
    if ( iListBox )
        {
        iListBox->SetFocus( IsFocused(), aDrawNow );
        }

    if ( iFindBox && iFindBox->IsVisible() )
        {
        iFindBox->SetFocus( IsFocused(), aDrawNow );
        if ( aDrawNow == EDrawNow && IsFocused() )
            {
            iFindBox->DrawDeferred();
            }
        }

    if (iCurrentState && IsNonFocusing())
        {
        iCurrentState->CoeControl().SetFocus(IsFocused(), aDrawNow);
        }
    if ( IsFocused() )
        {
        ShowThumbnail();
        }
    else
        {
        HideThumbnail();
        }
    TRAP_IGNORE(ReportEventL( MCoeControlObserver::EEventStateChanged ));
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SizeChanged
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::SizeChanged()
    {
    iCurrentState->SizeChanged();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::Draw
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::Draw(const TRect& aRect) const
    {
    CWindowGc& gc = SystemGc();
    iCurrentState->Draw(aRect, gc);
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::HandleResourceChange
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::HandleResourceChange(TInt aType)
    {
    CCoeControl::HandleResourceChange(aType);
    if ( iFindBox != NULL && aType == KAknMessageFocusLost )
        {
        iFindBox->DrawDeferred();
        }

/*  This is useless...no need to show or hide thumbnail on layout/skin change...thumbnail will handle it's own resouce change event
    if ( aType == KEikDynamicLayoutVariantSwitch ||
         aType == KAknsMessageSkinChange )
        {
        if ( IsFocused() )
            {
            RDebug::Print( _L("### NamesList::HandleResourceChangeL - show") );
            ShowThumbnail();
            }
        else
            {
            RDebug::Print( _L("### NamesList::HandleResourceChangeL - hide") );
            HideThumbnail();
            }
        }*/
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::HandlePointerEventL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::HandlePointerEventL(
    const TPointerEvent& aPointerEvent )
    {
    if( !iAllowPointerEvents )
        {
		//Passing event to listbox needed even if iCurrentState would be skipped (fix for ou1cimx1#316139)
        iListBox->HandlePointerEventL( aPointerEvent ); 
        return;
        }
    if ( AknLayoutUtils::PenEnabled() )
        {
        iCurrentState->HandlePointerEventL( aPointerEvent );
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ParentControl
// --------------------------------------------------------------------------
//
MPbk2ContactUiControl* CPbk2NamesListControl::ParentControl() const
    {
    // Name list controls has no parent
    return NULL;
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::NumberOfContacts
// --------------------------------------------------------------------------
//
TInt CPbk2NamesListControl::NumberOfContacts() const
    {
    TInt ret( iCurrentState->NumberOfContacts() );
    return ret;
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::FocusedContactL
// --------------------------------------------------------------------------
//
const MVPbkBaseContact* CPbk2NamesListControl::FocusedContactL() const
    {
    return iCurrentState->FocusedContactL();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::FocusedViewContactL
// --------------------------------------------------------------------------
//
const MVPbkViewContact* CPbk2NamesListControl::FocusedViewContactL() const
    {
    return iCurrentState->FocusedViewContactL();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::FocusedStoreContact
// --------------------------------------------------------------------------
//
const MVPbkStoreContact* CPbk2NamesListControl::FocusedStoreContact() const
    {
    return iCurrentState->FocusedStoreContact();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SetFocusedContactL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::SetFocusedContactL
        ( const MVPbkBaseContact& aContact )
    {
    iCurrentState->SetFocusedContactL(aContact);
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SetFocusedContactL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::SetFocusedContactL(
        const MVPbkContactBookmark& aContactBookmark )
    {
    iCurrentState->SetFocusedContactL( aContactBookmark );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SetFocusedContactL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::SetFocusedContactL(
        const MVPbkContactLink& aContactLink )
    {
    iCurrentState->SetFocusedContactL( aContactLink );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::FocusedContactIndex
// --------------------------------------------------------------------------
//
TInt CPbk2NamesListControl::FocusedContactIndex() const
    {
    return iCurrentState->FocusedContactIndex();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SetFocusedContactIndexL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::SetFocusedContactIndexL( TInt aIndex )
    {
    iCurrentState->SetFocusedContactIndexL( aIndex );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::NumberOfContactFields
// --------------------------------------------------------------------------
//
TInt CPbk2NamesListControl::NumberOfContactFields() const
    {
    return iCurrentState->NumberOfContactFields();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::FocusedField
// --------------------------------------------------------------------------
//
const MVPbkBaseContactField* CPbk2NamesListControl::FocusedField() const
    {
    return iCurrentState->FocusedField();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::FocusedFieldIndex
// --------------------------------------------------------------------------
//
TInt CPbk2NamesListControl::FocusedFieldIndex() const
    {
    return iCurrentState->FocusedFieldIndex();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SetFocusedFieldIndex
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::SetFocusedFieldIndex( TInt /*aIndex*/ )
    {
    // Do nothing
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ContactsMarked
// --------------------------------------------------------------------------
//
TBool CPbk2NamesListControl::ContactsMarked() const
    {
    return iCurrentState->ContactsMarked();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SelectedContactsL
// --------------------------------------------------------------------------
//
MVPbkContactLinkArray*
        CPbk2NamesListControl::SelectedContactsL() const
    {
    return iCurrentState->SelectedContactsL();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SelectedContactsOrFocusedContactL
// --------------------------------------------------------------------------
//
MVPbkContactLinkArray*
        CPbk2NamesListControl::SelectedContactsOrFocusedContactL() const
    {
    return iCurrentState->SelectedContactsOrFocusedContactL();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SelectedContactsIteratorL
// --------------------------------------------------------------------------
//
MPbk2ContactLinkIterator*
        CPbk2NamesListControl::SelectedContactsIteratorL() const
    {
    return iCurrentState->SelectedContactsIteratorL();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SelectedContactStoresL
// --------------------------------------------------------------------------
//
CArrayPtr<MVPbkContactStore>*
        CPbk2NamesListControl::SelectedContactStoresL() const
    {
    // This is not a contact store control
    return NULL;
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ClearMarks
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::ClearMarks()
    {
    iCurrentState->ClearMarks();
	ClearMarkedContactsInfo();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SetSelectedContactL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::SetSelectedContactL
        ( TInt aIndex, TBool aSelected )
    {
    iCurrentState->SetSelectedContactL( aIndex, aSelected );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SetSelectedContactL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::SetSelectedContactL(
        const MVPbkContactBookmark& aContactBookmark,
        TBool aSelected )
    {
    iCurrentState->SetSelectedContactL( aContactBookmark, aSelected );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SetSelectedContactL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::SetSelectedContactL(
        const MVPbkContactLink& aContactLink,
        TBool aSelected )
    {
    iCurrentState->SetSelectedContactL( aContactLink, aSelected );
    }
TInt CPbk2NamesListControl::CommandItemCount() const
    {
    MPbk2ContactUiControl2* tempCurrentState =
        reinterpret_cast<MPbk2ContactUiControl2*>
            (iCurrentState->ContactUiControlExtension
                (KMPbk2ContactUiControlExtension2Uid ));
    return tempCurrentState->CommandItemCount();
    }

const MPbk2UiControlCmdItem&
CPbk2NamesListControl::CommandItemAt( TInt aIndex ) const
    {
    MPbk2ContactUiControl2* tempCurrentState =
        reinterpret_cast<MPbk2ContactUiControl2*>
            (iCurrentState->ContactUiControlExtension
                (KMPbk2ContactUiControlExtension2Uid ));
    return tempCurrentState->CommandItemAt( aIndex );
    }

const MPbk2UiControlCmdItem* CPbk2NamesListControl::FocusedCommandItem() const
    {
    MPbk2ContactUiControl2* tempCurrentState =
        reinterpret_cast<MPbk2ContactUiControl2*>
            (iCurrentState->ContactUiControlExtension
                (KMPbk2ContactUiControlExtension2Uid ));
    return tempCurrentState->FocusedCommandItem();
    }

void CPbk2NamesListControl::DeleteCommandItemL( TInt aIndex )
    {
    iCommandItems.Remove(aIndex);
    iCurrentState->HandleCommandEventL(MPbk2NamesListState::EItemRemoved, aIndex);
    }

void CPbk2NamesListControl::AddCommandItemL(MPbk2UiControlCmdItem* aCommand, TInt aIndex)
    {
    // Fix ETKI-7NADZC
    DeleteIfAlreadyAdded(aCommand);

    // add aCommand to iCommandItems
    if (aIndex > iCommandItems.Count())
        {
        aIndex = iCommandItems.Count();
        }
    iCommandItems.Insert(aCommand, aIndex);
    iCurrentState->HandleCommandEventL(MPbk2NamesListState::EItemAdded, aIndex);
    }

void CPbk2NamesListControl::DeleteIfAlreadyAdded(const MPbk2UiControlCmdItem* aCommand)
    {
    for ( TInt n = 0; n < iCommandItems.Count(); ++n)
        {
        MPbk2UiControlCmdItem* cmd = iCommandItems[n];
        if(cmd->CommandId() == aCommand->CommandId())
            {
            iCommandItems.Remove(n);
            delete cmd;
            break;
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::DynInitMenuPaneL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::DynInitMenuPaneL(
        TInt aResourceId, CEikMenuPane* aMenuPane) const
    {
    iCurrentState->DynInitMenuPaneL(aResourceId, aMenuPane);
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ProcessCommandL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::ProcessCommandL( TInt aCommandId ) const
    {
    iCurrentState->ProcessCommandL(aCommandId);
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::UpdateAfterCommandExecution
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::UpdateAfterCommandExecution()
    {
    if( iCommand )
        {
        /// Reset command pointer, command has completed
        iCommand->ResetUiControl(*this);
        iCommand = NULL;
        }
    TRAP_IGNORE( ProcessCommandL( EAknUnmarkAll); );
    if( iSearchFilter )
        {
        TRAP_IGNORE( iSearchFilter->ReDrawL(ETrue); );
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::GetMenuFilteringFlagsL
// --------------------------------------------------------------------------
//
TInt CPbk2NamesListControl::GetMenuFilteringFlagsL() const
    {
    return iCurrentState->GetMenuFilteringFlagsL();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ControlStateL
// --------------------------------------------------------------------------
//
CPbk2ViewState* CPbk2NamesListControl::ControlStateL() const
    {
    CPbk2ViewState* state = CPbk2ViewState::NewLC();
    const MVPbkBaseContact* focusedContact = FocusedContactL();
    if (focusedContact)
        {
        MVPbkContactLink* link = focusedContact->CreateLinkLC();
        if (link)
            {
            CleanupStack::Pop(); // link
            state->SetFocusedContact(link);
            }
        }

    const MVPbkViewContact* topContact = iCurrentState->TopContactL();
    if ( topContact )
        {
        MVPbkContactLink* link = topContact->CreateLinkLC();
        if (link)
            {
            CleanupStack::Pop(); // link
            state->SetTopContact( link );
            }
        }

    if (ContactsMarked())
        {
        state->SetMarkedContacts(SelectedContactsL());
        }
    CleanupStack::Pop(); // state
    return state;
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::RestoreControlStateL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::RestoreControlStateL(CPbk2ViewState* aState)
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPbk2NamesListControl::RestoreControlStateL(0x%x,0x%x)"),
        this, aState);

    if (aState)
        {
        iCurrentState->RestoreControlStateL(aState);
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::FindTextL
// --------------------------------------------------------------------------
//
const TDesC& CPbk2NamesListControl::FindTextL()
    {
    return iCurrentState->FindTextL();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ResetFindL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::ResetFindL()
    {
    iCurrentState->ResetFindL();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ShowThumbnail
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::ShowThumbnail()
    {
    iCurrentState->ShowThumbnail();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::HideThumbnail
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::HideThumbnail()
    {
    iCurrentState->HideThumbnail();
    }


// --------------------------------------------------------------------------
// CPbk2NamesListControl::SetBlank
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::SetBlank(TBool aBlank)
    {
    MakeVisible( !aBlank );

    // The focus status of CAknSearchField* iFindBox is expected to be
    // consistent with CPbk2NamesListControl when setting blank.

    if ( iFindBox )
        {
        if ( iFindBox->IsVisible() )
            {
            iFindBox->SetFocus( IsFocused() );
            }
        }

    iCurrentState->SetBlank( aBlank );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::RegisterCommand
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::RegisterCommand(
        MPbk2Command* aCommand)
    {
    iCommand = aCommand;
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SetTextL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::SetTextL( const TDesC& aText )
    {
    iCurrentState->SetTextL( aText );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ContactUiControlExtension
// --------------------------------------------------------------------------
//
TAny* CPbk2NamesListControl::ContactUiControlExtension(TUid aExtensionUid )
    {
     if( aExtensionUid == KMPbk2ContactUiControlExtension2Uid )
        {
        return static_cast<MPbk2ContactUiControl2*>( this );
        }

    return NULL;

    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ContactViewReady
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::ContactViewReady
        ( MVPbkContactViewBase& aView )
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPbk2NamesListControl::ContactViewReady(0x%x)"), this );
    TRAPD( error, DoHandleContactViewReadyL( aView ) );
    HandleError( error );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ContactViewUnavailable
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::ContactViewUnavailable
        ( MVPbkContactViewBase& aView )
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPbk2NamesListControl::ContactViewUnavailable(0x%x)"), this);

    if ( &aView == iViewStack )
        {
        TRAPD( err, iCurrentState =
            &iStateFactory->ActivateNotReadyStateL( iCurrentState ) );
        HandleError( err );
        RelayoutControls();
        TRAP( err, iEventSender->SendEventToObserversL(
                TPbk2ControlEvent::EUnavailable ) );
        HandleError( err );
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ContactAddedToView
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::ContactAddedToView(
        MVPbkContactViewBase& aView,
        TInt aIndex,
        const MVPbkContactLink& /*aContactLink*/)
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPbk2NamesListControl::ContactAddedToView()"));

    if (&aView == iViewStack)
        {
        if( !iCheckMassUpdate->MassUpdateDetected() )
            {
            TRAPD(err, DoHandleContactAdditionL(aIndex));
            HandleError(err);
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ContactRemovedFromView
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::ContactRemovedFromView(
        MVPbkContactViewBase& aView,
        TInt aIndex,
        const MVPbkContactLink& /*aContactLink*/ )
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPbk2NamesListControl::ContactRemovedFromView()"));

    if (&aView == iViewStack)
        {
        TRAPD(err, DoHandleContactRemovalL(aIndex));
        HandleError(err);
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ContactViewError
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::ContactViewError(
        MVPbkContactViewBase& /*aView*/,
        TInt aError,
        TBool /*aErrorNotified*/)
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPbk2NamesListControl::ContactViewError(%d)"), aError);

    // Error comes from the active view or from find view stack.
    // Actions are same in both cases. Show error note by forwarding
    // the error to CCoeEnv and try to reset control. Do reset asychronously
    // because the ContactViewError can be coming from view that is
    // destroyed when the control is reset.
    HandleError(aError);
    Reset();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::ContactViewObserverExtension
// --------------------------------------------------------------------------
//
TAny* CPbk2NamesListControl::ContactViewObserverExtension( TUid aExtensionUid )
    {
    if( aExtensionUid == KVPbkContactViewObserverExtension2Uid )
        {
        return static_cast<MVPbkContactViewObserverExtension*>( this );
        }
    return NULL;
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::FilteredContactRemovedFromView
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::FilteredContactRemovedFromView(
		MVPbkContactViewBase& /*aView*/ )
    {    
    DrawDeferred();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::FocusedItemPointed
// --------------------------------------------------------------------------
//
TBool CPbk2NamesListControl::FocusedItemPointed()
    {
    return iCurrentState->FocusedItemPointed();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::FocusableItemPointed
// --------------------------------------------------------------------------
//
TBool CPbk2NamesListControl::FocusableItemPointed()
    {
    return iCurrentState->FocusableItemPointed();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SearchFieldPointed
// --------------------------------------------------------------------------
//
TBool CPbk2NamesListControl::SearchFieldPointed()
    {
    return iCurrentState->SearchFieldPointed();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::HandleControlEventL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::HandleControlEventL
        ( CCoeControl* aControl, TCoeEvent aEventType )
    {
    iCurrentState->HandleControlEventL( aControl, aEventType, 0 );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::UpdateContact
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::UpdateContact
        ( const MVPbkContactLink& aContactLink )
    {
    TInt listBoxRow = KErrNotFound;

    TRAPD( err, listBoxRow = iViewStack->IndexOfLinkL( aContactLink ) );
    if ( err )
        {
        iEikonEnv->NotifyIdleErrorWhileRedrawing( err );
        }

    MPbk2ContactUiControl2* tempCurrentState =
        reinterpret_cast<MPbk2ContactUiControl2*>
            (iCurrentState->ContactUiControlExtension
                (KMPbk2ContactUiControlExtension2Uid ));

      if(tempCurrentState)
          {
        listBoxRow += tempCurrentState->CommandItemCount();
        }
    if ( listBoxRow >= 0 )
        {
        // If visible
        if ( listBoxRow >= iListBox->TopItemIndex() &&
             listBoxRow <= iListBox->BottomItemIndex() )
            {
            iListBox->RedrawItem( listBoxRow );
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::UpdateCommandItem
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::UpdateCommandItem( TInt aCommandId )
    {
    const TInt count = CommandItemCount();
    const TInt top = iListBox->TopItemIndex();
    const TInt bottom = iListBox->BottomItemIndex();

    for( TInt i = 0; i < count; ++i )
        {
        if( Rng( top, i, bottom ) ) // is in visible range
            {
            if( CommandItemAt( i ).CommandId() == aCommandId )
                {
                iListBox->RedrawItem( i );
                break; // only one command with same id
                }
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::Redraw
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::Redraw()
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING(
        "CPbk2NamesListControl(0x%x)::Redraw"), this );

    // Do not use DrawNow because:
    // 1) DrawNow will draw the control everytime it's called. This can
    //    cause flickering in list box focus e.g. when the application view
    //    is restoring the control state.
    // 2) Avoid unnecessary drawing because DrawDeferred can be called many
    //    times in short interval but it will draw the control only once.
    DrawDeferred();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::DoHandleContactViewReadyL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::DoHandleContactViewReadyL
        ( MVPbkContactViewBase& /*aView*/ )
    {
    // Change state
    SelectAndChangeReadyStateL();

    //When contact view is ready, state is activated. If there are multiple stores
    //state doesn't get event when other stores are ready. EContactViewUpdated event is
    //sent when contact view is ready, so after state activation, state can get multiple
    //contact view updated events.
    iCurrentState->HandleContactViewEventL( MPbk2NamesListState::EContactViewUpdated, 0 );

    // Check that there is still focus in list
    // Focus may be lost if for example store goes unavailable
    iListBox->CheckFocusIndex();
    // Control is ready and visible, inform observers
    TBool eventSent = iEventSender->SendEventToObserversL(
        TPbk2ControlEvent::EReady );
    // If Ready-event has been already sent, send
    // ContactSetChanged-event instead.
    if ( !eventSent )
        {
        iEventSender->SendEventToObserversL( TPbk2ControlEvent::
            EContactSetChanged );
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::DoHandleContactAdditionL
//
// NOTE: See also CPbk2FilteredViewStackObserver::ContactAddedToBaseView and
//       CPbk2NamesListControl::DoContactAddedToBaseView
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::DoHandleContactAdditionL( TInt aIndex )
    {
	//Prevent messing with focus with always-on when Phonebook hidden in
	//reseted state. Otherwise background-added contacts will change focus.
	//This would cause Phonebook not to look like freshly started when opened again.
	//And also make sure foreground-added contact will show the new contact
	//even though the focus is not seen.
    if( (static_cast<CPbk2AppUi*>(
            CEikonEnv::Static()->AppUi()))->IsForeground() )
        {
        SelectAndChangeReadyStateL();
        }

    if( !iCheckMassUpdate->MassUpdateDetected() )
        {
        iCurrentState->HandleContactViewEventL
            ( MPbk2NamesListState::EItemAdded, aIndex );
        }

    // At least names list view needs control event about contact addition,
    // so it knows to update CBAs
    iEventSender->SendEventToObserversL( TPbk2ControlEvent::EItemAdded );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::DoHandleContactRemovalL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::DoHandleContactRemovalL( TInt aIndex )
    {
    iCurrentState->HandleContactViewEventL
        ( MPbk2NamesListState::EItemRemoved, aIndex );
    SelectAndChangeReadyStateL();
    iEventSender->SendEventToObserversL( TPbk2ControlEvent::EItemRemoved );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::SelectAndChangeReadyStateL
// Changes between ready states (ready, empty, filtered).
// Can't handle a change to unavailable state
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::SelectAndChangeReadyStateL()
    {
    if ( iViewStack->ContactCountL() == 0 )
        {
        if ( iViewStack->Level() > 0 )
            {
            // If view was filtered beyond matches, activate filtered state
            iCurrentState = &iStateFactory->ActivateFilteredStateL
                ( iCurrentState );
            }
        else
            {
            // Empty state used only if there are no contacts
            // in the base view
            iCurrentState = &iStateFactory->ActivateEmptyStateL
                ( iCurrentState );
            }
        }
    else
        {
        iCurrentState =
            &iStateFactory->ActivateReadyStateL( iCurrentState );
        }

    // Controls have to be relayouted always. Relayouting only when
    // state was changed is not enough, it results to drawing problems.
    // Calling only Redraw() is not enough also.
    RelayoutControls();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::RelayoutControls
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::RelayoutControls()
    {
    SizeChanged();
    MakeVisible( IsVisible() );
    Redraw();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::HandleTopViewChangedL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::HandleTopViewChangedL
        ( MVPbkContactViewBase& aOldView )
    {
    SelectAndChangeReadyStateL();

    iCurrentState->TopViewChangedL( aOldView );

    // Inform observers
    iEventSender->SendEventToObserversL(
            TPbk2ControlEvent::EContactSetChanged );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::HandleTopViewUpdatedL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::HandleTopViewUpdatedL()
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPbk2NamesListControl::HandleTopViewUpdatedL(0x%x)"), this );

    SelectAndChangeReadyStateL();

    iCurrentState->TopViewUpdatedL();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::HandleBaseViewChangedL
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::HandleBaseViewChangedL()
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPbk2NamesListControl::HandleBaseViewChangedL(0x%x)"), this );

    SelectAndChangeReadyStateL();

    iCurrentState->BaseViewChangedL();

    iEventSender->SendEventToObserversL(
            TPbk2ControlEvent::EContactSetChanged );
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::HandleViewStackError
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::HandleViewStackError( TInt aError )
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPbk2NamesListControl::HandleBaseViewChangedL(0x%x, %d)"),
            this, aError );

    HandleError( aError );
    Reset();
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::HandleContactAddedToBaseView
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::HandleContactAddedToBaseView
        ( MVPbkContactViewBase& /*aBaseView*/,
          TInt /*aIndex*/, const MVPbkContactLink& /*aContactLink*/ )
    {
    // The find box must be reset when new items are added to
    // the list box. When find text is reset, the possible filter
    // result (subset of contacts) of the previous find criteria must be
    // reset too. So, we reset both the find box and the view stack.
    TRAPD( res,
        {
        // This will reset back to base view, however retain original view
		//when opening CCA
        if( !iOpeningCca ) 
            {
            iCurrentState->ResetFindL(); 
            }
        });
    HandleError( res );

    if( !iCheckMassUpdate->MassUpdateCheckThis() )
        {
        // If it is the first time to goto a contat's cca card, then in cca we 
        // will set a defualt number to that contact by CmsSetVoiceCallDefault.
        // Then db item changed event is notified to ui layer and names list control 
        // updated accordingly. But to end user that is not allowed, so use this 
        // flag to avoid this reset of ui control.
        if( iOpeningCca )
            {
            if( iCurrentState->NamesListState() == EStateEmpty )
                {
                SelectAndChangeReadyStateL();
                }
            }
        else
            {              
            Reset();
            }	
        }

    // Do not handle contact addition here (DoHandleContactAdditionL),
    // ContactAddedToView to notification is sent separately
    }

// --------------------------------------------------------------------------
//
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::HandleScrollEventL(CEikScrollBar* aScrollBar, TEikScrollEvent aEventType)
    {
//    iDidMove= EFalse ;

    switch( aEventType )
        {
        // drag events -> hide thumbnail
        // AL: this isn't very efficient way of doing this...
        // ...thumbnail loader interface should be extended to
        // enable thumbnail window to be hidden/shown without
        // destroying and reloading the bitmaps...
        case EEikScrollThumbDragHoriz:
        case EEikScrollThumbDragVert:
            {
            iDidMove = ETrue;
            HideThumbnail();
            break;
            }

        // release events
        case EEikScrollThumbReleaseHoriz:
        case EEikScrollThumbReleaseVert:
            {
            // AL: this isn't very efficient way of doing this...
            // ...thumbnail loader interface should be extended to
            // enable thumbnail window to be hidden/shown without
            // destroying and reloading the bitmaps...
            if( iDidMove )
                {
                iDidMove = EFalse;
                ShowThumbnail();
                }
            break;
            }

        default:
            {
            iDidMove= EFalse ;

            if( iThumbnailLoader )
                {
                iThumbnailLoader->Refresh();
                }


            }
        }

    // To avoid slow redraw of the scrollbar, make sure it gets drawn. Fixes MJAA-7ZGHRH.
    aScrollBar->DrawNow();
    }
// --------------------------------------------------------------------------
// CPbk2NamesListControl::HandleListBoxEventL
// Deal with the Panning/Flick event from listbox
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::HandleListBoxEventL( CEikListBox* /*aListBox*/, TListBoxEvent aEventType )
    {
    switch( aEventType )
        {
        case EEventPanningStarted:
        case EEventFlickStarted:
            {
            // Hide Thumbnial as the listbox is
            // Panning/Flicking
            HideThumbnail();
            break;
            }

        case EEventPanningStopped:
        case EEventFlickStopped:
            {
            // Show Thumbnial after the listbox
            // Panned/Flicked
            ShowThumbnail();
            break;
            }
        case EEventItemSingleClicked:
        case EEventItemDoubleClicked:
            {
            iEventSender->SendEventToObserversL(
                TPbk2ControlEvent::EContactDoubleTapped );
            break;
            }

        default:
            break;
        }
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::AdaptiveSearchTextChanged
//
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::AdaptiveSearchTextChanged( CAknSearchField* aSearchField )
    {
    //send event to current state
    //ETrue means that the event came from adaptvie search grid.
    TRAP_IGNORE(iCurrentState->HandleControlEventL( aSearchField, MCoeControlObserver::EEventStateChanged, ETrue));
    }

// --------------------------------------------------------------------------
// CPbk2NamesListControl::HandleForegroundEventL
//
// --------------------------------------------------------------------------
//
void CPbk2NamesListControl::HandleForegroundEventL(TBool aForeground)
    {
    if ( iSearchFilter )
        {
        iSearchFilter->HandleForegroundEventL( aForeground );
        }
    }

// ---------------------------------------------------------------------------
// CPbk2NamesListControl::StoreMarkedContactsAndResetViewL
// ---------------------------------------------------------------------------
//
void CPbk2NamesListControl::StoreMarkedContactsAndResetViewL()
    {
    delete iSelectedLinkArray;
    iSelectedLinkArray = NULL;

    iSelectedLinkArray = iCurrentState->SelectedContactsL();
    }


// ---------------------------------------------------------------------------
// CPbk2NamesListControl::RestoreMarkedContactsL
// ---------------------------------------------------------------------------
//
void CPbk2NamesListControl::RestoreMarkedContactsL()
    {
    //Set the Marked Contacts
    if ( iSelectedLinkArray )
        {
        for ( TInt index = 0; index<iSelectedLinkArray->Count(); index++ )
            {
            iCurrentState->SetSelectedContactL( iSelectedLinkArray->At(index), ETrue );
            }
        }

    delete iSelectedLinkArray;
    iSelectedLinkArray = NULL;
    }

// ---------------------------------------------------------------------------
// CPbk2NamesListControl::ClearMarkedContactsInfo
// ---------------------------------------------------------------------------
//
void CPbk2NamesListControl::ClearMarkedContactsInfo()
    {
    if ( iBgTask )
        {
        iBgTask->ClearAllEvents();
        }
    delete iSelectedLinkArray;
    iSelectedLinkArray = NULL;
    }

// ---------------------------------------------------------------------------
// CPbk2NamesListControl::HandleViewForegroundEventL
// ---------------------------------------------------------------------------
//
EXPORT_C void CPbk2NamesListControl::HandleViewForegroundEventL( TBool aForeground )
    {
    if ( aForeground )
        {
        if ( iBgTask )
            {
            iBgTask->AddEvent( CPbk2NamesListControl::EStateRestoreMarkedContacts );
            }
        }
    else
        {
        if ( iBgTask )
            {
            iBgTask->AddEvent( CPbk2NamesListControl::EStateSaveMarkedContacts );
            }
        }
    }

// ---------------------------------------------------------------------------
// CPbk2NamesListControl::SetOpeningCca
// ---------------------------------------------------------------------------
//
EXPORT_C void CPbk2NamesListControl::SetOpeningCca( TBool aIsOpening )
	{
	iOpeningCca = aIsOpening;
	}

// ---------------------------------------------------------------------------
// CPbk2NamesListControlBgTask::CPbk2NamesListControlBgTask
// ---------------------------------------------------------------------------
//
CPbk2NamesListControlBgTask::CPbk2NamesListControlBgTask( CPbk2NamesListControl& aControl ) :
    CActive(CActive::EPriorityStandard),
    iControl( aControl )
    {
    CActiveScheduler::Add(this);
    iEventQueue.Append(CPbk2NamesListControl::EStateBgTaskEmpty);
    }

// ---------------------------------------------------------------------------
// CPbk2NamesListControlBgTask::~CPbk2NamesListControlBgTask
// ---------------------------------------------------------------------------
//
CPbk2NamesListControlBgTask::~CPbk2NamesListControlBgTask()
    {
    Cancel();
    iEventQueue.Reset();
    }


// ---------------------------------------------------------------------------
// CPbk2NamesListControlBgTask::DoCancel
// ---------------------------------------------------------------------------
//
void CPbk2NamesListControlBgTask::DoCancel()
    {
    }

// ---------------------------------------------------------------------------
// CPbk2NamesListControlBgTask::RunL
// ---------------------------------------------------------------------------
//
void CPbk2NamesListControlBgTask::RunL()
    {

    if ( iEventQueue.Count() )
        {
        switch ( iEventQueue[0] )
            {
            case CPbk2NamesListControl::EStateSaveMarkedContacts:
                iControl.StoreMarkedContactsAndResetViewL();
                iEventQueue.Remove( 0 );
                break;

            case CPbk2NamesListControl::EStateRestoreMarkedContacts:
                iControl.RestoreMarkedContactsL();
                iEventQueue.Remove( 0 );
                break;

            case CPbk2NamesListControl::EStateBgTaskEmpty :
            default:
                iControl.ClearMarkedContactsInfo();
                break;
            }
        }
    }

// ---------------------------------------------------------------------------
// CPbk2NamesListControlBgTask::RunError
// ---------------------------------------------------------------------------
//
TInt CPbk2NamesListControlBgTask::RunError(TInt /*aError*/)
    {
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CPbk2NamesListControlBgTask::AddEvent
// ---------------------------------------------------------------------------
//
void CPbk2NamesListControlBgTask::AddEvent( CPbk2NamesListControl::TPbk2NamesListBgEvents aEvent )
    {
    iEventQueue.Insert( aEvent, iEventQueue.Count() - 1 );
    if ( !IsActive() )
        {
        TRequestStatus* status = &iStatus;
        User::RequestComplete(status, KErrNone);
        SetActive();
        }
    }


// ---------------------------------------------------------------------------
// CPbk2NamesListControlBgTask::RemoveEvent
// ---------------------------------------------------------------------------
//
void CPbk2NamesListControlBgTask::RemoveEvent( CPbk2NamesListControl::TPbk2NamesListBgEvents aEvent )
    {
    for ( TInt index = 0; index < iEventQueue.Count(); index++ )
        {
        if ( aEvent == iEventQueue[index] )
            {
            iEventQueue.Remove( index );
            if ( 0 == index )
                {
                Cancel();
                }
            break;
            }
        }
    }


// ---------------------------------------------------------------------------
// CPbk2NamesListControlBgTask::ClearAllEvents
// ---------------------------------------------------------------------------
//
void CPbk2NamesListControlBgTask::ClearAllEvents()
    {
    iEventQueue.Reset();
    iEventQueue.Append( CPbk2NamesListControl::EStateBgTaskEmpty );
    Cancel();
    }

//  End of File
