// 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