mobilemessaging/postcard/postcardsrc/PostcardContact.cpp
changeset 0 72b543305e3a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mobilemessaging/postcard/postcardsrc/PostcardContact.cpp	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,436 @@
+/*
+* Copyright (c) 2006 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:  
+*           Postcard application's interface to contacts (Virtual Phonebook
+*           and Phonebook2).
+*
+*/
+
+
+
+// INCLUDE FILES
+
+#include <s32file.h>
+#include <aknenv.h>
+#include <AiwServiceHandler.h>
+#include <AiwContactSelectionDataTypes.h>
+#include <CPbk2StoreConfiguration.h>
+#include <VPbkContactStoreUris.h>
+#include <CVPbkContactStoreUriArray.h>
+#include <TVPbkContactStoreUriPtr.h>
+#include <CVPbkContactLinkArray.h>
+#include <TVPbkFieldVersitProperty.h>
+#include <MVPbkStoreContact.h>
+#include <contactmatcher.h>
+#include <akninputblock.h>
+
+#include <Postcard.rsg>
+#include "PostcardContact.h"
+#include "PostcardPanic.h"
+
+// ================= Static Constant Data ===================
+
+// Table to convert from TLocation to virtual phonebook field type parameter
+const TVPbkFieldTypeParameter CPostcardContact::iLocToFieldTypeParam[] =
+    {
+    EVPbkVersitParamPREF,
+    EVPbkVersitParamHOME,
+    EVPbkVersitParamWORK
+    };
+
+// Table to convert from TAddressField to virtual phonebook subfield type
+const TVPbkSubFieldType CPostcardContact::iAddrFieldToSubFieldType[] =
+    {
+    EVPbkVersitSubFieldStreet,
+    EVPbkVersitSubFieldExtendedAddress,
+    EVPbkVersitSubFieldPostalCode,
+    EVPbkVersitSubFieldLocality,
+    EVPbkVersitSubFieldRegion,
+    EVPbkVersitSubFieldCountry
+    };
+
+// Table to convert from TPostcardControls to TAddressField
+const CPostcardContact::TAddressField CPostcardContact::iControlIdToAddrField[] =
+    {
+    CPostcardContact::EAddressFieldExtendedAddress,
+    CPostcardContact::EAddressFieldStreet,
+    CPostcardContact::EAddressFieldPostalCode,
+    CPostcardContact::EAddressFieldLocality,
+    CPostcardContact::EAddressFieldRegion,
+    CPostcardContact::EAddressFieldCountry
+    };
+
+// ================= MEMBER FUNCTIONS =======================
+
+// ---------------------------------------------------------
+//  Two-phased constructor
+// ---------------------------------------------------------
+CPostcardContact* CPostcardContact::NewL( RFs& aFs )
+    {
+    CPostcardContact* self = new (ELeave) CPostcardContact( aFs );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------
+//  Default destructor
+// ---------------------------------------------------------
+CPostcardContact::~CPostcardContact()
+    {
+    delete iStoreContact;
+    delete iContactMatcher;
+    delete iUriArray;
+    delete iAiwServiceHandler;
+    }
+
+// ---------------------------------------------------------
+// CPostcardContact
+// ---------------------------------------------------------
+CPostcardContact::CPostcardContact( RFs& aFs ) : iFs( aFs )
+    {
+    }
+
+
+// ---------------------------------------------------------
+// ConstructL
+// ---------------------------------------------------------
+void CPostcardContact::ConstructL( )
+    {
+#ifdef __WINS__
+    // Use default contact database store 
+    iUriArray = CVPbkContactStoreUriArray::NewL();
+    TVPbkContactStoreUriPtr uriPtr(VPbkContactStoreUris::DefaultCntDbUri());
+    iUriArray->AppendL(uriPtr);
+#else
+    // Get store configuration from phonebook2
+    CPbk2StoreConfiguration* storeConfiguration =
+        CPbk2StoreConfiguration::NewL();
+    CleanupStack::PushL(storeConfiguration);
+
+    iUriArray = storeConfiguration->CurrentConfigurationL();
+    CleanupStack::PopAndDestroy( storeConfiguration ); // storeConfiguration
+#endif
+
+    // Create contact matcher
+    iContactMatcher = CContactMatcher::NewL( &iFs );
+    iContactMatcher->OpenStoreL(*iUriArray);
+    
+    iShutdown = EFalse;
+    }
+
+// ---------------------------------------------------------
+// HasLocationL
+// ---------------------------------------------------------
+TBool CPostcardContact::HasLocationL(TLocation aLocation) const
+    {
+    // A small buffer to see if the contact has any fields
+    // defined for the location aLocation
+    const TInt KBufLen = 8;
+    TBuf<KBufLen> contactString;
+
+    GetContactStringL(contactString, aLocation);
+    return contactString.Length() > 0;
+    }
+
+// ---------------------------------------------------------
+// GetContactStringL
+// ---------------------------------------------------------
+void CPostcardContact::GetContactStringL(TDes& aBuffer,
+    TLocation aAddressLocation) const
+    {
+    static const TAddressField addrFields[] =
+        {
+        EAddressFieldStreet,
+        EAddressFieldExtendedAddress,
+        EAddressFieldPostalCode,
+        EAddressFieldLocality,
+        EAddressFieldRegion,
+        EAddressFieldCountry
+        };
+    const TInt KNumAddrFields = sizeof(addrFields) / sizeof(addrFields[0]);
+
+    _LIT(KPostcardAddressSelectionSeparator, ", ");
+    TPtrC fieldSeparator(KPostcardAddressSelectionSeparator);
+
+    aBuffer.Zero();
+    TInt bufferRemaining = aBuffer.MaxLength();
+
+    // Read address fields from the contact. Add field to buffer if there
+    // is space for the separator and at least one more character.
+    for(TInt i = 0; i < KNumAddrFields && bufferRemaining > fieldSeparator.Length(); i++)
+        {
+        HBufC* fieldText = GetAddressFieldLC(aAddressLocation, addrFields[i]);
+        if (fieldText->Length() > 0)
+            {
+            // Add the separator if this is not the first non-empty field
+            if (aBuffer.Length() > 0)
+                {
+                aBuffer.Append(fieldSeparator);
+                bufferRemaining -= fieldSeparator.Length();
+                }
+
+            if (bufferRemaining > fieldText->Length())
+                {
+                aBuffer.Append(*fieldText);
+                }
+            else
+                {
+                aBuffer.Append(fieldText->Left(bufferRemaining));
+                }
+            bufferRemaining = aBuffer.MaxLength() - aBuffer.Length();
+            }
+        CleanupStack::PopAndDestroy( fieldText );  // fieldText
+        }
+    }
+
+// ---------------------------------------------------------
+// GetAddressFieldLC
+// ---------------------------------------------------------
+HBufC* CPostcardContact::GetAddressFieldLC(TLocation aLocation,
+    TAddressField aAddressField) const
+    {
+    return GetContactFieldLC(EVPbkVersitNameADR,
+        AddrFieldToSubFieldType(aAddressField),
+        LocToFieldTypeParam(aLocation));
+    }
+
+// ---------------------------------------------------------
+// FetchContactL
+// ---------------------------------------------------------
+void CPostcardContact::FetchContactL()
+    {
+    // Fetch contact from Phonebook using AIW
+
+    if (!iAiwServiceHandler)
+        {
+        // Create AIW service handler
+        iAiwServiceHandler = CAiwServiceHandler::NewL();
+        iAiwServiceHandler->AttachL(R_POSTCARD_SINGLE_ENTRY_FETCH_INTEREST);
+        }
+
+
+    // A new contact is selected. Delete contact in case FetchContactL()
+    // was called before.
+    delete iStoreContact;
+    iStoreContact = NULL;
+
+    CAiwGenericParamList& inList = iAiwServiceHandler->InParamListL();
+    InitAiwContactFetchParamL( inList );
+
+    iAiwServiceHandler->ExecuteServiceCmdL( KAiwCmdSelect, inList,
+        iAiwServiceHandler->OutParamListL(), 0, this);
+
+    // Assign an input blocker, which will call cancel to phonebook
+    // e.g. if Postcard is closed via FSW.
+    CAknInputBlock* inputBlock = CAknInputBlock::NewCancelHandlerLC( this );
+
+    iActSchedWait.Start(); // wait ExecuteServiceCmdL() to complete
+
+    CleanupStack::PopAndDestroy( inputBlock );
+    
+    if ( iShutdown )
+        {
+        // This leave will be catched in AppUi's DoEditAddressL function.
+        User::Leave( KLeaveExit );
+        }
+    }
+
+// ---------------------------------------------------------
+// FetchContactL
+// ---------------------------------------------------------
+void CPostcardContact::FetchContactL(RFile& aFile)
+    {
+    __ASSERT_DEBUG( !iStoreContact, Panic(EPostcardPanicCoding));
+
+    // Using streams would be more elegant but Phonebook2 impletes it this
+    // way. Writes the descriptor to a file directly without a length.
+    TInt fileSize;
+    User::LeaveIfError( aFile.Size( fileSize ) );
+    HBufC8* buf = HBufC8::NewLC( fileSize );
+    TPtr8 ptr = buf->Des();
+    User::LeaveIfError( aFile.Read( ptr ) );
+    CVPbkContactLinkArray* linkArray = CVPbkContactLinkArray::NewLC(
+        *buf, iContactMatcher->GetContactStoresL());
+    if( linkArray->Count() == 0 )
+        {
+        User::Leave( KErrNotFound );
+        }
+    iContactMatcher->GetStoreContactL( linkArray->At( 0 ), &iStoreContact );
+    CleanupStack::PopAndDestroy( 2, buf ); // linkArray, buf
+    }
+
+// ---------------------------------------------------------
+// HandleNotifyL
+// ---------------------------------------------------------
+TInt CPostcardContact::HandleNotifyL(TInt /*aCmdId*/, TInt aEventId,
+    CAiwGenericParamList& aEventParamList,
+    const CAiwGenericParamList& /*aInParamList*/)
+    {
+
+    switch(aEventId)
+        {
+        case KAiwEventOutParamCheck: // fall through
+        case KAiwEventQueryExit:// fall through
+            // It is always ok for us to exit. Edited postcard will be
+            // saved to drafts.
+            return ETrue;
+
+        case KAiwEventCompleted:
+            // Fetch completed with or without a contact
+            TRAP_IGNORE(HandleAiwEventCompletedL(aEventParamList));
+            // Leave in HandleAiwEventCompletedL() is not progated further.
+            // After that the Postcard wouldn't respond to UI events. Even when
+            // AsyncStop() is called. Maybe Phonebook cannot handle a leave
+            // from here properly.
+
+            // Fallthrough
+        case KAiwEventCanceled:
+            // Fetch was cancelled by user or red key pressed
+            // Fallthrough
+        case KAiwEventError:
+            // Fetch is complete, there was an error
+            if (iActSchedWait.IsStarted())
+                {
+                // End nested active scheduler loop
+                iActSchedWait.AsyncStop();
+                }
+            break;
+        default:
+            Panic(EPostcardPanicAiwEvent);
+        }
+
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------
+// HandleAiwEventCompleted
+// ---------------------------------------------------------
+void CPostcardContact::HandleAiwEventCompletedL(
+    CAiwGenericParamList& aEventParamList)
+    {
+    // Single item fetch. The result should be a contact link array with
+    // 1 contact links and one contact field.
+    __ASSERT_ALWAYS(aEventParamList.Count() == 2,
+        Panic(EPostcardPanicAiwEventParam));
+    const TAiwGenericParam& param = aEventParamList[0];
+    __ASSERT_ALWAYS(param.SemanticId() == EGenericParamContactLinkArray,
+        Panic(EPostcardPanicAiwEventParam));
+    __ASSERT_DEBUG(param.Value().TypeId() == EVariantTypeDesC8,
+        Panic(EPostcardPanicAiwEventParam));
+    TPtrC8 contactLinks = param.Value().AsData();
+    CVPbkContactLinkArray* linkArray = CVPbkContactLinkArray::NewLC(
+        contactLinks, iContactMatcher->GetContactStoresL() );
+    TInt linkCount = linkArray->Count();
+    __ASSERT_DEBUG(linkCount <= 1, Panic(EPostcardPanicAiwEventParam));
+    if (linkCount)  // user selected a contact
+        {
+        iContactMatcher->GetStoreContactL( linkArray->At( 0 ), &iStoreContact );
+        }
+    CleanupStack::PopAndDestroy( linkArray );  // linkArray
+    }
+
+// ---------------------------------------------------------
+// InitAiwContactFetchParamL
+// ---------------------------------------------------------
+void CPostcardContact::InitAiwContactFetchParamL(
+    CAiwGenericParamList& aParamList ) const
+    {
+    TAiwGenericParam param( EGenericParamContactSelectionData );
+    TAiwSingleEntrySelectionDataV1 selectionData;
+    param.Value().Set( TAiwSingleEntrySelectionDataV1Pckg( selectionData ) );
+    aParamList.AppendL( param );
+
+    param.Reset();
+    param.SetSemanticId( EGenericParamContactStoreUriArray );
+    param.Value().Set( *iUriArray->PackLC() );
+    aParamList.AppendL( param );
+    CleanupStack::PopAndDestroy(); // packed uriArray
+    }
+
+// ---------------------------------------------------------
+// GetNameLC()
+// ---------------------------------------------------------
+HBufC* CPostcardContact::GetNameLC() const
+    {
+    // GetNameL() returns NULL if the contact has no name defined
+    HBufC* nameText = iContactMatcher->GetNameL(iStoreContact->Fields());
+    if (nameText)
+        {
+        CleanupStack::PushL(nameText);        
+        }
+    else
+        {
+        nameText = HBufC::NewLC(0);
+        }
+    return nameText;
+    }
+
+// ---------------------------------------------------------
+// GetContactFieldLC
+// ---------------------------------------------------------
+HBufC* CPostcardContact::GetContactFieldLC(TVPbkFieldTypeName aFieldType,
+    TVPbkSubFieldType aSubFieldType,
+    TVPbkFieldTypeParameter aFieldTypeParameter) const
+    {
+    TVPbkFieldVersitProperty prop;
+    
+    prop.SetName(aFieldType);
+    prop.SetSubField(aSubFieldType);
+
+    TVPbkFieldTypeParameters fieldTypeParameters;
+    fieldTypeParameters.Add(aFieldTypeParameter);
+    prop.SetParameters(fieldTypeParameters);
+
+    // Doesn't take ownership
+    const MVPbkFieldType* fieldType =
+        iContactMatcher->FieldTypes().FindMatch(prop, 0);
+
+    if (fieldType)
+        {
+	    TPtrC src =
+            iContactMatcher->GetFieldDataTextL(*iStoreContact, *fieldType);
+        HBufC *data = HBufC::NewLC(src.Length());
+        *data = src;
+        data->Des().Trim();
+        return data;
+        }
+    else
+        {
+        return HBufC::NewLC(0);
+        }
+    }
+
+// ---------------------------------------------------------
+// AknInputBlockCancel
+// ---------------------------------------------------------
+void CPostcardContact::AknInputBlockCancel()
+    {
+    if ( iActSchedWait.IsStarted() )
+        {
+        // Cancels currently outstanding AIW request to phonebook.
+        TRAPD( error, iAiwServiceHandler->ExecuteServiceCmdL( KAiwCmdSelect, 
+                                                   iAiwServiceHandler->InParamListL(), 
+                                                   iAiwServiceHandler->OutParamListL(),
+                                                   KAiwOptCancel,
+                                                   this ) );
+        if ( error == KErrNone )
+            {
+            iShutdown = ETrue;
+            }
+        }
+    }
+
+// End of File