phonebookengines_old/contactsmodel/cntview/Groupview.cpp
branchRCL_3
changeset 62 5b6f26637ad3
equal deleted inserted replaced
58:d4f567ce2e7c 62:5b6f26637ad3
       
     1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <cntview.h>
       
    17 #include "CNTSTD.H"
       
    18 #include <cntitem.h>
       
    19 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    20 #include "cnthint.h"
       
    21 #endif
       
    22 
       
    23 
       
    24 //#define CNTVIEW_API_PROFILING
       
    25 
       
    26 // To see the diferences between class versions check the in source documentation of TContactViewEvent
       
    27 const TUint KClassVersion1 = 1;
       
    28 const TUint KClassVersion2 = 2;
       
    29  
       
    30 
       
    31 CContactGroupView::CContactGroupView(const CContactDatabase& aDb,CContactViewBase& aView,TGroupType aGroupType)
       
    32 :CContactViewBase(aDb),iGroupId(KErrNotFound),iView(aView),iGroupType(aGroupType), iClassVersion(KClassVersion1)
       
    33 	{}
       
    34 
       
    35 CContactGroupView::~CContactGroupView() 
       
    36 /** Destructor */
       
    37 	{
       
    38 	iView.Close(*this);
       
    39 	iGroupContacts.Close();
       
    40 	}
       
    41 
       
    42 EXPORT_C CContactGroupView* CContactGroupView::NewL(const CContactDatabase& aDb,CContactViewBase& aView,MContactViewObserver& aObserver,const TContactItemId aGroupId,const TGroupType aGroupType)
       
    43 /** Allocates and constructs a CContactGroupView version 1 object, identifying the group 
       
    44 by its ID.
       
    45 
       
    46 A group with the specified ID must exist in the database, otherwise when an 
       
    47 attempt is made to update the view, a leave will occur with KErrNotFound. To 
       
    48 create an unfiled view, the group id must be KNullContactId and the group type 
       
    49 'EShowContactsNotInAnyGroup'. In this case the group id isn't used and no leave
       
    50 will occur.
       
    51 
       
    52 When adding contacts in the view, MContactViewObserver observer will receive 
       
    53 TContactViewEvent events with iInt parameter set to KErrNone.
       
    54 When deleting contacts in the view, MContactViewObserver observer will receive 
       
    55 TContactViewEvent events with iInt parameter set to index into the observed view of the deleted item
       
    56 
       
    57 
       
    58 @param aDb The database containing the contact group.
       
    59 @param aView The underlying view.
       
    60 @param aObserver An observer that receives notifications when this view is 
       
    61 ready for use and when changes take place in it. The observer receives a TContactViewEvent::EReady 
       
    62 event when the view is ready. An attempt to use the view before this notification 
       
    63 causes a panic.
       
    64 @param aGroupId The ID of the contact group.
       
    65 @param aGroupType Controls whether the view displays items belonging to the 
       
    66 group, items that do not belong to the group or items that do not belong to 
       
    67 any group.
       
    68 @return The newly constructed group view object. */
       
    69 	{
       
    70 #ifdef CNTVIEW_API_PROFILING
       
    71 	RDebug::Print(_L("[CNTMODEL] CContactGroupView::NewL(Group Id %u)\n"), aGroupId);
       
    72 #endif
       
    73 	CContactGroupView* self=new(ELeave) CContactGroupView(aDb,aView,aGroupType);
       
    74 	CleanupStack::PushL(self);
       
    75 	self->ConstructL(aObserver,aGroupId);
       
    76 	CleanupStack::Pop(self); 
       
    77 	return self;
       
    78 	}
       
    79 
       
    80 EXPORT_C CContactGroupView* CContactGroupView::NewL(const CContactDatabase& aDb,CContactViewBase& aView,MContactViewObserver& aObserver,const TDesC& aGroupName,const TGroupType aGroupType)
       
    81 /** Allocates and constructs a CContactGroupView version 1 object, identifying the group 
       
    82 by its label.
       
    83 
       
    84 A group with the specified label must exist in the database, otherwise when 
       
    85 an attempt is made to update the view, a leave will occur with KErrNotFound. 
       
    86 
       
    87 When adding contacts in the view, MContactViewObserver observer will receive 
       
    88 TContactViewEvent events with iInt parameter set to KErrNone.
       
    89 When deleting contacts in the view, MContactViewObserver observer will receive 
       
    90 TContactViewEvent events with iInt parameter set to index into the observed view of the deleted item
       
    91 
       
    92 
       
    93 @param aDb The database containing the contact group.
       
    94 @param aView The underlying view.
       
    95 @param aObserver An observer that receives notifications when this view is 
       
    96 ready for use and when changes take place in it. The observer receives a TContactViewEvent::EReady 
       
    97 event when the view is ready. An attempt to use the view before this notification 
       
    98 causes a panic.
       
    99 @param aGroupName The group label.
       
   100 @param aGroupType Controls whether the view displays items belonging to the 
       
   101 group, items that do not belong to the group or items that do not belong to 
       
   102 any group.
       
   103 @return The newly constructed group view object. */
       
   104 	{
       
   105 #ifdef CNTVIEW_API_PROFILING
       
   106 	RDebug::Print(_L("[CNTMODEL] CContactGroupView::NewL(Group Name \"%s\")\n"), &aGroupName);
       
   107 #endif
       
   108 	CContactGroupView* self=new(ELeave) CContactGroupView(aDb,aView,aGroupType);
       
   109 	CleanupStack::PushL(self);
       
   110 	TContactItemId groupId = self->GetGroupIdbyNameL(aGroupName);
       
   111 	self->ConstructL(aObserver,groupId);
       
   112 	CleanupStack::Pop(self); 
       
   113 	return self;
       
   114 	}
       
   115   EXPORT_C CContactGroupView* CContactGroupView::NewL(CContactViewBase& aView,const CContactDatabase& aDb, MContactViewObserver& aObserver,const TContactItemId aGroupId,const TGroupType aGroupType)
       
   116 /** Allocates and constructs a CContactGroupView version 2 object, identifying the group 
       
   117 by its ID.
       
   118 
       
   119 A group with the specified ID must exist in the database, otherwise when an 
       
   120 attempt is made to update the view, a leave will occur with KErrNotFound. To 
       
   121 create an unfiled view, the group id must be KNullContactId and the group type 
       
   122 'EShowContactsNotInAnyGroup'. In this case the group id isn't used and no leave
       
   123 will occur.
       
   124 
       
   125 When adding/deleting contacts in the view, MContactViewObserver observer will receive 
       
   126 TContactViewEvent events with iInt parameter set to index into the observed view of the added/deleted item
       
   127 
       
   128 @param aDb The database containing the contact group.
       
   129 @param aView The underlying view.
       
   130 @param aObserver An observer that receives notifications when this view is 
       
   131 ready for use and when changes take place in it. The observer receives a TContactViewEvent::EReady 
       
   132 event when the view is ready. An attempt to use the view before this notification 
       
   133 causes a panic.
       
   134 @param aGroupId The ID of the contact group.
       
   135 @param aGroupType Controls whether the view displays items belonging to the 
       
   136 group, items that do not belong to the group or items that do not belong to 
       
   137 any group.
       
   138 @return The newly constructed group view object. */
       
   139 	{
       
   140 #ifdef CNTVIEW_API_PROFILING
       
   141 	RDebug::Print(_L("[CNTMODEL] CContactGroupView::NewL(Group Id %u)\n"), aGroupId);
       
   142 #endif
       
   143 	CContactGroupView* self=new(ELeave) CContactGroupView(aDb,aView,aGroupType);
       
   144 	CleanupStack::PushL(self);
       
   145 	self->ConstructL(aObserver,aGroupId);
       
   146 	self->iClassVersion = KClassVersion2;
       
   147 	CleanupStack::Pop(self); 
       
   148 	return self;
       
   149 	}
       
   150 
       
   151 EXPORT_C CContactGroupView* CContactGroupView::NewL(CContactViewBase& aView, const CContactDatabase& aDb, MContactViewObserver& aObserver,const TDesC& aGroupName,const TGroupType aGroupType)
       
   152 /** Allocates and constructs a CContactGroupView version 2 object, identifying the group 
       
   153 by its label. 
       
   154 
       
   155 A group with the specified label must exist in the database, otherwise when 
       
   156 an attempt is made to update the view, a leave will occur with KErrNotFound.
       
   157 
       
   158 When adding/deleting contacts in the view, MContactViewObserver observer will receive 
       
   159 TContactViewEvent events with iInt parameter set to index into the observed view of the added/deleted item
       
   160  
       
   161 @param aDb The database containing the contact group.
       
   162 @param aView The underlying view.
       
   163 @param aObserver An observer that receives notifications when this view is 
       
   164 ready for use and when changes take place in it. The observer receives a TContactViewEvent::EReady 
       
   165 event when the view is ready. An attempt to use the view before this notification 
       
   166 causes a panic.
       
   167 @param aGroupName The group label.
       
   168 @param aGroupType Controls whether the view displays items belonging to the 
       
   169 group, items that do not belong to the group or items that do not belong to 
       
   170 any group.
       
   171 @return The newly constructed group view object. */
       
   172 	{
       
   173 #ifdef CNTVIEW_API_PROFILING
       
   174 	RDebug::Print(_L("[CNTMODEL] CContactGroupView::NewL(Group Name \"%s\")\n"), &aGroupName);
       
   175 #endif
       
   176 	CContactGroupView* self=new(ELeave) CContactGroupView(aDb,aView,aGroupType);
       
   177 	CleanupStack::PushL(self);
       
   178 	TContactItemId groupId = self->GetGroupIdbyNameL(aGroupName);
       
   179 	self->ConstructL(aObserver,groupId);
       
   180 	self->iClassVersion = KClassVersion2;
       
   181 	CleanupStack::Pop(self); 
       
   182 	return self;
       
   183 	}
       
   184 	
       
   185 
       
   186 
       
   187 /*
       
   188  * Second phase constructor 
       
   189  * @param aObserver view observer
       
   190  */
       
   191 void CContactGroupView::ConstructL(MContactViewObserver& aObserver,const TContactItemId aGroupId)
       
   192 	{
       
   193 	CContactViewBase::ConstructL();
       
   194 	OpenL(aObserver);
       
   195 	iView.OpenL(*this);
       
   196 	iGroupId=aGroupId;
       
   197 	}	
       
   198 
       
   199 // Update iGroupContacts based on group view options
       
   200 EXPORT_C void CContactGroupView::UpdateGroupViewL()
       
   201 /** Populates the group view.
       
   202 
       
   203 Removes any existing items from the group view then searches the underlying 
       
   204 view. The group view is repopulated with those items, maintaining the order 
       
   205 in which they occur in the underlying view.
       
   206 
       
   207 @leave KErrNotFound The group, identified by the label or ID specified during 
       
   208 construction, does not exist in the database. */
       
   209 	{
       
   210 	switch(iGroupType)
       
   211 		{
       
   212 		case EShowContactsInGroup:
       
   213 			UpdateForContactsInGroupL();
       
   214 			break;
       
   215 		case EShowContactsNotInGroup:
       
   216 			iGroupContacts.Reset();
       
   217 			UpdateForContactsNotInThisGroupL();
       
   218 			break;
       
   219 		case EShowContactsNotInAnyGroup:
       
   220 			iGroupContacts.Reset();
       
   221 			UpdateForUnfiledContactsL();
       
   222 			break;
       
   223 		default:
       
   224 			ASSERT(EFalse);
       
   225 		};
       
   226 	}
       
   227 
       
   228 /*
       
   229  * This is a reserved virtual exported function that is used for BC proofing 
       
   230  * against present and future additions of new exported virtual functions.
       
   231  **/
       
   232 TAny* CContactGroupView::CContactViewBase_Reserved_1(TFunction aFunction,TAny* aParams)
       
   233 	{
       
   234 	return CContactViewBase::CContactViewBase_Reserved_1(aFunction,aParams);
       
   235 	}
       
   236 
       
   237 /* Identify all contacts in the view which are not members of the group */
       
   238 void CContactGroupView::UpdateForContactsNotInThisGroupL()
       
   239 	{
       
   240 	CContactGroup* group = STATIC_CAST(CContactGroup*,MUTABLE_CAST(CContactDatabase&,iDb).ReadContactLC(iGroupId));
       
   241 	const CContactIdArray* memberArray = group->ItemsContained();
       
   242 	if (memberArray)
       
   243 		{
       
   244 		const TInt numContacts=iView.CountL();
       
   245 		TContactIdWithMapping idMapping;
       
   246 		TInt insertError=0;
       
   247 		for (TInt ii=0;ii<numContacts;++ii)
       
   248 			{
       
   249 			const TContactItemId id = iView.AtL(ii);
       
   250 			if(memberArray->Find(id)==KErrNotFound)
       
   251 				{
       
   252 				idMapping.iId=id;
       
   253 				idMapping.iMapping=ii;
       
   254 
       
   255 				TRAPD(err,insertError=iGroupContacts.InsertInOrder(idMapping,TLinearOrder<TContactIdWithMapping>(CompareMappingsL)));
       
   256 				User::LeaveIfError(err);
       
   257 				User::LeaveIfError(insertError);
       
   258 				}
       
   259 			}
       
   260 		}
       
   261 	CleanupStack::PopAndDestroy(group);
       
   262 	}
       
   263 
       
   264 /* Identify all members of the group in the view */
       
   265 void CContactGroupView::UpdateForContactsInGroupL()
       
   266 	{
       
   267 	CContactGroup* group = STATIC_CAST(CContactGroup*,MUTABLE_CAST(CContactDatabase&,iDb).ReadContactLC(iGroupId));
       
   268 	const CContactIdArray* memberArray = group->ItemsContained();
       
   269 		
       
   270 	if (memberArray && iClassVersion == KClassVersion2)
       
   271 		{
       
   272 		//Simulate members removed event. 
       
   273 		//We have to do this because the item removed event which arrives after group change event would be filtered out.
       
   274 		NotifyRemovedMembersL(memberArray);
       
   275 		}
       
   276 	
       
   277 	iGroupContacts.Reset();
       
   278 	if (memberArray)
       
   279 		{
       
   280 		UpdateForContactListL(memberArray);
       
   281 		}
       
   282 	CleanupStack::PopAndDestroy(group);
       
   283 	}
       
   284 
       
   285 /* 
       
   286  * Identify all "unfiled" contacts in the view. 
       
   287  * "Unfiled" contacts are all contacts which do not belong to any group
       
   288  */
       
   289 void CContactGroupView::UpdateForUnfiledContactsL()
       
   290 	{
       
   291 	CContactIdArray* unfiled= MUTABLE_CAST(CContactDatabase&,iDb).UnfiledContactsL();
       
   292 	CleanupStack::PushL(unfiled);
       
   293 	UpdateForContactListL(unfiled);
       
   294 	CleanupStack::PopAndDestroy(unfiled);
       
   295 	}
       
   296 
       
   297 /* Iterate through aArray and if they are in the view, add them to iGroupContacts */
       
   298 void CContactGroupView::UpdateForContactListL(const CContactIdArray* aArray)
       
   299 	{
       
   300 	const TInt count = aArray->Count();
       
   301 	TInt pos=KErrNotFound;
       
   302 	TContactIdWithMapping idMapping;
       
   303 	TInt insertError=KErrNone;
       
   304 
       
   305 	for (TInt ii=0;ii<count;++ii)
       
   306 		{
       
   307 		pos = iView.FindL((*aArray)[ii]);
       
   308 		if(pos!=KErrNotFound)
       
   309 			{
       
   310 			idMapping.iId=iView.AtL(pos);
       
   311 			idMapping.iMapping=pos;
       
   312 			TRAPD(err,insertError=iGroupContacts.InsertInOrder(idMapping,TLinearOrder<TContactIdWithMapping>(CompareMappingsL)));
       
   313 			User::LeaveIfError(err);
       
   314 			User::LeaveIfError(insertError);
       
   315 			}
       
   316 		}
       
   317 	}
       
   318 
       
   319 
       
   320 /* Static comparision method used for iGroupContacts ordering */
       
   321 TInt CContactGroupView::CompareMappingsL(const TContactIdWithMapping& aFirst,const TContactIdWithMapping& aSecond)
       
   322 	{
       
   323 	if(aFirst.iMapping>aSecond.iMapping)
       
   324 		{
       
   325 		return 1;
       
   326 		}
       
   327 	if(aFirst.iMapping<aSecond.iMapping)
       
   328 		{
       
   329 		return -1;
       
   330 		}
       
   331 	ASSERT(aFirst.iMapping!=aSecond.iMapping);
       
   332 	return 0;
       
   333 	}
       
   334 
       
   335 /* 
       
   336  * Find a group ID given a group name.
       
   337  * @param aGroupName Group name
       
   338  * @return Group Item ID if found, KNullContactItemId if group doesn't exist
       
   339  */
       
   340 TContactItemId CContactGroupView::GetGroupIdbyNameL(const TDesC& aGroupName)
       
   341 	{
       
   342 	ASSERT(aGroupName.Length()>0);
       
   343 	
       
   344 	TContactItemId groupId = KNullContactId;
       
   345 	CContactIdArray* groups =  iDb.GetGroupIdListL();
       
   346 	CleanupStack::PushL(groups);
       
   347 	const TInt groupCount = groups->Count();
       
   348 	for (TInt ii=0;ii<groupCount;++ii)
       
   349 		{
       
   350 		CContactGroup* group = STATIC_CAST(CContactGroup*,MUTABLE_CAST(CContactDatabase&,iDb).ReadContactLC((*groups)[ii]));	
       
   351 		if(group->GetGroupLabelL().Compare(aGroupName)==0)
       
   352 			{
       
   353 			//found Group
       
   354 			groupId = (*groups)[ii];
       
   355 			CleanupStack::PopAndDestroy(group);
       
   356 			break;
       
   357 			}
       
   358 		CleanupStack::PopAndDestroy(group);
       
   359 		}
       
   360 	CleanupStack::PopAndDestroy(groups);
       
   361 
       
   362 	return groupId;
       
   363 	}
       
   364 
       
   365 /* Handle events from the parent view */
       
   366 void CContactGroupView::HandleContactViewEvent(const CContactViewBase& aView,const TContactViewEvent& aEvent)
       
   367 	{
       
   368 	ASSERT(&aView==&iView);
       
   369 	TContactViewEvent event=aEvent;
       
   370 	TBool notifyObservers = ETrue;
       
   371 	TInt err;
       
   372 	switch (event.iEventType)
       
   373 		{
       
   374 		case TContactViewEvent::EUnavailable:
       
   375 		case TContactViewEvent::ESortError:
       
   376 		case TContactViewEvent::EServerError:
       
   377 			iState=ENotReady;
       
   378 			break;
       
   379 		case TContactViewEvent::ESortOrderChanged:
       
   380 		case TContactViewEvent::EReady:
       
   381 			{
       
   382 			if(&iView==&aView)
       
   383 				{
       
   384 				TState oldState = iState;
       
   385 				iState = EReady;
       
   386 				TRAP(err,UpdateGroupViewL());
       
   387 				if(err!=KErrNone)
       
   388 					{
       
   389 					iState = oldState;
       
   390 					NotifyObservers(TContactViewEvent(TContactViewEvent::ESortError,err));
       
   391 					notifyObservers = EFalse;
       
   392 					break;
       
   393 					}
       
   394 				}
       
   395 			}
       
   396 			break;
       
   397 		case TContactViewEvent::EItemAdded:
       
   398 			if(&iView==&aView)
       
   399 				{
       
   400 				TRAP(err, notifyObservers = HandleAddEventL(event));
       
   401 				if(err!=KErrNone)
       
   402 					{
       
   403 					NotifyObservers(TContactViewEvent(TContactViewEvent::ESortError,err));
       
   404 					notifyObservers = EFalse;
       
   405 					break;
       
   406 					}
       
   407 				}
       
   408 			break;
       
   409 		case TContactViewEvent::EItemRemoved:
       
   410 			if(&iView==&aView)
       
   411 				{
       
   412                 if (event.iContactId == iGroupId)
       
   413                     {
       
   414                     // The group which this class represents has been deleted
       
   415                     // so we need to re-build.
       
   416                     TRAP(err, UpdateGroupViewL());
       
   417 					}
       
   418 				else
       
   419 					{
       
   420                     // Just a single contact has been deleted.
       
   421                     TRAP(err, notifyObservers = HandleRemoveEventL(event));
       
   422 					}
       
   423 					
       
   424 				if(err!=KErrNone)
       
   425 					{
       
   426 					NotifyObservers(TContactViewEvent(TContactViewEvent::ESortError,err));
       
   427 					notifyObservers = EFalse;
       
   428 					break;
       
   429 					}
       
   430 				}
       
   431 			break;
       
   432 		case TContactViewEvent::EGroupChanged:
       
   433 			{
       
   434 			if(aEvent.iContactId==iGroupId || iGroupId==KNullContactId)
       
   435 				{
       
   436 				// The group which this class represents has changed or this
       
   437 				// view represents the "unfiled" group so we need to re-build.
       
   438 				TRAP(err,UpdateGroupViewL());
       
   439 				event.iEventType = TContactViewEvent::ESortOrderChanged;//force children views to re-build themselves.
       
   440 				//ESortOrderChanged should be changed in future to something like EUnderlyingDataChanged
       
   441 				event.iContactId = KNullContactId;
       
   442 				if(err!=KErrNone)
       
   443 					{
       
   444 					NotifyObservers(TContactViewEvent(TContactViewEvent::ESortError,err));
       
   445 					notifyObservers = EFalse;
       
   446 					break;
       
   447 					}
       
   448 				}
       
   449 
       
   450 			}
       
   451 			break;
       
   452 		default:
       
   453 			ASSERT(EFalse);
       
   454 		}	
       
   455 
       
   456 	if (notifyObservers)
       
   457 		{
       
   458 		NotifyObservers(event);
       
   459 		}
       
   460 	}
       
   461 
       
   462 /* Handles a EItemRemoved event from the underlying view */
       
   463 TBool CContactGroupView::HandleRemoveEventL(TContactViewEvent& aEvent)
       
   464 	{
       
   465 	TBool retval = EFalse;
       
   466 	TContactIdWithMapping mapping;
       
   467 	TInt pos = 0;
       
   468 
       
   469 	// check to see if the contact being removed belongs to us,
       
   470 	mapping.iMapping = aEvent.iInt;
       
   471 	mapping.iId = aEvent.iContactId;
       
   472 	pos = iGroupContacts.Find(mapping,TIdentityRelation<TContactIdWithMapping>(IdsEqual));
       
   473 	if ( pos != KErrNotFound ) // contact is a member of our list
       
   474 		{
       
   475 		retval = ETrue; // inform clients.
       
   476 		iGroupContacts.Remove(pos); // remove from our list
       
   477 		aEvent.iInt = pos;
       
   478 		}
       
   479 
       
   480 	UpdateMappingsL();
       
   481 	return retval;
       
   482 	}
       
   483 
       
   484 /* Handles a EItemAdded event from the underlying view */
       
   485 TBool CContactGroupView::HandleAddEventL(TContactViewEvent& aEvent)
       
   486 	{
       
   487 	TBool retval = ETrue;
       
   488     aEvent.iInt = KErrNone;
       
   489 
       
   490 	switch(iGroupType)
       
   491 		{
       
   492 		case EShowContactsInGroup:
       
   493 		case EShowContactsNotInGroup:
       
   494 				UpdateGroupViewL();
       
   495 				//Positions have changed in underlying view
       
   496 				UpdateMappingsL();
       
   497 		break;
       
   498 
       
   499 
       
   500 		case EShowContactsNotInAnyGroup:
       
   501 			{
       
   502 			retval = HandleAddEventForUnfiledContactsL(aEvent);
       
   503 			}
       
   504 		break;
       
   505 
       
   506 		};
       
   507     if(retval && iClassVersion == KClassVersion2) 	//if is the second version of the class put the right values in event
       
   508 		{
       
   509 		TContactIdWithMapping mapping;
       
   510 		mapping.iMapping = aEvent.iInt;
       
   511 		mapping.iId = aEvent.iContactId;
       
   512 		TInt pos = iGroupContacts.Find(mapping,TIdentityRelation<TContactIdWithMapping>(IdsEqual));
       
   513 		
       
   514 		if ( pos != KErrNotFound ) // contact is a member of our list
       
   515 			{
       
   516 			aEvent.iInt = pos;
       
   517 			}
       
   518 		else
       
   519 			{
       
   520 			retval = EFalse;
       
   521 			}
       
   522 		}
       
   523 
       
   524 	return retval;
       
   525 	}
       
   526 
       
   527 
       
   528 TInt CContactGroupView::CompareIndexesAllowingDuplicates(const TContactIdWithMapping& aFirst,const TContactIdWithMapping& aSecond)
       
   529 	{
       
   530 	TInt retval = 0;
       
   531 	if (aFirst.iMapping > aSecond.iMapping) retval = 1;
       
   532 	if (aFirst.iMapping < aSecond.iMapping) retval = -1;
       
   533 	return retval;
       
   534 	}
       
   535 
       
   536 
       
   537 TBool CContactGroupView::HandleAddEventForUnfiledContactsL(const TContactViewEvent& aEvent )
       
   538 	{
       
   539 	TBool retval = EFalse;
       
   540 	TContactIdWithMapping contactIdWithMapping;
       
   541 	CContactItem* contact = const_cast<CContactDatabase&>(iDb).ReadContactLC(aEvent.iContactId);
       
   542 
       
   543 
       
   544 	// If contact is a group then don't do anything - the add event is of no
       
   545 	// consequence.
       
   546 	if (contact->Type() == KUidContactGroup)
       
   547 		{
       
   548 		CleanupStack::PopAndDestroy(contact);
       
   549 		// No need to notify observers so return EFalse.
       
   550 		return EFalse;
       
   551 		}
       
   552 
       
   553 
       
   554 	UpdateMappingsL();
       
   555 
       
   556 	const CContactItemPlusGroup* contactCard = static_cast<const CContactCard*>(contact);
       
   557 	const CContactIdArray* idArray = contactCard->GroupsJoined();
       
   558 
       
   559 	if (idArray == NULL || idArray->Count() == 0) //
       
   560 		{
       
   561 		contactIdWithMapping.iId = aEvent.iContactId;
       
   562 		
       
   563 		// iGroupContacts contains contactIdWithMapping objects which have an index 
       
   564 		// to the contact item held in the underlying array iView.
       
   565 		// The mapping needs to be updated with this index before being added to iGroupContacts. 
       
   566 		contactIdWithMapping.iMapping = iView.FindL(contactIdWithMapping.iId);
       
   567 		
       
   568 		iGroupContacts.InsertInOrder(contactIdWithMapping,
       
   569 							TLinearOrder<TContactIdWithMapping>(CompareIndexesAllowingDuplicates));
       
   570 		retval = ETrue;
       
   571 		}
       
   572 
       
   573 
       
   574 	CleanupStack::PopAndDestroy(contact);
       
   575 	UpdateMappingsL();
       
   576 	return retval;
       
   577 	}
       
   578 
       
   579 /* 
       
   580  * Update view mappings.
       
   581  * This is called when an item has been added or removed from the underlying
       
   582  * view and the current mappings are therefore invalid.
       
   583  */
       
   584 void CContactGroupView::UpdateMappingsL()
       
   585 	{
       
   586 	TInt updatedViewIndex=KErrNotFound;
       
   587 	for (TInt i=0; i < iGroupContacts.Count(); ++i)
       
   588 		{
       
   589 		const TContactItemId idUpdate = iGroupContacts[i].iId;
       
   590 		updatedViewIndex=iView.FindL(idUpdate);
       
   591 		if(updatedViewIndex==KErrNotFound)
       
   592 			{
       
   593 			//local view has removed this contact, so we need to as well.
       
   594 			iGroupContacts.Remove(i);
       
   595 			i--;
       
   596 			continue;
       
   597 			}
       
   598 		iGroupContacts[i].iMapping=updatedViewIndex;
       
   599 		}
       
   600 	}
       
   601 
       
   602 TContactItemId CContactGroupView::AtL(TInt aIndex) const
       
   603 /** Gets the contact item ID at the specified view index.
       
   604 
       
   605 @param aIndex Index into the group view.
       
   606 @leave KErrNotFound aIndex is outside the bounds of the array.
       
   607 @return The contact item ID. */
       
   608 	{
       
   609 	if(aIndex>=iGroupContacts.Count())
       
   610 		{
       
   611 		//Out of Bounds.
       
   612 		User::Leave(KErrNotFound);
       
   613 		}
       
   614 	return (iGroupContacts)[aIndex].iId;
       
   615 	}
       
   616 
       
   617 const CViewContact& CContactGroupView::ContactAtL(TInt aIndex) const
       
   618 /** Gets the contact item at the specified view index.
       
   619 
       
   620 @param aIndex Index into the view of the required item.
       
   621 @leave KErrNotFound aIndex is outside the bounds of the array.
       
   622 @return The contact item. */
       
   623 	{
       
   624 	if(aIndex>=iGroupContacts.Count())
       
   625 		{
       
   626 		//Out of Bounds.
       
   627 		User::Leave(KErrNotFound);
       
   628 		}	
       
   629 	return iView.ContactAtL((iGroupContacts)[aIndex].iMapping);
       
   630 	}
       
   631 
       
   632 TInt CContactGroupView::CountL() const
       
   633 /** Gets the number of contact item IDs in the group view.
       
   634 
       
   635 @return The number of contact items in the group view. */
       
   636 	{
       
   637 	return iGroupContacts.Count();
       
   638 	}
       
   639 
       
   640 TInt CContactGroupView::FindL(TContactItemId aId) const
       
   641 /** Finds the index into the group view of the specified contact item.
       
   642 
       
   643 @param aId The contact item ID to search for.
       
   644 @leave KErrNotReady The view is not ready for use.
       
   645 @return The index of the first matching item in the view or KErrNotFound if 
       
   646 no matching item can be found. 
       
   647 */
       
   648 	{
       
   649 	if (iState != EReady)
       
   650 		{
       
   651 		User::Leave(KErrNotReady);
       
   652 		}
       
   653 	TContactIdWithMapping idWithDummyMapping;
       
   654 	idWithDummyMapping.iId=aId;
       
   655 	return iGroupContacts.Find(idWithDummyMapping,TIdentityRelation<TContactIdWithMapping>(IdsEqual));
       
   656 	}
       
   657 
       
   658 HBufC* CContactGroupView::AllFieldsLC(TInt aIndex,const TDesC& aSeparator) const
       
   659 /** Gets a descriptor containing the contents of all fields in an item in the 
       
   660 view.
       
   661 
       
   662 The fields are separated by aSeparator.
       
   663 
       
   664 @param aIndex The index into the view of the contact item.
       
   665 @param aSeparator The string to use to separate the fields.
       
   666 @return Pointer to the contact item descriptor. */
       
   667 	{
       
   668 	return iView.AllFieldsLC((iGroupContacts)[aIndex].iMapping,aSeparator);
       
   669 	}
       
   670 
       
   671 TContactViewPreferences CContactGroupView::ContactViewPreferences()
       
   672 /** Gets the underlying view's view preferences.
       
   673 
       
   674 @return The view preferences. */
       
   675 	{
       
   676 	return iView.ContactViewPreferences();
       
   677 	}
       
   678 
       
   679 const RContactViewSortOrder& CContactGroupView::SortOrderL() const
       
   680 /** Gets the underlying view's sort order.
       
   681 
       
   682 @return The sort order. */
       
   683 	{
       
   684 	return iView.SortOrderL();
       
   685 	}
       
   686 
       
   687 void CContactGroupView::NotifyRemovedMembersL(const CContactIdArray* aArray)
       
   688 	{
       
   689 	
       
   690 	TInt count = iGroupContacts.Count();
       
   691 	
       
   692 	if(count > aArray->Count())
       
   693 		{
       
   694 		TInt pos = KErrNotFound;
       
   695 		TContactViewEvent event(TContactViewEvent::EItemRemoved);				
       
   696 
       
   697 		for(TInt loop = 0;loop < count;++loop)
       
   698 			{
       
   699 			pos = aArray->Find(iGroupContacts[loop].iId);
       
   700 			if(pos != KErrNotFound) 
       
   701 				{
       
   702 				iGroupContacts[loop].iMapping = iView.FindL(iGroupContacts[loop].iId);	
       
   703 				}
       
   704 			}
       
   705 		
       
   706 		for(TInt loop = 0;loop < count;++loop)
       
   707 			{
       
   708 			pos = aArray->Find(iGroupContacts[loop].iId);
       
   709 			if(pos == KErrNotFound)
       
   710 				{
       
   711 				event.iContactId = iGroupContacts[loop].iId;
       
   712 				event.iInt = loop;
       
   713 				iGroupContacts.Remove(loop);
       
   714 				--count;
       
   715 				--loop;
       
   716 				NotifyObservers(event);
       
   717 				}
       
   718 			} // for
       
   719 		} // if
       
   720 	}