/*
* Copyright (c) 2005-2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Top Contact opeartion
*
*/
// INCLUDES
#include "CVPbkTopContactOperation.h"
#include <barsc.h>
#include <barsread.h>
#include <MVPbkContactViewBase.h>
#include <VPbkStoreUriLiterals.h>
#include <CVPbkContactViewDefinition.h>
#include <CVPbkContactLinkArray.h>
#include <MVPbkContactLink.h>
#include <MVPbkContactOperationBase.h>
#include <MVPbkContactStoreProperties.h>
#include <MVPbkContactStoreList.h>
#include <CVPbkContactStoreUriArray.h>
#include <TVPbkFieldTypeMapping.h>
#include <MVPbkContactFieldTextData.h>
#include <CVPbkFieldTypeSelector.h>
#include <MVPbkFieldType.h>
#include <CVPbkContactManager.h>
#include <MVPbkContactStore.h>
#include <VPbkContactViewFilterBuilder.h>
#include <CVPbkSortOrder.h>
#include <VPbkEng.rsg>
#include <VPbkDataCaging.hrh>
#include <RLocalizedResourceFile.h>
#include <TVPbkFieldVersitProperty.h>
#include "CVPbkContactEasyManager.h"
#include "VPbkDebug.h"
#include <CVPbkSortOrderAcquirer.h>
#include <CVPbkEComImplementationsList.h>
#include <VPbkSortOrderAcquirerUid.h>
namespace
{
const TInt KFirstTopOrderIndex = 1;
const TInt KTcFieldLength = 10;
_LIT( KAllContactsSortOrderDisplayName, "AllContacts" );
/**
* Custom cleanup function.
*
* @param aObj Object to clean.
*/
void CleanupResetAndDestroy( TAny* aObj )
{
if ( aObj )
{
static_cast<RImplInfoPtrArray*>( aObj )->ResetAndDestroy();
}
}
#ifdef _DEBUG
enum TTopErrors
{
ETopErrorWrongLogic1,
ETopErrorWrongLogic2,
ETopErrorWrongLogic3,
EInvalidViewOperation,
EInvalidLinksOperation,
EInvalidTopOperation,
ETopErrorAlreadyHaveAStore,
ETopErrorAlreadyHaveAView,
ETopErrorNoView,
ETopErrorNoFieldData,
ETopErrorNoLinks,
ETopViewMissing,
ETopErrorBadIndex,
ETopErrorOldArrayExists,
ETopErrorNoContacts,
ETopErrorWrongState,
ETopErrorWrongStateRun,
};
_LIT( KPanicStrTopManagement, "VPbk_topManag");
void Panic(TTopErrors aReason)
{
User::Panic(KPanicStrTopManagement,aReason);
}
#endif
}
///////////////////////////////////////////////////////////////////////////////
CVPbkTopContactOperation* CVPbkTopContactOperation::NewLC(
CVPbkContactManager& aContactManager,
MVPbkOperationErrorObserver& aErrorObserver,
TTopOperation aOperation)
{
CVPbkTopContactOperation* self = new (ELeave) CVPbkTopContactOperation(
aContactManager,
aErrorObserver,
aOperation );
CleanupStack::PushL( self );
self->ConstructL();
return self;
}
void CVPbkTopContactOperation::ConstructL()
{
iContactEasyManager = CVPbkContactEasyManager::NewL( iContactManager );
}
CVPbkTopContactOperation::CVPbkTopContactOperation(
CVPbkContactManager& aContactManager,
MVPbkOperationErrorObserver& aErrorObserver,
TTopOperation aOperation )
: CActive( EPriorityStandard ),
iCurrentOperation(aOperation),
iNextState(EStateOpenStore),
iContactManager(aContactManager),
iErrorObserver(&aErrorObserver)
{
CActiveScheduler::Add( this );
CompleteOurself(); //start execution right away
}
CVPbkTopContactOperation::~CVPbkTopContactOperation()
{
Cancel();
delete iContactOperation;
delete iContactEasyManager;
iContacts.ResetAndDestroy();
delete iInputLinks;
delete iView;
if ( iContactStore )
{
// Store is not owned by us.
iContactStore->Close( *this );
}
}
MVPbkContactOperationBase* CVPbkTopContactOperation::NewGetViewOperationL(
CVPbkContactManager& aContactManager,
MVPbkOperationResultObserver<MVPbkContactViewBase*>& aObserver,
MVPbkOperationErrorObserver& aErrorObserver,
TTopOperation aOperation )
{
__ASSERT_DEBUG( aOperation == EGetTopContacts ||
aOperation == EGetNonTopContacts,
Panic(EInvalidViewOperation) );
CVPbkTopContactOperation* self = NewLC(
aContactManager,
aErrorObserver,
aOperation );
self->iViewObserver = &aObserver;
CleanupStack::Pop(self);
return self;
}
MVPbkContactOperationBase* CVPbkTopContactOperation::NewGetViewLinksOperationL(
CVPbkContactManager& aContactManager,
MVPbkOperationResultObserver<MVPbkContactLinkArray*>& aObserver,
MVPbkOperationErrorObserver& aErrorObserver,
TTopOperation aOperation )
{
__ASSERT_DEBUG( aOperation == EGetTopContactLinks ||
aOperation == EGetNonTopContactLinks,
Panic(EInvalidLinksOperation) );
CVPbkTopContactOperation* self = NewLC(
aContactManager,
aErrorObserver,
aOperation );
self->iLinksObserver = &aObserver;
CleanupStack::Pop(self);
return self;
}
MVPbkContactOperationBase* CVPbkTopContactOperation::NewTopOperationL(
CVPbkContactManager& aContactManager,
const MVPbkContactLinkArray& aContactLinks,
MVPbkOperationObserver& aObserver,
MVPbkOperationErrorObserver& aErrorObserver,
TTopOperation aOperation )
{
__ASSERT_DEBUG( aOperation == EAddToTop || aOperation == ERemoveFromTop ||
aOperation == EReorderTop,
Panic(EInvalidTopOperation) );
CVPbkTopContactOperation* self = NewLC(
aContactManager,
aErrorObserver,
aOperation );
self->iObserver = &aObserver;
self->iInputLinks = CloneArrayL( aContactLinks );
CleanupStack::Pop(self);
return self;
}
void CVPbkTopContactOperation::DoCancel()
{
delete iContactOperation;
iContactOperation = NULL;
iContactEasyManager->Cancel();
}
void CVPbkTopContactOperation::RunL()
{
if ( iNextState == EStateAbortWithError )
{
NotifyError( iAbortError );
}
else
{
switch ( iCurrentOperation )
{
case EAddToTop:
case ERemoveFromTop:
case EReorderTop:
{
Top_RunL();
break;
}
case EGetNonTopContacts:
case EGetTopContacts:
case EGetTopContactLinks:
case EGetNonTopContactLinks:
{
GetView_RunL();
break;
}
default:
__ASSERT_DEBUG( EFalse,
Panic( ETopErrorWrongStateRun ) );
}
}
}
TInt CVPbkTopContactOperation::RunError( TInt aError )
{
NotifyError( aError );
return KErrNone;
}
//---------------------------------------------------------------
// These are from MVPbkContactViewObserver
void CVPbkTopContactOperation::ContactViewReady(
MVPbkContactViewBase& aView )
{
aView.RemoveObserver(*this);
CompleteOurself();
}
void CVPbkTopContactOperation::ContactViewUnavailable(
MVPbkContactViewBase& aView )
{
aView.RemoveObserver(*this);
AbortWithError( KErrGeneral );
}
void CVPbkTopContactOperation::ContactAddedToView(
MVPbkContactViewBase& /*aView*/,
TInt /*aIndex*/,
const MVPbkContactLink& /*aContactLink*/ )
{
}
void CVPbkTopContactOperation::ContactRemovedFromView(
MVPbkContactViewBase& /*aView*/,
TInt /*aIndex*/,
const MVPbkContactLink& /*aContactLink*/ )
{
}
void CVPbkTopContactOperation::ContactViewError(
MVPbkContactViewBase& /*aView*/,
TInt aError,
TBool /*aErrorNotified*/ )
{
AbortWithError( aError );
}
//---------------------------------------------------------------
// These are from MVPbkContactStoreObserver
void CVPbkTopContactOperation::StoreReady(MVPbkContactStore& /*aContactStore*/)
{
CompleteOurself();
}
void CVPbkTopContactOperation::StoreUnavailable(
MVPbkContactStore& /*aContactStore*/, TInt aReason)
{
AbortWithError( aReason );
}
void CVPbkTopContactOperation::HandleStoreEventL(
MVPbkContactStore& /*aContactStore*/,
TVPbkContactStoreEvent /*aStoreEvent*/)
{
}
//---------------------------------------------------------------
// These are from MVPbkBatchOperationObserver
void CVPbkTopContactOperation::StepComplete(
MVPbkContactOperationBase& /*aOperation*/,
TInt /*aStepSize*/ )
{
// Ignore.
}
TBool CVPbkTopContactOperation::StepFailed(
MVPbkContactOperationBase& /*aOperation*/,
TInt /*aStepSize*/, TInt aError )
{
AbortWithError( aError );
delete iContactOperation;
iContactOperation = NULL;
return EFalse; // do not continue
}
void CVPbkTopContactOperation::OperationComplete(
MVPbkContactOperationBase& /*aOperation*/ )
{
// Committing of contacts has completed.
delete iContactOperation;
iContactOperation = NULL;
iContacts.ResetAndDestroy();
//can leave only when returning links
TRAP_IGNORE(NotifyResultL());
}
//---------------------------------------------------------------
// From MVPbkContactEasyManagerObserver
void CVPbkTopContactOperation::VPbkOperationCompleted(
MVPbkContactOperationBase* /*aOperation*/)
{
// Retrieving and locking of contacts is now complete.
CompleteOurself();
// Continue processing in RunL()
}
void CVPbkTopContactOperation::VPbkOperationFailed(
MVPbkContactOperationBase* /*aOperation*/,
TInt aError )
{
AbortWithError( aError );
}
// --------------------------------------------------------------------------
// Creates contact link array from a contact view.
// --------------------------------------------------------------------------
MVPbkContactLinkArray* CVPbkTopContactOperation::ViewToLinkArrayL(
const MVPbkContactViewBase& aView )
{
CVPbkContactLinkArray* links = CVPbkContactLinkArray::NewLC();
TInt count = aView.ContactCountL();
for ( TInt n = 0; n < count; ++n )
{
MVPbkContactLink* link = aView.CreateLinkLC( n );
links->AppendL( link );
CleanupStack::Pop(); // link
}
CleanupStack::Pop( links );
return links;
}
// --------------------------------------------------------------------------
// Loads and opens contact store
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::OpenStoreL( const TVPbkContactStoreUriPtr& aUri )
{
// First need to open the store.
iContactManager.LoadContactStoreL( aUri );
iContactStore = iContactManager.ContactStoresL().Find( aUri );
// Asynchronous opening call.
iContactStore->OpenL(*this);
}
// --------------------------------------------------------------------------
// Loads and opens default contact store
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::OpenDefaultStoreL()
{
TVPbkContactStoreUriPtr uri( KVPbkDefaultCntDbURI );
OpenStoreL( uri );
}
// --------------------------------------------------------------------------
// Requests a top contact view. The completion is signalled to this
// object through MVPbkContactViewObserver. The observer callback will pass
// the event on in a certain way that is dependent on the current iState
// value.
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::RequestTopContactsViewL()
{
__ASSERT_DEBUG( !iView, Panic(ETopErrorAlreadyHaveAView) );
CVPbkContactViewDefinition* viewDef = CVPbkContactViewDefinition::NewLC();
viewDef->SetUriL( KVPbkDefaultCntDbURI );
CVPbkFieldTypeSelector* filter = CVPbkFieldTypeSelector::NewL(
iContactManager.FieldTypes());
CleanupStack::PushL(filter);
VPbkContactViewFilterBuilder::BuildContactViewFilterL( *filter,
TVPbkContactViewFilter(EVPbkContactViewFilterTopContact), iContactManager );
viewDef->SetFieldTypeFilterL( filter );
CleanupStack::PopAndDestroy( filter );
CVPbkSortOrderAcquirer* soa = AllContactsSortOrderL();
CleanupStack::PushL(soa);
iView = iContactManager.CreateContactViewLC(
*this, *viewDef, soa->SortOrder() );
CleanupStack::Pop(); // iView
CleanupStack::PopAndDestroy( soa );
CleanupStack::PopAndDestroy( viewDef );
}
// --------------------------------------------------------------------------
// Requests a top contact view. The completion is signalled to this
// object through MVPbkContactViewObserver. The observer callback will pass
// the event on in a certain way that is dependent on the current iState
// value.
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::RequestNonTopContactsViewL()
{
__ASSERT_DEBUG( !iView, Panic(ETopErrorAlreadyHaveAView) );
CVPbkContactViewDefinition* viewDef = CVPbkContactViewDefinition::NewLC();
viewDef->SetUriL( KVPbkDefaultCntDbURI );
CVPbkSortOrderAcquirer* soa = AllContactsSortOrderL();
CleanupStack::PushL(soa);
// Add the Non-Top Contacts selector
// No filter (i.e. with a field x) is used
// but a contact selector
viewDef->SetContactSelector(this); // ownership not transferred
iView = iContactManager.CreateContactViewLC(
*this, *viewDef, soa->SortOrder() );
CleanupStack::Pop(); // iView
CleanupStack::PopAndDestroy( soa );
CleanupStack::PopAndDestroy( viewDef );
}
// --------------------------------------------------------------------------
// The RunL handler for top operations.
// --------------------------------------------------------------------------
inline void CVPbkTopContactOperation::Top_RunL()
{
if ( iNextState == EStateOpenStore )
{
if ( iInputLinks->Count() > 0 )
{
// view is needed for AddToTop operation to get next top index
if ( iCurrentOperation == EAddToTop )
{
iNextState = EStateCreateView;
}
else
{
iNextState = EStateRetrieveLock;
}
OpenStoreL( iInputLinks->At(0).ContactStore().StoreProperties().Uri() );
}
else
{
// Empty input array is ok do nothing
// just signal completion right away
iNextState = EStateNone;
NotifyResultL();
}
}
else if ( iNextState == EStateCreateView )
{
iNextState = EStateRetrieveLock;
RequestTopContactsViewL();
// When view is ready, we come back to this function.
}
else if ( iNextState == EStateRetrieveLock )
{
iNextState = EStateModifyCommit;
iContactEasyManager->RetrieveAndLockContactsL(
*iInputLinks, iContacts, *this, *this );
// The contacts are placed into iContacts.
// Completion is signalled to our callback, which
// will complete ourself so we come back here to the next state.
}
else if ( iNextState == EStateModifyCommit )
{
DoTopOperationL();
iNextState = EStateNone;
iContactOperation = iContactManager.CommitContactsL(
iContacts.Array(), *this );
// Completion is signalled to our callback, where our observer is
// called for informing that everything is done.
}
}
// --------------------------------------------------------------------------
// Perform actual contact modification, add, remove or change toppnes
// depending on the operation
// --------------------------------------------------------------------------
inline void CVPbkTopContactOperation::DoTopOperationL()
{
switch( iCurrentOperation )
{
case EAddToTop:
{
// get next top index and delete the view right away,
__ASSERT_DEBUG( iView, Panic(ETopViewMissing) );
TInt nextTopIndex = NextTopOrderIndexL( *iView );
__ASSERT_DEBUG( nextTopIndex >= 0, Panic(ETopErrorBadIndex) );
delete iView;
iView = NULL;
SetTopOrderToContactsL( iContacts, nextTopIndex );
break;
}
case ERemoveFromTop:
{
RemoveTopnessFromContacts( iContacts );
break;
}
case EReorderTop:
{
ReorderContactsL( iContacts );
break;
}
default:
__ASSERT_DEBUG( EFalse, Panic(ETopErrorWrongState) );
}
}
// --------------------------------------------------------------------------
// The RunL handler for get view/links operation.
// --------------------------------------------------------------------------
inline void CVPbkTopContactOperation::GetView_RunL()
{
if ( iNextState == EStateOpenStore )
{
iNextState = EStateCreateView;
OpenDefaultStoreL();
}
else if ( iNextState == EStateCreateView )
{
iNextState = EStateNone;
switch( iCurrentOperation )
{
case EGetTopContacts:
case EGetTopContactLinks:
{
RequestTopContactsViewL();
break;
}
case EGetNonTopContacts:
case EGetNonTopContactLinks:
{
RequestNonTopContactsViewL();
break;
}
default:
__ASSERT_DEBUG( EFalse, Panic(ETopErrorWrongState) );
}
}
else
{
__ASSERT_DEBUG( iNextState == EStateNone, Panic(ETopErrorWrongState) );
// The view is ready.
NotifyResultL();
}
}
// --------------------------------------------------------------------------
// Finds out what is the top ordering index for new top contacts.
// It looks at the collection of top contacts in iView which has been fetched
// earlier.
// @return The next top index, or KFirstTopOrderIndex if no valid data was found.
// --------------------------------------------------------------------------
TInt CVPbkTopContactOperation::NextTopOrderIndexL(
const MVPbkContactViewBase& aView )
{
const TInt count = aView.ContactCountL();
TInt result = KFirstTopOrderIndex; // The default if no tops exist yet.
if ( count > 0 )
{
// Take the last contact.
const MVPbkViewContact& contact = aView.ContactAtL( count - 1 );
const TInt orderValue = TopOrder( contact );
// Check the validity of the stored value.
if ( orderValue >= KFirstTopOrderIndex && orderValue < KMaxTInt )
{
// Yes the value is OK.
// Offset of one from existing last top contact.
result = orderValue + 1;
}
}
return result;
}
// --------------------------------------------------------------------------
// Completes this active object.
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::CompleteOurself()
{
if ( !IsActive() )
{
TRequestStatus* status = &iStatus;
User::RequestComplete( status, KErrNone );
SetActive();
}
else
{
__ASSERT_DEBUG( EFalse, Panic(ETopErrorWrongLogic3) );
}
}
// --------------------------------------------------------------------------
// Clone contact link array, used to copy input link array
// --------------------------------------------------------------------------
CVPbkContactLinkArray* CVPbkTopContactOperation::CloneArrayL(
const MVPbkContactLinkArray& aArray )
{
CVPbkContactLinkArray* newArray = CVPbkContactLinkArray::NewLC();
const TInt count = aArray.Count();
for ( TInt n = 0; n < count; ++n )
{
MVPbkContactLink* link = aArray.At(n).CloneLC();
newArray->AppendL( link );
CleanupStack::Pop(); // link
}
CleanupStack::Pop( newArray );
return newArray;
}
// --------------------------------------------------------------------------
// Sets the top contact data to the contacts.
// Does not commit the contacts.
// The contacts might already have some top data. If not then
// the data holder is created.
// @param aContacts The contacts to be modified.
// @param aHighestOrderIndex The value from which ordering starts. The order
// value increases in steps of one.
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::SetTopOrderToContactsL(
RPointerArray<MVPbkStoreContact>& aContacts,
TInt aHighestOrderIndex )
{
TInt topOrderIndex = aHighestOrderIndex;
const TInt count = aContacts.Count();
for ( TInt n = 0; n < count; ++ n )
{
MVPbkStoreContact& contact = *aContacts[ n ];
SetTopOrderL( contact, topOrderIndex );
++topOrderIndex;
}
}
// --------------------------------------------------------------------------
// Remove "top" field from contacts
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::RemoveTopnessFromContacts(
RPointerArray<MVPbkStoreContact>& aContacts )
{
const TInt count = aContacts.Count();
for ( TInt n = 0; n < count; ++ n )
{
MVPbkStoreContact& contact = *aContacts[ n ];
RemoveTopnessFromContact( contact );
}
}
// --------------------------------------------------------------------------
// Find and remove the "top" field from a contact
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::RemoveTopnessFromContact(
MVPbkStoreContact& aContact )
{
MVPbkStoreContactFieldCollection& fields = aContact.Fields();
const TInt count = fields.FieldCount();
for ( TInt n = 0; n < count; ++n )
{
TVPbkFieldVersitProperty versitProp;
versitProp.SetName(EVPbkVersitNameTopContact);
const MVPbkFieldType* fieldType = fields.FieldAt(n).BestMatchingFieldType();
if ( fieldType && fieldType->Matches(versitProp, 0) )
{
aContact.RemoveField( n );
break;
}
}
}
// --------------------------------------------------------------------------
// Change contacts "top" field according to their relative order
// in the input array. Reuses top values the contacts
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::ReorderContactsL(
RPointerArray<MVPbkStoreContact>& aContacts )
{
const TInt count = aContacts.Count();
RArray<TInt> topOrders;
RPointerArray<MVPbkStoreContact> contactsToBeReordered; // does not own
CleanupClosePushL(topOrders);
CleanupClosePushL(contactsToBeReordered);
for ( TInt n = 0; n < count; ++n )
{
const MVPbkStoreContact& contact = *aContacts[ n ];
const TInt topOrder = TopOrder( contact );
if ( topOrder >= 0 )
{
// Yes it is a top contact.
User::LeaveIfError( contactsToBeReordered.Append( &contact ) );
topOrders.AppendL( topOrder );
}
}
topOrders.Sort();
// Now set the order values. Reuse the old order values, but assign them
// now to different contacts.
const TInt reorderCount = topOrders.Count();
for ( TInt i = 0; i < reorderCount; ++i )
{
MVPbkStoreContact& contact = *contactsToBeReordered[ i ];
SetTopOrderL( contact, topOrders[ i ] );
}
CleanupStack::PopAndDestroy(); //contactsToBeReordered
CleanupStack::PopAndDestroy(); // topOrders
}
// --------------------------------------------------------------------------
// Returns field type for the top field type
// --------------------------------------------------------------------------
const MVPbkFieldType& CVPbkTopContactOperation::TopContactFieldTypeL()
{
const MVPbkFieldType* fieldType;
TVPbkFieldTypeMapping mapping;
TVPbkFieldVersitProperty versitProp;
versitProp.SetName(EVPbkVersitNameTopContact);
mapping.SetVersitProperty(versitProp);
fieldType = mapping.FindMatch(iContactManager.FieldTypes());
if (!fieldType)
{
User::Leave(KErrNotFound);
}
return *fieldType;
}
// --------------------------------------------------------------------------
// Gives the top contact order value.
// If there is no valid Top Contact order value, then returns
// KErrNotFound.
//
// @param aTopContact The top contact.
// @return Order value, or KErrNotFound if there is no
// Top Contact data.
// --------------------------------------------------------------------------
TInt CVPbkTopContactOperation::TopOrder( const MVPbkBaseContact& aContact )
{
const MVPbkContactFieldTextData* textData = FindTopFieldTextData( aContact );
TInt result = KErrNotFound;
if ( textData )
{
TPtrC text(textData->Text());
const TBool isEmpty = textData->IsEmpty();
TLex lexer(text);
if ( !isEmpty )
{
TInt topOrder;
if(!lexer.Val(topOrder))
{
result=topOrder;
}
}
}
return result;
}
// --------------------------------------------------------------------------
// From MVPbkContactSelector
// --------------------------------------------------------------------------
TBool CVPbkTopContactOperation::IsContactIncluded( const MVPbkBaseContact& aContact )
{
return (TopOrder(aContact) == KErrNotFound);
}
// --------------------------------------------------------------------------
// Saves top index to the contact field
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::SetTopOrderL(
MVPbkContactFieldTextData& aTextData, TInt aTopOrderIndex )
{
TBuf<KTcFieldLength> text;
text.NumFixedWidth(aTopOrderIndex, EDecimal, KTcFieldLength);
aTextData.SetTextL( text );
}
// --------------------------------------------------------------------------
// Adds given top index to a store contact
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::SetTopOrderL(
MVPbkStoreContact& aContact, TInt aTopOrderIndex )
{
MVPbkContactFieldTextData* textData = FindTopFieldTextData( aContact );
if ( textData )
{
// The field already exists
SetTopOrderL( *textData, aTopOrderIndex );
}
else
{
// Need to create the field.
MVPbkStoreContactField* field = aContact.CreateFieldLC(
TopContactFieldTypeL() );
MVPbkContactFieldTextData& fieldData =
MVPbkContactFieldTextData::Cast( field->FieldData() );
SetTopOrderL( fieldData, aTopOrderIndex );
// Add VPbk Field to the contact
aContact.AddFieldL(field);
CleanupStack::Pop(); // field
}
}
// --------------------------------------------------------------------------
// Retruns top field text data of a view contact
// or NULL if aContact doesn't have top field
// --------------------------------------------------------------------------
const MVPbkContactFieldTextData* CVPbkTopContactOperation::FindTopFieldTextData(
const MVPbkBaseContact& aContact )
{
// Loop through all VPbk fields in the contact
// check if a field contains top contact type.
const MVPbkBaseContactFieldCollection& fields = aContact.Fields();
const TInt count = fields.FieldCount();
const MVPbkContactFieldTextData* result = NULL;
for ( TUint i = 0; i < count && !result; ++i )
{
const MVPbkBaseContactField& field = fields.FieldAt(i);
TVPbkFieldVersitProperty versitProp;
versitProp.SetName(EVPbkVersitNameTopContact);
const MVPbkFieldType* fieldType = field.BestMatchingFieldType();
if ( fieldType && fieldType->Matches(versitProp, 0) )
{
// Contact Template has Top Contact Field, therefore
// a newly created contact will have an empty TC field
// So, remember to make an additional check to see if the field
// has data or not by calling IsEmpty().
result = &MVPbkContactFieldTextData::Cast( field.FieldData() );
}
}
return result;
}
// --------------------------------------------------------------------------
// Retruns top field text data of a store contact
// or NULL if aContact doesn't have top field
// --------------------------------------------------------------------------
MVPbkContactFieldTextData* CVPbkTopContactOperation::FindTopFieldTextData(
MVPbkStoreContact& aContact )
{
// Loop through all VPbk fields in the contact
// check if a field contains top contact type.
MVPbkStoreContactFieldCollection& fields = aContact.Fields();
const TInt count = fields.FieldCount();
MVPbkContactFieldTextData* result = NULL;
for ( TUint i = 0; i < count && !result; ++i )
{
MVPbkStoreContactField& field = fields.FieldAt(i);
TVPbkFieldVersitProperty versitProp;
versitProp.SetName(EVPbkVersitNameTopContact);
const MVPbkFieldType* fieldType = field.BestMatchingFieldType();
if ( fieldType && fieldType->Matches(versitProp, 0) )
{
// Contact Template has Top Contact Field, therefore
// a newly created contact will have an empty TC field
// So, remember to make an additional check to see if the field
// has data or not by calling IsEmpty().
result = &MVPbkContactFieldTextData::Cast( field.FieldData() );
}
}
return result;
}
// --------------------------------------------------------------------------
// Notifies operation observer of results
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::NotifyResultL()
{
switch( iCurrentOperation )
{
case EGetTopContacts:
case EGetNonTopContacts:
{
__ASSERT_DEBUG( iView, Panic(ETopErrorNoView) );
MVPbkContactViewBase* view = iView;
iView = NULL; //transfer ownership
iViewObserver->VPbkOperationResultCompleted( this, view );
break;
}
case EGetTopContactLinks:
case EGetNonTopContactLinks:
{
__ASSERT_DEBUG( iView, Panic(ETopErrorNoView) );
MVPbkContactLinkArray* links = ViewToLinkArrayL( *iView );
iLinksObserver->VPbkOperationResultCompleted( this, links );
break;
}
case EAddToTop:
case ERemoveFromTop:
case EReorderTop:
{
iObserver->VPbkOperationCompleted( this );
break;
}
default:
__ASSERT_DEBUG( EFalse, Panic(ETopErrorWrongState) );
}
}
// --------------------------------------------------------------------------
// Sends error notification to the error observer
// --------------------------------------------------------------------------
inline void CVPbkTopContactOperation::NotifyError(TInt aErr)
{
iErrorObserver->VPbkOperationFailed( this, aErr );
}
// --------------------------------------------------------------------------
// Notify error async
// --------------------------------------------------------------------------
void CVPbkTopContactOperation::AbortWithError(TInt aErr)
{
iAbortError = aErr;
iNextState = EStateAbortWithError;
CompleteOurself();
}
// --------------------------------------------------------------------------
// Aquire sort order from presentation layer
// --------------------------------------------------------------------------
CVPbkSortOrderAcquirer* CVPbkTopContactOperation::AllContactsSortOrderL() const
{
CVPbkSortOrderAcquirer* result = NULL;
// Acquire group sort order
RImplInfoPtrArray implementations;
REComSession::ListImplementationsL
( TUid::Uid( KVPbkSortOrderAcquirerInterfaceUID ), implementations );
CleanupStack::PushL( TCleanupItem
( CleanupResetAndDestroy, &implementations ) );
TBool found = EFalse;
const TInt count = implementations.Count();
for ( TInt i = count - 1; i >= 0 && !found ; --i )
{
CImplementationInformation* implInfo = implementations[i];
if ( implInfo->DisplayName().
CompareC( KAllContactsSortOrderDisplayName ) == 0 )
{
TUid implUid = implInfo->ImplementationUid();
CVPbkSortOrderAcquirer::TSortOrderAcquirerParam param
( iContactManager.FieldTypes() );
result = CVPbkSortOrderAcquirer::NewL
( implUid, param );
found = ETrue;
}
}
CleanupStack::PopAndDestroy(); // implementations
return result;
}
// end of file