phonebookui/Phonebook/App/src/CPbkSendContactCmd.cpp
changeset 0 e686773b3f54
child 68 9da50d567e3c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook/App/src/CPbkSendContactCmd.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,781 @@
+/*
+* Copyright (c) 2002 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: 
+*           Provides phonebook send contacts command object methods.
+*
+*/
+
+
+// INCLUDE FILES
+#include "CPbkSendContactCmd.h"
+#include "CPbkvCardConverter.h"
+#include "CPbkAppGlobals.h"
+
+#include <BCardEng.h>
+#include <CPbkFieldInfo.h>
+#include <Phonebook.rsg>
+#include <CPbkContactEngine.h>
+#include <CPbkProgressNoteWrapper.h>
+#include <CPbkConstants.h>
+#include <CPbkContactItem.h>
+
+#include <AknNoteWrappers.h>
+#include <eikclb.h>         // CEikListBox
+#include <sendui.h>         // Send UI API
+#include <SendUiMtmUids.h>  // Send UI MTM uid's
+#include <MsgBioUids.h>
+#include <txtrich.h>        // CRichText
+#include <barsread.h>       // TResourceReader
+#include <CMessageData.h>
+#include <PbkUID.h>
+#include <MenuFilteringFlags.h>
+#include <SendUiConsts.h>   // Postcard Uid
+#include <MPbkCommandObserver.h>
+
+#include <pbkdebug.h>
+
+/// Unnamed namespace for local definitions
+namespace {
+
+const TUint KNoMenu = 0;
+
+/**
+ * Represents the different listbox index selections.
+ */
+enum TPbkListBoxSelections
+    {
+    EFirstSelection = 0,
+    ESecondSelection,
+    EThirdSelection
+    };
+
+
+// LOCAL DEBUG CODE
+#ifdef _DEBUG
+enum TPanicCode
+    {
+	EPanicPreCond_SendvCardsL = 1,
+    EPanicLogic_CmdSendContactDataL,
+    EPanicLogic_MapSelection
+    };
+
+void Panic(TPanicCode aReason)
+    {
+    _LIT(KPanicText, "CPbkSendContactCmd");
+    User::Panic(KPanicText,aReason);
+    }
+#endif // _DEBUG
+
+// ==================== LOCAL FUNCTIONS ====================
+
+/**
+ * Creates a rich text object and packages contents of a file to it. The file's
+ * data is not converted in any way except that characters are widened to 16 
+ * bits.
+ *
+ * @param aEikEnv   EIKON environment.
+ * @param aFileName name of the file to convert.
+ * @return  a new rich text object with file's contents. The returned object is
+ *          also left on top of the cleanup stack.
+ */
+CRichText* CreateRichTextFromFileLC
+    (CEikonEnv& aEikEnv, const TDesC& aFileName);
+
+/**
+ * Helper class for sending the vCard(s) in async callback.
+ */
+class CVCardSender : public CIdle
+	{
+	public:  // Constructors
+		/*
+		 * Creates a new instance of this object.
+		 * @param aPriority desired priority
+		 */
+		static CVCardSender* NewL(TInt aPriority);
+
+	private:  // from CIdle
+		void RunL();
+		TInt RunError(TInt aError);
+
+	private:
+		/*
+		 * Constructor.
+		 * @param aPriority desired priority
+		 */
+		CVCardSender(TInt aPriority);
+	};
+
+
+inline CVCardSender::CVCardSender(TInt aPriority) 
+	: CIdle(aPriority) 
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CVCardSender* CVCardSender::NewL(TInt aPriority)
+	{
+	return new(ELeave) CVCardSender(aPriority);
+	}
+
+void CVCardSender::RunL()
+	{
+	CIdle::RunL();
+    // Destroy self. 
+    // If RunL (the callback) leaves RunError will handle the deletion.
+	delete this;
+	}
+
+TInt CVCardSender::RunError(TInt aError)
+	{
+	delete this;
+    // Forward all errors to the active scheduler
+	return aError;
+	}
+
+
+
+CRichText* CreateRichTextFromFileLC
+        (CEikonEnv& aEikEnv, const TDesC& aFileName)
+    {
+    // Common allocation granularity and buffer size for rich text and
+    // file reading
+    const TInt KBufSize = CEditableText::EDefaultTextGranularity;
+
+    // Create a rich text object with default formatting
+    CRichText* richText = CRichText::NewL(
+        aEikEnv.SystemParaFormatLayerL(), 
+        aEikEnv.SystemCharFormatLayerL(),
+        CEditableText::ESegmentedStorage,
+        KBufSize  // Allocation granularity
+        );
+    CleanupStack::PushL(richText);
+
+    // Open the file for reading
+    RFile file;
+    User::LeaveIfError(file.Open
+        (aEikEnv.FsSession(), aFileName, 
+        EFileRead|EFileStream|EFileShareReadersOnly));
+    CleanupClosePushL(file);
+
+    // Create two buffers: 8-bit for reading from file and 16-bit for
+    // converting to 16-bit format
+    HBufC8* buf8 = HBufC8::NewLC(KBufSize);
+    TPtr8 ptr8 = buf8->Des();
+    HBufC16* buf16 = HBufC16::NewLC(ptr8.MaxLength());
+    TPtr16 ptr16 = buf16->Des();
+
+    // Read, convert and append to rich text until the file ends
+    for (TInt err = file.Read(ptr8); 
+        ptr8.Length() > 0; 
+        err = file.Read(ptr8))
+        {
+        User::LeaveIfError(err);
+        ptr16.Copy(ptr8);
+        richText->InsertL(richText->DocumentLength(), ptr16);
+        }
+
+    // Cleanup and return
+    CleanupStack::PopAndDestroy(3);  // buf16, buf8, file
+    return richText;
+    }
+
+}  // namespace
+
+
+// ================= MEMBER FUNCTIONS =======================
+inline CPbkSendContactCmd::CPbkSendContactCmd(
+        TPbkSendingParams aParams,
+        CPbkContactEngine& aEngine,
+        TContactItemId aContactId,
+        const CContactIdArray* aContacts,
+        TPbkContactItemField* aField
+        ) :
+            iEngine( aEngine ),            
+            iParams( aParams ),            
+			iContactId( aContactId ),
+            iContacts( aContacts ),
+            iField( aField )
+	{  
+    PBK_DEBUG_PRINT
+        (PBK_DEBUG_STRING("CPbkSendContactCmd::CPbkSendContactCmd(0x%x)"), this);
+    }
+
+void CPbkSendContactCmd::ConstructL
+        (CBCardEngine& aBCardEng)
+    {
+    iEikEnv = CEikonEnv::Static();
+    iConverter = CPbkvCardConverter::NewL(iEikEnv->FsSession(),
+		iEngine, aBCardEng);
+	iVcardSender = CVCardSender::NewL(CActive::EPriorityIdle);
+    iWaitNoteWrapper = CPbkProgressNoteWrapper::NewL();
+    }
+
+/**
+ * Static constructor. 
+ */
+CPbkSendContactCmd* CPbkSendContactCmd::NewL
+        (TPbkSendingParams aParams,
+        CPbkContactEngine& aEngine, CBCardEngine& aBCardEng,
+        TContactItemId aContactId,
+        TPbkContactItemField* aField)
+    {
+    CPbkSendContactCmd* self = new(ELeave)
+        CPbkSendContactCmd(aParams,aEngine, aContactId, NULL, aField);
+    CleanupStack::PushL(self);
+    self->ConstructL(aBCardEng);
+    CleanupStack::Pop(); // self
+    return self;
+    }
+
+/**
+ * Static constructor (variation for multiple contacts).
+ */
+CPbkSendContactCmd* CPbkSendContactCmd::NewL
+	    (TPbkSendingParams aParams,
+	    CPbkContactEngine& aEngine, CBCardEngine& aBCardEng,
+		const CContactIdArray& aContacts)
+    {
+    CPbkSendContactCmd* self = new(ELeave)
+		CPbkSendContactCmd(aParams, aEngine, KNullContactId, &aContacts, NULL);
+    CleanupStack::PushL(self);
+    self->ConstructL(aBCardEng);
+    CleanupStack::Pop(); // self
+    return self;
+    }
+
+/**
+ * Destructor.
+ */
+CPbkSendContactCmd::~CPbkSendContactCmd()
+    {
+    PBK_DEBUG_PRINT
+        (PBK_DEBUG_STRING("CPbkSendContactCmd::~CPbkSendContactCmd(0x%x)"), this);
+
+    iUnderDestruction = ETrue;
+    delete iWaitNoteWrapper;
+    delete iConverter;
+	delete iVcardSender;
+    }
+
+void CPbkSendContactCmd::ExecuteLD()
+    {
+    PBK_DEBUG_PRINT
+        (PBK_DEBUG_STRING("CPbkSendContactCmd::ExecuteLD(0x%x)"), this);
+
+	CleanupStack::PushL(this);
+	
+	iMtmUid = ShowSendQueryL();
+	
+    if ( ( iContactId == KNullContactId && 
+          ( !iContacts || iContacts->Count()==0 ) ) ||
+         iMtmUid == KNullUid )
+        {
+        CleanupStack::PopAndDestroy();
+        return;
+        }
+    
+    TInt selectionIndex(ESendAllData);
+
+    // Ask the user to select the contact data to be send, if needed
+    selectionIndex = SelectSentDataL();
+
+    if (selectionIndex != ECancel)
+        {
+	    if (iContactId != KNullContactId)
+		    {
+		    iConverter->ConvertContactL(iContactId, iField, selectionIndex);
+		    }
+	    else
+		    {
+            // iContacts validity is checked in function entry
+		    iConverter->ConvertContactsL(*iContacts, selectionIndex);
+		    }
+	
+        // Then send contact(s)
+        CPbkWaitNoteWrapperBase::TNoteParams noteParams;
+        noteParams.iObserver = this;
+	    // ProcessFinished will be called when execution is finished.
+        iWaitNoteWrapper->ExecuteL
+            (*iConverter, R_QTN_SM_WAIT_BUSINESS_CARD, noteParams);
+        
+    	if ( iObserver )
+            {
+            iObserver->CommandFinished( *this );
+            }
+
+        CleanupStack::Pop(); // this
+
+	    // The promised self destruction will happen in SendvCardsL,
+	    // which is called by ProcessFinished
+        }
+    else
+        {
+        // User canceled the sending, exit
+        CleanupStack::PopAndDestroy();
+        }
+    }
+
+
+/**
+ * Send the vCards from an idle callback to get standard active scheduler 
+ * error handling. This is especially important to handle special leave
+ * code KLeaveExit which is propagated by SendUi in case the 'Exit" is 
+ *  picked from the message editor's menu.
+ */
+void CPbkSendContactCmd::ProcessFinished(MPbkBackgroundProcess& /*aProcess*/)
+    {
+    PBK_DEBUG_PRINT
+        (PBK_DEBUG_STRING("CPbkSendContactCmd::ProcessFinished(0x%x)"), this);
+        
+    // Cancel before usage of active object.
+    iVcardSender->Cancel();
+    iVcardSender->Start(TCallBack(&CPbkSendContactCmd::SendvCardsLD, this));
+    }
+
+/**
+ * Sends prepared vCard files using send UI.
+ */
+void CPbkSendContactCmd::SendvCardsLD()
+    {
+    // Relinquish ownership, iVcardSender takes care of it self
+	iVcardSender = NULL;
+
+	CleanupStack::PushL(this);
+    CMessageData* messageData = CMessageData::NewL();
+    CleanupStack::PushL( messageData );
+
+    if (iConverter->FileNames().MdcaCount() > 0 &&
+		!iUnderDestruction)
+        {
+		// Get globals (does not take ownership)
+        CPbkAppGlobals* globals = CPbkAppGlobals::InstanceL();              
+
+		if (iMtmUid == KSenduiMtmSmsUid)
+			{
+			// Sending through SMS -> there should be only one vCard
+			// attachment. Package the attachment to a rich text object and
+			// send it as the message body.
+			__ASSERT_DEBUG(iConverter->FileNames().MdcaCount()==1, 
+				Panic(EPanicPreCond_SendvCardsL));
+
+			// Copy the one and only attachment into a rich text object
+			CRichText* msgBody = CreateRichTextFromFileLC
+				(*iEikEnv, iConverter->FileNames().MdcaPoint(0));
+
+            messageData->SetBodyTextL( msgBody );
+
+			// Send the message using Send Ui
+			globals->SendUiL()->CreateAndSendMessageL(
+				iMtmUid, messageData, KMsgBioUidVCard );
+
+			CleanupStack::PopAndDestroy(msgBody);
+			}
+		else
+			{
+			// Not sending through SMS, just pass the attachments
+			__ASSERT_DEBUG(iConverter->FileNames().MdcaCount()>=1, 
+				Panic(EPanicPreCond_SendvCardsL));
+
+            //Fill message data
+            const TInt count( iConverter->FileNames().MdcaCount());
+            for( TInt i( 0 ); i < count; ++i )
+                {
+                messageData->AppendAttachmentL( 
+                        iConverter->FileNames().MdcaPoint( i ) );
+                }
+
+			// Send the message using Send Ui
+			globals->SendUiL()->CreateAndSendMessageL(
+				iMtmUid, messageData, KMsgBioUidVCard );            
+			}
+        }
+
+    // Destroy itself as promised
+	CleanupStack::PopAndDestroy(2); //this, messageData		
+    }
+
+TInt CPbkSendContactCmd::SendvCardsLD(TAny* aThis)
+    {
+	CPbkSendContactCmd* self = static_cast<CPbkSendContactCmd*>(aThis);
+	self->SendvCardsLD();
+
+    return EFalse;
+    }
+
+
+/**
+ * If necessary, shows a popup selection list from which the
+ * the user selects what details are sent in a vCard.
+ * @return user selection mapped into TPbkChoiceItemEnumerations
+ */
+
+TInt CPbkSendContactCmd::SelectSentDataL()
+    {
+    TInt selectionIndex(ESendAllData);
+
+    // Get the resource id of the menu to be shown
+    TInt resourceId = SelectionListL();
+
+    if (resourceId)
+        {
+        // Create a list box
+        CEikColumnListBox* listBox = static_cast<CEikColumnListBox*>
+		    (EikControlFactory::CreateByTypeL
+		    (EAknCtSinglePopupMenuListBox).iControl);
+        CleanupStack::PushL(listBox);
+
+        // Create a popup list
+        CAknPopupList* popupList = CAknPopupList::NewL
+		    (listBox, R_AVKON_SOFTKEYS_OK_CANCEL,
+            AknPopupLayouts::EMenuGraphicWindow);
+        CleanupStack::PushL(popupList);
+
+        HBufC* headingText= CCoeEnv::Static()->AllocReadResourceLC
+		    (R_PBK_BUSINESSCARD_SEND_HEADING);
+	    popupList->SetTitleL(*headingText);
+        CleanupStack::PopAndDestroy(); // headingText
+
+        // Init list box
+        listBox->SetContainerWindowL(*popupList);
+
+        TResourceReader resReader;
+        CCoeEnv::Static()->CreateResourceReaderLC(resReader, resourceId);
+        listBox->ConstructFromResourceL(resReader);
+        CleanupStack::PopAndDestroy();  // resReader
+
+	    listBox->CreateScrollBarFrameL(ETrue);
+	    listBox->ScrollBarFrame()->SetScrollBarVisibilityL
+		    (CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto);
+
+        CleanupStack::Pop(); // popupList
+
+        // Show popuplist dialog
+        TInt res = popupList->ExecuteLD();
+        if (res)
+            {
+            selectionIndex = listBox->CurrentItemIndex();
+
+            // We have to remap the selection index since
+            // several different listbox configurations
+            MapSelection(selectionIndex, resourceId);
+            }
+        else
+            {
+            selectionIndex = ECancel;
+            }
+        CleanupStack::PopAndDestroy(); // listBox
+        }
+
+    return selectionIndex;
+    }
+
+
+/**
+ * Decides what selection list to show the user.
+ * @return resource id of the menu to show
+ */
+TInt CPbkSendContactCmd::SelectionListL() const
+    {
+    TInt ret(KNoMenu);
+    TBool supportsFieldType(ETrue);
+
+    // Check is the 'send selected fields' feature enabled
+    TBool sendSelectedFeatureEnabled(iEngine.Constants()->
+        LocallyVariatedFeatureEnabled(EPbkLVSendSelectedContactFields));
+
+    // Check is the sending media SMS and does the contact
+    // have a thumbnail
+    TBool smsAndThumbnail(EFalse);
+    if ((AnyThumbnailsL()) && (IsSmsMtmL()))
+        {
+        smsAndThumbnail = ETrue;
+        }
+
+    // If focused field is supplied, the command object was
+    // launched from contact info view and that requires
+    // we have to check is the field supported by vCard spec
+    if (iField)
+        {
+        CBCardEngine& bcardEng = CPbkAppGlobals::InstanceL()->BCardEngL(iEngine);
+        if (!bcardEng.SupportsFieldType(iField->FieldInfo().FieldId()))
+            {
+            supportsFieldType = EFalse;
+            }
+        }
+
+    // Now check the cases when the menu needs to be shown
+    if (sendSelectedFeatureEnabled)
+        {
+        // There are two main branches depending on which view
+        // this command object was launched from
+        if (iField)
+            {
+            // Command object was launched from contact info view.
+
+            if (!smsAndThumbnail)
+                {
+                // When there is no thumbnail involved the selection
+                // menu is shown only if we are over vCard supported
+                // field
+                if (supportsFieldType)
+                    {
+                    ret = R_PBK_CONTACTINFO_SEND_OPTIONS;
+                    }
+                }
+            else
+                {
+                // Thumbnail is involved, the selection menu depends
+                // on whether we are over vCard supported field or not
+                if (supportsFieldType)
+                    {
+                    ret = R_PBK_CONTACTINFO_SEND_OPTIONS_SMS_THUMBNAIL;
+                    }
+                else
+                    {
+                    ret = R_PBK_CONTACTINFO_SEND_OPTIONS_SMS_THUMBNAIL_NO_FIELD;
+                    }
+                }
+            }
+        else
+            {
+            // Command object was launched from contact list view,
+            // the menu is shown only in case there is thumbnail
+            // involded and the sending media is SMS
+            if (smsAndThumbnail)
+                {
+                ret = R_PHONEBOOK_SEND_OPTIONS;
+                }
+            }
+        }
+    else
+        {
+        // If the 'send selected fields' is disabled, the menu
+        // needs to be shown only if the user is in contact info
+        // view and over a vCard supported field
+        if ((iField) && (supportsFieldType))
+            {
+            ret = R_PBK_CONTACTINFO_SEND_OPTIONS;
+            }
+        }
+    return ret;
+    }
+
+
+/**
+ * Maps selection index to choice item TPbkChoiceItemEnumerations.
+ * @param aSelection goes in as a selection index made by user in
+ *      the selection list, when exiting contains the selection value
+ *      mapped to TPbkChoiceItemEnumerations
+ * @param aShownMenu what menu was shown to the user (resource id)
+ */
+void CPbkSendContactCmd::MapSelection(TInt& aSelection,
+        TInt aShownMenu)
+    {
+    switch (aShownMenu)
+        {
+        case R_PBK_CONTACTINFO_SEND_OPTIONS:
+            //'send item data'
+            //'send all data'
+            {
+            switch (aSelection)
+                {
+                case EFirstSelection:
+                    {
+                    aSelection = ESendCurrentItem;
+                    break;
+                    }
+
+                case ESecondSelection:
+                    {
+                    aSelection = ESendAllData;
+                    break;
+                    }
+
+                default:
+                    {
+                    __ASSERT_DEBUG(EFalse, Panic(EPanicLogic_MapSelection));
+                    break;
+                    }
+                }
+            break;
+            }
+
+        case R_PBK_CONTACTINFO_SEND_OPTIONS_SMS_THUMBNAIL:
+            //'send item data'
+            //'send detail without image'
+            //'send detail with image'
+            {
+            switch (aSelection)
+                {
+                case EFirstSelection:
+                    {
+                    aSelection = ESendCurrentItem;
+                    break;
+                    }
+
+                case ESecondSelection:
+                    {
+                    aSelection = ESendAllDataWithoutPicture;
+                    break;
+                    }
+
+                case EThirdSelection:
+                    {
+                    aSelection = ESendAllData;
+                    break;
+                    }
+
+                default:
+                    {
+                    __ASSERT_DEBUG(EFalse, Panic(EPanicLogic_MapSelection));
+                    break;
+                    }
+                }
+            break;
+            }
+
+        case R_PBK_CONTACTINFO_SEND_OPTIONS_SMS_THUMBNAIL_NO_FIELD:
+            //'send detail without image'
+            //'send detail with image'
+            {
+            switch (aSelection)
+                {
+                case EFirstSelection:
+                    {
+                    aSelection = ESendAllDataWithoutPicture;
+                    break;
+                    }
+
+                case ESecondSelection:
+                    {
+                    aSelection = ESendAllData;
+                    break;
+                    }
+
+                default:
+                    {
+                    __ASSERT_DEBUG(EFalse, Panic(EPanicLogic_MapSelection));
+                    break;
+                    }
+                }
+            break;
+            }
+
+        case R_PHONEBOOK_SEND_OPTIONS:
+            //'send without image'
+            //'send with image'
+            {
+            switch (aSelection)
+                {
+                case EFirstSelection:
+                    {
+                    aSelection = ESendAllDataWithoutPicture;
+                    break;
+                    }
+
+                case ESecondSelection:
+                    {
+                    aSelection = ESendAllData;
+                    break;
+                    }
+
+                default:
+                    {
+                    __ASSERT_DEBUG(EFalse, Panic(EPanicLogic_MapSelection));
+                    break;
+                    }
+                }
+            break;
+            }
+        
+        default:
+            {
+            __ASSERT_DEBUG(EFalse, Panic(EPanicLogic_MapSelection));
+            break;
+            }
+        }
+    }
+
+
+/**
+ * Checks are there any thumbnails in the contact set.
+ * @return ETrue if there was even one thumbnail, EFalse otherwise
+ */
+TBool CPbkSendContactCmd::AnyThumbnailsL() const
+    {
+    TBool ret(EFalse);
+    if (iContactId != KNullContactId)
+        {
+        CPbkContactItem* contact = iEngine.ReadContactLC(iContactId);
+        ret = HasThumbnail(*contact);
+        CleanupStack::PopAndDestroy(contact);
+        }
+	else if (iContacts && iContacts->Count() > 0)
+		{
+        for (TInt i=0; i < iContacts->Count(); ++i)
+            {
+            CPbkContactItem* contact = iEngine.ReadContactLC((*iContacts)[i]);
+            ret = HasThumbnail(*contact);
+            CleanupStack::PopAndDestroy(contact);
+            if (ret)
+                {
+                // We can exit the loop as soon as a thumbnail
+                // is found
+                break;
+                }
+            }
+		}
+
+    return ret;
+    }
+
+
+/**
+ * Checks does aItem have a thumbnail.
+ * @return ETrue if the contact has a thumbnail, EFalse otherwise
+ */
+TBool CPbkSendContactCmd::HasThumbnail(CPbkContactItem& aItem) const
+    {
+    const TPbkContactItemField* field =
+        aItem.FindField(EPbkFieldIdThumbnailImage);
+    return (field && !field->IsEmptyOrAllSpaces());
+    }
+
+/**
+ * Checks is the selected sending media SMS.
+ * @return ETrue if SMS is the sending media, EFalse otherwise
+ */
+TBool CPbkSendContactCmd::IsSmsMtmL() const
+    {
+    TBool ret(EFalse);
+    if ( iMtmUid == KSenduiMtmSmsUid )
+        {
+        ret = ETrue;
+        }
+    return ret;
+    }
+
+TUid CPbkSendContactCmd::ShowSendQueryL()
+    {
+	return CPbkAppGlobals::InstanceL()->SendUiL()
+		->ShowSendQueryL( NULL, iParams.iCapabilities, iParams.iMtmFilter );
+    }    
+
+void CPbkSendContactCmd::AddObserver( MPbkCommandObserver& aObserver )
+    {
+    iObserver = &aObserver;
+    }
+
+
+//  End of File