phonebookui/Phonebook/View/src/CPbkContactInfoControl.cpp
changeset 0 e686773b3f54
child 21 9da50d567e3c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook/View/src/CPbkContactInfoControl.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,923 @@
+/*
+* 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 UI control of phonebook "Contact Info View".
+*
+*/
+
+
+// INCLUDE FILES
+#include "CPbkContactInfoControl.h"  // Class declarations
+
+#include <barsread.h>    // TResourceReader
+#include <akntitle.h>    // CAknTitlePane
+#include <aknlists.h>    // CAknDoubleGraphicStyleListBox
+#include <cntdef.h>
+#include <AknsConstants.h>
+#include <AknDef.h>      // KEikDynamicLayoutVariantSwitch
+#include <bautils.h>
+
+#include <PbkDebug.h>
+#include <PbkView.rsg>           // View resources
+#include <PbkView.hrh>
+#include "CPbkViewState.h"
+#include "CPbkThumbnailPopup.h"
+#include "CPbkFieldListBoxModel.h"
+#include <CPbkIconArray.h>
+
+#include <CPbkExtGlobals.h>
+#include <MPbkExtensionFactory.h>
+
+// PbkEng.dll
+#include <CPbkContactEngine.h>
+#include <CPbkFieldInfo.h>
+#include <CPbkContactItem.h>
+
+
+/// Unnamed namespace for local definitions
+namespace {
+
+// LOCAL CONSTANTS AND MACROS
+enum TPanicCode
+    {
+    EPanicPreCond_CurrentField = 1,
+    EPanicLogic_CurrentField,
+    EPanicPostCond_Constructor,
+    EPanicPreCond_ConstructFromResourceL,
+    EPanicPostCond_ConstructFromResourceL,
+    EPanicInvalidListBoxType,
+    EPanicPreCond_ContactItem,
+    EPanicPreCond_CurrentFieldIndex,
+    EPanicPostCond_CurrentFieldIndex,
+    EPanicPreCond_FieldPos, // 10
+    EPanicPreCond_UpdateL,
+    EPanicPostCond_UpdateL,
+    EPanicPreCond_OfferKeyEventL,
+    EPanicPreCond_SizeChanged,
+    EPanicPreCond_CountComponentControls,
+    EPanicPreCond_ComponentControl,
+    EPanicPreCond_FieldCount,
+    EPanicPreCond_ListBox
+    };
+
+void Panic(TInt aReason)
+    {
+    _LIT(KPanicText, "CPbkContactInfoControl");
+    User::Panic(KPanicText, aReason);
+    }
+
+} // namespace
+
+// MODULE DATA STRUCTURES
+
+/**
+ * listbox item drawer for CPbkContactInfoControl.
+ */
+NONSHARABLE_CLASS(CPbkContactInfoControl::CItemDrawer) :
+        public CFormattedCellListBoxItemDrawer
+    {
+    public: // interface
+        /**
+         * Constructor.
+         */
+        inline CItemDrawer(MTextListBoxModel* aTextListBoxModel,
+                const CFont* aFont,
+                CFormattedCellListBoxData* aFormattedCellData);
+
+        /**
+         * Sets iFields to aFields.
+         */
+        inline void SetFields(const CPbkFieldArray& aFields);
+
+    private: // from CListItemDrawer
+        TListItemProperties Properties(TInt aItemIndex) const;
+
+    private: // data members
+        /// Ref: array of fields.
+        const CPbkFieldArray* iFields;
+    };
+
+/**
+ * Listbox for CPbkContactInfoControl
+ */
+NONSHARABLE_CLASS(CPbkContactInfoControl::CListBox) :
+        public CAknFormDoubleGraphicStyleListBox
+    {
+    public: // constructor
+        inline CListBox();
+	    inline CItemDrawer* ItemDrawer() const;
+        inline void SetIconArray(CPbkIconArray* aIconArray);
+        inline CPbkIconArray* IconArray();
+    public: // from CEikFormattedCellListBox
+    	void CreateItemDrawerL();
+
+    };
+
+/**
+ * Data holding helper class for CPbkContactInfoControl::UpdateL().
+ */
+NONSHARABLE_CLASS(CPbkContactInfoControl::CUpdateData) :
+        public CBase
+    {
+    public:  // Interface
+        // Compiler-generated default constructor is ok for this class
+        ~CUpdateData();
+
+        /**
+         * Saves data into this object which restores aListBox's state (model,
+         * top and current item index) in this objects destructor.
+         */
+        void StoreListBoxState(CEikTextListBox& aListBox);
+
+        /**
+         * Resets any data set with StoreListBoxState().
+         */
+        inline void ResetListBoxState();
+
+    public:  // Data
+        CPbkFieldArray* iFieldArray;
+        HBufC* iTitlePaneText;
+        CPbkThumbnailPopup* iThumbnailHandler;
+        MDesCArray* iListBoxModel;
+
+    private:  // Data
+        CEikTextListBox* iListBox;
+        MDesCArray* iItemTextArray;
+        TInt iRestoreTopItem;
+        TInt iRestoreCurrentItem;
+    };
+
+
+/**
+ * Helper class for UpdateL module test.
+ */
+NONSHARABLE_CLASS(CPbkContactInfoControl::CUpdateTestData) :
+        public CBase
+    {
+    public:  // Interface
+        void ConstructL(CPbkContactInfoControl& aControl);
+        ~CUpdateTestData();
+        TBool Compare(CPbkContactInfoControl& aControl) const;
+
+    private:  // Data
+        CPbkContactItem* iContactItem;
+        TInt iTopIndex;
+        TInt iCurrentIndex;
+        CAknTitlePane* iTitlePane;
+        HBufC* iTitlePaneText;
+        CPbkFieldArray* iFieldArray;
+        CPbkThumbnailPopup* iThumbnailHandler;
+    };
+
+// ==================== LOCAL FUNCTIONS ====================
+
+template<class Type>
+inline void Swap(Type& aObj1, Type& aObj2)
+    {
+    Type tmp = aObj1;
+    aObj1 = aObj2;
+    aObj2 = tmp;
+    }
+
+
+// ================= MEMBER FUNCTIONS =======================
+inline
+CPbkContactInfoControl::CItemDrawer::CItemDrawer
+        (MTextListBoxModel* aTextListBoxModel,
+        const CFont* aFont,
+        CFormattedCellListBoxData* aFormattedCellData) :
+    CFormattedCellListBoxItemDrawer(
+        aTextListBoxModel,
+        aFont,
+        aFormattedCellData)
+    {
+    }
+
+inline
+void CPbkContactInfoControl::CItemDrawer::SetFields
+        (const CPbkFieldArray& aFields)
+    {
+    iFields = &aFields;
+    }
+
+TListItemProperties CPbkContactInfoControl::CItemDrawer::Properties
+        (TInt aItemIndex) const
+    {
+    TListItemProperties result =
+        CFormattedCellListBoxItemDrawer::Properties(aItemIndex);
+
+   // TODO: aItemIndex<iFields->Count() and aItemIndex>=0 restrictions below
+   // because class' internal data is corrupted,
+   // probably in CPbkContactInfoControl::UpdateL
+   if (iFields && aItemIndex>=0 && aItemIndex<iFields->Count() &&
+        (*iFields)[aItemIndex].DefaultPhoneNumberField())
+        {
+        // default phonenumber field prompt is underlined
+        result.SetUnderlined(ETrue);
+        }
+    return result;
+    }
+
+inline
+CPbkContactInfoControl::CListBox::CListBox()
+    {
+    }
+
+inline
+CPbkContactInfoControl::CItemDrawer* CPbkContactInfoControl::CListBox::ItemDrawer
+        (  ) const
+    {
+    return static_cast<CPbkContactInfoControl::CItemDrawer*>(CAknDoubleGraphicStyleListBox::ItemDrawer());
+    }
+
+inline
+void CPbkContactInfoControl::CListBox::SetIconArray(CPbkIconArray* aIconArray)
+    {
+    ItemDrawer()->ColumnData()->SetIconArray(aIconArray);
+    }
+
+inline
+CPbkIconArray* CPbkContactInfoControl::CListBox::IconArray()
+    {
+    return static_cast<CPbkIconArray*>(ItemDrawer()->ColumnData()->IconArray());
+    }
+
+void CPbkContactInfoControl::CListBox::CreateItemDrawerL()
+    {
+    CFormattedCellListBoxData* formattedData = CFormattedCellListBoxData::NewL();
+    CleanupStack::PushL(formattedData);
+    iItemDrawer = new(ELeave) CPbkContactInfoControl::CItemDrawer(Model(), iEikonEnv->NormalFont(), formattedData);
+    CleanupStack::Pop();
+    }
+
+CPbkContactInfoControl::CUpdateData::~CUpdateData()
+    {
+    if (iListBox)
+        {
+        iListBox->Model()->SetItemTextArray(iItemTextArray);
+        if (iRestoreTopItem >= 0) iListBox->SetTopItemIndex(iRestoreTopItem);
+        if (iRestoreCurrentItem >= 0) iListBox->SetCurrentItemIndex(iRestoreCurrentItem);
+        }
+    delete iThumbnailHandler;
+    delete iTitlePaneText;
+    delete iListBoxModel;
+    delete iFieldArray;
+    }
+
+void CPbkContactInfoControl::CUpdateData::StoreListBoxState
+        (CEikTextListBox& aListBox)
+    {
+    iListBox = &aListBox;
+    iItemTextArray = iListBox->Model()->ItemTextArray();
+    iRestoreTopItem = iListBox->TopItemIndex();
+    iRestoreCurrentItem = iListBox->CurrentItemIndex();
+    }
+
+inline void CPbkContactInfoControl::CUpdateData::ResetListBoxState()
+    {
+    iListBox = NULL;
+    }
+
+EXPORT_C CPbkContactInfoControl* CPbkContactInfoControl::NewL
+        (TInt aResId,
+        const CCoeControl& aParent,
+        CPbkContactItem* aContact,
+        CPbkContactEngine* aEngine)
+    {
+    CPbkContactInfoControl* self = new(ELeave) CPbkContactInfoControl;
+    CleanupStack::PushL(self);
+
+    self->iContactEngine = aEngine;
+    self->SetContainerWindowL(aParent);
+
+    TResourceReader reader;
+    self->iCoeEnv->CreateResourceReaderLC(reader, aResId);
+    self->ConstructFromResourceL(reader);
+    CleanupStack::PopAndDestroy();  // reader
+
+    self->UpdateL(aContact);
+    CleanupStack::Pop();  // self
+    return self;
+    }
+
+CPbkContactInfoControl::CPbkContactInfoControl()
+    {
+    iShowThumbnail = ETrue;
+    // new(ELeave) will reset member data
+    __ASSERT_DEBUG(
+        !iListBox && iFlags==0 && !iFields && !iContactItem && !iThumbnailHandler,
+        Panic(EPanicPostCond_Constructor));
+    }
+
+void CPbkContactInfoControl::ConstructFromResourceL(TResourceReader& aReader)
+    {
+    __ASSERT_DEBUG(
+        !iListBox && !iListBoxModel && iFlags==0 && !iFields && !iContactItem && !iThumbnailHandler,
+        Panic(EPanicPreCond_ConstructFromResourceL));
+
+    TPtrC emptyText = aReader.ReadTPtrC();
+    iFlags = aReader.ReadUint32();
+    const TInt listBoxType = aReader.ReadInt16();
+    // It is no more possible to specify the listbox type from resource file
+    __ASSERT_ALWAYS(listBoxType == EAknCtDoubleGraphicListBox,
+        Panic(EPanicInvalidListBoxType));
+
+    iListBox = new(ELeave) CListBox;
+    iListBox->SetContainerWindowL(*this);
+    iListBox->ConstructFromResourceL(aReader);
+    iListBox->View()->SetListEmptyTextL(emptyText);
+
+    // Load list box icons
+    TInt iconArrayRes = aReader.ReadInt32();
+	// Use granularity of 4
+    CPbkIconArray* iconArray = new(ELeave) CPbkIconArray(4);
+    CleanupStack::PushL(iconArray);
+    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
+    iListBox->SetIconArray(iconArray);
+
+    iDefaultIconId = static_cast<TPbkIconId>(aReader.ReadInt32());
+
+    // Set up the listbox
+    iListBox->CreateScrollBarFrameL(ETrue);
+    iListBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto);
+    // Take ownership of default listbox model
+    iListBoxModel = iListBox->Model()->ItemTextArray();
+    iListBox->Model()->SetOwnershipType(ELbmDoesNotOwnItemArray);
+
+    __ASSERT_DEBUG(
+        iListBox && iListBoxModel && !iFields && !iContactItem && !iThumbnailHandler,
+        Panic(EPanicPostCond_ConstructFromResourceL));
+    }
+
+CPbkContactInfoControl::~CPbkContactInfoControl()
+    {
+    delete iMarkedItemsArray;
+    delete iThumbnailHandler;
+    delete iListBox;
+    delete iListBoxModel;
+    delete iFields;
+    }
+
+void CPbkContactInfoControl::UpdateL(CPbkContactItem* aContact)
+    {
+    // PreCond:
+    __ASSERT_DEBUG(aContact && iListBox, Panic(EPanicPreCond_UpdateL));
+
+    iVoiceTagField = NULL;
+    iVoiceTagFetchCompleted = EFalse;
+
+    CUpdateData* updateData = new(ELeave) CUpdateData;
+    CleanupStack::PushL(updateData);
+    updateData->iFieldArray = new(ELeave) CPbkFieldArray(8);  // granularity of 8
+
+    CheckRingToneFieldL( aContact );
+
+    const TInt fieldCount = aContact->CardFields().Count();
+    for (TInt i = 0; i < fieldCount; ++i)
+        {
+        TPbkContactItemField& field = aContact->CardFields()[i];
+        if (!field.IsHidden() &&  // Don't show hidden fields
+            !field.IsEmptyOrAllSpaces() &&  // Don't show empty fields
+              // Don't show name fields unless specfied by flags
+            ((iFlags & KPbkContactInfoControlShowNameFields) || !field.FieldInfo().NameField()) &&
+              // Don't show image fields unless specfied by flags
+            ((iFlags & KPbkContactInfoControlShowImageFields) || !field.FieldInfo().IsImageField()))
+            {
+            updateData->iFieldArray->AppendL(field);
+            }
+        }
+
+    CEikStatusPane* statusPane = iEikonEnv->AppUiFactory()->StatusPane();
+    CAknTitlePane* titlePane = NULL;
+    if (statusPane && (iFlags & KPbkContactInfoControlUpdateStatusPane))
+        {
+        if ((iFlags & KPbkContactInfoControlUpdateTitlePane) &&
+            statusPane->PaneCapabilities(TUid::Uid(EEikStatusPaneUidTitle)).IsPresent())
+            {
+            titlePane = static_cast<CAknTitlePane*>(statusPane->ControlL(TUid::Uid(EEikStatusPaneUidTitle)));
+            updateData->iTitlePaneText = aContact->GetContactTitleOrNullL();
+            if (!updateData->iTitlePaneText)
+                {
+                updateData->iTitlePaneText = iCoeEnv->AllocReadResourceL(R_QTN_PHOB_UNNAMED);
+                }
+            }
+        if ( (iFlags & KPbkContactInfoControlUpdateContextPane) && iShowThumbnail )
+            {
+            updateData->iThumbnailHandler = CPbkThumbnailPopup::NewL(*iContactEngine);
+            updateData->iThumbnailHandler->Load(*aContact, iListBox );
+            }
+        }
+
+    // Contact must be set before setting listbox
+    iContactItem = aContact;
+
+    // Update list box
+    HBufC* timeFormat = iCoeEnv->AllocReadResourceLC(R_QTN_DATE_USUAL);
+
+	CPbkFieldListBoxModel::TParams params(
+		*updateData->iFieldArray,
+		*timeFormat,
+		*iListBox->IconArray());
+	params.iDefaultIconId = iDefaultIconId;
+	params.iFieldAnalyzer = this;
+
+	CPbkFieldListBoxModel* listBoxModel = CPbkFieldListBoxModel::NewL(params);
+    CleanupStack::PopAndDestroy();  // timeFormat
+    listBoxModel->SetClipper(*this);
+    updateData->iListBoxModel = listBoxModel;
+    updateData->StoreListBoxState(*iListBox);
+    iListBox->Model()->SetItemTextArray(updateData->iListBoxModel);
+    iListBox->Reset();
+    iListBox->UpdateScrollBarsL();
+
+    // All code that might leave has been executed succesfully
+    // -> Change state and redraw.
+    updateData->ResetListBoxState();
+    Swap(iFields, updateData->iFieldArray);
+    Swap(iListBoxModel, updateData->iListBoxModel);
+    iListBox->ItemDrawer()->SetFields(*iFields);
+    iContactItem = aContact;
+    if (titlePane && updateData->iTitlePaneText)
+        {
+        titlePane->SetText(updateData->iTitlePaneText);
+        updateData->iTitlePaneText = NULL;
+        }
+    Swap(iThumbnailHandler, updateData->iThumbnailHandler);
+
+    // Cleanup
+    CleanupStack::PopAndDestroy();  // updateData
+
+    __ASSERT_DEBUG(iListBox && iContactItem && iFields && iListBoxModel, Panic(EPanicPostCond_UpdateL));
+    __ASSERT_DEBUG(iContactItem->CardFields().Count() >= iFields->Count(), Panic(EPanicPostCond_UpdateL));
+    __ASSERT_DEBUG(&static_cast<CPbkFieldListBoxModel*>(iListBoxModel)->Array() == iFields, Panic(EPanicPostCond_UpdateL));
+    __ASSERT_DEBUG(iListBox->Model()->ItemTextArray() == iListBoxModel, Panic(EPanicPostCond_UpdateL));
+    __ASSERT_DEBUG(iListBox->Model()->NumberOfItems() == iFields->Count(), Panic(EPanicPostCond_UpdateL));
+    }
+
+CPbkContactItem& CPbkContactInfoControl::ContactItem()
+    {
+    __ASSERT_DEBUG(iContactItem, Panic(EPanicPreCond_ContactItem));
+    return *iContactItem;
+    }
+
+TPbkContactItemField* CPbkContactInfoControl::CurrentField() const
+    {
+    // PreCond:
+    __ASSERT_DEBUG(iListBox, Panic(EPanicPreCond_CurrentField));
+
+    const TInt index = iListBox->CurrentItemIndex();
+    // CPbkFieldArray will check index
+    if (index >= 0)
+        {
+        __ASSERT_DEBUG(index < iFields->Count(), Panic(EPanicLogic_CurrentField));
+        return &(*iFields)[index];
+        }
+    else
+        {
+        return NULL;
+        }
+    }
+
+EXPORT_C TInt CPbkContactInfoControl::CurrentFieldIndex
+        (  ) const
+    {
+    // PreCond:
+    __ASSERT_DEBUG(iFields, Panic(EPanicPreCond_CurrentFieldIndex));
+
+    const TPbkContactItemField* currentField = CurrentField();
+	// Initialize the index to surely errornous value
+    TInt index = -1;
+    if (currentField)
+        {
+        // Search the field in the stored fields array
+        index = iContactItem->FindFieldIndex(*currentField);
+        // Field must be found
+        __ASSERT_DEBUG(index >= 0, Panic(EPanicPostCond_CurrentFieldIndex));
+        }
+    return index;
+    }
+
+EXPORT_C TInt CPbkContactInfoControl::FieldPos(const TPbkContactItemField& aField)
+    {
+    // PreCond:
+    __ASSERT_DEBUG(iFields, Panic(EPanicPreCond_FieldPos));
+
+    for (TInt i = 0; i < iFields->Count(); ++i)
+        {
+        if ((*iFields)[i].IsSame(aField))
+            {
+            // aField found
+            return i;
+            }
+        }
+
+    // aField not found
+    return -1;
+    }
+
+EXPORT_C TInt CPbkContactInfoControl::FieldCount() const
+    {
+    // PreCond:
+    __ASSERT_DEBUG(iFields, Panic(EPanicPreCond_FieldCount));
+
+    return iFields->Count();
+    }
+
+EXPORT_C CPbkViewState* CPbkContactInfoControl::GetStateL() const
+    {
+    CPbkViewState* state = GetStateLC();
+    CleanupStack::Pop();  // state
+    return state;
+    }
+
+EXPORT_C CPbkViewState* CPbkContactInfoControl::GetStateLC() const
+    {
+    CPbkViewState* state = CPbkViewState::NewLC();
+    state->SetFocusedContactId(iContactItem->Id());
+    if (iListBox->Model()->NumberOfItems() > 0)
+        {
+        state->SetFocusedFieldIndex(CurrentFieldIndex());
+        const TInt topIndex = iListBox->TopItemIndex();
+        if (topIndex >= 0)
+            {
+            const TPbkContactItemField& topField = (*iFields)[topIndex];
+            state->SetTopFieldIndex(iContactItem->FindFieldIndex(topField));
+            }
+        }
+    return state;
+    }
+
+EXPORT_C void CPbkContactInfoControl::RestoreStateL(const CPbkViewState* aState)
+    {
+    const TInt numItems = iListBox->Model()->NumberOfItems();
+    if (aState && numItems > 0)
+        {
+        TInt focusIndex = 0;
+        TInt topIndex = 0;
+        const TInt height = iListBox->View()->NumberOfItemsThatFitInRect(iListBox->View()->ViewRect());
+
+        // The index of field to-be-focused depends on whether the shown
+        // contact is the latest contact that has been shown in ContactInfo.
+        // For re-opened contacts the focus is same as before the ContactInfo
+        // was closed. For new contact the first POC field should be focused.
+        if (aState->FocusedFieldIndex() == -1)
+            {
+            // "New" contact. Set focus to first POC field
+            for (TInt i = 0; i < iFields->Count(); i++)
+                {
+                if ((*iFields)[i].FieldInfo().IsPocField())
+                    {
+                    focusIndex = i;
+                    break;
+                    }
+                }
+            // Set top index so that focused field is bottom-most visible field
+            topIndex = Max(focusIndex - height + 1, 0);
+            }
+        else
+            {
+            // "Old" contact. Set focus to previously selected field
+            // Set top item
+            if (aState->TopFieldIndex() >= 0 && aState->TopFieldIndex() < iContactItem->CardFields().Count())
+                {
+                topIndex = Max(FieldPos(iContactItem->CardFields()[aState->TopFieldIndex()]), 0);
+                }
+
+            // Set listIndex so that maximum number of items are visible
+            if (topIndex + height > numItems)
+                {
+                topIndex += numItems - (height + topIndex);
+                if (topIndex < 0) topIndex = 0;
+                }
+
+            // Set focus
+            if (aState->FocusedFieldIndex() >= 0)
+                {
+                if (aState->FocusedFieldIndex() < iContactItem->CardFields().Count())
+                    {
+                    focusIndex = Max(FieldPos(iContactItem->CardFields()[aState->FocusedFieldIndex()]), 0);
+                    }
+                else
+                    {
+                    focusIndex = iContactItem->CardFields().Count() - 1;
+                    }
+                }
+            }
+        iListBox->SetTopItemIndex(topIndex);
+
+        // TODO: focusIndex may be invalid e.g. after contact ringing tone
+        // removal/addition.
+        if (focusIndex<0)
+            {
+            focusIndex=0;
+            }
+        else if (focusIndex>=numItems )
+            {
+            focusIndex=numItems-1;
+            }
+        iListBox->SetCurrentItemIndex(focusIndex);
+        }
+    else
+        {
+        iListBox->Reset();
+        }
+    iListBox->UpdateScrollBarsL();
+    }
+
+EXPORT_C CEikListBox& CPbkContactInfoControl::ListBox()
+    {
+    __ASSERT_DEBUG(iListBox, Panic(EPanicPreCond_ListBox));
+    return *iListBox;
+    }
+
+void CPbkContactInfoControl::HideThumbnail()
+    {
+    iShowThumbnail = EFalse;
+    if (iThumbnailHandler)
+        {
+        iThumbnailHandler->CancelLoading();
+        }
+    }
+
+void CPbkContactInfoControl::ShowThumbnailL()
+    {
+    iShowThumbnail = ETrue;
+    if (iFlags & KPbkContactInfoControlUpdateContextPane)
+        {
+        if (iContactItem)
+            {
+            if (!iThumbnailHandler)
+                {
+                iThumbnailHandler = CPbkThumbnailPopup::NewL(*iContactEngine);
+                }
+            iThumbnailHandler->Load(*iContactItem, iListBox);
+            }
+        }
+    }
+
+TKeyResponse CPbkContactInfoControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
+    {
+    __ASSERT_DEBUG(iListBox, Panic(EPanicPreCond_OfferKeyEventL));
+
+    if ( iThumbnailHandler &&
+        (aKeyEvent.iScanCode == EStdKeyUpArrow || aKeyEvent.iScanCode == EStdKeyDownArrow ))
+        {
+        iThumbnailHandler->Refresh();
+        }
+    // Forward all key events to the list box
+    return iListBox->OfferKeyEventL(aKeyEvent,aType);
+    }
+
+TInt CPbkContactInfoControl::NumberOfItems() const
+	{
+	// This control displays only one item
+	return 1;
+	}
+
+TBool CPbkContactInfoControl::ItemsMarked() const
+	{
+	// No items can be marked in this control
+	return EFalse;
+	}
+
+const CContactIdArray& CPbkContactInfoControl::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());
+    iMarkedItemsArray->AddL(FocusedContactIdL());
+
+    return *iMarkedItemsArray;
+	}
+
+TContactItemId CPbkContactInfoControl::FocusedContactIdL() const
+	{
+	return iContactItem->Id();
+	}
+
+const TPbkContactItemField* CPbkContactInfoControl::FocusedField() const
+	{
+	return CurrentField();
+	}
+
+MObjectProvider* CPbkContactInfoControl::ObjectProvider()
+    {
+    return this;
+    }
+
+TInt CPbkContactInfoControl::FocusedFieldIndex() const
+	{
+	return CurrentFieldIndex();
+	}
+
+TBool CPbkContactInfoControl::ClipFromBeginning(TDes& aBuffer, TInt aItemIndex, TInt aSubCellNumber)
+    {
+    return AknTextUtils::ClipToFit(aBuffer, AknTextUtils::EClipFromBeginning,
+        this->iListBox, aItemIndex, aSubCellNumber);
+    }
+
+TBool CPbkContactInfoControl::HasVoiceTagL(const TPbkContactItemField& aField) const
+    {
+    if (!iVoiceTagFetchCompleted)
+        {
+        iVoiceTagField = iContactItem->VoiceTagField();
+        iVoiceTagFetchCompleted = ETrue;
+        }
+    if (iVoiceTagFetchCompleted && iVoiceTagField)
+        {
+        return (!iVoiceTagField->IsEmptyOrAllSpaces() && iVoiceTagField->IsSame(aField));
+        }
+    else
+        {
+        return EFalse;
+        }
+    }
+
+TBool CPbkContactInfoControl::HasSpeedDialL(const TPbkContactItemField& aField) const
+    {
+    if (!iContactEngine)
+        {
+        return EFalse;
+        }
+
+    const TInt fieldIndex = iContactItem->FindFieldIndex(aField);
+
+    // If there is no such a field, KErrNotFound is returned as a
+    // field index.
+    if ( fieldIndex != KErrNotFound )
+        {
+        return (iContactEngine->IsSpeedDialAssigned(*iContactItem, fieldIndex));
+        }
+    else
+        {
+        return EFalse;
+        }
+    }
+
+void CPbkContactInfoControl::SizeChanged()
+    {
+    __ASSERT_DEBUG(iListBox, Panic(EPanicPreCond_SizeChanged));
+    // Listbox occupies whole area of this control
+    iListBox->SetRect(Rect());
+    }
+
+TInt CPbkContactInfoControl::CountComponentControls() const
+    {
+    __ASSERT_DEBUG(iListBox, Panic(EPanicPreCond_CountComponentControls));
+    // Always only one child control: the list box.
+    return 1;
+    }
+
+CCoeControl* CPbkContactInfoControl::ComponentControl(TInt PBK_DEBUG_ONLY(aIndex)) const
+    {
+    __ASSERT_DEBUG(iListBox && aIndex==0, Panic(EPanicPreCond_ComponentControl));
+    // Return the one and only child control
+    return iListBox;
+    }
+
+void CPbkContactInfoControl::HandleResourceChange(TInt aType)
+    {
+    CPbkContactDetailsBaseControl::HandleResourceChange(aType);
+    TRAP_IGNORE(DoHandleResourceChangeL(aType));
+    }
+
+void CPbkContactInfoControl::DoHandleResourceChangeL(TInt aType)
+    {
+    if (aType == KAknsMessageSkinChange || aType == KEikDynamicLayoutVariantSwitch)
+        {
+        CPbkIconArray* iconArray = iListBox->IconArray();
+        if (iconArray)
+            {
+            iconArray->RefreshL(R_PBK_ICON_INFO_ARRAY);
+            }
+        const TBool isNonFocusing( IsNonFocusing() );
+        if ( iContactItem )
+            {
+            if ( !isNonFocusing )
+                {
+				if (IsFocused())
+					{
+					iThumbnailHandler->Load(*iContactItem, iListBox);
+					}
+                }
+            }
+        if (aType == KEikDynamicLayoutVariantSwitch)
+            {
+            SizeChanged();
+            if ( !isNonFocusing )
+                {
+				if (IsFocused())
+					{
+					// cause also refreshing of thumbnail
+					ShowThumbnailL();
+					}
+                }
+            }
+        }
+    }
+
+
+void CPbkContactInfoControl::FocusChanged( TDrawNow aDrawNow )
+    {
+    CCoeControl::FocusChanged( aDrawNow );
+    const TBool focused( IsFocused() );
+
+    if (focused)
+        {
+        // No big deal if thumbnail is not shown
+        TRAP_IGNORE( ShowThumbnailL() );
+        }
+    else
+        {
+        HideThumbnail();
+        }
+
+    if( iListBox )
+        {
+        iListBox->SetFocus( IsFocused(), aDrawNow );
+        }
+    }
+
+void CPbkContactInfoControl::CheckRingToneFieldL( CPbkContactItem* aContact )
+    {
+    // Check is there ringtone field and if there is, check that file is still
+    // available. If not, hide the field.
+    TPbkContactItemField* ringtoneField =
+        aContact->FindField( EPbkFieldIdPersonalRingingToneIndication );
+    if ( ringtoneField )
+        {
+        if ( ringtoneField->StorageType()==KStorageTypeText )
+            {
+            if ( !BaflUtils::FileExists(
+                iContactEngine->FsSession(),
+                ringtoneField->Text()) )
+                {
+                ringtoneField->SetHidden( ETrue );
+                }
+            }
+        }
+    }
+
+// CPbkContactInfoControl::CUpdateTestData implementation
+#ifdef __TEST_UpdateL__
+void CPbkContactInfoControl::CUpdateTestData::ConstructL(CPbkContactInfoControl& aControl)
+    {
+    iContactItem = aControl.iContactItem;
+    iTopIndex = aControl.iListBox->TopItemIndex();
+    iCurrentIndex = aControl.iListBox->CurrentItemIndex();
+
+    CEikStatusPane* statusPane = static_cast<CEikonEnv*>(aControl.iCoeEnv)->AppUiFactory()->StatusPane();
+    if (statusPane && statusPane->PaneCapabilities(TUid::Uid(EEikStatusPaneUidTitle)).IsPresent())
+        {
+        iTitlePane = static_cast<CAknTitlePane*>(statusPane->ControlL(TUid::Uid(EEikStatusPaneUidTitle)));
+        iTitlePaneText = iTitlePane->Text()->AllocL();
+        }
+
+    iFieldArray = aControl.iFields;
+    iThumbnailHandler = aControl.iThumbnailHandler;
+    }
+
+CPbkContactInfoControl::CUpdateTestData::~CUpdateTestData()
+    {
+    delete iTitlePaneText;
+    }
+
+TBool CPbkContactInfoControl::CUpdateTestData::Compare(CPbkContactInfoControl& aControl) const
+    {
+    return
+        iContactItem == aControl.iContactItem &&
+        (iTopIndex < 0 || iTopIndex == aControl.iListBox->TopItemIndex()) &&
+        (iCurrentIndex < 0 || iCurrentIndex == aControl.iListBox->CurrentItemIndex()) &&
+        iTitlePaneText->Compare(*iTitlePane->Text())==0 &&
+        iFieldArray == aControl.iFields &&
+        (!iFieldArray || iFieldArray == &static_cast<CPbkFieldListBoxModel*>(aControl.iListBoxModel)->Array()) &&
+        iThumbnailHandler == aControl.iThumbnailHandler;
+    }
+#endif
+
+//  End of File