--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/VirtualPhonebook/VPbkEng/src/CVPbkTopContactOperation.cpp Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1005 @@
+/*
+* 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