--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines_old/contactsmodel/cntview/ViewBase.cpp Fri Jun 11 13:29:23 2010 +0300
@@ -0,0 +1,1807 @@
+// Copyright (c) 2001-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:
+//
+
+// System includess
+#include "ecom/ecom.h" // For REComSession
+#include <ecom/ecomresolverparams.h>
+
+// User includes
+#include <cntviewbase.h>
+#include "CNTSTD.H"
+#include <cntviewfindconfig.h>
+#include "CVIEWCONTACTEXTENSION.h"
+#include <cntviewsortplugin.h>
+#include "cntviewprivate.h"
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <cntviewsortpluginbase.h>
+#endif
+
+extern void DebugLogViewNotification(const TDesC& aMethod, const TContactViewEvent& aEvent);
+
+//uncomment in conjunction with LocalView and T_Cnt_ViewSortProfiling
+//#define __PROFILE_SORT__
+
+
+EXPORT_C RContactViewSortOrder::RContactViewSortOrder() : iSpare(KErrNone), iSpare2(0), iSpare3(0)
+/** Default C++ constructor. */
+ {
+ }
+
+EXPORT_C void RContactViewSortOrder::Close()
+/** Closes the sort order array and frees all memory allocated to it. */
+ {
+ iFields.Close();
+ }
+
+EXPORT_C void RContactViewSortOrder::CopyL(const RContactViewSortOrder& aSortOrder)
+/** Copies the field types contained in the specified sort order object into this
+object.
+
+Any existing field types in this object are replaced.
+
+@param aSortOrder The sort order to be copied. */
+ {
+ iFields.Reset();
+ const TInt numFields=aSortOrder.iFields.Count();
+ for (TInt ii=0;ii<numFields;++ii)
+ {
+ TFieldType field = aSortOrder.iFields[ii];
+ AppendL(field);
+ }
+ }
+
+EXPORT_C void RContactViewSortOrder::InternalizeL(RReadStream& aStream)
+/** Internalises a sort order object from a read stream.
+
+@param aStream The stream to read from. */
+ {
+ iSpare = aStream.ReadInt32L();
+ iSpare2 = aStream.ReadInt32L();
+ iSpare3 = aStream.ReadInt32L();
+ TInt numFields;
+ numFields = aStream.ReadInt32L();
+ for (TInt ii=0;ii<numFields;++ii)
+ {
+ TFieldType thisField;
+ aStream >> thisField.iUid;
+ AppendL(thisField);
+ }
+ }
+
+EXPORT_C void RContactViewSortOrder::ExternalizeL(RWriteStream& aStream) const
+/** Externalises a sort order object to a write stream.
+
+@param aStream The stream to write to. */
+ {
+ aStream.WriteInt32L(iSpare);
+ aStream.WriteInt32L(iSpare2);
+ aStream.WriteInt32L(iSpare3);
+ const TInt numFields=iFields.Count();
+ aStream.WriteInt32L(numFields);
+ for (TInt ii=0;ii<numFields;++ii)
+ {
+ aStream << iFields[ii].iUid;
+ }
+ }
+
+/*
+ * The current implementation relies on the externalized size provided by
+ * the STORE implementation.
+ */
+EXPORT_C TInt RContactViewSortOrder::ExternalizedSize() const
+/** Retrieves the number of bytes required to store the sort order when externalised.
+
+@return The size of the sort order object. */
+ {
+ return (sizeof(TInt)*4)+(iFields.Count()*sizeof(TFieldType));
+ }
+
+EXPORT_C TBool RContactViewSortOrder::operator==(const RContactViewSortOrder& aSortOrder) const
+/** Compares two sort order objects for equivalence.
+
+@param aSortOrder The sort order object to compare with this one.
+@return ETrue if the two sort orders are the same, EFalse if not. */
+ {
+ TBool sortOrdersMatch = ETrue;
+
+ const TInt numFields=iFields.Count();
+ if (numFields!=aSortOrder.Count())
+ {
+ sortOrdersMatch = EFalse;
+ }
+ else
+ {
+ for (TInt ii=0;ii<numFields;++ii)
+ {
+ if (iFields[ii]!=aSortOrder.iFields[ii])
+ {
+ sortOrdersMatch = EFalse;
+ break;
+ }
+ }
+ }
+
+ return sortOrdersMatch;
+ }
+
+
+EXPORT_C void CContactViewBase::OpenL(MContactViewObserver& aObserver)
+/** Appends an observer to the view's observer array.
+
+If the view's state is EReady, the observer is notified asynchronously that
+the view is ready.
+
+An error causes the function to leave.
+
+@param aObserver The contact view observer to be added. */
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewApiOpenL);
+#endif
+ iObserverArray.AppendL(&aObserver);
+ if (GetErrorValueFromExtensionClass()!=KErrNone)
+ {
+ NotifyObservers(TContactViewEvent(TContactViewEvent::ESortError,iExtension->iError));
+ }
+ if (iState==EReady)
+ {
+ User::LeaveIfError(NotifyObserverAsync(aObserver,TContactViewEvent(TContactViewEvent::EReady)));
+ }
+ }
+
+EXPORT_C TInt CContactViewBase::Open(MContactViewObserver& aObserver)
+/** Appends an observer to the view's observer array.
+
+If the view's state is EReady, the observer is notified asynchronously that
+the view is ready.
+
+This function does not leave; an error code is returned instead.
+
+@param aObserver The contact view observer to add.
+@return A standard error code, or KErrNone if the function completed without
+an error. */
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewApiOpen);
+#endif
+ TInt err=iObserverArray.Append(&aObserver);
+ if (iExtension->iError!=KErrNone)
+ {
+ NotifyObservers(TContactViewEvent(TContactViewEvent::ESortError,iExtension->iError));
+ }
+ if (err)
+ {
+ return err;
+ }
+ if (iState==EReady)
+ {
+ err = NotifyObserverAsync(aObserver,TContactViewEvent(TContactViewEvent::EReady));
+ if (err!=KErrNone)
+ {
+ return err;
+ }
+ }
+ return err;
+ }
+
+/**
+Removes an observer from the view's observer array.
+
+Any outstanding notifications for aObserver are first cancelled.
+
+@capability None
+@param aObserver The contact view observer to be removed.
+@return ETrue if the view's observer array is empty as a result of the removal;
+EFalse if it is not empty or if aObserver could not be found in the observer
+array.
+*/
+EXPORT_C TBool CContactViewBase::Close(const MContactViewObserver& aObserver)
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewApiClose);
+#endif
+ const TInt observerIndex = iObserverArray.Find(&aObserver);
+ if (observerIndex != KErrNotFound)
+ {
+ //the observer that just closed may be expecting a notification
+ for (TInt outstandingIndex=iOutstandingNotifications.Count()-1; outstandingIndex>=0; --outstandingIndex)
+ {
+ if (iOutstandingNotifications[outstandingIndex].iObserverToNotify == &aObserver)
+ {
+ iOutstandingNotifications.Remove(outstandingIndex);
+ }
+ }
+ if(iOutstandingNotifications.Count()==0)
+ {
+ iOutstandingNotifications.Reset();
+ if(iAsyncNotifier->IsActive())
+ {
+ //AsyncNotifier is Active with nothing to notifiy so we need to cancel it.
+ iAsyncNotifier->Cancel();
+ }
+ }
+ //remove observer from main array.
+ iObserverArray.Remove(observerIndex);
+ if (iObserverArray.Count()==0)
+ {
+ delete this;
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+
+EXPORT_C CContactViewBase::CContactViewBase(const CContactDatabase& aDb)
+ : iDb(aDb),iState(EInitializing)
+/** Protected C++ constructor.
+
+Initialises the view's state to EInitializing.
+
+@param aDb The database that contains the contact items. */
+ {
+ }
+
+EXPORT_C CContactViewBase::~CContactViewBase()
+/** Destructor.
+
+Cancels all outstanding notifications and deletes all resources owned by the object. */
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewDestructor);
+#endif
+ delete iExtension;
+ REComSession::FinalClose(); // This line is necessary to make sure the plug-in is unloaded properly
+ iObserverArray.Close();
+ delete iAsyncNotifier;
+ iOutstandingNotifications.Close();
+ }
+
+EXPORT_C void CContactViewBase::ConstructL()
+/** Protected second phase constructor.
+
+Called from a derived class's ConstructL(). Creates the view's asynchronous
+notifier and adds it to the active scheduler. */
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewApiConstructL);
+#endif
+ iAsyncNotifier=CIdle::NewL(CActive::EPriorityStandard);
+ iExtension = CContactViewBaseExtension::NewL();
+ if(iExtension)
+ {
+ iExtension->iFindPluginUid = KNullUid;
+ iExtension->iError = KErrNone;
+ }
+ }
+
+EXPORT_C void CContactViewBase::NotifyObservers(const TContactViewEvent& aEvent)
+/** Called by derived view classes to notify their observers synchronously of an
+event, by calling their HandleContactViewEvent() function.
+
+@param aEvent Identifies the event that occurred. */
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewApiNotifyObservers, aEvent);
+#endif
+ TInt Observer=iObserverArray.Count();
+#if defined(__VERBOSE_DEBUG__)
+ //Print the message to be broadcated to the views
+ if (Observer)
+ {
+ DebugLogViewNotification(_L("[CNTMODEL] CContactViewBase::NotifyObservers"), aEvent);
+ }
+#endif
+ // We iterate backwards to allow for observers removing themselves from the array
+ while (Observer--)
+ {
+ iObserverArray[Observer]->HandleContactViewEvent(*this,aEvent);
+ }
+ }
+
+EXPORT_C TInt CContactViewBase::NotifyObserverAsync(MContactViewObserver& aObserver,const TContactViewEvent& aEvent)
+/** Called to notify a single view observer asynchronously of an event.
+
+If other notifications are outstanding, this notification is appended to the
+queue.
+
+If the view's asynchronous notifier is not active, it is started as a background
+task.
+
+This function is called by OpenL() and Open() to notify the observer that
+the view is ready.
+
+@param aObserver The contact view observer to notify. This must have previously
+been added to the view's observer array.
+@param aEvent Identifies the event that occurred.
+@return KErrNone if the function completed without error, otherwise one of
+the standard error codes. */
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewApiNotifyObserverAsync, aEvent);
+#endif
+ TInt err = KErrNone;
+ __ASSERT_DEBUG(iObserverArray.Find(&aObserver)!=KErrNotFound,Panic(ECntPanicObserverNotFound));
+ TObserverAndEvent outstandingNotification;
+ outstandingNotification.iAsyncEvent=aEvent;
+ outstandingNotification.iObserverToNotify=&aObserver;
+ err = iOutstandingNotifications.Append(outstandingNotification);
+ if (err==KErrNone)
+ {
+ if(!(iAsyncNotifier->IsActive()))
+ {
+ //No current outstanding notifications, start the asyn notifier to deal with the event that
+ //was just added
+ __ASSERT_DEBUG(iAsyncNotifier->IsActive()==EFalse,Panic(ECntPanicAsyncViewNotificationPending));
+ iAsyncNotifier->Start(TCallBack(AsyncNotifyCallBack,this));
+ }
+ }
+ return err;
+ }
+
+TInt CContactViewBase::AsyncNotifyCallBack(TAny* aSelf)
+ {
+ //Notifiy the bottom element in the outstanding notifiers array,
+ //at the end of the function if the array is not empty there are further observers to notify.
+ CContactViewBase* self=STATIC_CAST(CContactViewBase*,aSelf);
+#ifdef _DEBUG
+ TInt outstandingNotifCount = self->iOutstandingNotifications.Count();
+ __ASSERT_DEBUG(outstandingNotifCount>0,Panic(ECntPanicObserverNotFound));
+#endif
+ TContactViewEvent event=self->iOutstandingNotifications[0].iAsyncEvent;
+ MContactViewObserver* observerToNotify=self->iOutstandingNotifications[0].iObserverToNotify;
+ __ASSERT_DEBUG(observerToNotify && self->iObserverArray.Find(observerToNotify)!=KErrNotFound,Panic(ECntPanicObserverNotFound));
+ self->iOutstandingNotifications.Remove(0);
+ observerToNotify->HandleContactViewEvent(*self,event);
+ return self->iOutstandingNotifications.Count();
+ }
+
+EXPORT_C TBool CContactViewBase::IdsMatch(const CViewContact& aFirst,const CViewContact& aSecond)
+/** Tests whether the IDs of two contact items are the same.
+
+@param aFirst The first contact item.
+@param aSecond The second contact item.
+@return True if the IDs match, otherwise false. */
+ {
+ return (aFirst.Id()==aSecond.Id());
+ }
+
+EXPORT_C HBufC* CContactViewBase::FieldsWithSeparatorLC(const RPointerArray<CViewContact>& aContacts,TInt aIndex,const TDesC& aSeparator) const
+/** Allocates and returns a descriptor filled with the contents of all the fields
+in a contact item.
+
+The fields are separated by the specified separator.
+
+@param aContacts An array of contact items.
+@param aIndex An index into the specified array.
+@param aSeparator The text to use to separate the fields.
+@return A pointer to a heap descriptor containing the contents of each of the
+contact item's fields. The field separator is appended to each field except
+the last one. The pointer is left on the cleanup stack. */
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewApiFieldsWithSeparatorLC);
+#endif
+ // Calculate the length of the buffer.
+ TInt bufLength=0;
+ const CViewContact& viewContact = *(aContacts[aIndex]);
+ const TInt separatorLength=aSeparator.Length();
+ const TInt numFields=viewContact.FieldCount();
+ for (TInt ii=0;ii<numFields;++ii)
+ {
+ bufLength+=viewContact.Field(ii).Length()+separatorLength;
+ }
+ HBufC* buf=HBufC::NewLC(bufLength);
+ TPtr bufPtr(buf->Des());
+
+ // Fill the buffer.
+ for (TInt j=0;j<numFields;++j)
+ {
+ bufPtr.Append(viewContact.Field(j));
+
+ // Only put a separator in if this isn't the last field.
+ if (j!=numFields-1)
+ {
+ bufPtr.Append(aSeparator);
+ }
+ }
+ return buf;
+ }
+
+EXPORT_C TBool CContactViewBase::MatchesCriteriaL(const CViewContact& aContact,const MDesCArray& aFindWords)
+/** Searches a single contact item for fields that contain one or more search strings.
+
+The search uses wildcard matching so that the search strings can occur anywhere
+in any of the item's fields. For a match to occur, all of the search strings
+must be found in the contact item.
+
+Any find configuration plug-in that has been set (by calling SetViewFindConfigPlugin())
+will be used.
+
+@param aContact The contact item to search.
+@param aFindWords A descriptor array containing one or more search strings.
+@return True if all of the search strings were present in the contact item's
+fields. False if not. */
+ {
+ return MatchesCriteriaL(aContact,aFindWords,EFullSearch,iExtension);
+ }
+
+EXPORT_C TBool CContactViewBase::MatchesCriteriaL(const CViewContact& aContact,const MDesCArray& aFindWords, TSearchType aSearchType)
+/** Searches a single contact item for fields that contain one or more search strings.
+
+The search type indicates whether the search strings can occur anywhere in
+a field, or must occur at the start of a field only. For a match to occur,
+all of the search strings must be found in the contact item.
+
+This function does not use any find configuration plug-in that has been set
+(by calling SetViewFindConfigPlugin()), so new code should use one of the other
+overloads instead. This function has been maintained for binary compatibility
+with previous OS versions.
+
+@param aContact The contact item to search.
+@param aFindWords A descriptor array containing one or more search strings.
+@param aSearchType The search type. This controls whether a search term can
+occur anywhere in a contact item field, or just at the beginning of a field.
+@return True if all of the search strings were present in the contact item's
+fields. False if not. */
+ {
+ return MatchesCriteriaL(aContact,aFindWords,aSearchType,NULL);
+ }
+
+EXPORT_C TBool CContactViewBase::MatchesCriteriaL(const CViewContact& aContact,const MDesCArray& aFindWords, TSearchType aSearchType,CContactViewBase::CContactViewBaseExtension* aExtension)
+/** Searches a single contact item for fields that contain one or more search strings.
+
+The search type indicates whether the search strings can occur anywhere in
+a field, or must occur at the start of a field only. For a match to occur,
+all of the search strings must be found in the contact item.
+
+If a find configuration plug-in UID is specified in the fourth parameter,
+this overload uses it, loading it first if necessary. This overrides any plug-in
+that had previously been set by a call to SetViewFindConfigPlugin().
+
+@param aContact The contact item to search.
+@param aFindWords A descriptor array containing one or more search strings.
+@param aSearchType The search type. This controls whether a search term can
+occur anywhere in a contact item field, or just at the beginning of a field.
+@param aExtension Optionally, this can be used to specify the UID of a find
+configuration plug-in, overriding any that has previously been set by a call
+to SetViewFindConfigPlugin().
+@return True if all of the search strings were present in the contact item's
+fields. False if not. */
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewApiMatchesCriteriaL, aContact.Id());
+#endif
+ CDesCArrayFlat* findWordArray = CreateFindWordArrayLC(aFindWords, aSearchType);
+ TBool result = ContactMatchesCriteriaL(aContact, *findWordArray,aExtension);
+ CleanupStack::PopAndDestroy(findWordArray);
+ return result;
+ }
+
+/*
+ * Create an array of words to use when matching contact data.
+ * @param aFindWords Array of words
+ * @param aSearchType Specifies a prefix or substring match
+ * @return Array of words
+ */
+CDesCArrayFlat* CContactViewBase::CreateFindWordArrayLC(const MDesCArray& aFindWords, TSearchType aSearchType)
+ {
+ const TInt numFindWords=aFindWords.MdcaCount();
+ CDesCArrayFlat* findWordArray = new (ELeave) CDesCArrayFlat(numFindWords);
+ CleanupStack::PushL(findWordArray);
+
+ for (TInt i=0; i<numFindWords; ++i)
+ {
+ TPtrC original(aFindWords.MdcaPoint(i));
+ HBufC* findString=HBufC::NewLC(original.Length()+2);
+ TPtr ptr(findString->Des());
+ switch(aSearchType)
+ {
+ case EFullSearch:
+ ptr.Append('*');
+ break;
+ case EPrefixSearch:
+ break;
+ default: // programming error.
+ break;
+ }
+ ptr.Append(original);
+ ptr.Append('*');
+ findWordArray->AppendL(*findString);
+ CleanupStack::PopAndDestroy(findString);
+ }
+ return findWordArray;
+ }
+
+/*
+ * Check if aContact matches aFindWords
+ * @return ETrue if matched, EFalse otherwise
+ * new parameter has been added aExtension CContactViewBase extension class.
+ */
+TBool CContactViewBase::ContactMatchesCriteriaL(const CViewContact& aContact,const MDesCArray& aFindWords,CContactViewBase::CContactViewBaseExtension* aExtension)
+ {
+ TInt hits = 0;
+ const TInt numFields=aContact.FieldCount();
+ const TInt numFindWords=aFindWords.MdcaCount();
+ if(aExtension->iFindPluginUid != KNullUid && aExtension->iFindPluginImpl == NULL)
+ {
+ //Load plug-in
+ aExtension->iFindPluginImpl = CContactViewFindConfigInterface::NewL(aExtension->iFindPluginUid);
+ }
+ if (aExtension->iFindPluginImpl)
+ {
+ for (TInt jj=0;jj<numFindWords;++jj)
+ {
+ TPtrC word(aFindWords.MdcaPoint(jj));
+ if (aExtension->iFindPluginImpl->IsWordValidForMatching(word))
+ {
+ for (TInt kk=0;kk<numFields;++kk)
+ {
+ if (aExtension->iFindPluginImpl->Match(aContact.Field(kk), word))
+ {
+ ++hits;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (TInt kk=0;kk<numFields;++kk)
+ {
+ if (aContact.Field(kk).MatchC(word)!=KErrNotFound)
+ {
+ ++hits;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for (TInt jj=0;jj<numFindWords;++jj)
+ {
+ TPtrC word(aFindWords.MdcaPoint(jj));
+ for (TInt kk=0;kk<numFields;++kk)
+ {
+ if (aContact.Field(kk).MatchC(word)!=KErrNotFound)
+ {
+ ++hits;
+ break;
+ }
+ }
+ }
+ }
+ return (hits==numFindWords);
+ }
+
+/* Implementation of ContactsMatchingCriteriaL and ContactsMatchingPrefixL */
+void CContactViewBase::MatchContactsL(const MDesCArray& aFindWords,RPointerArray<CViewContact>& aMatchedContacts, TSearchType aSearchType)
+ {
+ CDesCArrayFlat* findWordArray = CreateFindWordArrayLC(aFindWords, aSearchType);
+ const TInt viewCount = CountL();
+ TBool match = EFalse;
+ for (TInt ii=0;ii<viewCount;++ii)
+ {
+ const CViewContact& contact = ContactAtL(ii);
+ match=ContactMatchesCriteriaL(contact,*findWordArray,iExtension);
+ if (match)
+ {
+ CViewContact* thisContact = CViewContact::NewL(contact);
+ CleanupStack::PushL(thisContact);
+ aMatchedContacts.AppendL(thisContact);
+ CleanupStack::Pop(thisContact);
+ }
+ }
+ CleanupStack::PopAndDestroy(findWordArray);
+ }
+
+/** Searches all contact items in the view for fields that contain all of the search
+strings specified.
+
+The search uses wildcard matching so that the search strings can occur anywhere
+in the item's fields. For a match to occur, all of the search strings must
+be found in a contact item.
+
+@capability ReadUserData
+@param aFindWords A descriptor array containing one or more search strings.
+@param aMatchedContacts On return, an array of matching contact items. */
+EXPORT_C void CContactViewBase::ContactsMatchingCriteriaL(const MDesCArray& aFindWords, RPointerArray<CViewContact>& aMatchedContacts)
+ {
+ MatchContactsL(aFindWords,aMatchedContacts,EFullSearch);
+ }
+
+/** Searches all contact items in the view for fields that contain all of the search
+strings specified.
+
+Unlike ContactsMatchingCriteriaL(), the search term can only occur at the
+beginning of a field.
+
+@capability ReadUserData
+@param aFindWords A descriptor array containing one or more search strings.
+@param aMatchedContacts On return, an array of matching contact items. */
+EXPORT_C void CContactViewBase::ContactsMatchingPrefixL(const MDesCArray& aFindWords, RPointerArray<CViewContact>& aMatchedContacts)
+ {
+ MatchContactsL(aFindWords,aMatchedContacts, EPrefixSearch);
+ }
+
+/**
+This is a reserved virtual exported function that is used for BC proofing against
+addition of new exported virtual functions.
+This function now aids addition of new exported virtual methods without
+having to break BC,by simply having those virtual methods as
+non-virtual and helper methods, called from this one and only reserved virtual
+exported method.A public enumeration type that is defined in the base class
+CContactViewBase identifies which of the helper 'virtual' methods are being called.
+All derived classes of CContactViewBase that are public should mandatorily implement
+this method.
+
+Returns any return values of the helper methods called from this function.
+
+@capability ReadUserData
+@param aFunction an enum value that identifies which helper method is called.
+@param aParams parameters to the helper method being called.
+@return Any return values of the helper methods called from this function or NULL.
+*/
+EXPORT_C TAny* CContactViewBase::CContactViewBase_Reserved_1(TFunction aFunction,TAny* aParams)
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewApiContactViewBase_Reserved_1);
+#endif
+ switch(aFunction)
+ {
+ case ECContactViewBaseVirtualFunction1:
+ {
+ TVirtualFunction1Params* vFuncParams = STATIC_CAST(TVirtualFunction1Params*,aParams);
+ GetContactIdsL(*vFuncParams->iIndexes,*vFuncParams->iIdArray);
+ }
+ break;
+ case ECContactViewBaseVirtualFunction2:
+ {
+ TVirtualFunction2Params* vFuncParams = STATIC_CAST(TVirtualFunction2Params*,aParams);
+ GetContactsMatchingFilterL(vFuncParams->iFilter, vFuncParams->iMatchingContacts);
+ }
+ break;
+ case ECContactViewBaseVirtualFunction3:
+ {
+ TVirtualFunction3Params* vFuncParams = STATIC_CAST(TVirtualFunction3Params*,aParams);
+ TInt error = KErrNone;
+ error = InsertContactInView(vFuncParams->iContacts,vFuncParams->iNewContact,EFalse,NULL);
+ // stuff error code into a TAny *
+ return reinterpret_cast<TAny*> (error);
+ }
+ default:
+ break;
+ }
+ return NULL;
+ }
+
+EXPORT_C void CContactViewBase::SetViewFindConfigPlugin(TUid aUid)
+/** Sets the UID of the view's find configuration plug-in to use in calls to ContactsMatchingCriteriaL(),
+ContactsMatchingPrefixL() and MatchesCriteriaL().
+
+@param aUid The UID of the view's find configuration plug-in.
+@see CContactViewFindConfigInterface */
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewApiSetViewFindConfigPlugin);
+#endif
+ iExtension->iFindPluginUid = aUid;
+ }
+
+EXPORT_C TUid CContactViewBase::GetViewFindConfigPlugin()
+/** Gets the UID of the view's find configuration plug-in, as set by SetViewFindConfigPlugin().
+
+@return The UID of the view's find configuration plug-in. KNullUid if none
+has been set.
+@see CContactViewFindConfigInterface */
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewApiGetViewFindConfigPlugin);
+#endif
+ return iExtension->iFindPluginUid ;
+ }
+
+/** Gets an array containing the IDs of the contact items at the specified view
+indexes.
+
+The IDs are appended to the array.
+
+@capability ReadUserData
+@param aIndexes An array of indexes into this view.
+@param aContactIds On return, an array to which the contact item IDs of each
+of the indexed items are appended. */
+EXPORT_C void CContactViewBase::GetContactIdsL(const CArrayFix<TInt>& aIndexes, CContactIdArray& aContactIds)
+ {
+#ifdef CONTACTS_API_PROFILING
+ TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassViewBase, TContactsApiProfile::ECntViewApiGetContactIdsL);
+#endif
+ const TInt myCount = CountL();
+ const TInt indexCount = aIndexes.Count();
+ for (TInt i=0; i < indexCount; ++i)
+ {
+ const TInt index = aIndexes[i];
+ if (index >= 0 && index < myCount)
+ {
+ aContactIds.AddL(AtL(index));
+ }
+ }
+ }
+/**
+ * Gets an array containing the IDs of the contact items that match
+ * the filter supplied by the client.
+ *
+ * @param aFilter Filter The filter to use
+ * @param aMatchingContacts Array of matching contact IDs
+ */
+void CContactViewBase::GetContactsMatchingFilterL(TInt aFilter, RArray<TContactIdWithMapping>& aMatchingContacts)
+ {
+ TContactIdWithMapping idMap;
+ const TInt viewCount(CountL());
+ for (TInt i=0;i<viewCount;++i)
+ {
+ const CViewContact& contact = ContactAtL(i);
+ if(contact.ContactMatchesFilter(aFilter))
+ {
+ idMap.iId=contact.Id();
+ idMap.iMapping=i;
+ aMatchingContacts.AppendL(idMap);
+ }
+ }
+ }
+
+EXPORT_C TBool CContactViewBase::IdsEqual(const TContactIdWithMapping& aFirst,const TContactIdWithMapping& aSecond)
+/** Tests whether the IDs of two contact items are the same.
+
+@param aFirst The contact ID/view index struct representing the first item.
+@param aSecond The contact ID/view index struct representing the second item.
+@return True if the IDs match, false if not. */
+ {
+ return (aFirst.iId==aSecond.iId);
+ }
+
+EXPORT_C TBool CContactViewBase::IndexesEqual(const TContactIdWithMapping& aFirst,const TContactIdWithMapping& aSecond)
+/** Tests whether the view indexes of two contact items are the same.
+
+@param aFirst The contact ID/view index struct representing the first item.
+@param aSecond The contact ID/view index struct representing the second item.
+@return True if the indexes match, false if not. */
+ {
+ return (aFirst.iMapping==aSecond.iMapping);
+ }
+
+/*
+ See defect EXT-59BFK6 "Contact view sorting does not use default collation rules"
+ for further information.
+ This 'static' function is used by Sort Plugin.
+ See method below for version used by default sort.
+ Generally fixes should be applied to both!
+ */
+EXPORT_C TInt CContactViewBase::CompareFieldsL(const CViewContact& aFirst,const CViewContact& aSecond)
+/** Collates two contact items' field contents.
+
+This is done by comparing each contact item on a field by field basis starting
+with the loosest collation level initially, and then progressing to tighter
+collation levels only if the items are considered the same at the looser level.
+This is required so that items differing by case only are sorted correctly.
+If a field isn't present, then the comparison is done using the first field
+that is present.
+
+@param aFirst The first contact item.
+@param aSecond The second contact item.
+@return A positive value indicates that aFirst's field contents are greater
+than aSecond's (so that aFirst would occur after aSecond in a sort order).
+A negative value indicates that aFirst's field contents are less than aSecond's
+(so that aFirst would occur before aSecond in a sort order). Zero indicates
+that aFirst and aSecond have identical field contents. */
+ {
+ const TInt KDefaultCollationLevel=3;
+ TInt comparison = 0; // result of comparison, Zero = fields are identical
+ TInt collationLevel = 0;
+
+ TCollationMethod collateMethod = *Mem::CollationMethodByIndex(0);
+ collateMethod.iFlags|=TCollationMethod::EIgnoreNone;
+
+ do
+ {
+ comparison = CompareFieldsWithCollationLevel(aFirst, aSecond, collationLevel, &collateMethod);
+ ++collationLevel;
+ }
+ while (comparison == 0 && collationLevel <= KDefaultCollationLevel);
+
+ return comparison;
+ }
+
+/*
+ Similar to 'static', exported CompareFieldsL() method above.
+ Except (for performance) it uses cached copy of TCollationMethod belonging to the view.
+ Generally fixes should be applied to both!
+ */
+TInt CContactViewBase::TextCompareFieldsL(const CViewContact& aFirst,const CViewContact& aSecond) const
+/** Collates two contact items' field contents.
+
+This is done by comparing each contact item on a field by field basis starting
+with the loosest collation level initially, and then progressing to tighter
+collation levels only if the items are considered the same at the looser level.
+This is required so that items differing by case only are sorted correctly.
+If a field isn't present, then the comparison is done using the first field
+that is present.
+
+Faster than static CompareFieldsL() method as it uses prefetched collation method.
+
+@param aFirst The first contact item.
+@param aSecond The second contact item.
+@return A positive value indicates that aFirst's field contents are greater
+than aSecond's (so that aFirst would occur after aSecond in a sort order).
+A negative value indicates that aFirst's field contents are less than aSecond's
+(so that aFirst would occur before aSecond in a sort order). Zero indicates
+that aFirst and aSecond have identical field contents. */
+ {
+ const TInt KDefaultCollationLevel=3;
+ TInt comparison = 0; // result of comparison, Zero = fields are identical
+ TInt collationLevel = 0;
+
+ do
+ {
+ comparison = CompareFieldsWithCollationLevel(aFirst, aSecond, collationLevel, &iExtension->iCollationMethod);
+ ++collationLevel;
+ }
+ while (comparison == 0 && collationLevel <= KDefaultCollationLevel);
+
+ return comparison;
+ }
+
+/** Gets the recorded error value.
+If an error occurs within the view, before each of the views
+observers are notified, then the view records the error code internally.
+This function provides access to a copy of that error code.
+
+
+@return The recorded error value. If this does not equal KErrNone, then something is wrong with the view.
+*/
+EXPORT_C TInt CContactViewBase::Error() const
+ {
+ return iExtension->iError;
+ }
+
+/*
+ * Extension class for maintaining BC in member variables.
+ */
+CContactViewBase::CContactViewBaseExtension* CContactViewBase::CContactViewBaseExtension::NewL()
+/** Constructs a new instance of the class.
+
+If a plug-in has been loaded, its OpenL() function is called, see CContactViewFindConfigInterface::OpenL().
+
+@return Pointer to the newly created extension object. */
+ {
+ CContactViewBaseExtension* self =
+ new( ELeave ) CContactViewBaseExtension;
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CContactViewBase::CContactViewBaseExtension::CContactViewBaseExtension()
+ {
+ }
+
+CContactViewBase::CContactViewBaseExtension::~CContactViewBaseExtension()
+/* Destructor.
+
+If a Find plug-in has been loaded, its Close() function is called. See CContactViewFindConfigInterface::Close() */
+ {
+ if ( iFindPluginImpl )
+ {
+ delete iFindPluginImpl;
+ }
+ if (iSortPluginImpl)
+ { // unload
+ delete iSortPluginImpl;
+ }
+ }
+
+
+TInt CContactViewBase::CompareFieldsWithCollationLevel(const CViewContact& aFirst, const CViewContact& aSecond,
+ TInt aCollationLevel, TCollationMethod* aCollateMethod)
+ {
+ const TInt KLastField = aFirst.FieldCount() - 1;
+
+ TInt retval = 0; // result of comparison, Zero = fields are identical
+ TInt firstField(-1);
+ TInt secondField(-1);
+ TPtrC first;
+ TPtrC second;
+
+ for (TInt counter=0; !retval && (counter <= KLastField); counter++)
+ {
+ // if the 1st populated field has a greater index than counter,
+ // that means we'd get the same result from FindFirstPopulatedField.
+ // So, don't bother. Of course we always have to run it at least once.
+
+ if (firstField < counter)
+ {
+ first.Set(aFirst.FindFirstPopulatedField(counter, firstField));
+ }
+
+ if (secondField < counter)
+ {
+ second.Set(aSecond.FindFirstPopulatedField(counter, secondField));
+ }
+
+ // no fields in either item
+ if ((firstField < 0) && (secondField < 0))
+ {
+ break;
+ }
+
+ if (firstField < 0)
+ {
+ // first item sorts lower
+ retval = -1;
+ }
+ else if (secondField < 0)
+ {
+ // second item sorts lower
+ retval = 1;
+ }
+ else
+ {
+ // set counter to the first field populated by either contact
+ while ((firstField > counter) && (secondField > counter))
+ counter++;
+
+ retval = first.CompareC(second, aCollationLevel, aCollateMethod);
+ }
+ }
+
+ return retval;
+ }
+
+
+void CContactViewBase::CContactViewBaseExtension::ConstructL()
+ {
+ if ( iFindPluginImpl )
+ {
+ iFindPluginImpl->OpenL();
+ }
+
+ // Collation method by index 0 stays the same (only changes at a reboot)
+ iCollationMethod = *Mem::CollationMethodByIndex(0);
+ iCollationMethod.iFlags |= TCollationMethod::EIgnoreNone;
+ }
+
+/*
+ * Finds the first populated field within a contact.
+ *
+ * Starting at aOffset search for the first populated field. Search up to
+ * the maximum number of fields available within the contact.
+ *
+ * If no populated field is found, then this function will return a zero
+ * length TPtrC and set aFoundPosition to -1.
+ *
+ * @param aOffset The starting offset
+ * @param aFoundPosition The offset of the field found
+ * @return The contents of the field located at the found position
+ */
+TPtrC CViewContact::FindFirstPopulatedField(TInt aOffset, TInt& aFoundPosition) const
+ {
+ if (iExtension)
+ {
+ const TInt max = iTextIndexes.Count() - 1;
+ TInt lengthOfText=0;
+
+ for (TInt counter = aOffset; counter <= max; counter++)
+ {
+ const TInt fieldStartPos = iTextIndexes[counter];
+
+ if (counter < max)
+ {
+ lengthOfText = iTextIndexes[counter+1] - fieldStartPos;
+ }
+ else
+ {
+ lengthOfText = iExtension->FieldText().Length() - fieldStartPos;
+ }
+
+ if (lengthOfText > 0 )
+ {
+ aFoundPosition = counter;
+ return iExtension->FieldText().Mid(fieldStartPos, lengthOfText);
+ }
+ }
+ }
+
+ // no more fields with text
+ aFoundPosition = -1;
+ return TPtrC(KNullDesC);
+ }
+
+/**
+@internalComponent
+*/
+EXPORT_C CViewContact::CViewContact(TContactItemId aId)
+: iId(aId), iExtension(NULL)
+/** Constructs a CViewContact object.
+
+This should not be called by clients. CViewContact::NewLC() should be used instead.
+
+@param aId The contact ID to assign to the object. */
+ {
+ }
+
+EXPORT_C void CViewContact::InternalizeL(RReadStream& aStream)
+/** Internalises a CViewContact object from a read stream.
+
+@param aStream Stream from which the object is internalised. */
+ {
+ //
+ if(!iExtension)
+ {
+ iExtension = CViewContactExtension::NewL();
+ }
+
+ iId = aStream.ReadInt32L();
+ iContactType = STATIC_CAST(TViewContactType,aStream.ReadInt32L());
+ SetContactTypeUid(TUid::Uid(aStream.ReadInt32L()));
+ iExtension->HintBitField() = aStream.ReadInt32L();
+ const TInt indxCount = aStream.ReadInt32L();
+ TInt fieldpos=0;
+ for (TInt ii=0;ii<indxCount;++ii)
+ {
+ fieldpos=aStream.ReadInt32L();
+ iTextIndexes.AppendL(fieldpos);
+ }
+
+ const TInt fieldLength = aStream.ReadInt32L();
+ if(fieldLength>0)
+ {
+ HBufC* field = HBufC::NewLC(fieldLength);
+ TPtr ptr(field->Des());
+ aStream.ReadL(ptr, fieldLength);
+ CleanupStack::Pop(field);
+ iExtension->SetFieldText(field);
+ }
+ else
+ {
+ iExtension->CreateEmptyFieldTextL();
+ }
+ }
+
+/*
+ * Stores the data in a CViewContact.
+ *
+ * The chevron operator is not used when externalizing the field text buffer
+ * because using the Unicode compression scheme varies the size of the
+ * externalized text. Using the standard operators is less efficient but
+ * guaranteed to be consistent.
+ *
+ * The descriptor is only externalized if it has some length. Store doesn't
+ * like externalizing Null descriptors.
+ *
+ * @param aStream Stream to write data to
+ */
+EXPORT_C void CViewContact::ExternalizeL(RWriteStream& aStream) const
+/** Externalises a CViewContact object to a write stream.
+
+@param aStream Stream to which the object is externalised. */
+ {
+ aStream.WriteInt32L(iId);
+ aStream.WriteInt32L(iContactType);
+ aStream.WriteInt32L(ContactTypeUid().iUid);
+
+ TPtrC pFieldText(KNullDesC);
+ TInt hintBitValue = 0;
+ if (iExtension)
+ {
+ hintBitValue = iExtension->HintBitField();
+ pFieldText.Set(iExtension->FieldText());
+ }
+ //
+ aStream.WriteInt32L(hintBitValue);
+ const TInt indxCount = iTextIndexes.Count();
+ aStream.WriteInt32L(indxCount);
+ for (TInt ii=0;ii<indxCount;++ii)
+ {
+ aStream.WriteInt32L((iTextIndexes)[ii]);
+ }
+ //
+ const TInt fieldLength = pFieldText.Length();
+ aStream.WriteInt32L(fieldLength);
+ if (fieldLength>0)
+ {
+ aStream.WriteL(pFieldText);
+ }
+ }
+
+EXPORT_C TInt CViewContact::ExternalizedSize() const
+/** Retrieves the number of bytes required to store the contact view item when
+externalised.
+
+@return The size of the contact view item. */
+ {
+ TInt size = sizeof(TContactItemId);
+ const TInt indxCount = iTextIndexes.Count();
+ size += sizeof(TViewContactType);//for contact Type;
+ size += sizeof(TUid);
+ size += sizeof(TInt); // for iExtension->HintBitField()
+ size += sizeof(TInt);//for index count;
+ size += sizeof(TInt)*indxCount;//for indexes
+ size += sizeof(TInt);//for fieldTextSize
+ //
+ TInt fieldTextSize = 0;
+ if (iExtension)
+ {
+ fieldTextSize = iExtension->FieldText().Size();
+ }
+ size += fieldTextSize;
+ //
+ return size;
+ }
+
+/**
+@internalTechnology
+ */
+EXPORT_C TUid CViewContact::ContactTypeUid() const
+ {
+ if(iExtension)
+ {
+ return iExtension->ContactTypeUid();
+ }
+
+ return TUid::Null();
+ }
+
+/**
+@internalTechnology
+Note: This method can leave.
+
+@leave KErrNoMemory The CViewContactExtension cannot be allocated.
+ */
+EXPORT_C void CViewContact::SetContactTypeUid(TUid aUid)
+ {
+ if(!iExtension)
+ {
+ iExtension = CViewContactExtension::NewL(); // can leave
+ }
+
+ iExtension->SetContactTypeUid(aUid);
+ }
+
+EXPORT_C CViewContact::~CViewContact()
+/** Destructor. */
+ {
+ iTextIndexes.Close();
+ delete iExtension;
+ }
+
+/**
+@internalTechnology
+ */
+CViewContact* CViewContact::NewLC(RReadStream& aStream)
+ {
+ CViewContact* viewContact = new (ELeave) CViewContact(KErrNotFound);
+ CleanupStack::PushL(viewContact);
+ viewContact->ConstructL();
+ viewContact->InternalizeL(aStream);
+ return viewContact;
+ }
+
+/*
+ * Second phase constructor
+ */
+void CViewContact::ConstructL(TInt aLength)
+ {
+ iExtension = CViewContactExtension::NewL(aLength);
+ }
+
+/*
+ * Second phase constructor
+ * @param aContact Contact item to copy
+ */
+void CViewContact::ConstructL(const CViewContact& aContact)
+ {
+ CopyL(aContact);
+ }
+
+EXPORT_C CViewContact* CViewContact::NewLC(TContactItemId aId)
+/** Allocates and constructs a CViewContact object, based on an existing one.
+@param aId ID of the existing CViewContact object whose values are used to initialise
+the new one.
+@return Pointer to the newly created representation of a contact item used in contact views.
+*/
+ {
+ CViewContact* contact = new(ELeave) CViewContact(aId);
+ CleanupStack::PushL(contact);
+ contact->ConstructL();
+ return contact;
+ }
+
+
+/** Allocates and constructs a CViewContact object, based on an existing one.
+
+@param aId ID of the existing CViewContact object whose values are used
+to initialise the new one.
+@param aLength initial MaxLenght of a contact buffer
+@internalTechnology
+*/
+EXPORT_C CViewContact* CViewContact::NewL(TContactItemId aId, TInt aLength)
+ {
+ CViewContact* contact = new(ELeave) CViewContact(aId);
+ CleanupStack::PushL(contact);
+ contact->ConstructL(aLength);
+ CleanupStack::Pop(contact);
+ return contact;
+ }
+
+
+
+EXPORT_C CViewContact* CViewContact::NewL(const CViewContact& aContact)
+/** Allocates and constructs a CViewContact object, based on an existing one.
+@param aContact An existing CViewContact object whose values are used to initialise
+the new one.
+@return Pointer to the newly created representation of a contact item used in contact views.
+*/
+ {
+ CViewContact* contact=new(ELeave)CViewContact(aContact.iId);
+ CleanupStack::PushL(contact);
+ contact->ConstructL(aContact);
+ CleanupStack::Pop(contact);
+ return contact;
+ }
+
+EXPORT_C TBool CViewContact::ContactMatchesFilter(TInt aFilter) const
+/** Checks if this contact matches the supplied filter.
+@return ETrue, if this contact matches the filter supplied; EFalse, otherwise.
+ */
+ {
+ TInt hintBitField = 0;
+ if (iExtension)
+ {
+ hintBitField = iExtension->HintBitField();
+ }
+ //
+ return HintFieldMatchesFilter(hintBitField, aFilter);
+ }
+
+EXPORT_C TInt CViewContact::FieldCount() const
+/** Gets the number of fields in the contact view item.
+
+@return The number of fields in the item. */
+ {
+ return iTextIndexes.Count();
+ }
+
+EXPORT_C TPtrC CViewContact::Field(TInt aPosition) const
+/** Gets a pointer descriptor to the contents of the single field located
+at the specified field index.
+
+@param aPosition A field index.
+@return The contents of the field located at the specified field index.
+@panic CNTMODEL 27 In debug builds, this indicates that aPosition is invalid.
+It must be less than the number of fields in the item. */
+ {
+ __ASSERT_DEBUG(aPosition >= 0 && aPosition < FieldCount(),Panic(ECntPanicInvalidViewIndex));
+ //
+ if (!iExtension)
+ {
+ // Have to resort to default value if there is no extension
+ // since we cannot obtain the field text without it.
+ return TPtrC(KNullDesC);
+ }
+ //
+ const TPtrC pFullFieldText(iExtension->FieldText());
+ const TInt fieldStartPos = iTextIndexes[aPosition];
+ TInt lengthOfText=0;
+ TPtrC fieldPtr;
+ if(aPosition<FieldCount()-1)
+ {
+ //work out the length of the buffer.
+ TInt nextFieldPos = iTextIndexes[aPosition+1];
+ lengthOfText=nextFieldPos-fieldStartPos;
+ fieldPtr.Set(pFullFieldText.Mid(fieldStartPos,lengthOfText));
+ }
+ else
+ {
+ //this is the last field.
+ fieldPtr.Set(pFullFieldText.Mid(fieldStartPos));
+ }
+ return fieldPtr;
+ }
+
+/*
+ * Adds a new field to the CViewContact.
+ * Fields are stored in one HBufC. Each field can be accessed using the
+ * indexes stored in the iTextIndexes member.
+ * @param aField Field data
+ */
+EXPORT_C void CViewContact::AddFieldL(const TDesC& aField)
+ {
+ if(!iExtension)
+ {
+ iExtension = CViewContactExtension::NewL();
+ }
+
+ const TInt insertionPosition = iExtension->FieldText().Length();
+ if (aField.Length())
+ {
+ iExtension->AppendToFieldTextL(aField);
+ }
+ iTextIndexes.AppendL(insertionPosition);
+
+#ifdef _DEBUG
+ // Ensure the field added to single hbuf & index is identical to aField when retrieved.
+ TPtrC addedField= Field(FieldCount()-1);
+ TInt comp=addedField.Compare(aField);
+ __ASSERT_DEBUG(comp==0,Panic(ECntPanicInvalidFieldText));
+#endif
+ }
+
+
+/**
+Set the first field text for the CViewContact.
+Fields are stored in one HBufC. Each field can be accessed using the
+indexes stored in the iTextIndexes member.
+
+@param aField Field data
+@internalTechnology
+ */
+EXPORT_C void CViewContact::SetFirstFieldForBlankContactL(const TDesC& aFirstField)
+ {
+ if(!iExtension)
+ {
+ iExtension = CViewContactExtension::NewL();
+ }
+
+ // shouldn't be any existing text
+ __ASSERT_DEBUG(iExtension->FieldText().Length()==0,Panic(ECntPanicFieldTextNotBlank));
+
+ iExtension->AppendToFieldTextL(aFirstField);
+
+ const TInt length = aFirstField.Length();
+ const TInt count = iTextIndexes.Count();
+ if (count)
+ {
+ for (TInt j = 1; j < count; ++j)
+ {
+ iTextIndexes[j] = length;
+ }
+ }
+ else
+ {
+ iTextIndexes.AppendL(0);
+ }
+
+#ifdef _DEBUG
+ // Ensure the field added to single hbuf & index is identical to aField when retrieved.
+ TPtrC addedField= Field(0);
+ TInt comp=addedField.Compare(aFirstField);
+ __ASSERT_DEBUG(comp==0,Panic(ECntPanicInvalidFieldText));
+#endif
+ }
+
+
+
+/**
+Used for creating a view.
+Allows to re-use the same contact object what reduces the number of memory re-allocations.
+Resets the indexes array and contact buffer. The buffer MaxLength stays the same.
+@internalTechnology
+*/
+EXPORT_C void CViewContact::Reset()
+ {
+ SetId(KNullContactId);
+ SetContactType(EContactItem);
+ SetContactTypeUid(KNullUid);
+ iTextIndexes.Reset();
+ if(iExtension)
+ {
+ iExtension->SetLengthZero();
+ }
+ }
+
+
+
+/**
+* Compares a given hint field with any given filter.
+* static function. Used to support member function ContactMatchesFilter
+* and exported function ContactMatchesHintFieldL, from CContactDatabase.
+*
+* @param aHintField the hint bit flag field
+* @param aFilter the filter to compare against
+*/
+TBool CViewContact::HintFieldMatchesFilter(TInt aHintField, TInt aFilter)
+ {
+ TBool match=EFalse;
+
+ if (aFilter==CContactDatabase::EUnfiltered)
+ {
+ return ETrue;
+ }
+
+ if (aFilter & ~aHintField & (CContactDatabase::EWork | CContactDatabase::EHome))
+ {
+ return EFalse;
+ }
+
+ match = aFilter & aHintField
+ & (
+ CContactDatabase::ELandLine
+ | CContactDatabase::ESmsable
+ | CContactDatabase::EMailable
+ | CContactDatabase::EFaxable
+ | CContactDatabase::EPhonable
+ | CContactDatabase::ERingTone
+ | CContactDatabase::EVoiceDial
+ | CContactDatabase::EIMAddress
+ | CContactDatabase::EWirelessVillage
+ | CContactDatabase::ECustomFilter1
+ | CContactDatabase::ECustomFilter2
+ | CContactDatabase::ECustomFilter3
+ | CContactDatabase::ECustomFilter4
+ );
+
+ return match;
+ }
+
+/**
+Get this contact's hint field value
+@return The contact hint value
+@internalTechnology
+ */
+EXPORT_C TInt CViewContact::ContactHint() const
+ {
+ TInt hint = 0;
+ if (iExtension)
+ {
+ hint = iExtension->HintBitField();
+ }
+ return hint;
+ }
+
+/**
+Set this contact's hint field value
+
+@param aHint The new contact hint value
+@internalTechnology
+ */
+EXPORT_C void CViewContact::SetContactHint(TInt aHint)
+ {
+ if(iExtension)
+ {
+ iExtension->HintBitField() = aHint;
+ }
+ }
+
+
+/**
+Test if contact is 'Sortable'
+@internalTechnology
+ */
+EXPORT_C TBool CViewContact::IsSortable() const
+ {
+ // If total field text length > 0 then contact is sortable
+ if (iExtension && iExtension->FieldText().Length())
+ {
+ return ETrue;
+ }
+
+ return EFalse;
+ }
+
+/**
+Change the view contact object to lightweight object to save memory.
+It actually just delete the instance of CViewContactExtension.
+
+@internalTechnology
+ */
+EXPORT_C void CViewContact::ChangeToLightweightObject()
+ {
+ iTextIndexes.Reset();
+ delete iExtension;
+ iExtension = NULL;
+ }
+
+
+/**
+Check if the view contact object is a lightweight object.
+
+@internalComponent
+ */
+TBool CViewContact::IsLightweightObject() const
+ {
+ return (iExtension == NULL);
+ }
+
+
+/**
+Copy the given view contact object to this instance.
+
+@param aContact the view contact to be copied.
+@leave KErrNoMemory
+@internalComponent
+ */
+void CViewContact::CopyL(const CViewContact& aContact)
+ {
+ iTextIndexes.Reset();
+ if(!iExtension)
+ {
+ iExtension = CViewContactExtension::NewL();
+ }
+
+ iContactType = aContact.iContactType;
+ SetContactTypeUid( aContact.ContactTypeUid() );
+ iExtension->HintBitField() = aContact.iExtension->HintBitField();
+ HBufC* fieldText = aContact.iExtension->FieldText().AllocL();
+ iExtension->SetFieldText(fieldText);
+ //
+ const TInt indxCount= aContact.iTextIndexes.Count();
+ TInt textPos=0;
+ for(TInt ii=0;ii<indxCount;++ii)
+ {
+ textPos = aContact.iTextIndexes[ii];
+ iTextIndexes.AppendL(textPos);
+ }
+ }
+
+
+/** Used for view sorting and insersion. In order to give a stable result
+if contact details match, it falls back to comparing contact IDs.
+If a contact view sort plugin is loaded it uses its SortCompareViewContactsL() method.
+
+@internalAll */
+EXPORT_C TInt CContactViewBase::CompareContactsAndIdsL(const CViewContact& aFirst, const CViewContact& aSecond) const
+ {
+ TInt result = 0;
+
+ // Profiler
+#ifdef __PROFILE_SORT__
+ RDebug::ProfileStart(3);
+#endif
+
+ CViewContactSortPlugin* sortPluginImpl = iExtension->iSortPluginImpl;
+ if (sortPluginImpl)
+ {
+ // use View Sort plugin
+ result = sortPluginImpl->SortCompareViewContactsL(aFirst,aSecond);
+ }
+ else
+ {
+ // no View sort plugin loaded
+ result = TextCompareFieldsL(aFirst, aSecond);
+ }
+
+ if (result == 0)
+ {
+ result = aFirst.Id() - aSecond.Id();
+ }
+
+ // Profiler
+#ifdef __PROFILE_SORT__
+ RDebug::ProfileEnd(3);
+#endif
+
+ return result;
+ }
+
+
+/** @internalAll */
+EXPORT_C TInt CContactViewBase::CompareContactIds(const CViewContact& aFirst, const CViewContact& aSecond)
+ {
+ return aFirst.Id() - aSecond.Id();
+ }
+
+
+/** Asks the contact if it is sortable.
+'static' function used by Sort Plugin.
+
+@internalAll */
+EXPORT_C TBool CContactViewBase::ContactIsSortable(const CViewContact& aContact)
+ {
+ return aContact.IsSortable();
+ }
+
+
+/** @internalAll */
+EXPORT_C TUid CContactViewBase::GetViewSortPluginImplUid() const
+ {
+ return iExtension->iSortPluginUid;
+ }
+
+
+/** @internalComponent */
+TUid CContactViewBase::FindSortPluginImplL (const TDesC8& aSortPluginName,TBool aWildCard) const
+ {
+ TUid result = KNullUid;
+
+ TEComResolverParams resolverParams;
+ RImplInfoPtrArray implInfoArray;
+
+ CleanupResetAndDestroyPushL(implInfoArray);
+
+ resolverParams.SetDataType(aSortPluginName);
+ resolverParams.SetWildcardMatch(aWildCard);
+
+ // look for ECOM implementations, only in ROM
+ REComSession::ListImplementationsL(KCntSortPluginInterfaceUid, resolverParams,
+ KRomOnlyResolverUid, implInfoArray);
+
+ if (implInfoArray.Count() == 1)
+ {
+ result = implInfoArray[0]->ImplementationUid();
+ }
+
+ CleanupStack::PopAndDestroy(&implInfoArray);
+ return result;
+ }
+
+
+/** @internalComponent */
+void CContactViewBase::LoadViewSortPluginL (TUid aSortPluginUid, TContactViewPreferences& aViewPreferences)
+ {
+ if (aSortPluginUid == KNullUid)
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ // Parameter block for View
+ TSortPluginViewParamsRev1 pluginViewParams(aViewPreferences, CompareFieldsL, ContactIsSortable);
+ // General parameter block to load plug-in
+ TSortPluginParams pluginParams(KCntSortPluginInterfaceUid, aSortPluginUid, &pluginViewParams);
+
+ iExtension->iSortPluginImpl = CViewContactSortPlugin::NewL(&pluginParams);
+ iExtension->iSortPluginUid = aSortPluginUid;
+ }
+
+
+/** @internalComponent */
+TUid CContactViewBase::FindDefaultViewSortPluginImplL () const
+ {
+ // _LIT8(KTestDefaultPluginName, "contacts.vnd.symbian.com/reverse sort");
+ return FindSortPluginImplL (KViewSortPluginDefaultName /* KTestDefaultPluginName */ ,ETrue);
+ }
+
+/** This function determines whether a contact should be added to the normal
+sorted array (iContacts) or put into the alternative iUnSortedContacts array.
+Depending on the view preferences, these "unsorted" contacts are either
+ignored (deleted), or added to the beginning or end of the iContacts
+sorted list by At(), Find() etc... methods.
+
+@internalComponent */
+TBool CContactViewBase::IsContactSortable(const CViewContact& aContact, TContactViewPreferences& aViewPreferences) const
+ {
+ TBool sortableContact=EFalse;
+
+ // only test contact if it matters
+ if(aViewPreferences & (EIgnoreUnSorted | EUnSortedAtBeginning | EUnSortedAtEnd)) //Distinguish Unsorted
+ {
+ CViewContactSortPlugin* sortPluginImpl = iExtension->iSortPluginImpl;
+ if (sortPluginImpl)
+ {
+ // use plugin
+ sortableContact = sortPluginImpl->ViewContactIsSortable(aContact);
+ }
+ else
+ {
+ // ask contact itself
+ sortableContact = aContact.IsSortable();
+ }
+ }
+ else
+ {
+ // Sortable
+ sortableContact = ETrue;
+ }
+
+ return sortableContact;
+ }
+
+/** @internalComponent */
+CViewContactSortPlugin* CContactViewBase::SortPluginImpl() const
+ {
+ return iExtension->iSortPluginImpl;
+ }
+
+
+/** Does a binary search of the contacts array, and inserts a new contact.
+Uses the current sort plugin, if any.
+
+@internalComponent */
+TInt CContactViewBase::InsertContactInView(RPointerArray<CViewContact>& aContacts, const CViewContact* aNewContact, TBool aSortByIdOnly, TInt* aIndex) const
+ {
+ CViewContactSortPlugin* sortPluginImpl = SortPluginImpl();
+
+ TInt error = KErrNone;
+
+ TInt maxPos = aContacts.Count() - 1;
+ TInt minPos = 0;
+ TInt position = 0;
+
+ if (maxPos >= 0)
+ {
+ // at least one compare required
+ if (sortPluginImpl)
+ {
+ error = sortPluginImpl->SortStart(CViewContactSortPlugin::ESortStartInsertOne, 1);
+ if (error)
+ {
+ return error;
+ }
+ }
+
+
+ position = (minPos + maxPos + 1) / 2;
+
+ while (maxPos >= minPos)
+ {
+ TInt diff = 0;
+
+ if (aSortByIdOnly)
+ {
+ diff = CompareContactIds(*aNewContact, *aContacts[position]);
+ }
+ else
+ {
+ TRAP(error,diff = CompareContactsAndIdsL(*aNewContact, *aContacts[position]));
+ if (error)
+ {
+ return error;
+ }
+ }
+
+ if (diff == 0)
+ {
+ // duplicate Id
+ error = KErrAlreadyExists;
+ break;
+ }
+
+ if (diff < 0)
+ {
+ maxPos = position - 1;
+ }
+ else // diff > 0
+ {
+ minPos = position + 1;
+ }
+
+ position = (minPos + maxPos + 1) / 2;
+ }
+
+ // all compares done
+ if (sortPluginImpl)
+ {
+ sortPluginImpl->SortCompleted();
+ }
+ }
+
+
+ if (error == KErrNone)
+ {
+ error = aContacts.Insert(aNewContact, position);
+ }
+
+ if (aIndex)
+ {
+ // index of new item for caller
+ *aIndex = position;
+ }
+ return error;
+ }
+
+TInt CContactViewBase::GetErrorValueFromExtensionClass()
+ {
+ return iExtension->iError;
+ }
+