/*
* Copyright (c) 2002-2007 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: Contacts Model store filtered contact view implementation.
*
*/
// INCLUDES
#include "CFindView.h"
// VPbkCntModel
#include "CRefineView.h"
#include "CViewBase.h"
#include "CContactBookmark.h"
#include "CContactStore.h"
// From Virtual Phonebook
#include <CVPbkContactNameConstructionPolicy.h>
#include <CVPbkContactFindPolicy.h>
#include <MVPbkContactBookmarkCollection.h>
// System includes
#include <cntdef.h>
// Debugging headers
#include <VPbkProfile.h>
namespace VPbkCntModel {
// --------------------------------------------------------------------------
// CFindView::CFindView
// --------------------------------------------------------------------------
//
inline CFindView::CFindView( CViewBase& aBaseView )
: CFindViewBase( aBaseView, aBaseView, ETrue )
{
}
// --------------------------------------------------------------------------
// CFindView::ConstructL
// --------------------------------------------------------------------------
//
void CFindView::ConstructL( const MDesCArray& aFindStrings,
const MVPbkContactBookmarkCollection* aAlwaysIncludedContacts,
MVPbkContactViewObserver& aExternalViewObserver, RFs& aRFs )
{
CVPbkContactFindPolicy::TParam findPolicyParams(
iBaseView.Store().MasterFieldTypeList(), aRFs );
iFindPolicy = CVPbkContactFindPolicy::NewL( findPolicyParams );
BaseConstructL( aFindStrings, *iFindPolicy,
aExternalViewObserver );
SetAlwaysIncludedContactsL( aAlwaysIncludedContacts );
}
// --------------------------------------------------------------------------
// CFindView::NewLC
// --------------------------------------------------------------------------
//
CFindView* CFindView::NewLC(
const MDesCArray& aFindStrings,
CViewBase& aParentView,
MVPbkContactViewObserver& aExternalViewObserver,
const MVPbkContactBookmarkCollection* aAlwaysIncludedContacts,
RFs& aRFs )
{
CFindView* self =
new ( ELeave ) CFindView( aParentView );
CleanupStack::PushL( self );
self->ConstructL( aFindStrings, aAlwaysIncludedContacts,
aExternalViewObserver, aRFs );
return self;
}
// --------------------------------------------------------------------------
// CFindView::~CFindView
// --------------------------------------------------------------------------
//
CFindView::~CFindView()
{
delete iFindPolicy;
iAlwaysIncluded.Close();
iContactsModelMatchContacts.ResetAndDestroy();
}
// --------------------------------------------------------------------------
// CFindView::SetAlwaysIncludedContactsL
// --------------------------------------------------------------------------
//
void CFindView::SetAlwaysIncludedContactsL(
const MVPbkContactBookmarkCollection* aAlwaysIncludedContacts )
{
// Destroy old ids
iAlwaysIncluded.Reset();
if ( aAlwaysIncludedContacts )
{
MVPbkContactStore& store = ParentObject().ContactStore();
const TInt count = aAlwaysIncludedContacts->Count();
for ( TInt i = 0; i < count; ++i )
{
const CContactBookmark* bookmark =
dynamic_cast<const CContactBookmark*>(
&aAlwaysIncludedContacts->At( i ) );
// If bookmark was from VPbkCntModel and if it's from same store
// as this view then it's added to array.
if ( bookmark &&
&bookmark->ContactStore() == &store )
{
iAlwaysIncluded.AppendL( bookmark->ContactId() );
}
}
}
}
// --------------------------------------------------------------------------
// CFindView::MatchL
// --------------------------------------------------------------------------
//
void CFindView::MatchL(
RPointerArray<CCntModelViewContact>& aMatchedContacts )
{
CleanupClosePushL( aMatchedContacts );
iContactsModelMatchContacts.ResetAndDestroy();
VPBK_PROFILE_START(VPbkProfile::ECntModelFind);
// Get matches from Contacts Model
iBaseView.NativeView().ContactsMatchingPrefixL(
FindStrings(), iContactsModelMatchContacts );
VPBK_PROFILE_END(VPbkProfile::ECntModelFind);
if (iAlwaysIncluded.Count() == 0)
{
// No always included contacts. The match can be done using
// only the Contacts Model matched contacts.
CViewContact* viewContact = CViewContact::NewL( iBaseView, SortOrder() );
CleanupStack::PushL(viewContact);
const TInt count = iContactsModelMatchContacts.Count();
for (TInt i = 0; i < count; ++i)
{
viewContact->SetViewContact( *iContactsModelMatchContacts[i] );
if ( IsMatchL( *viewContact ) )
{
// Keep the order of the contacts same and move contact
// from iContactsModelMatchContacts to aMatchedContacts
aMatchedContacts.AppendL(iContactsModelMatchContacts[i]);
// Don't remove the contact to keep indexes correct.
// Set to NULL so that ResetAndDestroy doesn't crash in
// destructor
iContactsModelMatchContacts[i] = NULL;
}
}
CleanupStack::PopAndDestroy( viewContact );
}
else
{
// Sort the matched contacts again with the CCompareView::CompareFieldsL
// compare function. Mark sure the result of binary search is correct in
// function FindFromMatchArray().
// See defect ou1cimx1#333760
// Title: "Adding contacts (add recipent) issue while creating new message"
// Root cause: When contact's first or last name contain blank spaces,
// the comparison result may be different between CCompareView::CompareFieldsL
// and CntSortPlugin. e.g. "AB" and "A khan"
HeapSortL( iContactsModelMatchContacts );
// Do it slowly by looping all the parent view contacts.
const TInt contactCount = iParentView.ContactCountL();
for ( TInt i = 0; i < contactCount; ++i )
{
// iParentView is always VPbkCntModel view and the contacts type
// is CViewContact
const CViewContact& candidate = static_cast<const CViewContact&>(
iParentView.ContactAtL( i ) );
MatchContactL( candidate, aMatchedContacts );
}
}
iContactsModelMatchContacts.ResetAndDestroy();
CleanupStack::Pop();
}
// --------------------------------------------------------------------------
// CFindView::DoContactAddedToViewL
// --------------------------------------------------------------------------
//
void CFindView::DoContactAddedToViewL( MVPbkContactViewBase& aView,
TInt aIndex, const MVPbkContactLink& /*aContactLink*/,
RPointerArray<CCntModelViewContact>& aMatchedContacts )
{
if ( &iParentView == &aView )
{
const CViewContact& viewContact = static_cast<const CViewContact&>(
iParentView.ContactAtL( aIndex ) );
if ( IsMatchL( viewContact ) )
{
CCntModelViewContact* cnt =
CCntModelViewContact::NewL( *viewContact.NativeContact() );
CleanupStack::PushL( cnt );
aMatchedContacts.InsertInOrderAllowRepeatsL( cnt,
TLinearOrder<CCntModelViewContact>(
CCompareView::CompareFieldsL ) );
CleanupStack::Pop( cnt );
}
}
}
// --------------------------------------------------------------------------
// CFindView::UpdateFilterL
// --------------------------------------------------------------------------
//
void CFindView::UpdateFilterL(
const MDesCArray& aFindWords,
const MVPbkContactBookmarkCollection* aAlwaysIncludedContacts )
{
SetFindStringsL( aFindWords );
SetAlwaysIncludedContactsL( aAlwaysIncludedContacts );
ActivateContactMatchL();
}
// --------------------------------------------------------------------------
// CFindView::MatchContactL
// --------------------------------------------------------------------------
//
void CFindView::MatchContactL( const CViewContact& aViewContact,
RPointerArray<CCntModelViewContact>& aMatchedContacts )
{
CleanupResetAndDestroyPushL( aMatchedContacts );
// aContact matches if it's one of the always included contacts OR
// if it's one of Contacts Model matched contacts AND it also
// passes our own match.
TInt matchArrayIndex = KErrNotFound;
TBool matched = EFalse;
if ( IsContactAlwaysIncluded( aViewContact ) )
{
// Remove from match array to save memory
RemoveFromMatchArrayIfFound( aViewContact );
matched = ETrue;
}
else if ( IsContactsModelMatchL( aViewContact, matchArrayIndex ) )
{
// Remove from match array to save memory
delete iContactsModelMatchContacts[matchArrayIndex];
iContactsModelMatchContacts.Remove( matchArrayIndex );
if ( IsMatchL( aViewContact ) )
{
matched = ETrue;
}
}
if ( matched )
{
// Contact matched.
// CFindView owns its contacts so create a copy
CCntModelViewContact* cnt =
CCntModelViewContact::NewL( *aViewContact.NativeContact() );
CleanupStack::PushL( cnt );
aMatchedContacts.AppendL( cnt );
CleanupStack::Pop( cnt );
}
CleanupStack::Pop( &aMatchedContacts );
}
// --------------------------------------------------------------------------
// CFindView::IsContactAlwaysIncluded
// --------------------------------------------------------------------------
//
TBool CFindView::IsContactAlwaysIncluded(
const CViewContact& aContact ) const
{
return iAlwaysIncluded.Find( aContact.Id() ) != KErrNotFound;
}
// --------------------------------------------------------------------------
// CFindView::IsContactsModelMatchL
// --------------------------------------------------------------------------
//
TBool CFindView::IsContactsModelMatchL( const CViewContact& aContact,
TInt& aMatchArrayIndex ) const
{
// Contacts are in order in iContactsModelMatchContacts. Use binary
// search to check if aContact is can be found from the array.
aMatchArrayIndex = FindFromMatchArray( aContact );
return aMatchArrayIndex != KErrNotFound;
}
// --------------------------------------------------------------------------
// CFindView::RemoveFromMatchArrayIfFound
// --------------------------------------------------------------------------
//
void CFindView::RemoveFromMatchArrayIfFound( const CViewContact& aContact )
{
TInt index = FindFromMatchArray( aContact );
if ( index != KErrNotFound )
{
delete iContactsModelMatchContacts[index];
iContactsModelMatchContacts.Remove(index);
}
}
// --------------------------------------------------------------------------
// CFindView::FindFromMatchArray
// --------------------------------------------------------------------------
//
TInt CFindView::FindFromMatchArray( const CViewContact& aContact ) const
{
return iContactsModelMatchContacts.FindInOrder(
aContact.NativeContact(),
TLinearOrder<CCntModelViewContact>( CCompareView::CompareFieldsL ) );
}
/**
Heap sort the give view contacts array.
This function only be called one time when some contacts be marked and we input
the first letter to the FindBox for searching.
@param aContacts the array of view contacts to be sorted.
@leave leave errors from CCompareView::CompareFieldsL
*/
void CFindView::HeapSortL(RPointerArray<CCntModelViewContact> aContacts)
{
// HeapSort (copied from RPointerArrayBase)
TInt ss = aContacts.Count();
if ( ss>1 )
{
TInt sh = ss>>1;
FOREVER
{
CCntModelViewContact* si;
if (sh != 0)
{
// make heap
--sh;
si = aContacts[sh];
}
else
{
// sort heap
--ss;
si = aContacts[ss];
aContacts[ss] = aContacts[0];
if (ss == 1)
{
aContacts[0] = si;
break;
}
}
// sift down
TInt ii = sh;
TInt jj = sh;
FOREVER
{
jj = (jj+1)<<1;
if ((jj >= ss) || (CCompareView::CompareFieldsL(*(aContacts[jj-1]),*(aContacts[jj])) > 0))
{
--jj;
}
if ((jj >= ss) || (CCompareView::CompareFieldsL(*(aContacts[jj]),*si) <= 0))
{
break;
}
aContacts[ii] = aContacts[jj];
ii = jj;
} //FOREVER
aContacts[ii] = si;
} //FOREVER
} //if (ss > 1)
}
} // namespace VPbkCntModel
// End of File