diff -r d4f567ce2e7c -r 5b6f26637ad3 phonebookengines_old/contactsmodel/cntview/ViewBase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phonebookengines_old/contactsmodel/cntview/ViewBase.cpp Tue Aug 31 15:05:21 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 + +// User includes +#include +#include "CNTSTD.H" +#include +#include "CVIEWCONTACTEXTENSION.h" +#include +#include "cntviewprivate.h" +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#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> 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;iiiError)); + } + 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& 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;iiDes()); + + // Fill the buffer. + for (TInt j=0;jDes()); + 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;jjiFindPluginImpl->IsWordValidForMatching(word)) + { + for (TInt kk=0;kkiFindPluginImpl->Match(aContact.Field(kk), word)) + { + ++hits; + break; + } + } + } + else + { + for (TInt kk=0;kk& aMatchedContacts, TSearchType aSearchType) + { + CDesCArrayFlat* findWordArray = CreateFindWordArrayLC(aFindWords, aSearchType); + const TInt viewCount = CountL(); + TBool match = EFalse; + for (TInt ii=0;ii& 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& 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 (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& 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& aMatchingContacts) + { + TContactIdWithMapping idMap; + const TInt viewCount(CountL()); + for (TInt i=0;iiCollationMethod); + ++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;ii0) + { + 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;ii0) + { + 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(aPositionFieldText().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;iiiSortPluginImpl; + 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& 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; + } +