/*
* Copyright (c) 2009-2009 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 contact view double list box model.
*
*/
// INCLUDE FILES
#include <featmgr/featmgr.h>
#include <MVPbkViewContact.h>
#include "MPbk2ClipListBoxText.h"
#include "cpbk2contactviewdoublelistboxmodel.h"
#include "CPbk2ThumbnailManager.h"
#include "Pbk2PresentationUtils.h"
#include "pbk2contactuicontroldoublelistboxextension.h"
#include "pbk2contactviewdoublelistboxdataelement.h"
#include "Pbk2Debug.h"
#include <MPbk2ContactNameFormatter2.h>
#include <MPbk2ContactNameFormatter.h>
#include <MPbk2ContactUiControlExtension.h>
#include <CPbk2ContactIconsUtils.h>
#include <CPbk2IconArray.h>
#include <Pbk2InternalUID.h>
//Virtual phonebook
#include <MVPbkContactViewBase.h>
#include <MVPbkViewContact.h>
#include <MVPbkContactLink.h>
#include <MVPbkContactViewBase.h>
// CONSTANTS
namespace {
// Character used to replace invalid characters for UI
const TText KGraphicReplaceCharacter = ' ';
// Character used to separate listbox columns
const TText KListColumnSeparator = '\t';
// Index of contact name column
const TInt KNameColumn = 1;
// Index of secondary text column
const TInt KSecondaryTextColumn = 2;
// Default formating used for contacts
const TInt KDefaultListFormatting =
MPbk2ContactNameFormatter::EUseSeparator |
MPbk2ContactNameFormatter::EPreserveLeadingSpaces;
// iBuffer max size is EMaxListBoxText = 256
// -> max length for name data is 100 and max lenght for status data is 100
// rest 56 are reserved for icon data
const TInt KMaxTxtLength = 100;
const TInt KDataElementCacheSize = 20;
}
/**
* Cache for data elements, cache is made to avoid performance problems that
* caused in cases when avkon implementation calls multiple times MdcaPoint function with same index
* Cached items must be deleted when there is any change in contact list.
*/
NONSHARABLE_CLASS( CDataElementCache ) :
public CBase,
public MVPbkContactViewObserver,
public MPbk2FilteredViewStackObserver
{
public:
static CDataElementCache* NewL(MPbk2FilteredViewStack& aView);
~CDataElementCache();
void AppendL( CPbk2ContactViewDoubleListboxDataElement* aDataElement );
CPbk2ContactViewDoubleListboxDataElement* Element( TInt aListIndex );
private: // From MVPbkContactViewObserver
void ContactViewReady(
MVPbkContactViewBase& aView );
void ContactViewUnavailable(
MVPbkContactViewBase& aView );
void ContactAddedToView(
MVPbkContactViewBase& aView,
TInt aIndex,
const MVPbkContactLink& aContactLink );
void ContactRemovedFromView(
MVPbkContactViewBase& aView,
TInt aIndex,
const MVPbkContactLink& aContactLink );
void ContactViewError(
MVPbkContactViewBase& aView,
TInt aError,
TBool aErrorNotified );
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:
inline CDataElementCache( MPbk2FilteredViewStack& aView );
inline void ConstructL();
inline void Reset();
private:
RPointerArray<CPbk2ContactViewDoubleListboxDataElement> iCache;
MPbk2FilteredViewStack& iView;
};
// --------------------------------------------------------------------------
// CDataElementCache::NewL
// --------------------------------------------------------------------------
//
CDataElementCache* CDataElementCache::NewL( MPbk2FilteredViewStack& aView )
{
CDataElementCache* self = new (ELeave) CDataElementCache(aView);
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
// --------------------------------------------------------------------------
// CDataElementCache::CDataElementCache
// --------------------------------------------------------------------------
//
inline CDataElementCache::CDataElementCache( MPbk2FilteredViewStack& aView )
: iCache( KDataElementCacheSize ),
iView( aView )
{
}
// --------------------------------------------------------------------------
// CDataElementCache::ConstructL
// --------------------------------------------------------------------------
//
inline void CDataElementCache::ConstructL()
{
iView.AddObserverL(*this);
iView.AddStackObserverL(*this);
}
// --------------------------------------------------------------------------
// CDataElementCache::~CDataElementCache
// --------------------------------------------------------------------------
//
CDataElementCache::~CDataElementCache()
{
Reset();
iView.RemoveObserver(*this);
iView.RemoveStackObserver(*this);
}
// --------------------------------------------------------------------------
// CDataElementCache::AppendL
// --------------------------------------------------------------------------
//
void CDataElementCache::AppendL(
CPbk2ContactViewDoubleListboxDataElement* aDataElement )
{
iCache.InsertL( aDataElement, 0 );
const TInt cacheItemCount( iCache.Count() );
if( cacheItemCount > KDataElementCacheSize )
{
delete iCache[cacheItemCount - 1];
iCache.Remove(cacheItemCount - 1);
}
}
// --------------------------------------------------------------------------
// CDataElementCache::Reset
// --------------------------------------------------------------------------
//
inline void CDataElementCache::Reset()
{
iCache.ResetAndDestroy();
}
// --------------------------------------------------------------------------
// CDataElementCache::Element
// --------------------------------------------------------------------------
//
CPbk2ContactViewDoubleListboxDataElement*
CDataElementCache::Element( TInt aListIndex )
{
const TInt cacheItemCount( iCache.Count() );
for( TInt i = 0 ; i < cacheItemCount ; ++i )
{
CPbk2ContactViewDoubleListboxDataElement* p = iCache[i];
if( p->ListIndex() == aListIndex )
{
return p;
}
}
return NULL;
}
// --------------------------------------------------------------------------
// CDataElementCache::ContactViewReady
// --------------------------------------------------------------------------
//
void CDataElementCache::ContactViewReady(
MVPbkContactViewBase& /*aView*/ )
{
Reset();
}
// --------------------------------------------------------------------------
// CDataElementCache::ContactViewUnavailable
// --------------------------------------------------------------------------
//
void CDataElementCache::ContactViewUnavailable(
MVPbkContactViewBase& /*aView*/ )
{
Reset();
}
// --------------------------------------------------------------------------
// CDataElementCache::ContactAddedToView
// --------------------------------------------------------------------------
//
void CDataElementCache::ContactAddedToView(
MVPbkContactViewBase& /*aView*/,
TInt /*aIndex*/,
const MVPbkContactLink& /*aContactLink*/ )
{
Reset();
}
// --------------------------------------------------------------------------
// CDataElementCache::ContactRemovedFromView
// --------------------------------------------------------------------------
//
void CDataElementCache::ContactRemovedFromView(
MVPbkContactViewBase& /*aView*/,
TInt /*aIndex*/,
const MVPbkContactLink& /*aContactLink*/ )
{
Reset();
}
// --------------------------------------------------------------------------
// CDataElementCache::ContactViewError
// --------------------------------------------------------------------------
//
void CDataElementCache::ContactViewError(
MVPbkContactViewBase& /*aView*/,
TInt /*aError*/,
TBool /*aErrorNotified*/ )
{
Reset();
}
// --------------------------------------------------------------------------
// CDataElementCache::TopViewChangedL
// --------------------------------------------------------------------------
//
void CDataElementCache::TopViewChangedL(
MVPbkContactViewBase& /*aOldView*/ )
{
Reset();
}
// --------------------------------------------------------------------------
// CDataElementCache::TopViewUpdatedL
// --------------------------------------------------------------------------
//
void CDataElementCache::TopViewUpdatedL()
{
Reset();
}
// --------------------------------------------------------------------------
// CDataElementCache::BaseViewChangedL
// --------------------------------------------------------------------------
//
void CDataElementCache::BaseViewChangedL()
{
Reset();
}
// --------------------------------------------------------------------------
// CDataElementCache::ViewStackError
// --------------------------------------------------------------------------
//
void CDataElementCache::ViewStackError(
TInt /*aError*/ )
{
Reset();
}
// --------------------------------------------------------------------------
// CDataElementCache::ContactAddedToBaseView
// --------------------------------------------------------------------------
//
void CDataElementCache::ContactAddedToBaseView(
MVPbkContactViewBase& /*aBaseView*/,
TInt /*aIndex*/,
const MVPbkContactLink& /*aContactLink*/ )
{
Reset();
}
// --------------------------------------------------------------------------
// CPbk2ContactViewDoubleListBoxModel::CPbk2ContactViewDoubleListBoxModel
// --------------------------------------------------------------------------
//
CPbk2ContactViewDoubleListBoxModel::CPbk2ContactViewDoubleListBoxModel(
CPbk2ContactViewListBoxModel::TParams& aParams,
CPbk2ThumbnailManager& aThumbManager,
MPbk2FilteredViewStack& aFilteredViewStack ) :
CPbk2ContactViewListBoxModel( aParams ),
iThumbManager( aThumbManager ),
iFilteredViewStack( aFilteredViewStack )
{
TAny* object = aParams.iUiExtension->ContactUiControlExtensionExtension
( TUid::Uid( KPbk2ContactUiControlExtensionExtensionUID ) );
iDoubleListExtensionPoint =
static_cast<MPbk2ContactUiControlDoubleListboxExtension*>( object );
}
// --------------------------------------------------------------------------
// CPbk2ContactViewDoubleListBoxModel::~CPbk2ContactViewDoubleListBoxModel
// --------------------------------------------------------------------------
//
CPbk2ContactViewDoubleListBoxModel::~CPbk2ContactViewDoubleListBoxModel()
{
delete iDataElementCache;
}
// --------------------------------------------------------------------------
// CPbk2ContactViewDoubleListBoxModel::NewL
// --------------------------------------------------------------------------
//
CPbk2ContactViewDoubleListBoxModel* CPbk2ContactViewDoubleListBoxModel::NewL(
CPbk2ContactViewListBoxModel::TParams& aParams,
CPbk2ThumbnailManager& aThumbManager,
MPbk2FilteredViewStack& aFilteredViewStack )
{
CPbk2ContactViewDoubleListBoxModel* self =
new ( ELeave ) CPbk2ContactViewDoubleListBoxModel(
aParams, aThumbManager, aFilteredViewStack );
CleanupStack::PushL(self);
self->ConstructL( aParams.iStoreProperties, aParams.iUiExtension );
self->iDataElementCache = CDataElementCache::NewL( aFilteredViewStack );
CleanupStack::Pop();
return self;
}
// --------------------------------------------------------------------------
// CPbk2ContactViewDoubleListBoxModel::FormatBufferL
// --------------------------------------------------------------------------
//
void CPbk2ContactViewDoubleListBoxModel::FormatBufferL( const TInt aIndex ) const
{
PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
("CPbk2ContactViewDoubleListBoxModel::FormatBufferL(0x%x,%d), begin"),
this);
CPbk2ContactViewDoubleListboxDataElement* element =
iDataElementCache->Element( aIndex );
if( element )
{
FormatBufferForElementDataL(*element, aIndex);
}
else
{
const MVPbkViewContact& contact = iView->ContactAtL(aIndex);
FormatBufferForContactL(contact, aIndex );
}
PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
("CPbk2ContactViewDoubleListBoxModel::FormatBufferL(0x%x,%d), end"),
this);
}
// --------------------------------------------------------------------------
// CPbk2ContactViewDoubleListBoxModel::FormatBufferForElementDataL
// --------------------------------------------------------------------------
//
void CPbk2ContactViewDoubleListBoxModel::FetchDataFromExtension(
CPbk2ContactViewDoubleListboxDataElement& aDataElement,
TInt aIndex ) const
{
// Get element data from extension
//
if( iDoubleListExtensionPoint )
{
TRAPD( err,
iDoubleListExtensionPoint->FormatDataL(
*(aDataElement.ContactLink()), aDataElement ) );
if( err )
{
// extension's errors are ignored.
PBK2_DEBUG_PRINT( PBK2_DEBUG_STRING(
"CPbk2ContactViewDoubleListBoxModel::FormatBufferForElementDataL format error %d"),
err );
}
}
// Clip secondary text if it's a phone number
if( MPbk2DoubleListboxDataElement::ETypePhoneNumber ==
aDataElement.TextType( MPbk2DoubleListboxDataElement::EStatusText ) &&
iClipListBoxText )
{
TPtr secondary( aDataElement.TextPtr(
MPbk2DoubleListboxDataElement::EStatusText ) );
iClipListBoxText->ClipFromBeginning(
secondary, aIndex, KSecondaryTextColumn );
}
}
// --------------------------------------------------------------------------
// CPbk2ContactViewDoubleListBoxModel::FormatBufferForElementDataL
// --------------------------------------------------------------------------
//
void CPbk2ContactViewDoubleListBoxModel::FormatBufferForElementDataL(
CPbk2ContactViewDoubleListboxDataElement& aDataElement,
TInt aIndex ) const
{
FetchDataFromExtension(aDataElement, aIndex);
// start fill the new buffer for the avkon list
iBuffer.Zero();
AppendThumbnailL( aDataElement, aIndex );
// Format line buffer based on element's content
FormatBufferFromElement( aDataElement );
}
// --------------------------------------------------------------------------
// CPbk2ContactViewDoubleListBoxModel::FormatBufferForContactL
// --------------------------------------------------------------------------
//
void CPbk2ContactViewDoubleListBoxModel::FormatBufferForContactL(
const MVPbkViewContact& aViewContact,
TInt aIndex ) const
{
MVPbkContactLink* link = aViewContact.CreateLinkLC();
CPbk2ContactViewDoubleListboxDataElement* element =
CPbk2ContactViewDoubleListboxDataElement::NewL( link, aIndex );
CleanupStack::Pop(); // link
CleanupStack::PushL( element );
// get data for element
// get user name
HBufC* name = NULL;
if( FeatureManager::FeatureSupported( KFeatureIdFfContactsCompanyNames ))
{
MPbk2ContactNameFormatter2* nameformatterExtension =
reinterpret_cast<MPbk2ContactNameFormatter2*>(iNameFormatter.
ContactNameFormatterExtension( MPbk2ContactNameFormatterExtension2Uid ) );
name = nameformatterExtension->GetContactTitleWithCompanyNameL(
aViewContact.Fields(), KDefaultListFormatting );
}
else
{
name = iNameFormatter.GetContactTitleL(
aViewContact.Fields(), KDefaultListFormatting );
}
CleanupStack::PushL( name );
TPtr namePtr( name->Des() );
// Replace characters that can not be displayed correctly
Pbk2PresentationUtils::ReplaceNonGraphicCharacters(
namePtr, KGraphicReplaceCharacter );
if( CutFromBeginningFieldL( aViewContact.Fields() ) && iClipListBoxText )
{
iClipListBoxText->ClipFromBeginning( namePtr, aIndex, KNameColumn );
}
// takes ownership of 'name'
element->SetText( MPbk2DoubleListboxDataElement::EName, name,
MPbk2DoubleListboxDataElement::ETypeGenericText );
CleanupStack::Pop( name );
// get icons
RArray<TPbk2IconId> ids;
CleanupClosePushL( ids );
iContactIcons->GetIconIdsForContactL( aViewContact, ids );
// ids should contain at least one empty icon in any case
if( ids.Count() == 0 )
{
ids.Append( iEmptyIconId );
}
element->SetIconId( MPbk2DoubleListboxDataElement::EMainIcon, ids[0] );
CleanupStack::PopAndDestroy( &ids );
// Get element data from extension
FetchDataFromExtension( *element, aIndex );
// start format data for the avkon list
iBuffer.Zero();
AppendThumbnailL( *element, aIndex );
// Format line buffer based on element's content
FormatBufferFromElement( *element );
iDataElementCache->AppendL( element );
CleanupStack::Pop( element );
}
// --------------------------------------------------------------------------
// CPbk2ContactViewDoubleListBoxModel::FormatBufferFromElement
// --------------------------------------------------------------------------
//
void CPbk2ContactViewDoubleListBoxModel::FormatBufferFromElement(
const CPbk2ContactViewDoubleListboxDataElement& aElement ) const
{
// List model format:
// [thumbnail icon] \t [contact name] \t [secondary text] \t
// [trailing icon]
// (2) Contact name
AppendName( aElement.TextPtr(
MPbk2DoubleListboxDataElement::EName ).Left( KMaxTxtLength ) );
iBuffer.Append( KListColumnSeparator );
// (3) Secondary text
TPtr status( aElement.TextPtr( MPbk2DoubleListboxDataElement::EStatusText ) );
AppendText( status );
// (4) Trailing icon
AppendIconIndexIfFound(
aElement.IconId( MPbk2DoubleListboxDataElement::EMainIcon ) );
}
// --------------------------------------------------------------------------
// CPbk2ContactViewDoubleListBoxModel::AppendThumbnailL
// --------------------------------------------------------------------------
//
void CPbk2ContactViewDoubleListBoxModel::AppendThumbnailL(
CPbk2ContactViewDoubleListboxDataElement& aDataElement,
TInt aIndex ) const
{
// (1) Add thumbnail icon
//
TInt index = iThumbManager.GetPbkIconIndexL(
aIndex, *(aDataElement.ContactLink()) );
if( index != KErrNotFound )
{
iBuffer.AppendNum( index );
}
iBuffer.Append( KListColumnSeparator );
}
// --------------------------------------------------------------------------
// CPbk2ContactViewDoubleListBoxModel::AppendText
// --------------------------------------------------------------------------
//
void CPbk2ContactViewDoubleListBoxModel::AppendText( TDes& aText ) const
{
//Convert numbers to some languages specific version. E.g.: Arabic.
AknTextUtils::DisplayTextLanguageSpecificNumberConversion( aText );
// replace non-allowed characters with ' '
Pbk2PresentationUtils::ReplaceNonGraphicCharacters(
aText, KGraphicReplaceCharacter );
AknTextUtils::ReplaceCharacters(
aText, KAknReplaceListControlChars, KGraphicReplaceCharacter );
iBuffer.Append( aText.Left( KMaxTxtLength ) );
iBuffer.Append( KListColumnSeparator );
}
// --------------------------------------------------------------------------
// CPbk2ContactViewDoubleListBoxModel::AppendIconIndexIfFound
// --------------------------------------------------------------------------
//
void CPbk2ContactViewDoubleListBoxModel::AppendIconIndexIfFound( const TPbk2IconId& aIconId ) const
{
TInt iconIndex = iIconArray->FindIcon( aIconId );
// if icon is found
if( iconIndex != KErrNotFound )
{
iBuffer.AppendNum( iconIndex );
iBuffer.Append( KListColumnSeparator );
}
}
// End of File