/*
* 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 "CFilteredContactView.h"
// VPbkCntModel
#include "CContactStore.h"
#include "CFieldFactory.h"
#include "CCustomFilteredContactView.h"
#include <VPbkCntModelRes.rsg>
#include "VPbkCntModelRemoteViewPreferences.h"
#include "NamedRemoteViewViewDefinitionStoreUtility.h"
// VPbkEng
#include <CVPbkFieldTypeSelector.h>
#include <VPbkDataCaging.hrh>
#include <CVPbkFieldType.h>
#include <CVPbkFieldTypeList.h>
#include <CVPbkContactViewDefinition.h>
#include <TVPbkFieldVersitProperty.h>
#include <VPbkSendEventUtility.h>
#include <VPbkPrivateUid.h> // KFindPluingUID
#include <CVPbkSortOrder.h>
// VPbkEngUtils
#include <RLocalizedResourceFile.h>
// System includes
#include <cntview.h>
#include <barsread.h>
// Debugging headers
#include <VPbkDebug.h>
namespace VPbkCntModel {
// CONSTANTS
_LIT( KResourceFile, "VPbkCntModelRes.rsc" );
/// Field type filter mapping structure
struct TVPbkFieldTypeFilterMapping
{
/// Virtual Phonebook field type resource id
TUint iFieldTypeResourceId;
/// Contacst Model native filter matching the field type
TUint iNativeFilter;
};
/// Last element marker
const TUint KLastElement = 0;
/// Array of field type filter mappings
static const TVPbkFieldTypeFilterMapping FilterMapping[] =
{
{ R_CNTMODEL_NATIVE_FILTER_EMAIL_ADDRESS,
CContactDatabase::EMailable },
{ R_CNTMODEL_NATIVE_FILTER_PHONE_NUMBER,
CContactDatabase::EPhonable },
{ R_CNTMODEL_NATIVE_FILTER_SMS_ADDRESS,
CContactDatabase::ESmsable },
{ R_CNTMODEL_NATIVE_FILTER_FAX_NUMBER,
CContactDatabase::EFaxable },
{ R_CNTMODEL_NATIVE_FILTER_RINGING_TONE,
CContactDatabase::ERingTone },
{ R_CNTMODEL_NATIVE_FILTER_ASSISTANT_PHONE_NUMBER,
CContactDatabase::EPhonable },
{ R_CNTMODEL_NATIVE_FILTER_TOP_CONTACT,
CContactDatabase::ECustomFilter2 },
/// This has to be the last
{ KLastElement,
CContactDatabase::EUnfiltered }
};
/**
* Appends native filter aFilter based on the given field type resource id.
*
* @param aFieldTypeResourceId Field type resource id.
* @param aFilter Native Contacts Model filter.
*/
inline void BuildNativeFilter( const TInt aFieldTypeResourceId,
TUint& aFilter )
{
for ( TInt i=0;
FilterMapping[i].iFieldTypeResourceId != KLastElement; ++i )
{
if ( aFieldTypeResourceId == FilterMapping[i].iFieldTypeResourceId )
{
aFilter |= FilterMapping[i].iNativeFilter;
break;
}
}
}
/**
* Checks wheter custom filtering is needed. This is the case
* when the native filters cannot provide all the necessary filtering.
*
* @param aFieldType The field type which matched selectors field type
* collection.
* @param aFilterType The filter type which matched aFieldType, or NULL.
* @param aSelector The field type selector, the filtering criteria.
* @return ETrue if custom filtering is needed.
*/
TBool RequiresCustomFiltering(
const MVPbkFieldType& aFieldType,
const MVPbkFieldType* aFilterType,
const CVPbkFieldTypeSelector& aSelector )
{
TBool ret = ETrue;
if ( aFilterType )
{
const TVPbkFieldVersitProperty* matchingProperty =
aSelector.MatchingVersitProperty( aFieldType );
if ( matchingProperty )
{
const TInt maxMatchPriority =
aFilterType->VersitProperties().Count() - 1;
for ( TInt matchPriority = 0;
matchPriority <= maxMatchPriority; ++matchPriority )
{
TBool versitIsMatched = matchingProperty->Matches(
aFilterType->VersitProperties()[matchPriority]);
TBool excludedParmaterIsMatched =
aFilterType->ExcludedParameters().
ContainsAll(aFieldType.ExcludedParameters());
// if the FilterType is matched the Versit Property and
// the excludeParameter of FiledType, it needn't custom filter.
if ( versitIsMatched && excludedParmaterIsMatched )
{
ret = EFalse;
break;
}
}
}
else
{
TVPbkNonVersitFieldType matchingType =
aSelector.MatchingNonVersitType( aFieldType );
if ( aFieldType.NonVersitType() == matchingType )
{
ret = EFalse;
}
}
}
return ret;
}
/**
* Checks does the given field type match any of the native filter types.
*
* @param aFieldType The field type to inspect.
* @param aSupportedFilterTypes Field types which are supported
* by the native filters.
* @return Native filter field type which matched aFieldType,
* or NULL if no matches.
*/
inline const MVPbkFieldType* MatchesNativeFilter
( const MVPbkFieldType& aFieldType,
const CVPbkFieldTypeList& aSupportedFilterTypes )
{
const MVPbkFieldType* matchingType = NULL;
const TInt maxMatchPriority =
aFieldType.VersitProperties().Count() - 1;
for ( TInt matchPriority = 0;
matchPriority <= maxMatchPriority && !matchingType; ++matchPriority )
{
matchingType = aSupportedFilterTypes.FindMatch(
aFieldType.VersitProperties()[matchPriority],
matchPriority );
}
if ( !matchingType && aFieldType.NonVersitType() != EVPbkNonVersitTypeNone )
{
matchingType = aSupportedFilterTypes.FindMatch
( aFieldType.NonVersitType() );
}
return matchingType;
}
/**
* Converts VPbk field type filter to a native filter.
*
* @param aSource Field type filter to convert.
* @param aFieldTypeList List of supported field types
* of the store.
* @param aFs File server session.
* @param aCustomFilteringNeeded Indicates whether the native filters
* are enough, or do we have to do custom
* filtering.
* @return Native Contacts model contact view filter.
*/
TUint ConvertFieldTypeFilterL
( const CVPbkFieldTypeSelector& aSource,
const MVPbkFieldTypeList& aFieldTypeList,
RFs& aFs, TBool& aCustomFilteringNeeded )
{
TUint ret = CContactDatabase::EUnfiltered;
// Build own field type list containing field types supported
// by native filters
VPbkEngUtils::RLocalizedResourceFile resFile;
resFile.OpenLC( aFs,
KVPbkRomFileDrive, KDC_RESOURCE_FILES_DIR, KResourceFile );
TResourceReader reader;
reader.SetBuffer( resFile.AllocReadLC
( R_CNTMODEL_NATIVE_FILTER_FIELD_TYPES ) );
CVPbkFieldTypeList* supportedFilterTypes =
CVPbkFieldTypeList::NewL( resFile, reader );
CleanupStack::PushL( supportedFilterTypes );
// Go through the store's field type list
TInt typeCount = aFieldTypeList.FieldTypeCount();
for ( TInt i=0; i < typeCount; ++i )
{
const MVPbkFieldType& fieldType =
aFieldTypeList.FieldTypeAt( i );
if ( aSource.IsFieldTypeIncluded( fieldType ) )
{
// We have a match. Now lets inspect does it match
// any of the native filter field types
const MVPbkFieldType* matchingType =
MatchesNativeFilter( fieldType, *supportedFilterTypes );
if ( matchingType )
{
// We found a match to a native filter, lets build
// the native filter
BuildNativeFilter( matchingType->FieldTypeResId(), ret );
}
// Then, find out do we need to custom filtering
TBool customFilteringRequired = RequiresCustomFiltering
( fieldType, matchingType, aSource );
aCustomFilteringNeeded = customFilteringRequired;
if ( !matchingType && customFilteringRequired )
{
// Custom filtering is required and there is no appropriate
// native filter which could be used as a base filter.
// In this case the custom filter has to handle all
// the filtering. So reset the native filter and break out.
ret = CContactDatabase::EUnfiltered;
break;
}
}
}
CleanupStack::PopAndDestroy( 3 ); // supportedFilterTypes,
// reader, resFile
return ret;
}
// --------------------------------------------------------------------------
// CFilteredContactView::CFilteredContactView
// --------------------------------------------------------------------------
//
inline CFilteredContactView::CFilteredContactView
( CContactStore& aParentStore,
RFs& aFs ) :
CViewBase( aParentStore ),
iFs( aFs )
{
}
// --------------------------------------------------------------------------
// CFilteredContactView::~CFilteredContactView
// --------------------------------------------------------------------------
//
CFilteredContactView::~CFilteredContactView()
{
// Customically filtered view has to be destructed first
delete iCustomFilteredView;
delete iFilter;
// Set iView to NULL, so that CViewBase does not close it
iView = NULL;
if ( iFilteredView )
{
//after iFilteredView->Close( *iNativeObserver )
//both iFilteredView and iBaseView are deleted
iFilteredView->Close( *iNativeObserver );
}
else if ( iBaseView )
{
//but iBaseView's pointer is still not NULL
//make sure iBaseView is unable to call its member function
iBaseView->Close( *iNativeObserver );
}
}
// --------------------------------------------------------------------------
// CFilteredContactView::NewLC
// --------------------------------------------------------------------------
//
CFilteredContactView* CFilteredContactView::NewLC(
const CVPbkContactViewDefinition& aViewDefinition,
MVPbkContactViewObserver& aObserver,
CContactStore& aParentStore,
const MVPbkFieldTypeList& aSortOrder,
RFs& aFs )
{
CFilteredContactView* self = new ( ELeave ) CFilteredContactView
( aParentStore, aFs );
CleanupStack::PushL( self );
self->ConstructL( aViewDefinition, aObserver, aSortOrder );
return self;
}
// --------------------------------------------------------------------------
// CFilteredContactView::ConstructL
// --------------------------------------------------------------------------
//
void CFilteredContactView::ConstructL(
const CVPbkContactViewDefinition& aViewDefinition,
MVPbkContactViewObserver& aObserver,
const MVPbkFieldTypeList& aSortOrder )
{
CViewBase::ConstructL( aViewDefinition, aObserver, aSortOrder );
}
// --------------------------------------------------------------------------
// CFilteredContactView::Type
// --------------------------------------------------------------------------
//
TVPbkContactViewType CFilteredContactView::Type() const
{
return EVPbkContactsView;
}
// --------------------------------------------------------------------------
// CFilteredContactView::DoInitializeViewL
// --------------------------------------------------------------------------
//
void CFilteredContactView::DoInitializeViewL(
const CVPbkContactViewDefinition& aViewDefinition,
RContactViewSortOrder& aViewSortOrder )
{
// Construct the native filter
if ( aViewDefinition.FieldTypeFilter() )
{
const CFieldFactory& fieldFactory = Store().FieldFactory();
// Copy construct the filter
iFilter = CVPbkFieldTypeSelector::NewL(
*aViewDefinition.FieldTypeFilter() );
iNativeFilter = ConvertFieldTypeFilterL
( *iFilter, fieldFactory, iFs, iCustomFilteringNeeded );
}
if ( aViewDefinition.ContactSelector() )
{
iCustomFilteringNeeded = ETrue;
// Custom filtering and MVPbkContactSelector filtering cannot be used at the same time.
iNativeFilter = 0; // no filter
}
if ( iCustomFilteringNeeded )
{
// Stop observing the base view, the custom view
// will observe it and report back
// Construction of the iCustomFilteredView should be done in two
// phases. Due to that there is dependencies between views in this
// and iCustomFilteredView class.
iCustomFilteredView =
new (ELeave) CCustomFilteredContactView( Store(), iFilter,
*this, aViewDefinition.ContactSelector() );
ConstructBaseViewsL( aViewDefinition, *iCustomFilteredView,
aViewSortOrder );
if ( iFilteredView )
{
iBaseView->Close( *iCustomFilteredView );
}
iCustomFilteredView->ConstructL
( aViewDefinition, *this, *iSortOrder, *iView );
iView = &iCustomFilteredView->ContactViewBase();
}
else
{
ConstructBaseViewsL( aViewDefinition, *this, aViewSortOrder );
// If we built Contact's Model's native filtered view we must
// stop observing the base view since otherwise we get double
// view events and VPbk composite view does not tolerate double
// events
if ( iFilteredView )
{
iBaseView->Close( *this );
}
}
}
// --------------------------------------------------------------------------
// CFilteredContactView::DoTeardownView
// --------------------------------------------------------------------------
//
void CFilteredContactView::DoTeardownView()
{
}
// --------------------------------------------------------------------------
// CFilteredContactView::DoChangeSortOrderL
// --------------------------------------------------------------------------
//
TBool CFilteredContactView::DoChangeSortOrderL(
const CVPbkContactViewDefinition& aViewDefinition,
RContactViewSortOrder& aSortOrder )
{
TBool canBeChanged = ETrue;
if ( iRemoteView )
{
if ( RemoteViewName( aViewDefinition ).Compare(
KVPbkAllContactsViewName ) == 0 )
{
// Set Contacts Model default view setting only if client
// is using KVPbkAllContactsViewName shared view.
NamedRemoteViewViewDefinitionStoreUtility::
SetNamedRemoteViewViewDefinitionL(
KVPbkAllContactsViewName, aSortOrder,
KVPbkDefaultContactViewPrefs);
}
iRemoteView->ChangeSortOrderL( aSortOrder );
}
else
{
// CContactLocalView doesn't support ChangeSortOrderL
canBeChanged = EFalse;
}
return canBeChanged;
}
// --------------------------------------------------------------------------
// CFilteredContactView::ContactViewReady
// --------------------------------------------------------------------------
//
void CFilteredContactView::ContactViewReady(
MVPbkContactViewBase& aView )
{
VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
("CFilteredContactView::ContactViewReady(0x%x)"), &aView);
/* when custom filtering view is used, MVPbkContactViewObserver doesn't support
* sortOrder changed notification, CViewBase will send viewReady instead,
* use it to keep sort order up to date */
if ( iCustomFilteringNeeded )
{
DoUpdateTypeListL();
}
VPbkEng::SendViewEventToObservers( *this, iFilteringObservers,
&MFilteredViewSupportObserver::ContactViewReadyForFiltering,
&MVPbkContactViewObserver::ContactViewError );
VPbkEng::SendViewEventToObservers( *this, iObservers,
&MVPbkContactViewObserver::ContactViewReady,
&MVPbkContactViewObserver::ContactViewError );
VPbkEng::SendViewEventToObservers( *this, iFilteringObservers,
&MVPbkContactViewObserver::ContactViewReady,
&MVPbkContactViewObserver::ContactViewError );
}
// --------------------------------------------------------------------------
// CFilteredContactView::ContactViewUnavailable
// --------------------------------------------------------------------------
//
void CFilteredContactView::ContactViewUnavailable(
MVPbkContactViewBase& aView )
{
VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
("CFilteredContactView::ContactViewUnavailable(0x%x)"), &aView);
VPbkEng::SendViewEventToObservers( *this, iFilteringObservers,
&MFilteredViewSupportObserver::ContactViewUnavailableForFiltering,
&MVPbkContactViewObserver::ContactViewError );
VPbkEng::SendViewEventToObservers( *this, iObservers,
&MVPbkContactViewObserver::ContactViewUnavailable,
&MVPbkContactViewObserver::ContactViewError );
VPbkEng::SendViewEventToObservers( *this, iFilteringObservers,
&MVPbkContactViewObserver::ContactViewUnavailable,
&MVPbkContactViewObserver::ContactViewError );
}
// --------------------------------------------------------------------------
// CFilteredContactView::ContactAddedToView
// --------------------------------------------------------------------------
//
void CFilteredContactView::ContactAddedToView(
MVPbkContactViewBase& aView,
TInt aIndex, const MVPbkContactLink& aContactLink )
{
VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
("CFilteredContactView::ContactAddedToView(0x%x)"), &aView);
VPbkEng::SendViewEventToObservers( *this, aIndex, aContactLink,
iObservers,
&MVPbkContactViewObserver::ContactAddedToView,
&MVPbkContactViewObserver::ContactViewError );
VPbkEng::SendViewEventToObservers( *this, aIndex, aContactLink,
iFilteringObservers,
&MVPbkContactViewObserver::ContactAddedToView,
&MVPbkContactViewObserver::ContactViewError );
}
// --------------------------------------------------------------------------
// CFilteredContactView::ContactRemovedFromView
// --------------------------------------------------------------------------
//
void CFilteredContactView::ContactRemovedFromView(
MVPbkContactViewBase& aView,
TInt aIndex, const MVPbkContactLink& aContactLink )
{
VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
("CFilteredContactView::ContactRemovedFromView(0x%x)"), &aView);
VPbkEng::SendViewEventToObservers( *this, aIndex, aContactLink,
iObservers,
&MVPbkContactViewObserver::ContactRemovedFromView,
&MVPbkContactViewObserver::ContactViewError );
VPbkEng::SendViewEventToObservers( *this, aIndex, aContactLink,
iFilteringObservers,
&MVPbkContactViewObserver::ContactRemovedFromView,
&MVPbkContactViewObserver::ContactViewError );
}
// --------------------------------------------------------------------------
// CFilteredContactView::ContactViewError
// --------------------------------------------------------------------------
//
void CFilteredContactView::ContactViewError(
MVPbkContactViewBase& aView,
TInt aError, TBool aErrorNotified )
{
VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
("CFilteredContactView::ContactViewError(0x%x)"), &aView);
VPbkEng::SendEventToObservers( *this, aError, aErrorNotified, iObservers,
&MVPbkContactViewObserver::ContactViewError );
VPbkEng::SendEventToObservers( *this, aError, aErrorNotified,
iFilteringObservers, &MVPbkContactViewObserver::ContactViewError );
}
// --------------------------------------------------------------------------
// CFilteredContactView::ConstructBaseViewsL
// --------------------------------------------------------------------------
//
void CFilteredContactView::ConstructBaseViewsL
( const CVPbkContactViewDefinition& aViewDefinition,
MContactViewObserver& aObserver,
RContactViewSortOrder& aViewSortOrder )
{
iNativeObserver = &aObserver;
// Construct the all contacts view first
if ( RemoteViewDefinition( aViewDefinition ) )
{
iRemoteView = CContactNamedRemoteView::NewL(
*iNativeObserver, RemoteViewName( aViewDefinition ),
Store().NativeDatabase(), aViewSortOrder,
KVPbkDefaultContactViewPrefs );
iBaseView = iRemoteView;
}
else
{
iBaseView = CContactLocalView::NewL( *iNativeObserver,
Store().NativeDatabase(), aViewSortOrder,
KVPbkDefaultContactViewPrefs );
}
// Set base class view pointer
iView = iBaseView;
// If there is a native filter, construct a native filtered view
if ( iNativeFilter > 0 )
{
iFilteredView = CContactFilteredView::NewL
( *iNativeObserver, Store().NativeDatabase(),
*iBaseView, iNativeFilter );
// Set find plugin also for BaseView, otherwise searching doesn't
// work properly with other languages in other clients.
iView->SetViewFindConfigPlugin( TUid::Uid( KFindPluginUID ) );
iView = iFilteredView;
}
}
} // namespace VPbkCntModel
// End of File