phonebookui/Phonebook/View/src/CPbkContactViewListControl.cpp
changeset 0 e686773b3f54
child 21 9da50d567e3c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook/View/src/CPbkContactViewListControl.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1917 @@
+/*
+* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*       Provides methods for phonebook contact view list control.
+*
+*/
+
+
+// INCLUDE FILES
+#include <CPbkContactViewListControl.h>  // This class
+#include <barsread.h>    // TResourceReader
+#include <eikclbd.h>     // CColumnListBoxData
+#include <aknsfld.h>     // CAknSearchField
+#include <aknlists.h>    // AknListBoxUtils
+#include <AknsDrawUtils.h>
+#include <featmgr.h>
+#include <bldvariant.hrh>
+#include <PbkView.rsg>
+#include <AknDef.h>      // KEikDynamicLayoutVariantSwitch
+#include <AknUtils.h>
+
+
+// PbkView classes
+#include <PbkView.hrh>
+#include "CPbkViewState.h"
+#include "CPbkThumbnailPopup.h"
+#include <CPbkIconArray.h>
+#include <MPbkContactViewListControlObserver.h>
+#include "PbkFindPrimitivesFactory.h"
+#include "PbkContactViewListModelFactory.h"
+#include "MPbkFetchDlgSelection.h"
+
+// PbkEng classes
+#include <CPbkContactEngine.h>
+#include <CPbkConstants.h>
+#include <CPbkContactFindView.h>
+
+// PbkExt classes
+#include <CPbkExtGlobals.h>
+#include <MPbkViewExtension.h>
+#include <MPbkContactUiControlExtension.h>
+#include <MPbkExtensionFactory.h>
+
+// Phonebook common include files
+#include <PbkDebug.h>        // Phonebook debugging support
+
+
+// Unnamed namespace for local definitions
+namespace {
+
+// LOCAL CONSTANTS AND MACROS
+
+/// Listbox model's entry cache size
+const TInt KCacheSize = 32;
+
+const TUint16 KZwsChar = 0x200b;
+const TUint16 KZwnjChar = 0x200c;
+
+enum TPanicCode
+    {
+    EPanicPostCond_Constructor = 1,
+    EPanicPreCond_ConstructFromResourceL,
+    EPanicInvalidListBoxType_ConstructFromResourceL,
+    EPanicPostCond_ConstructFromResource,
+    EPanicPreCond_ConstructL,
+    EPanicPostCond_ConstructL,
+    EPanicListBoxNull,
+    EPanicLogic_ComponentControl,
+    EPanicPostCond_EnableFindBoxL,
+    EPanicPostCond_DisableFindBoxL,
+    EPanicLogic_FindTextL,
+    EPanicPre_SetControlExtensionL
+    };
+
+
+// MODULE DATA STRUCTURES
+
+NONSHARABLE_CLASS(TCleanupEnableListBoxViewRedraw)
+    {
+    public:  // Interface
+        inline TCleanupEnableListBoxViewRedraw(CListBoxView& aListBoxView)
+            : iCleanupItem(CleanupOp,&aListBoxView)
+            {
+            }
+
+        inline operator TCleanupItem() const
+            {
+            return iCleanupItem;
+            }
+
+    private:  // Implementation
+        static void CleanupOp(TAny* aPtr);
+
+    private:  // Data
+        TCleanupItem iCleanupItem;
+    };
+
+// ==================== LOCAL FUNCTIONS ====================
+
+/**
+ * Returns index of aValue in aArray or KErrNotFound.
+ */
+template<class T>
+TInt Find(const CArrayFix<T>& aArray, const T& aValue)
+    {
+    const TInt count = aArray.Count();
+    for (TInt i = 0; i < count; ++i)
+        {
+        if (aArray[i] == aValue)
+            {
+            return i;
+            }
+        }
+    return KErrNotFound;
+    }
+
+/**
+ * Returns CPbkIconArray icon array from aListBox.
+ */
+inline CPbkIconArray* IconArray(CEikColumnListBox& aListBox)
+    {
+    return static_cast<CPbkIconArray*>
+        (aListBox.ItemDrawer()->ColumnData()->IconArray());
+    }
+
+/**
+ * Sets aIconArray as aListBox'es icon array.
+ */
+inline void SetIconArray
+        (CEikColumnListBox& aListBox, CPbkIconArray* aIconArray)
+    {
+    aListBox.ItemDrawer()->ColumnData()->SetIconArray(aIconArray);
+    }
+
+void Panic(TPanicCode aReason)
+    {
+    _LIT(KPanicText, "CPbkContactViewListControl");
+    User::Panic(KPanicText, aReason);
+    }
+
+/**
+ * Returns ETrue, if a character is to be included in the search string
+ */
+inline TBool IsSearchableChar( const TChar aChar )
+    {
+    switch (aChar)
+        {
+        case KZwsChar:  // FALLTHROUGH
+        case KZwnjChar:
+            {
+            return EFalse;
+            }
+        }
+    return ETrue;
+    }
+
+// MACROS
+
+/// Define this to print find performance data to debug output
+#ifdef PBK_BENCHMARK_FIND
+  #pragma message("Warning: PBK_BENCHMARK_FIND is set")
+#endif
+
+// MODULE DATA STRUCTURES
+
+#ifdef PBK_BENCHMARK_FIND
+
+/// Benchmarking helper class.
+template<class NumT>
+NONSHARABLE_CLASS(TRunningTimes)
+    {
+    public:  // Interface
+        /**
+         * Constructor.
+         */
+        inline TRunningTimes()
+            {
+            Reset();
+            }
+        /**
+         * () operator.
+         */
+        inline NumT operator()() const
+            {
+            return iTotal;
+            }
+
+        inline void Start()
+            {
+            iStart.UniversalTime();
+            }
+        inline void Stop()
+            {
+            iStop.UniversalTime();
+            const TInt timeDiff =
+                I64LOW(iStop.MicroSecondsFrom(iStart).Int64()) / 1000;
+            iTotal += timeDiff;
+            iCount++;
+            }
+
+        inline TInt Count() const
+            {
+            return iCount;
+            }
+
+        /**
+         * Returns total time
+         */
+        inline NumT Total() const
+            {
+            return iTotal;
+            }
+
+        /**
+         * Reset.
+         */
+        inline void Reset()
+            {
+            iTotal=0; iCount=0;
+            }
+
+    private:  // Data
+        TTime iStart;
+        TTime iStop;
+        /// Own: count
+        TInt iCount;
+        /// Own: total time
+        NumT iTotal;
+    };
+
+#endif  // PBK_BENCHMARK_FIND
+
+}  // namespace
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+//
+// CPbkContactViewListControl
+//
+inline CEikColumnListBox& CPbkContactViewListControl::ListBox() const
+    {
+    __ASSERT_DEBUG(iListBox, Panic(EPanicListBoxNull));
+    return(*iListBox);
+    }
+
+inline MPbkContactViewListModel& CPbkContactViewListControl::Model() const
+    {
+    return(*static_cast<MPbkContactViewListModel*>
+        (iListBox->Model()->ItemTextArray()));
+    }
+
+inline TBool CPbkContactViewListControl::PostCond_Constructor()
+    {
+    return
+        (!iListBox && !iFindBox && !iFindTextBuf && !iBaseView && !iView &&
+        !iResourceData.iUnnamedText && !iResourceData.iFindEmptyText &&
+        !iMarkedItemsArray && !iThumbnailPopup);
+    }
+
+inline TBool CPbkContactViewListControl::PostCond_ConstructFromResource()
+    {
+    return
+        (iListBox && !iFindBox && !iFindTextBuf &&
+        iResourceData.iUnnamedText && !iMarkedItemsArray);
+    }
+
+EXPORT_C CPbkContactViewListControl* CPbkContactViewListControl::NewL
+        (CPbkContactEngine& aEngine,
+        CContactViewBase& aView,
+        TInt aResourceId,
+        const CCoeControl* aParent)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkContactViewListControl::NewL()"));
+    CPbkContactViewListControl* self = new(ELeave) CPbkContactViewListControl();
+    CleanupStack::PushL(self);
+    self->ConstructL(aEngine, aView, aResourceId, aParent);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+EXPORT_C CPbkContactViewListControl::CPbkContactViewListControl() :
+    iLastFocusId(KNullContactId),
+    iChangedIndexes(1 /*allocation granularity*/)
+    {
+    // CBase::operator new(TLeave) resets other members
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+        ("CPbkContactViewListControl::CPbkContactViewListControl(0x%x)"),
+            this);
+    __ASSERT_DEBUG(PostCond_Constructor(), Panic(EPanicPostCond_Constructor));
+    }
+
+void CPbkContactViewListControl::ConstructFromResourceL
+        (TResourceReader& aReader)
+    {
+    __ASSERT_DEBUG(PostCond_Constructor(),
+        Panic(EPanicPreCond_ConstructFromResourceL));
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+        ("CPbkContactViewListControl::ConstructFromResourceL(0x%x)"),this);
+
+    // emptyText
+    TPtrC emptyText = aReader.ReadTPtrC();
+    // unnamedText
+    iResourceData.iUnnamedText = aReader.ReadHBufCL();
+    // flags
+    iResourceData.iFlags = aReader.ReadUint32();
+
+    // Empty text in find state
+    TResourceReader rr;
+    iEikonEnv->CreateResourceReaderLC(rr, R_AVKON_FIND_NO_MATCHES);
+    iResourceData.iFindEmptyText = rr.ReadHBufCL();
+    CleanupStack::PopAndDestroy(); // rr
+
+    // listboxType
+    TInt listBoxType = aReader.ReadInt16();
+    iListBox = static_cast<CEikColumnListBox*>
+        (EikControlFactory::CreateByTypeL(listBoxType).iControl);
+    __ASSERT_ALWAYS(iListBox, Panic
+        (EPanicInvalidListBoxType_ConstructFromResourceL));
+    iListBox->SetContainerWindowL(*this);
+    // listbox
+    iListBox->ConstructFromResourceL(aReader);
+    iListBox->View()->SetListEmptyTextL(emptyText);
+    iListBox->CreateScrollBarFrameL(ETrue);
+    iListBox->ScrollBarFrame()->SetScrollBarVisibilityL
+        (CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto);
+    iListBox->SetObserver(this);
+    iListBox->MakeVisible(EFalse);
+
+    // iconArray, use granularity of 4
+
+    CPbkIconArray* iconArray = new(ELeave) CPbkIconArray(4);
+    CleanupStack::PushL(iconArray);
+    const TInt iconArrayRes = aReader.ReadInt32();
+    iconArray->ConstructFromResourceL(iconArrayRes);
+
+    // get extension factory for setting extension icons
+    CPbkExtGlobals* extGlobal = CPbkExtGlobals::InstanceL();
+    extGlobal->PushL();
+    MPbkExtensionFactory& factory = extGlobal->FactoryL();
+    factory.AddPbkFieldIconsL(NULL, iconArray);
+    CleanupStack::PopAndDestroy(extGlobal);
+
+    CleanupStack::Pop(iconArray);
+
+    SetIconArray(*iListBox,iconArray);
+
+    // emptyIconId
+    iResourceData.iEmptyIconId =
+        static_cast<TPbkIconId>(aReader.ReadInt16());
+    // defaultIconId
+    iResourceData.iDefaultIconId =
+        static_cast<TPbkIconId>(aReader.ReadInt16());
+
+    // Preallocate space for the one required integer
+    iChangedIndexes.AppendL(-1);
+
+    __ASSERT_DEBUG(PostCond_ConstructFromResource(),
+        Panic(EPanicPostCond_ConstructFromResource));
+    }
+
+EXPORT_C void CPbkContactViewListControl::ConstructL
+        (CPbkContactEngine& aEngine,
+        CContactViewBase& aView)
+    {
+    // Check that ConstructFromResourceL is executed
+    __ASSERT_DEBUG(PostCond_ConstructFromResource() && !iBaseView && !iView,
+        Panic(EPanicPreCond_ConstructL));
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+        ("CPbkContactViewListControl::ConstructL(0x%x)"),this);
+
+    iFindPrimitives = PbkFindPrimitivesFactory::CreateL(
+        aEngine.ContactNameFormat());
+    iBaseView = &aView;
+    iView = CPbkContactFindView::NewL(
+        aEngine, *iBaseView, *this, *iFindPrimitives);
+
+    // Set aParams for MPbkContactViewListModel
+    PbkContactViewListModelFactory::TParams params;
+    params.iEngine = &aEngine;
+    params.iView = iView;
+    params.iCacheSize = KCacheSize;
+    params.iIconArray = IconArray(*iListBox);
+    params.iEmptyId = iResourceData.iEmptyIconId;
+    params.iDefaultId = iResourceData.iDefaultIconId;
+
+    // Listbox model
+    MPbkContactViewListModel* model = PbkContactViewListModelFactory::
+                                            CreateL(params);
+    model->SetUnnamedText(iResourceData.iUnnamedText);
+    iListBox->Model()->SetItemTextArray(model);
+    iListBox->Model()->SetOwnershipType(ELbmOwnsItemArray);
+
+    // thumbnail handler
+    if (iResourceData.iFlags & KPbkContactViewListControlUpdateContextPane)
+        {
+        iThumbnailPopup = CPbkThumbnailPopup::NewL(aEngine);
+        }
+
+    // Sets up TLS, must be done before FeatureManager is used.
+    FeatureManager::InitializeLibL();
+    // iEngine != NULL means that Featuremanager has been initialized
+    iEngine = &aEngine;
+
+    __ASSERT_DEBUG(PostCond_ConstructFromResource() && iBaseView && iView &&
+        iThumbnailPopup || !(iResourceData.iFlags &
+        KPbkContactViewListControlUpdateContextPane),
+        Panic(EPanicPostCond_ConstructL));
+    }
+
+CPbkContactViewListControl::~CPbkContactViewListControl()
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+        ("CPbkContactViewListControl::~CPbkContactViewListControl(0x%x)"),
+        this);
+
+    // This should be done before listbox delete
+    // (which deletes dummy control extension)
+    Release(iControlExtension);
+
+    // Fetch dialog pages might delay calling ConstructL and thus Feature
+    // manager might not be initialized if destructing early.
+    if (iEngine)
+        {
+        // iEngine != NULL means that Featuremanager has been initialized
+        FeatureManager::UnInitializeLib();
+        }
+
+    delete iOriginalEmptyText;
+    iObservers.Reset();
+    delete iFindTextBuf;
+    if (iView)
+        {
+        iView->Close(*this);
+        }
+    delete iFindPrimitives;
+    delete iThumbnailPopup;
+    delete iMarkedItemsArray;
+    delete iFindBox;
+    delete iListBox;
+    delete iResourceData.iFindEmptyText;
+    delete iResourceData.iUnnamedText;
+    }
+
+EXPORT_C TContactItemId CPbkContactViewListControl::ContactIdAtL
+        (TInt aIndex) const
+    {
+    return iView->AtL(aIndex);
+    }
+
+EXPORT_C TInt CPbkContactViewListControl::FindContactIdL
+        (TContactItemId aId) const
+    {
+    return iView->FindL(aId);
+    }
+
+EXPORT_C TInt CPbkContactViewListControl::CurrentItemIndex() const
+    {
+    return ListBox().CurrentItemIndex();
+    }
+
+EXPORT_C void CPbkContactViewListControl::SetCurrentItemIndex(TInt aIndex)
+    {
+    if (ListBox().CurrentItemIndex() != aIndex)
+        {
+        ListBox().SetCurrentItemIndex(aIndex);
+        HandleFocusChange();
+        }
+    }
+
+EXPORT_C void CPbkContactViewListControl::SetCurrentItemIndexAndDraw
+        (TInt aIndex)
+    {
+    if (ListBox().CurrentItemIndex() != aIndex)
+        {
+        ListBox().SetCurrentItemIndexAndDraw(aIndex);
+        HandleFocusChange();
+        }
+    }
+
+EXPORT_C void CPbkContactViewListControl::HandleMarkableListProcessCommandL
+        (TInt aCommandId)
+    {
+    AknSelectionService::HandleMarkableListProcessCommandL
+        (aCommandId, &ListBox());
+    }
+
+EXPORT_C void CPbkContactViewListControl::HandleMarkableListDynInitMenuPane
+        (TInt aResourceId,
+        CEikMenuPane *aMenu)
+    {
+    AknSelectionService::HandleMarkableListDynInitMenuPane
+        (aResourceId, aMenu, &ListBox());
+    }
+
+EXPORT_C void
+    CPbkContactViewListControl::HandleMarkableListUpdateAfterCommandExecution()
+    {
+    AknSelectionService::HandleMarkableListUpdateAfterCommandExecution
+        (&ListBox());
+    }
+
+EXPORT_C const TDesC& CPbkContactViewListControl::FindTextL() const
+    {
+    // Initial minimum size for the find text buffer
+    const TInt KInitialBufSize = 8;
+
+    if (iFindBox)
+        {
+        const TInt findBoxTextLength = iFindBox->TextLength();
+        if (findBoxTextLength > 0)
+            {
+            TInt bufCapacity = 0;
+            if (iFindTextBuf)
+                {
+                bufCapacity = iFindTextBuf->Des().MaxLength();
+                }
+            if (bufCapacity < findBoxTextLength)
+                {
+                // Allocate a new buffer of at least KInitialBufSize
+                // characters or twice as large as the previous one
+                const TInt newBufSize = Max(Max(KInitialBufSize,2*bufCapacity),
+                    findBoxTextLength);
+                HBufC* newBuf = HBufC::NewL(newBufSize);
+                delete iFindTextBuf;
+                iFindTextBuf = newBuf;
+                }
+            TPtr bufPtr = iFindTextBuf->Des();
+            __ASSERT_DEBUG
+                (bufPtr.MaxLength()>=KInitialBufSize && bufPtr.MaxLength()>=findBoxTextLength,
+                Panic(EPanicLogic_FindTextL));
+            iFindBox->GetSearchText(bufPtr);
+            // Strip from search string all unwanted characters that e.g. Hindi input places there
+            for( TInt i = bufPtr.Length()-1; i >= 0; --i )
+                {
+                if (!IsSearchableChar(bufPtr[i]))
+                    {
+                    bufPtr.Delete( i, 1 );
+                    }
+                }
+            return(*iFindTextBuf);
+            }
+        }
+    return KNullDesC;
+    }
+
+EXPORT_C void CPbkContactViewListControl::ResetFindL()
+    {
+    if (iFindBox && iFindBox->TextLength() > 0)
+        {
+        iFindBox->ResetL();
+        UpdateFindResultL();
+        iFindBox->DrawDeferred();
+        }
+    }
+
+EXPORT_C TBool CPbkContactViewListControl::ItemMarked(TInt aIndex) const
+    {
+    const CListBoxView::CSelectionIndexArray* selections =
+        ListBox().View()->SelectionIndexes();
+    return (selections ? Find(*selections,aIndex)!=KErrNotFound : EFalse);
+    }
+
+EXPORT_C TInt CPbkContactViewListControl::NextUnmarkedIndexFromFocus() const
+    {
+    const TInt focus = ListBox().CurrentItemIndex();
+    TInt index = focus;
+    const CListBoxView::CSelectionIndexArray* selections =
+        ListBox().SelectionIndexes();
+    if (selections && selections->Count() > 0)
+        {
+        const TInt count = iListBox->Model()->NumberOfItems();
+        for (index = focus; index < count; ++index)
+            {
+            if (Find(*selections,index) == KErrNotFound)
+                {
+                return index;
+                }
+            }
+        for (index = focus; index >= 0; --index)
+            {
+            if (Find(*selections,index) == KErrNotFound)
+                {
+                return index;
+                }
+            }
+        }
+    return index;
+    }
+
+EXPORT_C void CPbkContactViewListControl::MarkItemL
+        (TContactItemId aContactId,
+        TBool aMark)
+    {
+    const TInt index = FindContactIdL(aContactId);
+    if (index >= 0)
+        {
+        if (aMark)
+            {
+            ListBox().View()->SelectItemL(index);
+            }
+        else
+            {
+            ListBox().View()->DeselectItem(index);
+            }
+        }
+    }
+
+EXPORT_C void CPbkContactViewListControl::ClearMarks()
+    {
+    if (ItemsMarked())
+        {
+        CListBoxView& listBoxView = *ListBox().View();
+        listBoxView.SetDisableRedraw(ETrue);
+        ListBox().ClearSelection();
+        listBoxView.SetDisableRedraw(EFalse);
+        Redraw();
+        }
+    }
+
+EXPORT_C CPbkViewState* CPbkContactViewListControl::GetStateL
+        (TBool aSaveMarks/*=ETrue*/) const
+    {
+    CPbkViewState* state = GetStateLC(aSaveMarks);
+    CleanupStack::Pop();  // state
+    return state;
+    }
+
+EXPORT_C CPbkViewState* CPbkContactViewListControl::GetStateLC
+        (TBool aSaveMarks/*=ETrue*/) const
+    {
+    // Create a state object
+    CPbkViewState* state = CPbkViewState::NewLC();
+
+    // Init the state object
+    if (NumberOfItems() > 0)
+        {
+        TInt index;
+        if ((index = ListBox().TopItemIndex()) >= 0)
+            {
+            state->SetTopContactId(ContactIdAtL(index));
+            }
+        if ((index = ListBox().CurrentItemIndex()) >= 0)
+            {
+            state->SetFocusedContactId(ContactIdAtL(index));
+            }
+        if (aSaveMarks && ItemsMarked())
+            {
+            state->SetMarkedContactIds(CContactIdArray::NewL(&MarkedItemsL()));
+            }
+        }
+
+    // Return the state object
+    return state;
+    }
+
+EXPORT_C void CPbkContactViewListControl::RestoreStateL(const CPbkViewState* aState)
+    {
+    PBK_DEBUG_PRINT(
+        PBK_DEBUG_STRING("CPbkContactViewListControl::RestoreStateL(0x%x,0x%x)"),
+        this, aState);
+
+    if (!aState || !iStateFlags.IsSet(EReady))
+        {
+        return;
+        }
+
+    CEikColumnListBox& listBox = ListBox();
+    TBool redraw = EFalse;
+    if (aState->Flags() & CPbkViewState::EInitialized)
+        {
+        // Find box is recreated because default input language needs to
+        // be reset here if Always on feature is enabled for Phonebook
+        delete iFindBox;
+        iFindBox=NULL;
+
+        // Do not enable the find box if there does not exist any contacts
+        if (iBaseView->CountL() > 0)
+            {
+            EnableFindBoxL();
+            }
+
+        listBox.Reset();
+        redraw = ETrue;
+        }
+    else
+        {
+        if (iBaseView->CountL() > 0)
+            {
+            if (aState->Flags() & CPbkViewState::EFocusFirst)
+                {
+                listBox.SetTopItemIndex(0);
+                }
+            else if (aState->Flags() & CPbkViewState::EFocusLast)
+                {
+                listBox.SetCurrentItemIndex(listBox.Model()->NumberOfItems());
+                }
+            else
+                {
+                // Restore top item
+                if (aState->TopContactId() != KNullContactId)
+                    {
+                    const TInt index = FindContactIdL(aState->TopContactId());
+                    if (index >= 0)
+                        {
+                        const TInt prevIndex = listBox.TopItemIndex();
+                        listBox.SetTopItemIndex(index);
+                        FixTopItemIndex();
+                        if (index != prevIndex)
+                            {
+                            redraw = ETrue;
+                            }
+                        }
+                    }
+
+                // Restore focus
+                if (aState->FocusedContactId() != KNullContactId)
+                    {
+                    const TInt index = FindContactIdL(aState->FocusedContactId());
+                    if (index >= 0)
+                        {
+                        const TInt prevIndex = listBox.CurrentItemIndex();
+                        listBox.SetCurrentItemIndex(index);
+                        if (index != prevIndex)
+                            {
+                            redraw = ETrue;
+                            }
+                        }
+                    }
+
+                }
+            // Restore selections
+            const CContactIdArray* markedContactIds = aState->MarkedContactIds();
+            if (RestoreMarkedItemsL(markedContactIds))
+                {
+                redraw = ETrue;
+                }
+            }
+        }
+
+    if (redraw)
+        {
+        Redraw();
+        iListBox->UpdateScrollBarsL();
+        HandleFocusChange();
+        }
+    }
+
+void CPbkContactViewListControl::ShowThumbnail(TContactItemId aContactId)
+    {
+    if (!iThumbnailPopup && iEngine)
+        {
+        TRAP_IGNORE(iThumbnailPopup = CPbkThumbnailPopup::NewL( *iEngine ));
+        }
+
+    if (iThumbnailPopup && aContactId!=KNullContactId  && IsReadyToDraw() &&
+        !iStateFlags.IsSet(EBlank))
+        {
+        iThumbnailPopup->Load(aContactId, iListBox);
+        }
+    else if (iThumbnailPopup)
+        {
+        iThumbnailPopup->CancelLoading();
+        }
+    }
+
+EXPORT_C void CPbkContactViewListControl::ShowThumbnailL()
+    {
+    if (!iThumbnailPopup && iEngine)
+        {
+        iThumbnailPopup = CPbkThumbnailPopup::NewL( *iEngine );
+        }
+
+    if (iLastFocusId!=KNullContactId  && IsReadyToDraw() &&
+        !iStateFlags.IsSet(EBlank))
+        {
+        iThumbnailPopup->Load(iLastFocusId, iListBox);
+        }
+    else
+        {
+        iThumbnailPopup->CancelLoading();
+        }
+    }
+
+EXPORT_C void CPbkContactViewListControl::HideThumbnail()
+    {
+    if (iThumbnailPopup)
+        {
+        iThumbnailPopup->CancelLoading();
+        }
+    }
+
+EXPORT_C void CPbkContactViewListControl::AddObserverL
+        (MPbkContactViewListControlObserver& aObserver)
+    {
+    User::LeaveIfError(iObservers.Append(&aObserver));
+    }
+
+EXPORT_C void CPbkContactViewListControl::RemoveObserver
+        (MPbkContactViewListControlObserver& aObserver)
+    {
+    const TInt index = iObservers.Find(&aObserver);
+    if (index >= 0)
+        {
+        iObservers.Remove(index);
+        }
+    }
+
+EXPORT_C TBool CPbkContactViewListControl::IsReady() const
+    {
+    return (iStateFlags.IsSet(EReady));
+    }
+
+void CPbkContactViewListControl::SetDisableRedraw(TBool aDisableRedraw)
+    {
+    ListBox().View()->SetDisableRedraw(aDisableRedraw);
+    }
+
+void CPbkContactViewListControl::DisableRedrawEnablePushL()
+    {
+    CListBoxView& listBoxView = *ListBox().View();
+    listBoxView.SetDisableRedraw(ETrue);
+    CleanupStack::PushL(TCleanupEnableListBoxViewRedraw(listBoxView));
+    }
+
+EXPORT_C void CPbkContactViewListControl::SetBlank(TBool aBlank)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+        ("CPbkContactViewListControl::SetBlank(0x%x,%d)"),this,aBlank);
+
+    if ((iStateFlags.IsSet(EBlank) && aBlank) ||
+        (!iStateFlags.IsSet(EBlank) && !aBlank))
+        {
+        // No change in state
+        return;
+        }
+
+    // Set the EBlank flag
+    iStateFlags.Assign(EBlank,aBlank);
+
+    // Hide/unhide component controls
+    MakeComponentsVisible(!aBlank);
+    Redraw();
+    }
+
+EXPORT_C void CPbkContactViewListControl::SetEntryLoader
+        (MPbkContactEntryLoader& aContactEntryLoader)
+    {
+    Model().SetEntryLoader(aContactEntryLoader);
+    }
+
+
+void CPbkContactViewListControl::SetSelectionAccepter(MPbkFetchDlgSelection* aAccepter)
+    {
+    iSelectionAccepter = aAccepter;
+    }
+
+TInt CPbkContactViewListControl::NumberOfItems() const
+    {
+    return ListBox().Model()->NumberOfItems();
+    }
+
+TBool CPbkContactViewListControl::ItemsMarked() const
+    {
+    const CListBoxView::CSelectionIndexArray* selections =
+        ListBox().View()->SelectionIndexes();
+    return (selections && selections->Count()>0);
+    }
+
+const CContactIdArray& CPbkContactViewListControl::MarkedItemsL() const
+    {
+    if (!iMarkedItemsArray)
+        {
+        iMarkedItemsArray = CContactIdArray::NewL();
+        }
+
+    // Remove old contents of array (use Remove instead of Reset to keep the
+    // array buffer)
+    iMarkedItemsArray->Remove(0,iMarkedItemsArray->Count());
+
+    // Get the list boxes marked items index array
+    const CListBoxView::CSelectionIndexArray* selArray =
+        ListBox().SelectionIndexes();
+
+    if (selArray && selArray->Count() > 0)
+        {
+        // Initialize the marked contact id array using selArray
+        CContactViewBase::TVirtualFunction1Params params
+            (selArray, iMarkedItemsArray);
+
+        iView->CContactViewBase_Reserved_1
+            (CContactViewBase::ECContactViewBaseVirtualFunction1, &params);
+        }
+    else
+        {
+        // No items marked, add the focused contact to the array
+        iMarkedItemsArray->AddL(FocusedContactIdL());
+        }
+
+    return *iMarkedItemsArray;
+    }
+
+TContactItemId CPbkContactViewListControl::FocusedContactIdL() const
+    {
+    TContactItemId retId(KNullContactId);
+
+    const TInt focusIndex = ListBox().CurrentItemIndex();
+    if (focusIndex >= 0)
+        {
+        retId = iView->AtL(focusIndex);
+        }
+    return retId;
+    }
+
+const TPbkContactItemField* CPbkContactViewListControl::FocusedField() const
+    {
+    // This control does not support field level focus
+    return NULL;
+    }
+
+MObjectProvider* CPbkContactViewListControl::ObjectProvider()
+    {
+    return this;
+    }
+
+TKeyResponse CPbkContactViewListControl::OfferKeyEventL
+        (const TKeyEvent& aKeyEvent,TEventCode aType)
+    {
+    if (!iStateFlags.IsSet(EReady) || iStateFlags.IsSet(EBlank))
+        {
+        // Don't handle any keys when not ready or blanked
+        return EKeyWasNotConsumed;
+        }
+
+    TKeyResponse result = EKeyWasNotConsumed;
+
+    if (iFindBox)
+        {
+        // Find box is active, offer key first to it
+        result = iFindBox->OfferKeyEventL(aKeyEvent, aType);
+        }
+
+    if (result == EKeyWasNotConsumed && iListBox)
+        {
+        // Find box didn't consume the event -> offer it to the list box
+        const TInt focusIndex = iListBox->CurrentItemIndex();
+        const TBool markedBefore = ItemMarked(focusIndex);
+
+        // If selection key was pressed and the focused contact was earlier
+        // unselected, then first check from selection accepter if this item
+        // can be selected
+        // Also do the acception-check if there are no selected items and
+        // OK-softkey was pressed (causing focused item to be selected and
+        // closing the dialog
+        TBool checkSelection = EFalse;
+        const CListBoxView::CSelectionIndexArray* selArray =
+                ListBox().SelectionIndexes();
+        
+        
+        const TInt selectionKeyPressed(aKeyEvent.iCode == EKeyDevice3);
+        
+        // AVKON may create EKeyApplicationF key event 
+        // when list item is selected.
+        const TInt avkonSelectionKeyNotification(
+                        aKeyEvent.iCode == EKeyApplicationF);
+                        
+        const TBool noSelectionMade(!selArray||selArray->Count() == 0 );
+        
+        const TBool validNewFocusedItem(
+                        !markedBefore && focusIndex >= KErrNone);
+
+        if ((selectionKeyPressed || (avkonSelectionKeyNotification && noSelectionMade))
+            && validNewFocusedItem)
+            {
+            checkSelection = ETrue;
+            }
+        
+        const CListBoxView::CSelectionIndexArray* selections =
+            ListBox().SelectionIndexes();
+        TInt selCount = selections ? selections->Count() : 0;
+        
+        if (!checkSelection || !iSelectionAccepter ||
+            focusIndex != KErrNotFound &&
+            iSelectionAccepter->ContactSelectionAcceptedL(
+                ContactIdAtL(focusIndex), selCount))
+            {
+            result = iListBox->OfferKeyEventL(aKeyEvent, aType);
+
+            if (result == EKeyWasConsumed)
+                {
+                const TBool markedAfter = ItemMarked(focusIndex);
+                if (markedAfter != markedBefore)
+                    {
+                    TPbkContactViewListControlEvent
+                        event(TPbkContactViewListControlEvent::EContactSelected);
+                    event.iInt = focusIndex;
+                    event.iContactId = ContactIdAtL(focusIndex);
+                    if (!markedAfter)
+                        {
+                        event.iEventType =
+                            TPbkContactViewListControlEvent::EContactUnselected;
+                        }
+                    SendEventToObserversL(event);
+                    }                
+                }
+            }
+        else
+            {
+            result = EKeyWasConsumed;
+            }
+        }
+    return result;
+    }
+
+void CPbkContactViewListControl::HandlePointerEventL(
+        const TPointerEvent& aPointerEvent )
+    {
+    if ( AknLayoutUtils::PenEnabled() )
+        {
+        if ( iFindBox )
+            {
+            iFindBox->HandlePointerEventL( aPointerEvent );
+            }
+
+        if ( iListBox )
+            {
+            switch ( aPointerEvent.iType )
+                {
+                case TPointerEvent::EButton1Down:
+                    {
+                    iPrevIndex = iListBox->CurrentItemIndex();
+                    iListBox->HandlePointerEventL( aPointerEvent );
+                    break;
+                    }
+                case TPointerEvent::EButton1Up:
+                    {
+                    TInt focusIndex;
+                    TBool focusableContactPointed =
+                        iListBox->View()->XYPosToItemIndex(
+                            aPointerEvent.iPosition, focusIndex );
+                    if (!focusableContactPointed || focusIndex < 0)
+                        {
+                        // Nothing special to do when tapping empty space
+                        iListBox->HandlePointerEventL( aPointerEvent );
+                        }
+                    else
+                        {
+                        // Send contact tap events                        
+                        TPbkContactViewListControlEvent event(
+                            TPbkContactViewListControlEvent::EContactTapped );
+                        event.iInt = focusIndex;
+                        event.iContactId = ContactIdAtL( focusIndex );
+                        if ( iPrevIndex == iListBox->CurrentItemIndex() )
+                            {
+                            event.iEventType =
+                                TPbkContactViewListControlEvent::EContactDoubleTapped;
+                            }
+                        SendEventToObserversL( event );
+
+                        // Do markings
+                        const TBool markedBefore = ItemMarked(focusIndex);
+                        const CListBoxView::CSelectionIndexArray* selections =
+                            ListBox().SelectionIndexes();
+                        TInt selCount = selections ? selections->Count() : 0;
+
+                        if ( markedBefore ||         // can unmark always
+                             !iSelectionAccepter ||  // no select restrictions
+                             iSelectionAccepter->ContactSelectionAcceptedL(
+                                ContactIdAtL(focusIndex), selCount) )
+                            {
+                            // Handle the pointer event to list box to fix the problem that items in multiple
+                            // fetch dialog can't be select with touch screen.
+                            iListBox->HandlePointerEventL( aPointerEvent );
+                            
+                            const TBool markedAfter = ItemMarked( focusIndex );
+                            if ( markedAfter != markedBefore )
+                                {
+                                event.iEventType =
+                                    TPbkContactViewListControlEvent::EContactSelected;
+                                event.iInt = focusIndex;
+                                event.iContactId = ContactIdAtL(focusIndex);
+                                if (!markedAfter)
+                                    {
+                                    event.iEventType =
+                                        TPbkContactViewListControlEvent::EContactUnselected;
+                                    }
+                                SendEventToObserversL(event);
+                                }
+                            }
+                        }
+                    break;
+                    }
+                default:
+                    {
+                    iListBox->HandlePointerEventL( aPointerEvent );
+                    }
+                }
+            }
+        }
+    }
+
+void CPbkContactViewListControl::MakeVisible(TBool aVisible)
+    {
+    PBK_DEBUG_PRINT(
+        PBK_DEBUG_STRING("CPbkContactViewListControl::MakeVisible(0x%x,%d)"),
+        this, aVisible);
+
+    CCoeControl::MakeVisible(aVisible);
+    MakeComponentsVisible(aVisible);
+    }
+
+void CPbkContactViewListControl::UpdateContact(TContactItemId aContactId)
+    {
+    TInt listBoxRow = -1;
+    TRAPD(err, listBoxRow = FindContactIdL(aContactId) );
+    if (err)
+        {
+        iEikonEnv->NotifyIdleErrorWhileRedrawing(err);
+        }
+    if (listBoxRow >= 0)
+        {
+        // if visible
+        if (listBoxRow >= ListBox().TopItemIndex() &&
+            listBoxRow <= ListBox().BottomItemIndex() )
+            {
+            ListBox().DrawItem(listBoxRow);
+            }
+        }
+    }
+
+TInt CPbkContactViewListControl::CountComponentControls() const
+    {
+    TInt controls = 0;
+    if (iListBox)
+        {
+        ++controls;
+        }
+    if (iFindBox)
+        {
+        ++controls;
+        }
+    return controls;
+    }
+
+CCoeControl* CPbkContactViewListControl::ComponentControl(TInt aIndex) const
+    {
+    switch (aIndex)
+        {
+        case 0:
+            {
+            __ASSERT_DEBUG(iListBox, Panic(EPanicLogic_ComponentControl));
+            return iListBox;
+            }
+        case 1:
+            {
+            __ASSERT_DEBUG(iFindBox, Panic(EPanicLogic_ComponentControl));
+            return iFindBox;
+            }
+        default:
+            {
+            // Illegal state
+            __ASSERT_DEBUG(EFalse, Panic(EPanicLogic_ComponentControl));
+            return NULL;
+            }
+        }
+    }
+
+void CPbkContactViewListControl::FocusChanged(TDrawNow aDrawNow)
+    {
+    const TBool focused = IsFocused();
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+        ("CPbkContactViewListControl::FocusChanged(0x%x,%d),focused=%d"),
+        this, aDrawNow, focused ? ETrue : EFalse);
+
+    if (focused)
+        {
+        ShowThumbnail(iLastFocusId);
+        }
+    else
+        {
+        HideThumbnail();
+        }
+
+    const TInt count = CountComponentControls();
+    for (TInt i=0; i < count; ++i)
+        {
+        CCoeControl* componentControl = ComponentControl(i);
+        // Don't try to focus non-focusing controls
+        if (!componentControl->IsNonFocusing())
+            {
+            componentControl->SetFocus(focused,aDrawNow);
+            }
+        }
+    }
+
+void CPbkContactViewListControl::SizeChanged()
+    {
+    const TRect rect(Rect());
+    PBK_DEBUG_PRINT(
+        PBK_DEBUG_STRING("CPbkContactViewListControl::SizeChanged(0x%x), rect=(%d,%d,%d,%d)"),
+        this, rect.iTl.iX, rect.iTl.iY, rect.iBr.iX, rect.iBr.iY);
+
+    if (iListBox && iFindBox)
+        {
+        AknLayoutUtils::LayoutControl(iListBox, rect,
+            AKN_LAYOUT_WINDOW_list_gen_pane(1));
+        AknLayoutUtils::LayoutControl(iFindBox, rect,
+            AKN_LAYOUT_WINDOW_find_pane);
+        if (iFindBox->IsVisible() && iListBox->IsVisible())
+            {
+            // The correct line position to use is 2, which corresponds
+            // EABColumn in Avkon (not a public enumeration,
+            // hence hard-coding used here)
+            const TInt KSeparatorLinePos = 2;
+            iFindBox->SetLinePos(KSeparatorLinePos);
+            }
+        }
+    else if (iListBox)
+        {
+        AknLayoutUtils::LayoutControl(iListBox, rect,
+            AKN_LAYOUT_WINDOW_list_gen_pane(0));
+        }
+    }
+
+void CPbkContactViewListControl::Draw(const TRect& aRect) const
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+        "CPbkContactViewListControl::Draw(0x%x, TRect(%d,%d,%d,%d)), iStateFlags=0x%x"),
+        this, aRect.iTl.iX, aRect.iTl.iY, aRect.iBr.iX, aRect.iBr.iY, iStateFlags.iFlags);
+
+    if (!iStateFlags.IsSet(EReady) || iStateFlags.IsSet(EBlank))
+        {
+        // If control is not ready or blanked draw a blank background
+        CWindowGc& gc = SystemGc();
+        MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+        MAknsControlContext* cc = AknsDrawUtils::ControlContext(iListBox);
+        if ( !AknsDrawUtils::Background(skin, cc, iListBox, gc, aRect) )
+            {
+            // blank background if no skin present
+            gc.SetPenStyle(CGraphicsContext::ENullPen);
+            gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
+            gc.DrawRect(aRect);
+            }
+        }
+    }
+
+void CPbkContactViewListControl::HandleControlEventL
+        (CCoeControl* aControl,
+        TCoeEvent aEventType)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+        ("CPbkContactViewListControl::HandleControlEventL(0x%x,0x%x,%d)"),
+        this, aControl, aEventType);
+
+    if (aEventType == EEventStateChanged)
+        {
+        if (aControl == iListBox)
+            {
+            HandleFocusChange();
+            // Forward listbox state change events to this control's
+            // observers
+            ReportEventL(MCoeControlObserver::EEventStateChanged);
+            }
+        else if (aControl == iFindBox)
+            {
+            UpdateFindResultL();
+            }
+        }
+    }
+
+void CPbkContactViewListControl::HandleContactViewEvent
+        (const CContactViewBase& aView,const TContactViewEvent& aEvent)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+        ("CPbkContactViewListControl::HandleContactViewEvent(0x%x,0x%x,%d)"),
+        this, &aView, aEvent.iEventType);
+
+    if (&aView == iView)
+        {
+        TRAPD(err, DoHandleContactViewEventL(aView,aEvent));
+        if (err != KErrNone)
+            {
+            iEikonEnv->HandleError(err);
+            }
+        }
+    }
+
+/**
+ * Called from HandleContactViewEvent().
+ */
+void CPbkContactViewListControl::DoHandleContactViewEventL
+        (const CContactViewBase& /*aView*/,const TContactViewEvent& aEvent)
+    {
+    switch (aEvent.iEventType)
+        {
+        case TContactViewEvent::EReady:
+            {
+            iStateFlags.Set(EReady);
+            MakeComponentsVisible(IsVisible());
+            iListBox->Reset();
+            UpdateFindBoxL();
+            iListBox->UpdateScrollBarsL();
+            Redraw();
+            HandleFocusChange();
+            SendEventToObserversL(TPbkContactViewListControlEvent::EReady);
+            break;
+            }
+
+        case TContactViewEvent::ESortOrderChanged:
+            {
+            Model().FlushCache();
+            Model().RefreshSortOrderL();
+            iStateFlags.Set(EReady);
+            MakeComponentsVisible(IsVisible());
+            iListBox->Reset();
+            UpdateFindBoxL();
+            iListBox->UpdateScrollBarsL();
+            Redraw();
+            HandleFocusChange();
+            // Send EReady event
+            SendEventToObserversL(TPbkContactViewListControlEvent::EReady);
+            break;
+            }
+
+        case TContactViewEvent::EItemAdded:
+            {
+            HandleItemAdditionL(aEvent.iInt);
+            TPbkContactViewListControlEvent event
+                (TPbkContactViewListControlEvent::EItemAdded);
+            event.iInt = aEvent.iInt;
+            event.iContactId = aEvent.iContactId;
+            SendEventToObserversL(event);
+            break;
+            }
+
+        case TContactViewEvent::EItemRemoved:
+            {
+            Model().PurgeEntry(aEvent.iContactId);
+            HandleItemRemovalL(aEvent.iInt);
+            TPbkContactViewListControlEvent event
+                (TPbkContactViewListControlEvent::EItemRemoved);
+            event.iInt = aEvent.iInt;
+            event.iContactId = aEvent.iContactId;
+            SendEventToObserversL(event);
+            break;
+            }
+
+        case TContactViewEvent::EUnavailable:
+            {
+            iStateFlags.Clear(EReady);
+            MakeComponentsVisible(EFalse);
+            SendEventToObserversL
+                (TPbkContactViewListControlEvent::EUnavailable);
+            break;
+            }
+
+        case TContactViewEvent::ESortError:  //FALLTHROUGH
+        case TContactViewEvent::EServerError:  //FALLTHROUGH
+        case TContactViewEvent::EIndexingError:
+            {
+            iStateFlags.Clear(EReady);
+            MakeComponentsVisible(EFalse);
+            iEikonEnv->HandleError(aEvent.iInt);
+            iListBox->Reset();
+            DisableFindBoxL();
+            TPbkContactViewListControlEvent event
+                (TPbkContactViewListControlEvent::EUnavailable);
+            event.iInt = aEvent.iInt;
+            SendEventToObserversL(event);
+            break;
+            }
+
+        default:
+            {
+            break;
+            }
+        }
+    }
+
+void CPbkContactViewListControl::SendEventToObserversL
+        (const TPbkContactViewListControlEvent& aEvent)
+    {
+    // Loop backwards in case some observer destroys itself in the
+    // event handler
+    for (TInt i=iObservers.Count()-1; i>=0; --i)
+        {
+        iObservers[i]->HandleContactViewListControlEventL(*this,aEvent);
+        }
+    }
+
+void CPbkContactViewListControl::ConstructL
+        (CPbkContactEngine& aEngine,
+        CContactViewBase& aView,
+        TInt aResourceId,
+        const CCoeControl* aParent)
+    {
+    if (aParent)
+        {
+        SetContainerWindowL(*aParent);
+        }
+    else
+        {
+        CreateWindowL();
+        }
+    ConstructFromResourceL(aResourceId);
+    ConstructL(aEngine, aView);
+    CreateControlExtensionL(aEngine);
+    }
+
+void CPbkContactViewListControl::ConstructFromResourceL
+        (TInt aResourceId)
+    {
+    TResourceReader resReader;
+    iCoeEnv->CreateResourceReaderLC(resReader,aResourceId);
+    ConstructFromResourceL(resReader);
+    CleanupStack::PopAndDestroy();  // resReader
+    }
+
+void CPbkContactViewListControl::FixTopItemIndex()
+    {
+    CEikListBox& listBox = ListBox();
+    TInt index = listBox.TopItemIndex();
+    const TInt height = listBox.View()->NumberOfItemsThatFitInRect
+        (iListBox->View()->ViewRect());
+    const TInt numItems = listBox.Model()->NumberOfItems();
+    if (index + height > numItems)
+        {
+        index += numItems - (height + index);
+        if (index < 0)
+            {
+            index = 0;
+            }
+        if (index != listBox.TopItemIndex())
+            {
+            listBox.SetTopItemIndex(index);
+            }
+        }
+    }
+
+/**
+ * Redraws this control using DrawDeferred().
+ */
+void CPbkContactViewListControl::Redraw()
+    {
+    if (iStateFlags.IsSet(EReady) && !iStateFlags.IsSet(EBlank))
+        {
+        DrawDeferred();
+        }
+    }
+
+void CPbkContactViewListControl::MakeComponentsVisible(TBool aVisible)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+        ("CPbkContactViewListControl::MakeComponentsVisible(0x%x,%d)"),
+        this, aVisible);
+
+    if (aVisible && (!iStateFlags.IsSet(EReady) || iStateFlags.IsSet(EBlank)))
+        {
+        // Never make components visible if this control is not ready or in
+        // blank state
+        return;
+        }
+
+    if (iListBox)
+        {
+        iListBox->MakeVisible(aVisible);
+        }
+
+    if (iFindBox)
+        {
+        iFindBox->SetFocus(aVisible);
+        iFindBox->MakeVisible(aVisible);
+        }
+
+    // Hide/show thumbnail
+    if (aVisible)
+        {
+        ShowThumbnail(iLastFocusId);
+        }
+    else
+        {
+        HideThumbnail();
+        }
+    }
+
+void CPbkContactViewListControl::HandleItemAdditionL(TInt aIndex)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+        ("CPbkContactViewListControl::HandleItemAdditionL(0x%x, %d)"),
+        this, aIndex);
+
+    UpdateFindBoxL();
+
+    // Update listbox
+    iChangedIndexes[0] = aIndex;
+    iListBox->HandleItemAdditionL(iChangedIndexes);
+
+    // Maintain focus
+    const TInt index = iView->FindL(iLastFocusId);
+    if ( index >= 0 &&
+         index < iListBox->Model()->NumberOfItems() &&
+         index != iListBox->CurrentItemIndex() )
+        {
+        iListBox->SetCurrentItemIndex(index);
+        }
+    Redraw();
+    HandleFocusChange();
+    }
+
+void CPbkContactViewListControl::HandleItemRemovalL(TInt aIndex)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+        ("CPbkContactViewListControl::HandleItemRemovalL(0x%x, %d)"),
+        this, aIndex);
+
+    // Deselect item
+    CListBoxView& listBoxView = *ListBox().View();
+    listBoxView.SetDisableRedraw(ETrue);
+    listBoxView.DeselectItem(aIndex);
+    listBoxView.SetDisableRedraw(EFalse);
+
+    UpdateFindBoxL();
+
+    // Update listbox
+    TInt focusIndex = iListBox->CurrentItemIndex();
+    TInt topIndex = iListBox->TopItemIndex();
+    iChangedIndexes[0] = aIndex;
+    iListBox->HandleItemRemovalL(iChangedIndexes);
+
+    // Maintain focus
+    const TInt lastIndex = iListBox->Model()->NumberOfItems() - 1;
+    if (lastIndex == KNullContactId)
+        {
+        iListBox->Reset();
+        }
+    else
+        {
+        if (aIndex < focusIndex)
+            {
+            --focusIndex;
+            }
+        if (focusIndex > lastIndex || focusIndex < 0)
+            {
+            focusIndex = lastIndex;
+            }
+        const TInt numVisibleItems =
+            iListBox->View()->NumberOfItemsThatFitInRect
+                (iListBox->View()->ViewRect());
+        if (topIndex + numVisibleItems > lastIndex)
+            {
+            topIndex = Max(lastIndex - numVisibleItems + 1, 0);
+            }
+        if (topIndex >= 0)
+            {
+            iListBox->SetTopItemIndex(topIndex);
+            }
+        if (focusIndex >= 0)
+            {
+            iListBox->SetCurrentItemIndex(focusIndex);
+            }
+        }
+    Redraw();
+    HandleFocusChange();
+    }
+
+/**
+ * Hides or displays the find box depending on control state.
+ */
+void CPbkContactViewListControl::UpdateFindBoxL()
+    {
+    if ((iResourceData.iFlags & KPbkContactViewListControlFindBox) &&
+        iBaseView->CountL() > 0)
+        {
+        EnableFindBoxL();
+        }
+    else
+        {
+        DisableFindBoxL();
+        }
+    }
+
+void CPbkContactViewListControl::EnableFindBoxL()
+    {
+    if (!iFindBox)
+        {
+        // Create a find box
+        iFindBox = CAknSearchField::NewL
+            (*this, CAknSearchField::ESearch, NULL,
+            CPbkConstants::SearchFieldLength());
+
+        iFindBox->SetObserver(this);
+        iFindBox->SetFocus(ETrue);
+        iFindBox->ResetL();
+
+        // Set default input mode to Katakana if current UI language is Japanese
+        if (FeatureManager::FeatureSupported(KFeatureIdJapanese) &&
+            (User::Language() == ELangJapanese))
+            {
+            CEikEdwin& findEditor = iFindBox->Editor();
+            findEditor.SetAknEditorInputMode(EAknEditorKatakanaInputMode);
+            }
+
+        // Inform list box that find is visible again
+        static_cast<CAknColumnListBoxView*>(iListBox->View())
+            ->SetFindEmptyListState(ETrue);
+        SetFindEmptyTextL();
+
+        // Relayout view
+        SizeChanged();
+        UpdateFindResultL();
+        }
+    __ASSERT_DEBUG(iFindBox, Panic(EPanicPostCond_EnableFindBoxL));
+    }
+
+void CPbkContactViewListControl::DisableFindBoxL()
+    {
+    if (iFindBox)
+        {
+        // Important to set the find box non-focusing before
+        // deleting it, otherwise the focus changes triggered
+        // by the removal of the control from stack will focus
+        // the find box which is under deletion
+        iFindBox->SetNonFocusing();
+        delete iFindBox;
+        iFindBox = NULL;
+        // Inform list box that find is hidden
+        static_cast<CAknColumnListBoxView*>(iListBox->View())
+            ->SetFindEmptyListState(EFalse);
+        RemoveFindEmptyTextL();
+
+        // Relayout view
+        SizeChanged();
+        UpdateFindResultL();
+        }
+    __ASSERT_DEBUG(!iFindBox, Panic(EPanicPostCond_DisableFindBoxL));
+    }
+
+/**
+ * Updates find result.
+ * @return ETrue if there was a change in find result set.
+ */
+TBool CPbkContactViewListControl::UpdateFindResultL()
+    {
+    TBool result = EFalse;
+    const CContactIdArray* markedItems = NULL;
+    const TInt countBefore = iView->CountL();
+
+    if (ItemsMarked())
+        {
+        markedItems = &MarkedItemsL();
+        }
+    TRAPD( err,
+        result = iView->SetFindTextL(FindTextL(), markedItems) );
+    if (err != KErrNone)
+        {
+        iEikonEnv->HandleError(err);
+        }
+
+    const TInt countAfter = iView->CountL();
+
+    if (err)
+        {
+        // Error (possibly OOM), only redraw what remains in the screen
+        SizeChanged();
+        Redraw();
+        }
+    else if (result)
+        {
+        iListBox->DrawDeferred();
+        if (countAfter > countBefore)
+            {
+            iListBox->HandleItemAdditionL();
+            }
+        else if (countAfter < countBefore)
+            {
+            iListBox->HandleItemRemovalL();
+            }
+
+        if (markedItems)
+            {
+            // Restore item marks
+            CListBoxView& listBoxView = *iListBox->View();
+            listBoxView.SetDisableRedraw(ETrue);
+            CleanupStack::PushL(TCleanupEnableListBoxViewRedraw(listBoxView));
+            listBoxView.ClearSelection();
+            const TInt count = markedItems->Count();
+            #ifdef PBK_BENCHMARK_FIND
+            TRunningTimes<TInt> timer;
+            #endif
+            for (TInt i=0; i < count; ++i)
+                {
+                const TContactItemId contactId = (*markedItems)[i];
+                #ifdef PBK_BENCHMARK_FIND
+                timer.Start();
+                #endif
+                const TInt index =iView->FindL(contactId);
+                #ifdef PBK_BENCHMARK_FIND
+                timer.Stop();
+                #endif
+                listBoxView.SelectItemL(index);
+                }
+            #ifdef PBK_BENCHMARK_FIND
+            RDebug::Print(_L(
+                "CPbkContactViewListControl::UpdateFindResultL FindL calls %d tot %d"),
+                timer.Count(), timer.Total());
+            #endif
+            CleanupStack::PopAndDestroy(); //TCleanupEnableListBoxViewRedraw
+            }
+
+        // This event is send to observers,
+        // if contact set of the control is changed
+        TPbkContactViewListControlEvent
+            event(TPbkContactViewListControlEvent::EContactSetChanged);
+        SendEventToObserversL(event);
+        }
+
+    TInt focusIndex = iView->IndexOfFirstFindMatchL();
+    if (focusIndex < 0)
+        {
+        if (countAfter > 0)
+            {
+            focusIndex = 0;
+            }
+        }
+    if (focusIndex >= 0 && focusIndex != iListBox->CurrentItemIndex())
+        {
+        iListBox->SetCurrentItemIndexAndDraw(focusIndex);
+        }
+    HandleFocusChange();
+
+    return result;
+    }
+
+void CPbkContactViewListControl::SetFindEmptyTextL()
+    {
+    if (!iOriginalEmptyText)
+        {
+        iOriginalEmptyText = iListBox->View()->EmptyListText()->AllocL();
+        }
+    iListBox->View()->SetListEmptyTextL(*iResourceData.iFindEmptyText);
+    }
+
+void CPbkContactViewListControl::RemoveFindEmptyTextL()
+    {
+    if (iOriginalEmptyText)
+        {
+        iListBox->View()->SetListEmptyTextL(*iOriginalEmptyText);
+        }
+    }
+
+void CPbkContactViewListControl::HandleFocusChange()
+    {
+    TRAP_IGNORE(HandleFocusChangeL());
+    }
+
+void CPbkContactViewListControl::HandleFocusChangeL()
+    {
+    const TInt index = ListBox().CurrentItemIndex();
+    TContactItemId newFocusId = KNullContactId;
+    if (index >= 0 && index < iView->CountL())
+        {
+        newFocusId = iView->AtL(index);
+        }
+    if (newFocusId != iLastFocusId)
+        {
+        iLastFocusId = newFocusId;
+        HideThumbnail();
+        ShowThumbnail(newFocusId);
+        }
+    }
+
+/**
+ * Marks specified contacts in the listbox.
+ *
+ * @param aMarkedContactIds contacts to mark.
+ * @return true if any contacts were marked in the list.
+ */
+TBool CPbkContactViewListControl::RestoreMarkedItemsL
+        (const CContactIdArray* aMarkedContactIds)
+    {
+    CEikListBox& listBox = ListBox();
+    TBool result = EFalse;
+    DisableRedrawEnablePushL();
+    listBox.ClearSelection();
+    if (aMarkedContactIds)
+        {
+        const TInt count = aMarkedContactIds->Count();
+        for (TInt i=0; i < count; ++i)
+            {
+            const TInt index = FindContactIdL((*aMarkedContactIds)[i]);
+            if (index >= 0)
+                {
+                listBox.View()->SelectItemL(index);
+                result = ETrue;
+                }
+            }
+        }
+    CleanupStack::PopAndDestroy();  // DisableRedrawEnablePushL
+    return result;
+    }
+
+/**
+ * Creates control extension for a model, appends new icons
+ * and sets this object as control updator for the extension.
+ *
+ * @param aEngine provided for control extension
+ */
+void CPbkContactViewListControl::CreateControlExtensionL
+        (CPbkContactEngine& aEngine)
+    {
+    __ASSERT_DEBUG(&Model(), Panic(EPanicPre_SetControlExtensionL));
+    __ASSERT_DEBUG(!iControlExtension, Panic(EPanicPre_SetControlExtensionL));
+
+    CPbkExtGlobals* extGlobal = CPbkExtGlobals::InstanceL();
+    extGlobal->PushL();
+    iControlExtension = extGlobal->FactoryL().
+            CreatePbkUiControlExtensionL(aEngine);
+    CleanupStack::PopAndDestroy(extGlobal);
+
+    Model().SetContactUiControlExtension(*iControlExtension);
+
+    TInt arrayInfoId = 0;
+    TInt arrayId = 0;
+    iControlExtension->IconArrayResourceId(arrayInfoId, arrayId);
+    if ( arrayInfoId != 0 )
+        {
+        IconArray(*iListBox)->AppendIconsFromResourceL(arrayInfoId, arrayId);
+        }
+
+    iControlExtension->SetContactUiControlUpdate(this);
+    }
+
+void CPbkContactViewListControl::HandleResourceChange(TInt aType)
+    {
+    CPbkContactListControlBase::HandleResourceChange(aType);
+
+    TRAP_IGNORE(DoHandleResourceChangeL(aType));
+    }
+
+void CPbkContactViewListControl::RefreshIconArrayL()
+    {
+    // Control extension may be NULL when skin is changed at run-time
+    if (iControlExtension)
+        {
+        CPbkIconArray* iconArray = IconArray(*iListBox);
+        if (iconArray)
+            {
+            // refresh the main pbk icon array
+            iconArray->RefreshL(R_PBK_ICON_INFO_ARRAY);
+            // also refresh the control extension icon array
+            TInt arrayInfoId = 0;
+            TInt arrayId = 0;
+            iControlExtension->IconArrayResourceId(arrayInfoId, arrayId);
+            if (arrayInfoId != 0)
+                {
+                iconArray->RefreshL(arrayInfoId);
+                }
+            }
+        }
+    }
+
+void CPbkContactViewListControl::DoHandleResourceChangeL(TInt aType)
+    {
+    if (aType == KAknsMessageSkinChange)
+        {
+        RefreshIconArrayL();
+        }
+    else if (aType == KEikDynamicLayoutVariantSwitch)
+        {
+        RefreshIconArrayL();
+        SizeChanged();
+        const TBool focused( IsFocused() );
+        const TBool nonFocusing( IsNonFocusing() );
+        if ( focused && !nonFocusing )
+            {
+            ShowThumbnailL();
+            }
+        DrawNow();
+        }
+    }
+
+
+// TCleanupEnableListBoxViewRedraw
+void TCleanupEnableListBoxViewRedraw::CleanupOp(TAny* aPtr)
+    {
+    static_cast<CListBoxView*>(aPtr)->SetDisableRedraw(EFalse);
+    }
+
+EXPORT_C void CPbkContactViewListControl::DeleteThumbnail()
+    {
+    delete iThumbnailPopup;
+    iThumbnailPopup = NULL;
+    }
+    
+void CPbkContactViewListControl::EnableMSKObserver( TBool aEnable )
+    {
+    iListBox->EnableMSKObserver(aEnable);
+    }
+    
+TInt CPbkContactViewListControl::ItemCount()
+    {
+    return Model().MdcaCount(); 
+    }
+
+//  End of File
+