--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/contactsmodel/cntsrv/src/CViewSubSessions.cpp Wed Sep 01 12:29:52 2010 +0100
@@ -0,0 +1,1131 @@
+// Copyright (c) 2005-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:
+//
+
+/**
+ @file
+ @internalComponent
+ @released
+*/
+
+
+#include "cntviewprivate.h"
+#include "CViewSubSessions.h"
+#include "CCntIpcCodes.h"
+#include "CCntDbManager.h"
+#include "CCntServer.h"
+#include <cntviewstore.h>
+#include "CCntLogger.h"
+#include "CCntStateMachine.h"
+
+
+extern void DebugLogViewNotification(const TDesC& aMethod, const TContactViewEvent& aEvent);
+
+
+CViewSubSessionQueue::CViewSubSessionQueue()
+ {
+ }
+
+
+CViewSubSessionQueue::~CViewSubSessionQueue()
+ {
+ iEvents.Close();
+ }
+
+
+void CViewSubSessionQueue::QueueEvent(const TContactViewEvent& aEvent)
+ {
+ const TInt KInvalidValueForRemoteView = -1;
+
+ TBool haveToAddEventInQueue = ETrue;
+
+ if (iRequestPending)
+ {
+ if(aEvent.iEventType == TContactViewEvent::EItemAdded)
+ {
+ // is this first event sent? If yes and if the event is an
+ // EItemAdded event send first a fake event.
+ // This is because all EItemAdded should be sorted before send them
+
+ TContactViewEvent event;
+ event.iEventType = TContactViewEvent::EItemAdded;
+ event.iContactId = KInvalidValueForRemoteView;
+ event.iInt = KInvalidValueForRemoteView;
+ SendEventL(event);
+ }
+ else
+ {
+ SendEventL(aEvent);
+ haveToAddEventInQueue = EFalse;
+ }
+ }
+
+ if (haveToAddEventInQueue && !iQueueError)
+ {
+ // There are two requirements for this queue of events:
+ // 1. The iInt values for events in the Q at any given point in time
+ // should match the index of the underlying localview array. i.e If the addition/removal
+ // of a contact has caused the position of other contacts items to change in the underlying localview
+ // then previous events sent by them in this Q will have old iInt values and these need to be corrected.
+
+ // 2. When the client gets these events in order, it should have a valid view after every event,
+ // ie. if we have 2 additions, at positions 0 and 1,
+ // we cannot send the event for addition at position 1 before the addition at position 0.
+ //
+ // These requirements are fulfilled using the following algorithm.
+ // Events are inserted in the queue using following two condition
+ // 1. EItemAdded -
+ // 1.1 Find if an existing EItemAdded events iInt is greater or equal with incoming events iInt.
+ // if found,insert event before the found one and increment the iInt of the rest event by 1
+ // 1.2 if no match is found with same iInt, modify its iInt value with incoming events iInt,
+ // then append to the event queue.
+ // 1.3 If no EItemAdded events are in queue, append this one to Queue.
+ // 2. EItemRemoved -
+ // 2.1 Find if an existing EItemAdded events iInt matches with incoming EItemRemoved events iInt.
+ // if found, then remove that EItemAdded event from the Queue and decrement rest of the
+ // events iInt by 1.
+ // 2.2 if no match is found with same iInt, then insert the event before next greater iInt event
+ // and then decerement the iInt value of rest of the event by 1.
+ // 2.3 if no events greater than this then append this one to Queue.
+
+ TContactViewEvent event;
+ event.iEventType = aEvent.iEventType;
+ event.iContactId = aEvent.iContactId;
+ event.iInt = aEvent.iInt;
+ TInt eventsCount = iEvents.Count();
+ TUint pos=0;
+ if( event.iEventType == TContactViewEvent::EItemAdded )
+ {
+ TInt lastItemRemovedPosition = KErrNotFound;
+ //first check if this add event is not generated by a contact item change
+ for( pos=0; pos<eventsCount; ++pos )
+ {
+ if( iEvents[pos].iContactId == aEvent.iContactId &&
+ iEvents[pos].iEventType == TContactViewEvent::EItemRemoved )
+ {
+ lastItemRemovedPosition = pos;
+ }
+ }
+ if( lastItemRemovedPosition != KErrNotFound )
+ {
+ ++lastItemRemovedPosition;
+ if(lastItemRemovedPosition < eventsCount)
+ {
+ for( pos = lastItemRemovedPosition-1; pos < eventsCount;++pos )
+ {
+ if(iEvents[pos].iInt >= aEvent.iInt &&
+ iEvents[pos].iContactId != aEvent.iContactId)
+ {
+ if( iEvents[pos].iEventType == TContactViewEvent::EItemRemoved || iEvents[pos].iEventType == TContactViewEvent::EItemAdded)
+ {
+ iEvents[pos].iInt++;
+ }
+ }
+ }
+ iQueueError = iEvents.Insert(aEvent, lastItemRemovedPosition);
+ }
+ else
+ {
+ iQueueError = iEvents.Append(aEvent);
+ }
+ }
+ else
+ {
+ TBool haveToAppendEvent = ETrue;
+ for( pos=0; pos<eventsCount; ++pos )
+ {
+ if(iEvents[pos].iEventType == TContactViewEvent::EItemAdded)
+ {
+ if(iEvents[pos].iInt >= event.iInt)
+ {
+ iQueueError = iEvents.Insert(event, pos);
+ eventsCount=iEvents.Count();
+ for(TUint loop=pos+1; loop<eventsCount; ++loop)
+ {
+ if( iEvents[pos].iEventType == TContactViewEvent::EItemRemoved || iEvents[pos].iEventType == TContactViewEvent::EItemAdded)
+ {
+ iEvents[loop].iInt++;
+ }
+ }
+ haveToAppendEvent = EFalse;
+ break;
+ }
+ }
+ }
+ if( haveToAppendEvent )
+ {
+ iQueueError = iEvents.Append(event);
+ }
+ }
+ }
+ else
+ {
+ iQueueError = iEvents.Append(event);
+ }
+ DEBUG_PRINTVN2(__VERBOSE_DEBUG__,_L("[CNTMODEL] CViewSubSessionQueue::QueueEvent(): ->Q:"), event);
+ }
+ }
+
+
+void CViewSubSessionQueue::RequestEvent(const RMessage2& aMessage)
+ {
+ __ASSERT_DEBUG(!iRequestPending,User::Leave(KErrAlreadyExists)); // can only leave in debug mode
+ if (!iRequestPending)
+ {
+ iMessage=aMessage;
+ iRequestPending=ETrue;
+ if (iQueueError)
+ {
+ TContactViewEvent errorEvent(TContactViewEvent::EServerError,iQueueError);
+ iQueueError=KErrNone;
+ SendEventL(errorEvent);
+ }
+ else if (iEvents.Count()>0)
+ {
+ SendEventL(iEvents[0]);
+ iEvents.Remove(0);
+ }
+ }
+ }
+
+
+void CViewSubSessionQueue::CancelEventRequest()
+ {
+ if (iRequestPending)
+ {
+ iMessage.Complete(KErrCancel);
+ iRequestPending=EFalse;
+ }
+ }
+
+/**
+Send contact view event.
+
+@leave KErrNotFound In debug mode only, if there is a queue error.
+@leave KErrNotReady In debug mode only, if there is already an existing request still pending.
+@leave KErrBadDescriptor If there is a error writing aEvent to the RMessage2 to be sent.
+*/
+void CViewSubSessionQueue::SendEventL(const TContactViewEvent& aEvent)
+ {
+ __ASSERT_DEBUG(!iQueueError,User::Leave(KErrNotFound));
+
+ if (!iRequestPending)
+ {
+ return;
+ }
+
+ DEBUG_PRINTVN2(__VERBOSE_DEBUG__,_L("[CNTMODEL] CViewSubSessionQueue::SendEventL(): Q->:"), aEvent);
+
+ TRAPD(err,iMessage.WriteL(KSlot0,TPckgC<TContactViewEvent>(aEvent)));
+ if (err)
+ {
+ iRequestPending=EFalse;
+ User::Leave(KErrBadDescriptor);//iMessage is completed in CCntSession::ServiceError()
+ }
+ else
+ {
+ iMessage.Complete(KErrNone);
+ }
+
+ iRequestPending=EFalse;
+ }
+
+
+/**
+Called if derived class ServiceL()'s do not consume the opcode.
+*/
+TInt CViewSubSessionBase::ServiceL(const RMessage2& aMessage)
+ {
+ TInt reply(KErrNone);
+ switch (aMessage.Function())
+ {
+ case ECntViewCount:
+ CountL(aMessage);
+ break;
+ case ECntViewAt:
+ reply=AtL(aMessage);
+ break;
+ case ECntViewContactAtLength:
+ reply=ContactAtLengthL(aMessage);
+ break;
+ case ECntViewContactAt:
+ ContactAtL(aMessage);
+ break;
+ case ECntViewFind:
+ FindL(aMessage);
+ break;
+ case ECntAllFieldsLength:
+ reply=GetAllFieldsLengthL(aMessage);
+ break;
+ case ECntAllFieldsText:
+ GetAllFieldsTextL(aMessage);
+ break;
+ case ECntContactMatchingCriteriaExternalizedSize:
+ ContactMatchingCriteriaExternalizedSizeL(aMessage);
+ break;
+ case ECntGetContactMatchingCriteria:
+ GetContactMatchingCriteriaL(aMessage);
+ break;
+ case ECntGetIncludedTypes:
+ GetIncludedTypesL(aMessage);
+ break;
+ case ECntRequestViewEvent:
+ RequestViewEvent(aMessage);
+ reply=KErrNoComplete;
+ break;
+ case ECntCancelRequestViewEvent:
+ CancelRequestViewEvent();
+ break;
+ case ECntGetContactIds:
+ GetContactIdsL(aMessage);
+ break;
+ case ECntSendPluginUidToServer:
+ SendPluginUidToServer(aMessage);
+ break;
+ case ECntGetContactsMatchingFilter:
+ GetContactsMatchingFilterL(aMessage);
+ break;
+ case ECntGetSortPluginUidFromServer:
+ GetSortPluginUidFromServerL(aMessage);
+ break;
+ default:
+ User::Leave(KErrNotFound);
+ break;
+ }
+ return reply;
+ }
+
+
+CViewSubSessionBase::~CViewSubSessionBase()
+ {
+ delete iQueue;
+ delete iSortableText;
+ delete iContact;
+ DeleteFindContacts();
+ }
+
+
+CViewSubSessionBase::CViewSubSessionBase(CViewManager& aViewManager) : iViewManager(aViewManager),iContact(0)
+ {
+ }
+
+
+void CViewSubSessionBase::ConstructL()
+ {
+ iQueue = new(ELeave) CViewSubSessionQueue();
+ }
+
+
+void CViewSubSessionBase::CountL(const RMessage2& aMessage) const
+ {
+ TPckgBuf<TInt> pckg(iView->CountL());
+ aMessage.WriteL(0,pckg);
+ }
+
+
+TInt CViewSubSessionBase::AtL(const RMessage2& aMessage) const
+ {
+ TInt reply = KErrNone;
+ const TInt index=aMessage.Int0();
+ __ASSERT_ALWAYS(index>=0,User::Leave(KErrUnderflow));
+ if(!(index<iView->CountL()))
+ {
+ // Index is out of bounds.
+ reply=KErrNotFound;
+ return reply;
+ }
+ TPckgBuf<TContactItemId> pckg(iView->AtL(index));
+ aMessage.WriteL(1,pckg);
+ return reply;
+ }
+
+
+void CViewSubSessionBase::ContactAtL(const RMessage2& aMessage) const
+ {
+ const TInt externalizedSize=iContact->ExternalizedSize();
+ HBufC8* buf=HBufC8::NewLC(externalizedSize);
+ TPtr8 bufPtr(buf->Des());
+ RDesWriteStream writeStream(bufPtr);
+ CleanupClosePushL(writeStream);
+ writeStream << *iContact;
+ bufPtr.SetLength(externalizedSize);
+ aMessage.WriteL(0,*buf);
+ CleanupStack::PopAndDestroy(2); // writeStream, buf.
+ }
+
+
+/**
+Return the size of the externalized contact data.
+
+@param aMessage.Int0() Index.
+@param aMessage.Ptr1() Package buffer to return size.
+*/
+TInt CViewSubSessionBase::ContactAtLengthL(const RMessage2& aMessage)
+ {
+ TInt reply=KErrNone;
+ TInt index = aMessage.Int0();
+
+ __ASSERT_ALWAYS(index>=0,User::Leave(KErrUnderflow));
+
+ if(!(index<iView->CountL()))
+ {
+ // Index is out of bounds.
+ reply=KErrNotFound;
+ return reply;
+ }
+
+ const CViewContact& contact=iView->ContactAtL(index);
+
+ delete iContact;
+ iContact=NULL;
+ iContact = CViewContact::NewL(contact);
+
+ const TInt externalizedSize=iContact->ExternalizedSize();
+ TPckgBuf<TInt> pckg(externalizedSize);
+ aMessage.WriteL(1,pckg);
+
+ return reply;
+ }
+
+
+void CViewSubSessionBase::GetIncludedTypesL(const RMessage2& aMessage)
+ {
+ TPckgBuf<TContactViewPreferences> pckg(iView->ContactViewPreferences());
+ aMessage.WriteL(0,pckg);
+ }
+
+
+void CViewSubSessionBase::DeleteFindContacts()
+ {
+ iContacts.ResetAndDestroy();
+ }
+
+
+#ifdef _DEBUG
+void CViewSubSessionBase::HandleContactViewEvent(const CContactViewBase& aView,const TContactViewEvent& aEvent)
+#else
+void CViewSubSessionBase::HandleContactViewEvent(const CContactViewBase& /*aView*/,const TContactViewEvent& aEvent)
+#endif
+ {
+ ASSERT(&aView==iView);
+ iQueue->QueueEvent(aEvent);
+ }
+
+
+/**
+Match an array of search strings against the contacts in the view.
+
+The descriptor from the client contains a flag at the start to indicate if a
+prefix or substring search has been requested.
+
+@param aMessage.Ptr0() Size of contact data to read (to client).
+@param aMessage.Int1() Size of descriptor (from client).
+@param aMessage.Ptr2() Descriptor (from client).
+*/
+void CViewSubSessionBase::ContactMatchingCriteriaExternalizedSizeL(const RMessage2& aMessage)
+ {
+ TPckgBuf<TInt> size;
+ aMessage.ReadL(1,size);
+ const TInt bufferSize = size();
+
+ // Restore buffer.
+ CBufFlat* buffer = CBufFlat::NewL(bufferSize);
+ CleanupStack::PushL(buffer);
+ buffer->ExpandL(0,bufferSize);
+ TPtr8 des(buffer->Ptr(0));
+ aMessage.ReadL(2,des);
+
+ // Internalize the data from the stream.
+ RBufReadStream readStream(*buffer);
+ CleanupClosePushL(readStream);
+
+ TBool prefixSearch = readStream.ReadUint32L();
+ const TInt numFindWords = readStream.ReadUint32L();
+ CPtrC16Array* findDesArray = new(ELeave) CPtrC16Array(numFindWords);
+ CleanupStack::PushL(findDesArray);
+
+ TInt findWordLength=0;
+ for (TInt i=0; i<numFindWords; ++i)
+ {
+ findWordLength = readStream.ReadUint32L();
+ HBufC* findword = HBufC::NewLC(readStream,findWordLength);
+ findDesArray->AppendL(*findword);
+ }
+
+ DeleteFindContacts();
+
+ if (prefixSearch)
+ iView->ContactsMatchingPrefixL(*findDesArray,iContacts);
+ else
+ iView->ContactsMatchingCriteriaL(*findDesArray,iContacts);
+
+ findDesArray->Reset();
+
+ CleanupStack::PopAndDestroy(numFindWords);
+ CleanupStack::PopAndDestroy(3, buffer);
+
+ // Compute contacts externalized size.
+ const TInt contactsCount = iContacts.Count();
+ TInt contactsExternalizedSize=0;
+ contactsExternalizedSize+=sizeof(TInt32);
+ for (TInt jj=0;jj<contactsCount;++jj)
+ {
+ contactsExternalizedSize+=(iContacts)[jj]->ExternalizedSize();
+ }
+
+ TPckgBuf<TInt> pckg(contactsExternalizedSize);
+ aMessage.WriteL(0,pckg);
+ }
+
+
+/**
+Write matching contacts back to client.
+
+@param aMessage.Ptr0() Descriptor to write array of matching contacts.
+*/
+void CViewSubSessionBase::GetContactMatchingCriteriaL(const RMessage2& aMessage)
+ {
+ // Compute contacts externalized size.
+ const TInt contactsCount = iContacts.Count();
+ TInt contactsExternalizedSize=0;
+ contactsExternalizedSize+=sizeof(TInt32);
+ for (TInt jj=0;jj<contactsCount;++jj)
+ {
+ contactsExternalizedSize+=(iContacts)[jj]->ExternalizedSize();
+ }
+
+ HBufC8* buf=HBufC8::NewLC(contactsExternalizedSize);
+ TPtr8 bufPtr(buf->Des());
+ RDesWriteStream writeStream(bufPtr);
+ CleanupClosePushL(writeStream);
+
+ writeStream.WriteUint32L(contactsCount);
+ for (TInt ii=0;ii<contactsCount;++ii)
+ {
+ CViewContact* thisContact = (iContacts)[ii];
+ writeStream << *thisContact;
+ }
+
+ bufPtr.SetLength(contactsExternalizedSize);
+ aMessage.WriteL(0,*buf);
+
+ CleanupStack::PopAndDestroy(2, buf); //writeStream.Close(), buf
+
+ DeleteFindContacts();
+ }
+
+
+void CViewSubSessionBase::FindL(const RMessage2& aMessage) const
+ {
+ TPckgBuf<TContactItemId> pckg(iView->FindL(aMessage.Int0()));
+ aMessage.WriteL(1,pckg);
+ }
+
+
+TInt CViewSubSessionBase::GetAllFieldsLengthL(const RMessage2& aMessage)
+ {
+ TInt reply = KErrNone;
+ TInt index = aMessage.Int0();
+
+ __ASSERT_ALWAYS(index>=0,User::Leave(KErrUnderflow));
+
+ if(!(index<iView->CountL()))
+ {
+ // Index is out of bounds.
+ reply=KErrNotFound;
+ return reply;
+ }
+
+ TBuf<256> bufPtr;// = buf->Des();
+ aMessage.ReadL(1,bufPtr);
+
+ // Create sortable text from all fields of view contact at specified index.
+ delete iSortableText;
+ iSortableText=NULL;
+ HBufC* allfields=iView->AllFieldsLC(index,bufPtr);
+ CleanupStack::Pop(); // allfields
+ iSortableText=allfields;
+
+ TPckgBuf<TInt> pckg(iSortableText->Length());
+ aMessage.WriteL(2,pckg);
+
+ return reply;
+ }
+
+
+void CViewSubSessionBase::GetAllFieldsTextL(const RMessage2& aMessage)
+ {
+ TPtrC8 narrowPtr((TUint8*)iSortableText->Ptr(),iSortableText->Size());
+ aMessage.WriteL(0,narrowPtr);
+ }
+
+
+void CViewSubSessionBase::RequestViewEvent(const RMessage2& aMessage)
+ {
+ iQueue->RequestEvent(aMessage);
+ }
+
+
+void CViewSubSessionBase::CancelRequestViewEvent()
+ {
+ iQueue->CancelEventRequest();
+ }
+
+
+/**
+Provides conversion between view indexes and contact IDs.
+
+@param aMessage.Int0() Buffer size (from client).
+@param aMessage.Ptr1() Descriptor containing indices (from client).
+@param aMessage.Ptr2() Descriptor containing contact IDs (to client).
+*/
+void CViewSubSessionBase::GetContactIdsL(const RMessage2& aMessage)
+ {
+ TPckgBuf<TInt> size;
+ aMessage.ReadL(0,size);
+ const TInt bufferSize = size();
+
+ CBufFlat* buffer = CBufFlat::NewL(bufferSize);
+ CleanupStack::PushL(buffer);
+ buffer->ExpandL(0,bufferSize);
+ TPtr8 des(buffer->Ptr(0));
+ aMessage.ReadL(1,des);
+
+ RBufReadStream readStream(*buffer);
+ CleanupClosePushL(readStream);
+ const TInt count = readStream.ReadUint32L();
+
+ CArrayFixFlat<TInt>* indexes = new(ELeave) CArrayFixFlat<TInt>(8);
+ CleanupStack::PushL(indexes);
+
+ for (TInt i=0; i<count; ++i)
+ {
+ TInt index = readStream.ReadUint32L();
+ indexes->AppendL(index);
+ }
+
+ CContactIdArray* array = CContactIdArray::NewLC();
+ iView->GetContactIdsL(*indexes, *array);
+
+ HBufC8* buf=HBufC8::NewLC(bufferSize);
+ TPtr8 bufPtr(buf->Des());
+ RDesWriteStream writeStream(bufPtr);
+ CleanupClosePushL(writeStream);
+ writeStream << *array;
+ bufPtr.SetLength(bufferSize);
+ aMessage.WriteL(2,*buf);
+
+ CleanupStack::PopAndDestroy(6, buffer); // &writeStream, buf, array, indexes, &readStream, buffer
+ }
+
+
+void CViewSubSessionBase::SendPluginUidToServer(const RMessage2& aMessage)
+ {
+ TUid uid;
+ uid.iUid = aMessage.Int0();
+ iView->SetViewFindConfigPlugin(uid);
+ }
+
+
+/**
+Filter server-side view based on filter supplied by client. The IDs of matching
+contact items are externalized to the client-side.
+
+@param aMessage.Int0() Filter (from client).
+@param aMessage.Ptr1() Descriptor containing matching contact IDs (to client).
+*/
+void CViewSubSessionBase::GetContactsMatchingFilterL(const RMessage2& aMessage)
+ {
+ const TInt filter(aMessage.Int0());
+
+ RArray<TContactIdWithMapping> array;
+ CleanupClosePushL(array);
+ TContactIdWithMapping idMap;
+
+ // Filter view contacts.
+ const TInt viewCount(iView->CountL());
+ for (TInt i=0;i<viewCount;++i)
+ {
+ const CViewContact& contact = iView->ContactAtL(i);
+ if(contact.ContactMatchesFilter(filter))
+ {
+ idMap.iId=contact.Id();
+ idMap.iMapping=i;
+ User::LeaveIfError(array.Append(idMap));
+ }
+ }
+
+ // Externalize array to client.
+ const TInt count(array.Count());
+ const TInt maxBufSize = (1+(array.Count()*2))*sizeof(TInt);
+ HBufC8* buf=HBufC8::NewLC(maxBufSize);
+ TPtr8 bufPtr(buf->Des());
+ RDesWriteStream writeStream(bufPtr);
+ CleanupClosePushL(writeStream);
+ writeStream.WriteUint32L(count);
+ for (TInt j=0; j<count; ++j)
+ {
+ writeStream.WriteInt32L(array[j].iId);
+ writeStream.WriteInt32L(array[j].iMapping);
+ }
+ bufPtr.SetLength(maxBufSize);
+ aMessage.WriteL(1,*buf);
+ CleanupStack::PopAndDestroy(3,&array);
+ }
+
+
+void CViewSubSessionBase::GetSortPluginUidFromServerL(const RMessage2& aMessage)
+ {
+ TUid uid = iView->GetViewSortPluginImplUid();
+ TPckgBuf<TInt> pckg(uid.iUid);
+ aMessage.WriteL(0,pckg);
+ }
+
+
+CViewSubSession* CViewSubSession::NewL(CViewManager& aViewManager,const RMessage2& aMessage)
+ {
+ CViewSubSession* self=new(ELeave) CViewSubSession(aViewManager);
+ CleanupClosePushL (*self);
+ self->ConstructL(aMessage);
+ CleanupStack::Pop(); // self.
+ return self;
+ }
+
+
+/**
+Attempt to consume opcode. If the opcode is not consumed then the base class
+ServiceL() is called.
+*/
+TInt CViewSubSession::ServiceL(const RMessage2& aMessage)
+ {
+ switch (aMessage.Function())
+ {
+ case ECntViewSortOrderExternalizedSize:
+ ExternalizedSortOrderSizeL(aMessage);
+ break;
+ case ECntGetViewSortOrder:
+ GetSortOrderL(aMessage);
+ break;
+ default:
+ return CViewSubSessionBase::ServiceL(aMessage);
+ }
+ return 0;
+ }
+
+
+CViewSubSession::~CViewSubSession()
+ {
+ iViewManager.CloseView(View(),*this);
+ }
+
+
+CViewSubSession::CViewSubSession(CViewManager& aViewManager) : CViewSubSessionBase(aViewManager)
+ {
+ }
+
+
+void CViewSubSession::ConstructL(const RMessage2& aMessage)
+ {
+ CViewSubSessionBase::ConstructL();
+
+ RContactViewSortOrder sortOrder;
+ CleanupClosePushL(sortOrder);
+ TContactViewPreferences contactsToInclude;
+
+ TUid sortPluginImplUid;
+ HBufC8* sortPluginName = UnpackageSortOrderAndPluginDetailsLC(aMessage,sortOrder,contactsToInclude,sortPluginImplUid);
+
+ iView = &iViewManager.OpenViewL(sortOrder,*this,contactsToInclude,sortPluginImplUid,*sortPluginName);
+
+ CleanupStack::PopAndDestroy(2, &sortOrder); // sortPluginName, sortOrder
+ }
+
+
+void CViewSubSession::UnpackageSortOrderL(const RMessage2& aMessage,RContactViewSortOrder& aSortOrder,TContactViewPreferences& aContactTypes) const
+ {
+ HBufC8* buf=HBufC8::NewLC(aMessage.Int0());
+
+ TPtr8 bufPtr(buf->Des());
+ aMessage.ReadL(1,bufPtr);
+ RDesReadStream readStream(bufPtr);
+ CleanupClosePushL(readStream);
+
+ readStream >> (TInt32&)aContactTypes;
+ readStream >> aSortOrder;
+
+ CleanupStack::PopAndDestroy(2); //readstream, buf.
+ }
+
+
+HBufC8* CViewSubSession::UnpackageSortOrderAndPluginDetailsLC(const RMessage2& aMessage,RContactViewSortOrder& aSortOrder,TContactViewPreferences& aContactTypes,TUid& aSortPluginImplUid) const
+ {
+ HBufC8* buf=HBufC8::NewLC(aMessage.Int0());
+
+ TPtr8 bufPtr(buf->Des());
+ TInt32 nameLen;
+ aMessage.ReadL(1,bufPtr);
+ RDesReadStream readStream(bufPtr);
+ CleanupClosePushL(readStream);
+
+ readStream >> (TInt32&)aContactTypes;
+ readStream >> aSortOrder;
+
+ // Extract sort plugin UID.
+ aSortPluginImplUid.iUid = readStream.ReadInt32L();
+
+ // Extract sort plugin name.
+ nameLen = readStream.ReadInt32L();
+ HBufC8* pluginNameBuf = HBufC8::NewLC(nameLen);
+ TPtr8 pluginNamePtr = pluginNameBuf->Des();
+ readStream.ReadL(pluginNamePtr, nameLen);
+ CleanupStack::Pop(pluginNameBuf);
+ CleanupStack::PopAndDestroy(2); //readstream, buf.
+
+ CleanupStack::PushL(pluginNameBuf);
+ return pluginNameBuf;
+ }
+
+
+CContactLocalView& CViewSubSession::View() const
+ {
+ return STATIC_CAST(CContactLocalView&,*iView);
+ }
+
+
+void CViewSubSession::ExternalizedSortOrderSizeL(const RMessage2& aMessage) const
+ {
+ TPckgBuf<TInt> pckg(View().SortOrder().ExternalizedSize());
+ aMessage.WriteL(0,pckg);
+ }
+
+
+void CViewSubSession::GetSortOrderL(const RMessage2& aMessage) const
+ {
+ const RContactViewSortOrder& sortOrder=View().SortOrder();
+ const TInt externalizedSize=sortOrder.ExternalizedSize();
+ HBufC8* buf=HBufC8::NewLC(externalizedSize);
+ TPtr8 bufPtr(buf->Des());
+ RDesWriteStream writeStream(bufPtr);
+ CleanupClosePushL(writeStream);
+ writeStream << sortOrder;
+ bufPtr.SetLength(externalizedSize);
+ aMessage.WriteL(0,*buf);
+ CleanupStack::PopAndDestroy(2); // writeStream, buf.
+ }
+
+
+CNamedViewSubSession* CNamedViewSubSession::NewL(CViewManager& aViewManager,const RMessage2& aMessage)
+ {
+ CNamedViewSubSession* self=new(ELeave) CNamedViewSubSession(aViewManager);
+ CleanupClosePushL(*self); // CObject: Close will call the destructor.
+ self->ConstructL(aMessage);
+ CleanupStack::Pop(); // self.
+ return self;
+ }
+
+
+/**
+Attempt to consume opcode. If the opcode is not consumed then the base class
+ServiceL() is called.
+*/
+TInt CNamedViewSubSession::ServiceL(const RMessage2& aMessage)
+ {
+ switch (aMessage.Function())
+ {
+ case ECntChangeViewSortOrder:
+ ChangeSortOrderL(aMessage);
+ break;
+ default:
+ return CViewSubSession::ServiceL(aMessage);
+ }
+ return 0;
+ }
+
+
+CNamedViewSubSession::~CNamedViewSubSession()
+ {
+ iViewManager.CloseNamedView(View(),*this);
+ }
+
+
+CNamedViewSubSession::CNamedViewSubSession(CViewManager& aViewManager) : CViewSubSession(aViewManager)
+ {
+ }
+
+
+void CNamedViewSubSession::ConstructL(const RMessage2& aMessage)
+ {
+ CViewSubSessionBase::ConstructL();
+
+ // Read sort order.
+ RContactViewSortOrder sortOrder;
+ CleanupClosePushL(sortOrder);
+ TContactViewPreferences contactsToInclude;
+ TUid sortPluginImplUid;
+ HBufC8* sortPluginName = UnpackageSortOrderAndPluginDetailsLC(aMessage,sortOrder,contactsToInclude,sortPluginImplUid);
+
+ // Create a descriptor of the correct length.
+ HBufC* nameBuf=HBufC::NewLC(aMessage.GetDesLengthL(2));
+ TPtr wideNameBufPtr(nameBuf->Des());
+ // Extract the name of the view from the message.
+ aMessage.ReadL(2, wideNameBufPtr);
+
+ // Open view using name provided.
+ iView = &iViewManager.OpenNamedViewL(wideNameBufPtr,sortOrder,*this,contactsToInclude,sortPluginImplUid,*sortPluginName);
+
+ CleanupStack::PopAndDestroy(3,&sortOrder); // nameBuf, sortPluginName, sortOrder
+
+ sortOrder.Close();
+ }
+
+
+void CNamedViewSubSession::ChangeSortOrderL(const RMessage2& aMessage)
+ {
+ RContactViewSortOrder newSortOrder;
+ TContactViewPreferences contactsToInclude;
+ UnpackageSortOrderL(aMessage,newSortOrder,contactsToInclude);
+ View().ChangeSortOrderL(newSortOrder);
+ newSortOrder.Close();
+ }
+
+
+CContactNamedLocalView& CNamedViewSubSession::View() const
+ {
+ return STATIC_CAST(CContactNamedLocalView&,*iView);
+ }
+
+
+CViewManager* CViewManager::NewL(MLplPersistenceLayerFactory& aFactory,CCntDbManager& aManager)
+ {
+ CViewManager* self =new (ELeave) CViewManager(aFactory,aManager);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+CContactLocalView& CViewManager::OpenViewL(const RContactViewSortOrder& aSortOrder,MContactViewObserver& aObserver,TContactViewPreferences aContactTypeToInclude, const TUid aSortPluginImplUid, const TDesC8& aSortPluginName)
+ {
+ // Check to see if there is already a view with the required sort order,
+ // preferences and sort plugin.
+ const TInt numViews=iLocalViews.Count();
+ for (TInt ii=0;ii<numViews;++ii)
+ {
+ CContactLocalView& thisView=*iLocalViews[ii].iLocalView;
+ if ( thisView.SortOrder()==aSortOrder && thisView.ContactViewPreferences() == aContactTypeToInclude &&
+ iLocalViews[ii].iSortPluginImplUid == aSortPluginImplUid)
+ {
+ if(thisView.Error() == KErrNone)
+ {
+ // Found one with no sorting error, so share it.
+ thisView.OpenL(aObserver);
+ return thisView;
+ }
+ }
+ }
+
+ // No view found, so create a new one.
+ TViewHandle viewHandle;
+ viewHandle.iSortPluginImplUid = aSortPluginImplUid;
+
+ if (!iManager.StateMachineL().DatabaseReady())
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ // Dummy CContactDatabase done for BC. CContactLocalView does not use
+ // CContactDatabase.
+ CContactDatabase* dummy = NULL;
+
+ // If aSortPluginImplUid is KNullUid indicates no sort plugin.
+ if (aSortPluginName.Length() || (aSortPluginImplUid == KNullUid))
+ {
+ viewHandle.iLocalView=CContactLocalView::NewL(aObserver,*dummy,aSortOrder,aContactTypeToInclude,&iFactory,aSortPluginName);
+ }
+ else
+ {
+ viewHandle.iLocalView=CContactLocalView::NewL(aObserver,*dummy,aSortOrder,aContactTypeToInclude,&iFactory,KNullDesC8);
+ }
+
+ // Register this view as an observer of database events with the
+ // associated CCntDbManager.
+ iManager.RegisterDatabaseEventObserverL(*viewHandle.iLocalView);
+
+ TInt error = iLocalViews.Append(viewHandle);
+ if (error != KErrNone)
+ {
+ iManager.UnRegisterDatabaseEventObserver(*viewHandle.iLocalView);
+ viewHandle.iLocalView->Close(aObserver);
+ User::Leave(error);
+ }
+
+ return *viewHandle.iLocalView;
+ }
+
+
+CContactNamedLocalView& CViewManager::OpenNamedViewL(const TDesC& aName,const RContactViewSortOrder& aSortOrder,MContactViewObserver& aObserver,TContactViewPreferences aContactTypeToInclude, const TUid aSortPluginImplUid, const TDesC8& aSortPluginName)
+ {
+ // Check to see if named view already exists.
+ const TInt numViews=iNamedLocalViews.Count();
+ for (TInt ii=0;ii<numViews;++ii)
+ {
+ CContactNamedLocalView& thisView=*iNamedLocalViews[ii];
+ if (aName.Compare(thisView.Name())==0 )
+ {
+ if(thisView.Error() == KErrNone)
+ {
+ // Found a name match, so share it.
+ thisView.OpenL(aObserver);
+ return thisView;
+ }
+ }
+ }
+
+ // No name match found, so create a new one.
+ CContactNamedLocalView* newNamedView = NULL;
+
+ // Dummy CContactDatabase done for BC. CContactLocalView does not use
+ // CContactDatabase.
+ CContactDatabase* dummy = NULL;
+
+ // If aSortPluginImplUid is KNullUid indicates no sort plugin.
+ if (aSortPluginName.Length() || (aSortPluginImplUid == KNullUid))
+ {
+ newNamedView=CContactNamedLocalView::NewL(aObserver,aName,*dummy,aSortOrder,aContactTypeToInclude,&iFactory,aSortPluginName);
+ }
+ else
+ {
+ newNamedView=CContactNamedLocalView::NewL(aObserver,aName,*dummy,aSortOrder,aContactTypeToInclude,&iFactory,KNullDesC8);
+ }
+
+ // Register this view as an observer of database events with the
+ // associated CCntDbManager.
+ iManager.RegisterDatabaseEventObserverL(*newNamedView);
+
+ TInt error = iNamedLocalViews.Append(newNamedView);
+ if (error != KErrNone)
+ {
+ iManager.UnRegisterDatabaseEventObserver(*newNamedView);
+ newNamedView->Close(aObserver);
+ User::Leave(error);
+ }
+
+ return *newNamedView;
+ }
+
+
+void CViewManager::CloseView(const CContactLocalView& aView,MContactViewObserver& aObserver)
+ {
+ const TInt count = iLocalViews.Count();
+
+ // Be tolerant to view not being found, since a leave may have occured
+ // before the CViewSubSession derived object has had a chance to call
+ // OpenViewL().
+ for (TInt index = 0; index < count; index++)
+ {
+ // Found it?
+ if (iLocalViews[index].iLocalView == &aView)
+ {
+ if(iLocalViews[index].iLocalView->Close(aObserver))
+ {
+ // Removed last reference to the Local View so un-Register this
+ // view as an observer of database events with the associated
+ // CCntDbManager.
+ iManager.UnRegisterDatabaseEventObserver(*iLocalViews[index].iLocalView);
+ iLocalViews.Remove(index);
+ }
+ break;
+ }
+ }
+ }
+
+
+void CViewManager::CloseNamedView(const CContactNamedLocalView& aView,MContactViewObserver& aObserver)
+ {
+ TInt index = iNamedLocalViews.Find(&aView);
+
+ // Be tolerant to view not being found, since a leave may have occured
+ // before the CNamedViewSubSession derived object has had a chance to call
+ // OpenViewL().
+ if (index != KErrNotFound)
+ {
+ if (iNamedLocalViews[index]->Close(aObserver))
+ {
+ // Removed last reference to the Local View so un-Register this view
+ // as an observer of database events with the associated
+ // CCntDbManager.
+ iManager.UnRegisterDatabaseEventObserver(*iNamedLocalViews[index]);
+ iNamedLocalViews.Remove(index);
+ }
+ }
+ }
+
+
+CViewManager::CViewManager(MLplPersistenceLayerFactory& aFactory,CCntDbManager& aManager) :
+ iFactory(aFactory),
+ iManager(aManager)
+ {
+ }
+
+
+CViewManager::~CViewManager()
+ {
+ iLocalViews.Close();
+ iNamedLocalViews.Close();
+ }
+
+
+void CViewManager::ConstructL()
+ {
+ }
+
+
+#if defined(_DEBUG)
+void CViewManager::GetDefinitionsOfExistingViewsL(RPointerArray<CContactDefaultViewDefinition>& aViewDefs)
+ {
+ __ASSERT_DEBUG(aViewDefs.Count() == 0, User::Leave(KErrArgument));
+
+ TInt i;
+ CContactDefaultViewDefinition* viewDef;
+
+ // Anonymous views.
+ for (i = 0; i < iLocalViews.Count(); i++)
+ {
+ CContactLocalView* view = iLocalViews[i].iLocalView;
+ viewDef = CContactDefaultViewDefinition::NewLC(CContactDefaultViewDefinition::ERemoteView,
+ KNullDesC, view->SortOrderL(),
+ view->ContactViewPreferences(),
+ KNullDesC8/*pluginName*/);
+ aViewDefs.AppendL(viewDef);
+ CleanupStack::Pop(viewDef);
+ }
+
+ // Named views.
+ for (i = 0; i < iNamedLocalViews.Count(); i++)
+ {
+ CContactNamedLocalView* view = iNamedLocalViews[i];
+ viewDef = CContactDefaultViewDefinition::NewLC(CContactDefaultViewDefinition::ENamedRemoteView,
+ view->Name(), view->SortOrderL(),
+ view->ContactViewPreferences(),
+ KNullDesC8/*pluginName*/);
+ aViewDefs.AppendL(viewDef);
+ CleanupStack::Pop(viewDef);
+ }
+ }
+#else
+void CViewManager::GetDefinitionsOfExistingViewsL(RPointerArray<CContactDefaultViewDefinition>& )
+ {
+ }
+#endif // _DEBUG