emailuis/nmailui/src/nmeditorview.cpp
changeset 18 578830873419
child 20 ecc8def7944a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emailuis/nmailui/src/nmeditorview.cpp	Fri Apr 16 14:51:52 2010 +0300
@@ -0,0 +1,1124 @@
+/*
+* Copyright (c) 2009 - 2010 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: Message editor view
+*
+*/
+#include "nmuiheaders.h"
+
+// Layout file and view
+static const char *NMUI_EDITOR_VIEW_XML = ":/docml/nmeditorview.docml";
+static const char *NMUI_EDITOR_VIEW= "editorview";
+static const char *NMUI_EDITOR_SCROLL_AREA = "scrollArea";
+static const char *NMUI_EDITOR_SCROLL_AREA_CONTENTS = "scrollAreaContents";
+
+static const int nmOrientationTimer=100;
+
+static const QString Delimiter("; ");
+#define IMAGE_FETCHER_INTERFACE "Image"
+#define FETCHER_OPERATION "fetch(QVariantMap,QVariant)"
+
+/*!
+	\class NmEditorView
+	\brief Mail editor view
+*/
+
+/*!
+    Constructor
+*/
+NmEditorView::NmEditorView(
+    NmApplication &application,
+    NmUiStartParam* startParam,
+    NmUiEngine &uiEngine,
+    QGraphicsItem *parent)
+: NmBaseView(startParam, parent),
+mApplication(application),
+mUiEngine(uiEngine),
+mDocumentLoader(NULL),
+mScrollArea(NULL),
+mEditWidget(NULL),
+mHeaderWidget(NULL),
+mMessage(NULL),
+mContentWidget(NULL),
+mAttachContextMenu(NULL),
+mMessageCreationOperation(NULL),
+mAddAttachmentOperation(NULL),
+mRemoveAttachmentOperation(NULL),
+mCheckOutboxOperation(NULL)
+{
+    mDocumentLoader	= new HbDocumentLoader();
+    // Set object name
+    setObjectName("NmEditorView");
+    // Load view layout
+    loadViewLayout();
+    // Set mailbox name to title pane
+    setMailboxName();
+    // Set message data
+    setMessageData();
+}
+
+/*!
+    Destructor
+*/
+NmEditorView::~NmEditorView()
+{
+    delete mMessageCreationOperation;
+    delete mCheckOutboxOperation;
+
+    delete mMessage;
+
+    mWidgetList.clear();
+    delete mDocumentLoader;
+
+    delete mContentWidget;
+
+    delete mPrioritySubMenu;
+    delete mAttachContextMenu;
+}
+
+/*!
+    View layout loading from XML
+*/
+void NmEditorView::loadViewLayout()
+{
+    mPrioritySubMenu = NULL;
+
+    // Use document loader to load the view
+    bool ok = false;
+    mWidgetList = mDocumentLoader->load(NMUI_EDITOR_VIEW_XML, &ok);
+
+    if (ok == true && mWidgetList.count()) {
+        // Set view
+        QGraphicsWidget *view = mDocumentLoader->findWidget(NMUI_EDITOR_VIEW);
+        if (view){
+            setWidget(view);
+        }
+
+        mScrollArea = qobject_cast<NmBaseViewScrollArea *>
+            (mDocumentLoader->findObject(NMUI_EDITOR_SCROLL_AREA));
+        mScrollAreaContents = qobject_cast<HbWidget *>
+             (mDocumentLoader->findObject(NMUI_EDITOR_SCROLL_AREA_CONTENTS));
+
+        mContentWidget = new NmEditorContent(mScrollArea, this, mDocumentLoader);
+        mEditWidget = mContentWidget->editor();
+        mHeaderWidget = mContentWidget->header();
+
+        // Set default color for user - entered text if editor is in re/reAll/fw mode
+        NmUiEditorStartMode mode = mStartParam->editorStartMode();
+        if (mode == NmUiEditorReply || mode == NmUiEditorReplyAll || mode == NmUiEditorForward) {
+        mEditWidget->setCustomTextColor(true, Qt::blue);
+        }
+    }
+
+    // Connect signals from background scroll area
+    connect(mScrollArea, SIGNAL(handleMousePressEvent(QGraphicsSceneMouseEvent*)),
+            this, SLOT(sendMousePressEventToScroll(QGraphicsSceneMouseEvent*)));
+    connect(mScrollArea, SIGNAL(handleMouseReleaseEvent(QGraphicsSceneMouseEvent*)),
+            this, SLOT(sendMouseReleaseEventToScroll(QGraphicsSceneMouseEvent*)));
+    connect(mScrollArea, SIGNAL(handleMouseMoveEvent(QGraphicsSceneMouseEvent*)),
+            this, SLOT(sendMouseMoveEventToScroll(QGraphicsSceneMouseEvent*)));
+
+    connect(mScrollArea, SIGNAL(handleLongPressGesture(const QPointF &)),
+                this, SLOT(sendLongPressGesture(const QPointF &)));
+
+    // Connect options menu about to show to create options menu function
+    // Menu needs to be create "just-in-time"
+    connect(menu(), SIGNAL(aboutToShow()), this, SLOT(createOptionsMenu()));
+    NmAction *dummy = new NmAction(0);
+    menu()->addAction(dummy);
+
+    initializeVKB();
+    connect(mContentWidget->header(), SIGNAL(recipientFieldsHaveContent(bool)),
+            this, SLOT(setButtonsDimming(bool)) );
+
+    // call the createToolBar on load view layout
+    createToolBar();
+
+    // Set dimensions
+    adjustViewDimensions();
+	
+    // Connect to observe orientation change events
+    connect(mApplication.mainWindow(), SIGNAL(orientationChanged(Qt::Orientation)),
+            this, SLOT(orientationChanged(Qt::Orientation)));
+    // Signal for handling the attachment list selection
+    connect(mHeaderWidget, SIGNAL(attachmentRemoved(const NmId)),
+            this, SLOT(removeAttachment(const NmId)));
+}
+
+/*!
+    Reload view contents with new start parameters
+    Typically when view is already open and external view activation occurs
+    for this same view
+*/
+void NmEditorView::reloadViewContents(NmUiStartParam* startParam)
+{
+    // Check start parameter validity.
+    if (startParam&&startParam->viewId()==NmUiViewMessageEditor) {
+        // Delete existing start parameter data
+        delete mStartParam;
+        mStartParam=NULL;
+        // Store new start parameter data
+        mStartParam=startParam;
+        // Store existing edited message to drafts and reload
+        // editor with new start parameters.
+        // ..
+        // Reload editor with new message data
+        setMessageData();
+    }
+    else {
+        NMLOG("nmailui: Invalid editor start parameter");
+        // Unused start parameter needs to be deleted
+        delete startParam;
+        startParam = NULL;
+    }
+}
+
+/*!
+   Screen orientation changed. Editor view needs to be scaled when
+   landscape <-> portrait switch occurs because text needs to
+   be wrapped again.
+*/
+void NmEditorView::orientationChanged(Qt::Orientation orientation)
+{
+    Q_UNUSED(orientation);
+    // Adjust content height
+    QTimer::singleShot(nmOrientationTimer, this, SLOT(adjustViewDimensions()));
+}
+
+/*!
+    Set new dimensions after orientation change.
+*/
+void NmEditorView::adjustViewDimensions()
+{
+    if (mScrollAreaContents) {
+        const QSize reso = mApplication.screenSize();
+        mScrollAreaContents->setMinimumWidth(reso.width());
+        mScrollAreaContents->setMaximumWidth(reso.width());
+    }
+}
+
+/*!
+    View id
+*/
+NmUiViewId NmEditorView::nmailViewId() const
+{
+    return NmUiViewMessageEditor;
+}
+
+/*!
+    ScrollArea contents
+*/
+HbWidget* NmEditorView::scrollAreaContents()
+{
+    return mScrollAreaContents;
+}
+
+/*
+   Query user if we want to exit the editor
+ */
+bool NmEditorView::okToExitView()
+{
+    bool okToExit = true;
+
+    // show the query if the message has not been sent
+    if (mMessage && mContentWidget->header()) {
+        // see if editor has any content
+        NmEditorHeader *header = mContentWidget->header();
+
+        int toTextLength = 0;
+        if (header->toField()) {
+            toTextLength = header->toField()->text().length();
+        }
+        
+        int ccTextLength = 0;
+        if (header->ccField()) {
+            ccTextLength = header->ccField()->text().length();
+        }
+
+        int bccTextLength = 0;
+        if (header->bccField()) {
+            bccTextLength = header->bccField()->text().length();
+        }
+        
+        int subjectLength = 0;
+        if (header->subjectField()) {
+            subjectLength = header->subjectField()->text().length();
+        }
+        
+        okToExit = (toTextLength == 0 && ccTextLength == 0 && bccTextLength == 0 && 
+            subjectLength == 0 && mContentWidget->editor()->document()->isEmpty());
+
+        // content exists, verify exit from user
+        if (!okToExit) {
+            HbMessageBox *messageBox = new HbMessageBox(HbMessageBox::MessageTypeQuestion);
+            messageBox->setText(hbTrId("txt_mail_dialog_delete_message"));
+            messageBox->setTimeout(HbMessageBox::NoTimeout);
+        
+            // Read user selection
+            HbAction *action = messageBox->exec(); 
+            okToExit = (action == messageBox->primaryAction());
+        }
+    }
+
+    return okToExit;
+}
+
+/*!
+    About to exit view. Application calls this function when user has
+    pressed back key and editor needs to delete the draft message. This is
+    called when "auto-exiting" after a successful mail sending.
+*/
+void NmEditorView::aboutToExitView()
+{
+    // These operations need to be stopped before message can be deleted
+    delete mAddAttachmentOperation;
+    delete mRemoveAttachmentOperation;
+
+    if (mMessage) { // this is NULL if sending is started
+        // Delete message from drafts
+        NmId mailboxId = mMessage->mailboxId();
+        NmId folderId = mMessage->parentId();
+        NmId msgId = mMessage->envelope().id();
+        mUiEngine.removeMessage(mailboxId, folderId, msgId);
+    }
+}
+
+/*!
+    Find message data based on start parameters.  Method is called
+    when editor is started. If message data is found it means that
+    operation is forward or reply message.
+ */
+void NmEditorView::setMessageData()
+{
+    // Check the outbox.
+    delete mCheckOutboxOperation;
+	mCheckOutboxOperation = NULL;
+	
+	mCheckOutboxOperation = mUiEngine.checkOutbox(mStartParam->mailboxId());
+    
+    if (mCheckOutboxOperation) {
+        connect(mCheckOutboxOperation, SIGNAL(operationCompleted(int)),
+                this, SLOT(outboxChecked(int)));
+    }
+    else {
+        startMessageCreation( mStartParam->editorStartMode() );
+    }
+}
+
+/*!
+ */
+void NmEditorView::startMessageCreation(NmUiEditorStartMode startMode)
+{
+    NmId mailboxId = mStartParam->mailboxId();
+    NmId folderId = mStartParam->folderId();
+    NmId msgId = mStartParam->messageId();
+    
+    delete mMessageCreationOperation;
+	mMessageCreationOperation = NULL;
+	
+	// original message is now fetched so start message creation
+    if (startMode == NmUiEditorForward) {
+        mMessageCreationOperation = mUiEngine.createForwardMessage(mailboxId, msgId);
+    }
+    else if (startMode == NmUiEditorReply || startMode == NmUiEditorReplyAll) {
+        mMessageCreationOperation = mUiEngine.createReplyMessage(mailboxId, 
+            msgId, 
+            startMode == NmUiEditorReplyAll);
+    }
+    else {
+        mMessageCreationOperation = mUiEngine.createNewMessage(mailboxId);
+    }
+    
+    // operation continues in messageCreated() once it finishes ok
+    if (mMessageCreationOperation) {
+        connect(mMessageCreationOperation,
+                SIGNAL(operationCompleted(int)),
+                this,
+                SLOT(messageCreated(int)));
+    }    
+}
+
+/*!
+    Starting the message sending is handled here.
+ */
+void NmEditorView::startSending()
+{
+    // The message contents should be verified
+    updateMessageWithEditorContents();
+    
+    // verify addresses before sending
+    QList<NmAddress> invalidAddresses;
+    NmUtilities::getRecipientsFromMessage(*mMessage, invalidAddresses, NmUtilities::InvalidAddress);
+    
+    bool okToSend = true;
+    if (invalidAddresses.count() > 0) {
+        
+        // invalid addresses found, verify send from user
+        HbMessageBox *messageBox = new HbMessageBox(HbMessageBox::MessageTypeQuestion);
+        QString noteText = hbTrId("txt_mail_dialog_invalid_mail_address_send");
+        // set the first failing address to the note
+        noteText = noteText.arg(invalidAddresses.at(0).address());
+        messageBox->setText(noteText);
+        messageBox->setTimeout(HbMessageBox::NoTimeout);
+
+        // Read user selection
+        HbAction *action = messageBox->exec();
+        okToSend = (action == messageBox->primaryAction());
+    }
+    
+    if (okToSend) {
+        // ownership of mMessage changes
+        mUiEngine.sendMessage(mMessage);
+        mMessage = NULL;
+        // sending animation should be shown here, then exit
+        QTimer::singleShot(1000, &mApplication, SLOT(popView()));
+    }
+}
+
+/*!
+    This is signalled by mMessageCreationOperation when message is created.
+ */
+void NmEditorView::messageCreated(int result)
+{
+    delete mMessage;
+    mMessage = NULL;
+
+    if (result == NmNoError && mMessageCreationOperation) {
+        NmUiEditorStartMode startMode = mStartParam->editorStartMode();
+        
+        // get message "again" from engine to update the message contents 
+        mMessage = mUiEngine.message(
+            mStartParam->mailboxId(), 
+            mStartParam->folderId(), 
+            mMessageCreationOperation->getMessageId());
+        
+        fillEditorWithMessageContents();       
+    }
+}
+
+/*!
+   Updates the message with the editor contents.
+ */
+void NmEditorView::updateMessageWithEditorContents()
+{
+    if (mMessage) {
+        if (mContentWidget && mContentWidget->editor()) {
+            NmMessagePart* bodyPart = mMessage->htmlBodyPart();
+            if (bodyPart) {
+                bodyPart->setTextContent(mContentWidget->editor()->toHtml(), NmContentTypeTextHtml);
+            }
+            bodyPart = mMessage->plainTextBodyPart();
+            if (bodyPart) {
+                bodyPart->setTextContent(mContentWidget->editor()->toPlainText(), NmContentTypeTextPlain);
+            }
+        }
+        if (mContentWidget && mContentWidget->header() ) {
+            if (mContentWidget->header()->subjectField()) {
+                mMessage->envelope().setSubject(
+                    mContentWidget->header()->subjectField()->text());
+            }
+            if (mContentWidget->header()->toField()) {
+                QString toFieldText =
+                    mContentWidget->header()->toField()->text();
+
+                // This verification of zero length string isn't needed
+                // after list of addresses
+                if (toFieldText.length() > 0) {
+                    mMessage->envelope().setToRecipients(mContentWidget->header()->toField()->emailAddressList());  
+                }
+            }
+            if (mContentWidget->header()->ccField()) {
+                QString ccFieldText =
+                    mContentWidget->header()->ccField()->text();
+
+                if (ccFieldText.length() > 0) {
+                    mMessage->envelope().setCcRecipients(mContentWidget->header()->ccField()->emailAddressList());      
+                }
+            }
+            if (mContentWidget->header()->bccField()) {
+                QString bccFieldText =
+                    mContentWidget->header()->bccField()->text();
+
+                if (bccFieldText.length() > 0) {
+                    mMessage->envelope().setBccRecipients(mContentWidget->header()->bccField()->emailAddressList());  
+                }
+            }
+        }
+    }
+}
+
+
+/*!
+    Updates the message with the editor contents. Called only once when the
+    editor is launched.
+ */
+void NmEditorView::fillEditorWithMessageContents()
+{
+    if (!mMessage || !mContentWidget) {
+        return;
+    }
+
+    NmMessageEnvelope messageEnvelope(mMessage->envelope());
+    NmUiEditorStartMode editorStartMode = NmUiEditorCreateNew;
+    bool useStartParam(false);
+
+    if (mStartParam) {
+        editorStartMode = mStartParam->editorStartMode();
+
+        if (editorStartMode == NmUiEditorMailto) {
+            // Retrieve the message header data e.g. recipients from mStartParam.
+            useStartParam = true;        
+        }
+    }
+    
+    // Set recipients (to, cc and bcc).
+    QString toAddressesString;
+    QString ccAddressesString;
+    QString bccAddressesString;
+
+    if (useStartParam) {
+        toAddressesString = addressListToString(mStartParam->mailtoAddressList());
+        ccAddressesString = addressListToString(mStartParam->ccAddressList());
+        bccAddressesString = addressListToString(mStartParam->bccAddressList());
+    }
+    else {
+        toAddressesString = addressListToString(messageEnvelope.toRecipients());
+        ccAddressesString = addressListToString(messageEnvelope.ccRecipients());
+        bccAddressesString = addressListToString(messageEnvelope.bccRecipients());
+    }
+
+    mContentWidget->header()->toField()->setPlainText(toAddressesString);
+    mContentWidget->header()->ccField()->setPlainText(ccAddressesString);
+    mContentWidget->header()->bccField()->setPlainText(bccAddressesString);
+
+    if (ccAddressesString.length() || bccAddressesString.length()) {
+        // Since cc or/and bcc recipients exist, expand the group box to display
+        // the addresses by expanding the group box.
+        mContentWidget->header()->setGroupBoxCollapsed(false);
+    }
+
+    // Set subject.
+    if (useStartParam) {
+        QString *subject = mStartParam->subject();
+
+        if (subject) {
+            mContentWidget->header()->subjectField()->setPlainText(*subject);
+        }
+    }
+    else {
+        // If a message is taken from the outbox, no subject formatting is done.
+        NmId notUsed(0);
+
+        if (mCheckOutboxOperation &&
+            mCheckOutboxOperation->getMessageId(notUsed)) {
+            editorStartMode = NmUiEditorCreateNew;
+        }
+
+        // Construct the subject field.
+        mContentWidget->header()->subjectField()->setPlainText(
+            addSubjectPrefix(editorStartMode, messageEnvelope.subject()));
+    }
+
+    // Set priority.
+    mHeaderWidget->setPriority(messageEnvelope.priority());
+    
+    // Set the message body.
+    // Fetch plain text part form message store.
+    NmMessagePart *plainPart = mMessage->plainTextBodyPart();
+
+    if (plainPart) {
+        mUiEngine.contentToMessagePart(mMessage->mailboxId(),
+                                       mMessage->parentId(),
+                                       mMessage->envelope().id(),
+                                       *plainPart);
+    }
+
+    // Fetch html part form message store.
+    NmMessagePart *htmlPart = mMessage->htmlBodyPart();
+
+    if (htmlPart) {
+        mUiEngine.contentToMessagePart(mMessage->mailboxId(),
+                                       mMessage->parentId(),
+                                       mMessage->envelope().id(),
+                                       *htmlPart);
+    }
+
+    // Fetch attachment.html part form message store if such exists.
+    QList<NmMessagePart*> parts;
+    mMessage->attachmentList(parts);
+    NmMessagePart *attachmentHtml = NULL;
+
+    foreach(NmMessagePart *part, parts) {
+        if (part->contentDescription().startsWith(NmContentDescrAttachmentHtml)) {
+            attachmentHtml = part;
+        }
+    }
+
+    if (attachmentHtml) {
+        mUiEngine.contentToMessagePart(mMessage->mailboxId(),
+                                       mMessage->parentId(),
+                                       mMessage->envelope().id(),
+                                       *attachmentHtml);
+    }
+
+    mContentWidget->setMessageData(mMessage);
+    
+    // Get list of attachments from the message and set those into UI attachment list
+    QList<NmMessagePart*> attachments;
+    mMessage->attachmentList(attachments);
+
+    for (int i=0; i<attachments.count(); i++) {
+        mHeaderWidget->addAttachment(
+            attachments[i]->attachmentName(),
+            QString::number(attachments[i]->size()),
+            attachments[i]->id());
+    }
+
+    if (mStartParam) {
+        // Attach passed files to the message.
+        QStringList *fileList = mStartParam->attachmentList();
+
+        if (fileList) {
+            addAttachments(*fileList);
+        }
+    }
+
+    // TODO Switch the following arbitrary (magic number) timeout to a
+    // meaningful constant, please!
+    QTimer::singleShot(200, mHeaderWidget, SLOT(sendHeaderHeightChanged()));
+}
+
+
+/*!
+    createToolBar. Function asks menu commands from extension
+    to be added to toolbar owned by the HbView.
+*/
+void NmEditorView::createToolBar()
+{
+    HbToolBar *tb = toolBar();
+    NmUiExtensionManager &extMngr = mApplication.extManager();
+    if (tb && &extMngr && mStartParam) {
+        tb->clearActions();
+        NmActionRequest request(this, NmActionToolbar, NmActionContextViewEditor,
+                NmActionContextDataNone, mStartParam->mailboxId(), mStartParam->folderId() );
+        QList<NmAction *> list;
+        extMngr.getActions(request, list);
+        for (int i = 0; i < list.count(); i++) {
+            tb->addAction(list[i]);
+            // If action has NmSendable condition, it is shown only when send action
+            // is available, i.e. when at least one recipient field has data.
+            if( list[i]->availabilityCondition() == NmAction::NmSendable ) {
+                list[i]->setEnabled(false);
+            }
+        }
+    }
+}
+
+/*!
+    createOptionsMenu. Functions asks menu commands from extension
+    to be added to options menu.
+*/
+void NmEditorView::createOptionsMenu()
+{
+    if (!mPrioritySubMenu) {
+        mPrioritySubMenu = new HbMenu();
+    }
+    mPrioritySubMenu->clearActions();
+    menu()->clearActions();
+    NmActionRequest request(this, NmActionOptionsMenu, NmActionContextViewEditor,
+            NmActionContextDataMessage, mStartParam->mailboxId(), mStartParam->folderId(),
+            mStartParam->messageId());
+    NmUiExtensionManager &extMngr = mApplication.extManager();
+    QList<NmAction*> list;
+    extMngr.getActions(request, list);
+    for (int i = 0; i < list.count(); i++) {
+        mPrioritySubMenu->addAction(list[i]);
+    }
+    mPrioritySubMenu->setObjectName("editorPrioritySubMenu");
+    mPrioritySubMenu->setTitle(hbTrId("txt_mail_opt_add_priority"));
+    menu()->addMenu(mPrioritySubMenu);
+}
+
+/*!
+    handleActionCommand. From NmActionObserver, extension manager calls this
+    call to handle menu command in the UI.
+*/
+void NmEditorView::handleActionCommand(NmActionResponse &actionResponse)
+{
+    NmActionResponseCommand responseCommand = actionResponse.responseCommand();
+    
+    // Handle options menu
+    if (actionResponse.menuType() == NmActionOptionsMenu) {
+        setPriority(responseCommand);
+    }
+    else if (actionResponse.menuType() == NmActionToolbar) {
+        switch (responseCommand) {
+            case NmActionResponseCommandSendMail: {
+                startSending();
+                break;
+            }
+            case NmActionResponseCommandAttach : {
+                // Do nothing if previous addAttachment operation is still ongoing.
+                if(!mAddAttachmentOperation || !mAddAttachmentOperation->isRunning()) {
+                    //will be replaced by toolbar extension                                
+                    if (!mAttachContextMenu) {
+                        QList<NmAction *> actionList;
+                        NmAction* actionPhoto = new NmAction(0);
+                        actionPhoto->setText(QObject::tr("Photo", "txt_nmailui_photo_attach"));
+                        actionList.append(actionPhoto);
+                        connect(actionPhoto, SIGNAL(triggered()), this, SLOT(attachImage()));
+                                
+                        mAttachContextMenu = new HbMenu();
+                        mAttachContextMenu->clearActions();
+
+                        for (int i=0;i<actionList.count();i++) {
+                            mAttachContextMenu->addAction(actionList[i]);
+                        }
+                    }
+                
+                    QPointF menuPos(qreal(20),qreal(520));
+                    mAttachContextMenu->exec(menuPos);
+                }
+                break;
+            }
+            default:
+                break;
+        }
+    }
+}
+
+/*!
+    This function converts background scroll area coordinate point into
+    body text editor coordinate point.
+ */
+QPointF NmEditorView::viewCoordinateToEditCoordinate(QPointF orgPoint)
+{
+    QPointF contentWidgetPos = mScrollAreaContents->pos();
+    qreal y = orgPoint.y() - mHeaderWidget->headerHeight();
+    y -= contentWidgetPos.y();
+    qreal x = orgPoint.x() - contentWidgetPos.x();
+    return QPointF(x, y);
+}
+
+/*!
+   Send mouse press event to body edit widget
+*/
+void NmEditorView::sendMousePressEventToScroll(QGraphicsSceneMouseEvent *event)
+{
+    if (event && mEditWidget && mHeaderWidget) {
+        event->setPos(viewCoordinateToEditCoordinate(event->pos()));
+        event->setAccepted(true);
+        mEditWidget->sendMousePressEvent(event);
+    }
+}
+
+/*!
+   Send mouse release event to body edit widget
+*/
+void NmEditorView::sendMouseReleaseEventToScroll(QGraphicsSceneMouseEvent *event)
+{
+    if (event&& mEditWidget && mHeaderWidget) {
+        event->setPos(viewCoordinateToEditCoordinate(event->pos()));
+        event->setAccepted(true);
+        mEditWidget->sendMouseReleaseEvent(event);
+    }
+}
+
+/*!
+   Send mouse move event to body edit widget
+*/
+void NmEditorView::sendMouseMoveEventToScroll(QGraphicsSceneMouseEvent *event)
+{
+    if (event&& mEditWidget && mHeaderWidget) {
+        event->setPos(viewCoordinateToEditCoordinate(event->pos()));
+        event->setAccepted(true);
+        mEditWidget->sendMouseMoveEvent(event);
+    }
+}
+
+void NmEditorView::sendLongPressGesture(const QPointF &point)
+{
+    if (mEditWidget && mHeaderWidget) {
+        QPointF scenePos = mEditWidget->scenePos();
+        QPointF newPoint = QPointF(point.x()-scenePos.x(), point.y()-scenePos.y());
+        if(mEditWidget->contains(newPoint)) {
+            mEditWidget->sendLongPressEvent(point);
+        }
+    }
+}
+
+
+/*!
+   Sets all toolbar and VKB buttons dimmed state. All actions that have the
+   availability condition NmSendable set, will be enabled/disabled.
+*/
+void NmEditorView::setButtonsDimming(bool enabled)
+{
+    // Set the toolbar action states
+    HbToolBar *tb = toolBar();
+    if (tb) {
+        QList<QAction *> toolbarList = tb->actions();
+        int count = toolbarList.count();
+        for (int i = 0; i < count; i++) {
+            NmAction *action = static_cast<NmAction *>(toolbarList[i]);
+            if (action->availabilityCondition() == NmAction::NmSendable) {
+                action->setEnabled(enabled);
+            }
+        }
+
+        // Set the VKB action states
+        // All editors of the view share the same action, so it is enough to set
+        // this only to one of them.
+        HbEditorInterface editorInterface(mContentWidget->editor());
+        QList<HbAction *> vkbList = editorInterface.actions();
+        count = vkbList.count();
+        for (int i = 0; i < count; i++) {
+            NmAction *action = static_cast<NmAction *>(vkbList[i]);
+            if (action->availabilityCondition() == NmAction::NmSendable) {
+                action->setEnabled(enabled);
+            }
+        }
+    }
+}
+
+/*!
+    Initialize the Virtual Keyboard to show the "Send" button
+    for all editors of the view.
+*/
+void NmEditorView::initializeVKB()
+{
+    NmActionRequest request(this, NmActionVKB, NmActionContextViewEditor,
+         NmActionContextDataNone, mStartParam->mailboxId(), mStartParam->folderId() );
+    NmUiExtensionManager &extMngr = mApplication.extManager();
+    if (&extMngr) {
+        QList<NmAction *> list;
+        extMngr.getActions(request, list);
+
+        // VKB only supports one application key, but the responsibility of giving only one
+        // action is left to the extension plugin. The rest are still attached to the VKB, but
+        // they are not shown (unless VKB starts supporting more than one).
+        for (int i = 0; i < list.count(); i++) {
+            if( list[i]->availabilityCondition() == NmAction::NmSendable ) {
+                list[i]->setEnabled(false);
+            }
+            list[i]->setIcon(NmIcons::getIcon(NmIcons::NmIconSend));
+
+            // Link VKB to the action. This must be done to all
+            // editors that show the button in VKB.
+            HbEditorInterface editorInterface(mContentWidget->editor());
+            editorInterface.addAction(list[i]);
+            HbEditorInterface toEditorInterface(mContentWidget->header()->toField());
+            toEditorInterface.addAction(list[i]);
+            HbEditorInterface ccEditorInterface(mContentWidget->header()->ccField());
+            ccEditorInterface.addAction(list[i]);
+            HbEditorInterface bccEditorInterface(mContentWidget->header()->bccField());
+            bccEditorInterface.addAction(list[i]);
+            HbEditorInterface subjectEditorInterface(mContentWidget->header()->subjectField());
+            subjectEditorInterface.addAction(list[i]);
+        }
+    }
+}
+
+/*!
+    Set mailbox name to title
+*/
+void NmEditorView::setMailboxName()
+{
+    if (mStartParam){
+        NmMailboxMetaData *meta = mUiEngine.mailboxById(mStartParam->mailboxId());
+        if (meta){
+            setTitle(meta->name());
+        }
+    }
+}
+
+/*!
+   Adds a prefix to the subject for reply or forward. 
+   Strips other occurrences of the prefix from the beginning.
+ */
+QString NmEditorView::addSubjectPrefix( NmUiEditorStartMode startMode, const QString &subject )
+{
+    QString newSubject(subject.trimmed());
+    
+    if (startMode == NmUiEditorReply || startMode == NmUiEditorReplyAll || 
+        startMode == NmUiEditorForward) {
+        QString rePrefix(QObject::tr("Re:", "txt_nmailui_reply_subject_prefix"));
+        QString fwPrefix(QObject::tr("Fw:", "txt_nmailui_forward_subject_prefix"));
+        
+        // strip extra prefixes from beginning
+        int rePrefixLength(rePrefix.length());
+        int fwPrefixLength(fwPrefix.length());
+        
+        bool startswithRe(newSubject.startsWith(rePrefix, Qt::CaseInsensitive));
+        bool startswithFw(newSubject.startsWith(fwPrefix, Qt::CaseInsensitive));
+        
+        while (startswithRe || startswithFw) {            
+            if (startswithRe) {
+                newSubject.remove(0,rePrefixLength);
+                newSubject = newSubject.trimmed();
+            }
+            else if (startswithFw) {
+                newSubject.remove(0,fwPrefixLength);
+                newSubject = newSubject.trimmed();
+            }
+            startswithRe = newSubject.startsWith(rePrefix, Qt::CaseInsensitive);
+            startswithFw = newSubject.startsWith(fwPrefix, Qt::CaseInsensitive);
+        }
+        
+        if (startMode == NmUiEditorReply || startMode == NmUiEditorReplyAll) {
+            newSubject = rePrefix + " " + newSubject;
+        }
+        else if (startMode == NmUiEditorForward) {
+            newSubject = fwPrefix + " " + newSubject;
+        }
+    }
+    
+    return newSubject;
+}
+
+#ifdef Q_OS_SYMBIAN
+
+void NmEditorView::attachImage()
+{      
+    XQAiwRequest *request;
+    XQApplicationManager mAppmgr;
+    request = mAppmgr.create(IMAGE_FETCHER_INTERFACE, FETCHER_OPERATION, true);
+        
+    if (request) {
+        connect(request, SIGNAL(requestOk(const QVariant&)), this, SLOT(onAttachmentReqCompleted(const QVariant&)));
+    }
+    else {
+        //create request failed
+        NMLOG("appmgr: create request failed");
+        return;
+    }               
+
+    if (!(request)->send()) {
+        //sending request failed
+        NMLOG("appmgr: send request failed");
+    }
+    delete request;
+}
+
+/*!
+    This slot is called when 'attachment picker' request has been performed succesfully
+    Parameter 'value' contains file currently one file name but later list of the files. 
+*/
+void NmEditorView::onAttachmentReqCompleted(const QVariant &value)
+{
+    if (!value.isNull()) {
+        addAttachments(value.toStringList());
+    }
+}
+
+#endif
+
+/*!
+    Add list of attachments
+*/
+void NmEditorView::addAttachments(const QStringList& fileNames) 
+{
+    NMLOG("NmEditorView::addAttachments");
+
+    // Add attachment name into UI
+    foreach (QString fileName, fileNames)  {
+        // At this phase attachment size and nmid are not known
+        mHeaderWidget->addAttachment(fileName, QString("0"), NmId(0));
+        NMLOG(fileName);
+    }
+
+    // Start operation to attach file or list of files into mail message
+    // This will also copy files into message store
+    // Delete previous operation
+    if (mAddAttachmentOperation) {
+        if (!mAddAttachmentOperation->isRunning()) {
+            delete mAddAttachmentOperation;
+            mAddAttachmentOperation = NULL;
+        }
+    }
+    if (!mAddAttachmentOperation) {
+        mAddAttachmentOperation = mUiEngine.addAttachments(*mMessage, fileNames);
+
+        if (mAddAttachmentOperation) {
+            // Signal to inform completion of one attachment
+            connect(mAddAttachmentOperation,
+                    SIGNAL(operationPartCompleted(const QString &, const NmId &, int)),
+                    this,
+                    SLOT(oneAttachmentAdded(const QString &, const NmId &, int)));
+        
+            // Signal to inform the completion of the whole operation
+            connect(mAddAttachmentOperation,
+                    SIGNAL(operationCompleted(int)),
+                    this,
+                    SLOT(allAttachmentsAdded(int)));
+        }
+    }
+}
+
+/*!
+    This slot is called when attachment has been deleted from UI
+*/
+void NmEditorView::removeAttachment(const NmId attachmentPartId)
+{
+    // Delete previous operation
+    if (mRemoveAttachmentOperation) {
+        if (!mRemoveAttachmentOperation->isRunning()) {
+            delete mRemoveAttachmentOperation;
+            mRemoveAttachmentOperation = NULL;
+        }
+    }
+    if (!mRemoveAttachmentOperation) {
+        mRemoveAttachmentOperation = mUiEngine.removeAttachment(*mMessage, attachmentPartId);
+    }
+}
+
+/*!
+    This is signalled by mAddAttachmentOperation when the operation is
+    completed for one attachment.
+ */
+void NmEditorView::oneAttachmentAdded(const QString &fileName, const NmId &msgPartId, int result)
+{
+    if (result == NmNoError) {
+        // Get file size from the message when it works
+        mHeaderWidget->setAttachmentParameters(fileName, msgPartId, QString("0"), result);
+    }
+    else {
+        // Attachment adding failed. Show an error note and remove from UI attachment list.
+        NMLOG(QString("nmailui: attachment adding into message failed: %1").arg(fileName));
+        mHeaderWidget->removeAttachment(fileName);
+    }
+}
+
+/*!
+    This is signalled by mAddAttachmentOperation when the operation is
+    completed totally.
+ */
+void NmEditorView::allAttachmentsAdded(int result)
+{
+    if (result != NmNoError) {
+        HbMessageBox::warning(hbTrId("txt_mail_dialog_unable_to_add_attachment"));
+    }
+}
+
+/*!
+    This is signalled by mCheckOutboxOperation when the operation is complete.
+ */
+void NmEditorView::outboxChecked(int result)
+{
+    bool messageInOutbox = false;
+    
+    if (result == NmNoError && mCheckOutboxOperation) {
+
+        NmId messageId;
+        messageInOutbox = mCheckOutboxOperation->getMessageId(messageId);
+        
+        if (messageInOutbox) {
+            delete mMessage;
+            mMessage = NULL;
+
+            mMessage = mUiEngine.message(
+                mStartParam->mailboxId(), 
+                mUiEngine.standardFolderId(
+                    mStartParam->mailboxId(), NmFolderOutbox), 
+                messageId);
+            
+            fillEditorWithMessageContents();
+            
+            if (mMessage) {
+                HbMessageBox::warning(
+                    hbTrId("txt_mail_dialog_sending failed").arg(
+                        NmUtilities::truncate(
+                            mMessage->envelope().subject(), 20)));
+            }
+        }
+    }
+
+    if (!messageInOutbox) {
+        startMessageCreation(mStartParam->editorStartMode());
+    }
+}
+
+/*!
+   Sets priority for the message object that is being edited 
+*/
+void NmEditorView::setPriority(NmActionResponseCommand priority)
+{
+    mHeaderWidget->setPriority(priority);
+
+    if (mMessage) {
+        NmMessagePriority messagePriority = NmMessagePriorityNormal;
+        
+        if (priority == NmActionResponseCommandPriorityHigh) {
+            messagePriority = NmMessagePriorityHigh;
+        }
+        else if (priority == NmActionResponseCommandPriorityLow) {
+            messagePriority = NmMessagePriorityLow;
+        }
+        mMessage->envelope().setPriority(messagePriority);
+    }
+}
+
+
+/*!
+    Extracts the addresses from the given list into a string separated with a
+    delimiter.
+
+    \param list The list containing the addresses.
+    \return String containing the addresses.
+*/
+QString NmEditorView::addressListToString(const QList<NmAddress*> &list) const
+{
+    QString addressesString;
+    QList<NmAddress*>::const_iterator i = list.constBegin();
+    
+    while (i != list.constEnd() && *i) {
+        if (i > list.constBegin()) {
+            // Add the delimiter.
+            addressesString += Delimiter;
+        }
+
+        addressesString += (*i)->address();
+        ++i;
+    }
+
+    return addressesString;
+}
+
+
+/*!
+    Extracts the addresses from the given list into a string separated with a
+    delimiter.
+
+    \param list The list containing the addresses.
+    \return String containing the addresses.
+*/
+QString NmEditorView::addressListToString(const QList<NmAddress> &list) const
+{
+    QString addressesString;
+    QList<NmAddress>::const_iterator i = list.constBegin();
+    
+    while (i != list.constEnd()) {
+        if (i > list.constBegin()) {
+            // Add the delimiter.
+            addressesString += Delimiter;
+        }
+
+        addressesString += (*i).address();
+        ++i;
+    }
+
+    return addressesString;
+}
+
+
+// End of file.