--- /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