emailuis/nmailui/src/nmeditorview.cpp
changeset 18 578830873419
child 20 ecc8def7944a
equal deleted inserted replaced
4:e7aa27f58ae1 18:578830873419
       
     1 /*
       
     2 * Copyright (c) 2009 - 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: Message editor view
       
    15 *
       
    16 */
       
    17 #include "nmuiheaders.h"
       
    18 
       
    19 // Layout file and view
       
    20 static const char *NMUI_EDITOR_VIEW_XML = ":/docml/nmeditorview.docml";
       
    21 static const char *NMUI_EDITOR_VIEW= "editorview";
       
    22 static const char *NMUI_EDITOR_SCROLL_AREA = "scrollArea";
       
    23 static const char *NMUI_EDITOR_SCROLL_AREA_CONTENTS = "scrollAreaContents";
       
    24 
       
    25 static const int nmOrientationTimer=100;
       
    26 
       
    27 static const QString Delimiter("; ");
       
    28 #define IMAGE_FETCHER_INTERFACE "Image"
       
    29 #define FETCHER_OPERATION "fetch(QVariantMap,QVariant)"
       
    30 
       
    31 /*!
       
    32 	\class NmEditorView
       
    33 	\brief Mail editor view
       
    34 */
       
    35 
       
    36 /*!
       
    37     Constructor
       
    38 */
       
    39 NmEditorView::NmEditorView(
       
    40     NmApplication &application,
       
    41     NmUiStartParam* startParam,
       
    42     NmUiEngine &uiEngine,
       
    43     QGraphicsItem *parent)
       
    44 : NmBaseView(startParam, parent),
       
    45 mApplication(application),
       
    46 mUiEngine(uiEngine),
       
    47 mDocumentLoader(NULL),
       
    48 mScrollArea(NULL),
       
    49 mEditWidget(NULL),
       
    50 mHeaderWidget(NULL),
       
    51 mMessage(NULL),
       
    52 mContentWidget(NULL),
       
    53 mAttachContextMenu(NULL),
       
    54 mMessageCreationOperation(NULL),
       
    55 mAddAttachmentOperation(NULL),
       
    56 mRemoveAttachmentOperation(NULL),
       
    57 mCheckOutboxOperation(NULL)
       
    58 {
       
    59     mDocumentLoader	= new HbDocumentLoader();
       
    60     // Set object name
       
    61     setObjectName("NmEditorView");
       
    62     // Load view layout
       
    63     loadViewLayout();
       
    64     // Set mailbox name to title pane
       
    65     setMailboxName();
       
    66     // Set message data
       
    67     setMessageData();
       
    68 }
       
    69 
       
    70 /*!
       
    71     Destructor
       
    72 */
       
    73 NmEditorView::~NmEditorView()
       
    74 {
       
    75     delete mMessageCreationOperation;
       
    76     delete mCheckOutboxOperation;
       
    77 
       
    78     delete mMessage;
       
    79 
       
    80     mWidgetList.clear();
       
    81     delete mDocumentLoader;
       
    82 
       
    83     delete mContentWidget;
       
    84 
       
    85     delete mPrioritySubMenu;
       
    86     delete mAttachContextMenu;
       
    87 }
       
    88 
       
    89 /*!
       
    90     View layout loading from XML
       
    91 */
       
    92 void NmEditorView::loadViewLayout()
       
    93 {
       
    94     mPrioritySubMenu = NULL;
       
    95 
       
    96     // Use document loader to load the view
       
    97     bool ok = false;
       
    98     mWidgetList = mDocumentLoader->load(NMUI_EDITOR_VIEW_XML, &ok);
       
    99 
       
   100     if (ok == true && mWidgetList.count()) {
       
   101         // Set view
       
   102         QGraphicsWidget *view = mDocumentLoader->findWidget(NMUI_EDITOR_VIEW);
       
   103         if (view){
       
   104             setWidget(view);
       
   105         }
       
   106 
       
   107         mScrollArea = qobject_cast<NmBaseViewScrollArea *>
       
   108             (mDocumentLoader->findObject(NMUI_EDITOR_SCROLL_AREA));
       
   109         mScrollAreaContents = qobject_cast<HbWidget *>
       
   110              (mDocumentLoader->findObject(NMUI_EDITOR_SCROLL_AREA_CONTENTS));
       
   111 
       
   112         mContentWidget = new NmEditorContent(mScrollArea, this, mDocumentLoader);
       
   113         mEditWidget = mContentWidget->editor();
       
   114         mHeaderWidget = mContentWidget->header();
       
   115 
       
   116         // Set default color for user - entered text if editor is in re/reAll/fw mode
       
   117         NmUiEditorStartMode mode = mStartParam->editorStartMode();
       
   118         if (mode == NmUiEditorReply || mode == NmUiEditorReplyAll || mode == NmUiEditorForward) {
       
   119         mEditWidget->setCustomTextColor(true, Qt::blue);
       
   120         }
       
   121     }
       
   122 
       
   123     // Connect signals from background scroll area
       
   124     connect(mScrollArea, SIGNAL(handleMousePressEvent(QGraphicsSceneMouseEvent*)),
       
   125             this, SLOT(sendMousePressEventToScroll(QGraphicsSceneMouseEvent*)));
       
   126     connect(mScrollArea, SIGNAL(handleMouseReleaseEvent(QGraphicsSceneMouseEvent*)),
       
   127             this, SLOT(sendMouseReleaseEventToScroll(QGraphicsSceneMouseEvent*)));
       
   128     connect(mScrollArea, SIGNAL(handleMouseMoveEvent(QGraphicsSceneMouseEvent*)),
       
   129             this, SLOT(sendMouseMoveEventToScroll(QGraphicsSceneMouseEvent*)));
       
   130 
       
   131     connect(mScrollArea, SIGNAL(handleLongPressGesture(const QPointF &)),
       
   132                 this, SLOT(sendLongPressGesture(const QPointF &)));
       
   133 
       
   134     // Connect options menu about to show to create options menu function
       
   135     // Menu needs to be create "just-in-time"
       
   136     connect(menu(), SIGNAL(aboutToShow()), this, SLOT(createOptionsMenu()));
       
   137     NmAction *dummy = new NmAction(0);
       
   138     menu()->addAction(dummy);
       
   139 
       
   140     initializeVKB();
       
   141     connect(mContentWidget->header(), SIGNAL(recipientFieldsHaveContent(bool)),
       
   142             this, SLOT(setButtonsDimming(bool)) );
       
   143 
       
   144     // call the createToolBar on load view layout
       
   145     createToolBar();
       
   146 
       
   147     // Set dimensions
       
   148     adjustViewDimensions();
       
   149 	
       
   150     // Connect to observe orientation change events
       
   151     connect(mApplication.mainWindow(), SIGNAL(orientationChanged(Qt::Orientation)),
       
   152             this, SLOT(orientationChanged(Qt::Orientation)));
       
   153     // Signal for handling the attachment list selection
       
   154     connect(mHeaderWidget, SIGNAL(attachmentRemoved(const NmId)),
       
   155             this, SLOT(removeAttachment(const NmId)));
       
   156 }
       
   157 
       
   158 /*!
       
   159     Reload view contents with new start parameters
       
   160     Typically when view is already open and external view activation occurs
       
   161     for this same view
       
   162 */
       
   163 void NmEditorView::reloadViewContents(NmUiStartParam* startParam)
       
   164 {
       
   165     // Check start parameter validity.
       
   166     if (startParam&&startParam->viewId()==NmUiViewMessageEditor) {
       
   167         // Delete existing start parameter data
       
   168         delete mStartParam;
       
   169         mStartParam=NULL;
       
   170         // Store new start parameter data
       
   171         mStartParam=startParam;
       
   172         // Store existing edited message to drafts and reload
       
   173         // editor with new start parameters.
       
   174         // ..
       
   175         // Reload editor with new message data
       
   176         setMessageData();
       
   177     }
       
   178     else {
       
   179         NMLOG("nmailui: Invalid editor start parameter");
       
   180         // Unused start parameter needs to be deleted
       
   181         delete startParam;
       
   182         startParam = NULL;
       
   183     }
       
   184 }
       
   185 
       
   186 /*!
       
   187    Screen orientation changed. Editor view needs to be scaled when
       
   188    landscape <-> portrait switch occurs because text needs to
       
   189    be wrapped again.
       
   190 */
       
   191 void NmEditorView::orientationChanged(Qt::Orientation orientation)
       
   192 {
       
   193     Q_UNUSED(orientation);
       
   194     // Adjust content height
       
   195     QTimer::singleShot(nmOrientationTimer, this, SLOT(adjustViewDimensions()));
       
   196 }
       
   197 
       
   198 /*!
       
   199     Set new dimensions after orientation change.
       
   200 */
       
   201 void NmEditorView::adjustViewDimensions()
       
   202 {
       
   203     if (mScrollAreaContents) {
       
   204         const QSize reso = mApplication.screenSize();
       
   205         mScrollAreaContents->setMinimumWidth(reso.width());
       
   206         mScrollAreaContents->setMaximumWidth(reso.width());
       
   207     }
       
   208 }
       
   209 
       
   210 /*!
       
   211     View id
       
   212 */
       
   213 NmUiViewId NmEditorView::nmailViewId() const
       
   214 {
       
   215     return NmUiViewMessageEditor;
       
   216 }
       
   217 
       
   218 /*!
       
   219     ScrollArea contents
       
   220 */
       
   221 HbWidget* NmEditorView::scrollAreaContents()
       
   222 {
       
   223     return mScrollAreaContents;
       
   224 }
       
   225 
       
   226 /*
       
   227    Query user if we want to exit the editor
       
   228  */
       
   229 bool NmEditorView::okToExitView()
       
   230 {
       
   231     bool okToExit = true;
       
   232 
       
   233     // show the query if the message has not been sent
       
   234     if (mMessage && mContentWidget->header()) {
       
   235         // see if editor has any content
       
   236         NmEditorHeader *header = mContentWidget->header();
       
   237 
       
   238         int toTextLength = 0;
       
   239         if (header->toField()) {
       
   240             toTextLength = header->toField()->text().length();
       
   241         }
       
   242         
       
   243         int ccTextLength = 0;
       
   244         if (header->ccField()) {
       
   245             ccTextLength = header->ccField()->text().length();
       
   246         }
       
   247 
       
   248         int bccTextLength = 0;
       
   249         if (header->bccField()) {
       
   250             bccTextLength = header->bccField()->text().length();
       
   251         }
       
   252         
       
   253         int subjectLength = 0;
       
   254         if (header->subjectField()) {
       
   255             subjectLength = header->subjectField()->text().length();
       
   256         }
       
   257         
       
   258         okToExit = (toTextLength == 0 && ccTextLength == 0 && bccTextLength == 0 && 
       
   259             subjectLength == 0 && mContentWidget->editor()->document()->isEmpty());
       
   260 
       
   261         // content exists, verify exit from user
       
   262         if (!okToExit) {
       
   263             HbMessageBox *messageBox = new HbMessageBox(HbMessageBox::MessageTypeQuestion);
       
   264             messageBox->setText(hbTrId("txt_mail_dialog_delete_message"));
       
   265             messageBox->setTimeout(HbMessageBox::NoTimeout);
       
   266         
       
   267             // Read user selection
       
   268             HbAction *action = messageBox->exec(); 
       
   269             okToExit = (action == messageBox->primaryAction());
       
   270         }
       
   271     }
       
   272 
       
   273     return okToExit;
       
   274 }
       
   275 
       
   276 /*!
       
   277     About to exit view. Application calls this function when user has
       
   278     pressed back key and editor needs to delete the draft message. This is
       
   279     called when "auto-exiting" after a successful mail sending.
       
   280 */
       
   281 void NmEditorView::aboutToExitView()
       
   282 {
       
   283     // These operations need to be stopped before message can be deleted
       
   284     delete mAddAttachmentOperation;
       
   285     delete mRemoveAttachmentOperation;
       
   286 
       
   287     if (mMessage) { // this is NULL if sending is started
       
   288         // Delete message from drafts
       
   289         NmId mailboxId = mMessage->mailboxId();
       
   290         NmId folderId = mMessage->parentId();
       
   291         NmId msgId = mMessage->envelope().id();
       
   292         mUiEngine.removeMessage(mailboxId, folderId, msgId);
       
   293     }
       
   294 }
       
   295 
       
   296 /*!
       
   297     Find message data based on start parameters.  Method is called
       
   298     when editor is started. If message data is found it means that
       
   299     operation is forward or reply message.
       
   300  */
       
   301 void NmEditorView::setMessageData()
       
   302 {
       
   303     // Check the outbox.
       
   304     delete mCheckOutboxOperation;
       
   305 	mCheckOutboxOperation = NULL;
       
   306 	
       
   307 	mCheckOutboxOperation = mUiEngine.checkOutbox(mStartParam->mailboxId());
       
   308     
       
   309     if (mCheckOutboxOperation) {
       
   310         connect(mCheckOutboxOperation, SIGNAL(operationCompleted(int)),
       
   311                 this, SLOT(outboxChecked(int)));
       
   312     }
       
   313     else {
       
   314         startMessageCreation( mStartParam->editorStartMode() );
       
   315     }
       
   316 }
       
   317 
       
   318 /*!
       
   319  */
       
   320 void NmEditorView::startMessageCreation(NmUiEditorStartMode startMode)
       
   321 {
       
   322     NmId mailboxId = mStartParam->mailboxId();
       
   323     NmId folderId = mStartParam->folderId();
       
   324     NmId msgId = mStartParam->messageId();
       
   325     
       
   326     delete mMessageCreationOperation;
       
   327 	mMessageCreationOperation = NULL;
       
   328 	
       
   329 	// original message is now fetched so start message creation
       
   330     if (startMode == NmUiEditorForward) {
       
   331         mMessageCreationOperation = mUiEngine.createForwardMessage(mailboxId, msgId);
       
   332     }
       
   333     else if (startMode == NmUiEditorReply || startMode == NmUiEditorReplyAll) {
       
   334         mMessageCreationOperation = mUiEngine.createReplyMessage(mailboxId, 
       
   335             msgId, 
       
   336             startMode == NmUiEditorReplyAll);
       
   337     }
       
   338     else {
       
   339         mMessageCreationOperation = mUiEngine.createNewMessage(mailboxId);
       
   340     }
       
   341     
       
   342     // operation continues in messageCreated() once it finishes ok
       
   343     if (mMessageCreationOperation) {
       
   344         connect(mMessageCreationOperation,
       
   345                 SIGNAL(operationCompleted(int)),
       
   346                 this,
       
   347                 SLOT(messageCreated(int)));
       
   348     }    
       
   349 }
       
   350 
       
   351 /*!
       
   352     Starting the message sending is handled here.
       
   353  */
       
   354 void NmEditorView::startSending()
       
   355 {
       
   356     // The message contents should be verified
       
   357     updateMessageWithEditorContents();
       
   358     
       
   359     // verify addresses before sending
       
   360     QList<NmAddress> invalidAddresses;
       
   361     NmUtilities::getRecipientsFromMessage(*mMessage, invalidAddresses, NmUtilities::InvalidAddress);
       
   362     
       
   363     bool okToSend = true;
       
   364     if (invalidAddresses.count() > 0) {
       
   365         
       
   366         // invalid addresses found, verify send from user
       
   367         HbMessageBox *messageBox = new HbMessageBox(HbMessageBox::MessageTypeQuestion);
       
   368         QString noteText = hbTrId("txt_mail_dialog_invalid_mail_address_send");
       
   369         // set the first failing address to the note
       
   370         noteText = noteText.arg(invalidAddresses.at(0).address());
       
   371         messageBox->setText(noteText);
       
   372         messageBox->setTimeout(HbMessageBox::NoTimeout);
       
   373 
       
   374         // Read user selection
       
   375         HbAction *action = messageBox->exec();
       
   376         okToSend = (action == messageBox->primaryAction());
       
   377     }
       
   378     
       
   379     if (okToSend) {
       
   380         // ownership of mMessage changes
       
   381         mUiEngine.sendMessage(mMessage);
       
   382         mMessage = NULL;
       
   383         // sending animation should be shown here, then exit
       
   384         QTimer::singleShot(1000, &mApplication, SLOT(popView()));
       
   385     }
       
   386 }
       
   387 
       
   388 /*!
       
   389     This is signalled by mMessageCreationOperation when message is created.
       
   390  */
       
   391 void NmEditorView::messageCreated(int result)
       
   392 {
       
   393     delete mMessage;
       
   394     mMessage = NULL;
       
   395 
       
   396     if (result == NmNoError && mMessageCreationOperation) {
       
   397         NmUiEditorStartMode startMode = mStartParam->editorStartMode();
       
   398         
       
   399         // get message "again" from engine to update the message contents 
       
   400         mMessage = mUiEngine.message(
       
   401             mStartParam->mailboxId(), 
       
   402             mStartParam->folderId(), 
       
   403             mMessageCreationOperation->getMessageId());
       
   404         
       
   405         fillEditorWithMessageContents();       
       
   406     }
       
   407 }
       
   408 
       
   409 /*!
       
   410    Updates the message with the editor contents.
       
   411  */
       
   412 void NmEditorView::updateMessageWithEditorContents()
       
   413 {
       
   414     if (mMessage) {
       
   415         if (mContentWidget && mContentWidget->editor()) {
       
   416             NmMessagePart* bodyPart = mMessage->htmlBodyPart();
       
   417             if (bodyPart) {
       
   418                 bodyPart->setTextContent(mContentWidget->editor()->toHtml(), NmContentTypeTextHtml);
       
   419             }
       
   420             bodyPart = mMessage->plainTextBodyPart();
       
   421             if (bodyPart) {
       
   422                 bodyPart->setTextContent(mContentWidget->editor()->toPlainText(), NmContentTypeTextPlain);
       
   423             }
       
   424         }
       
   425         if (mContentWidget && mContentWidget->header() ) {
       
   426             if (mContentWidget->header()->subjectField()) {
       
   427                 mMessage->envelope().setSubject(
       
   428                     mContentWidget->header()->subjectField()->text());
       
   429             }
       
   430             if (mContentWidget->header()->toField()) {
       
   431                 QString toFieldText =
       
   432                     mContentWidget->header()->toField()->text();
       
   433 
       
   434                 // This verification of zero length string isn't needed
       
   435                 // after list of addresses
       
   436                 if (toFieldText.length() > 0) {
       
   437                     mMessage->envelope().setToRecipients(mContentWidget->header()->toField()->emailAddressList());  
       
   438                 }
       
   439             }
       
   440             if (mContentWidget->header()->ccField()) {
       
   441                 QString ccFieldText =
       
   442                     mContentWidget->header()->ccField()->text();
       
   443 
       
   444                 if (ccFieldText.length() > 0) {
       
   445                     mMessage->envelope().setCcRecipients(mContentWidget->header()->ccField()->emailAddressList());      
       
   446                 }
       
   447             }
       
   448             if (mContentWidget->header()->bccField()) {
       
   449                 QString bccFieldText =
       
   450                     mContentWidget->header()->bccField()->text();
       
   451 
       
   452                 if (bccFieldText.length() > 0) {
       
   453                     mMessage->envelope().setBccRecipients(mContentWidget->header()->bccField()->emailAddressList());  
       
   454                 }
       
   455             }
       
   456         }
       
   457     }
       
   458 }
       
   459 
       
   460 
       
   461 /*!
       
   462     Updates the message with the editor contents. Called only once when the
       
   463     editor is launched.
       
   464  */
       
   465 void NmEditorView::fillEditorWithMessageContents()
       
   466 {
       
   467     if (!mMessage || !mContentWidget) {
       
   468         return;
       
   469     }
       
   470 
       
   471     NmMessageEnvelope messageEnvelope(mMessage->envelope());
       
   472     NmUiEditorStartMode editorStartMode = NmUiEditorCreateNew;
       
   473     bool useStartParam(false);
       
   474 
       
   475     if (mStartParam) {
       
   476         editorStartMode = mStartParam->editorStartMode();
       
   477 
       
   478         if (editorStartMode == NmUiEditorMailto) {
       
   479             // Retrieve the message header data e.g. recipients from mStartParam.
       
   480             useStartParam = true;        
       
   481         }
       
   482     }
       
   483     
       
   484     // Set recipients (to, cc and bcc).
       
   485     QString toAddressesString;
       
   486     QString ccAddressesString;
       
   487     QString bccAddressesString;
       
   488 
       
   489     if (useStartParam) {
       
   490         toAddressesString = addressListToString(mStartParam->mailtoAddressList());
       
   491         ccAddressesString = addressListToString(mStartParam->ccAddressList());
       
   492         bccAddressesString = addressListToString(mStartParam->bccAddressList());
       
   493     }
       
   494     else {
       
   495         toAddressesString = addressListToString(messageEnvelope.toRecipients());
       
   496         ccAddressesString = addressListToString(messageEnvelope.ccRecipients());
       
   497         bccAddressesString = addressListToString(messageEnvelope.bccRecipients());
       
   498     }
       
   499 
       
   500     mContentWidget->header()->toField()->setPlainText(toAddressesString);
       
   501     mContentWidget->header()->ccField()->setPlainText(ccAddressesString);
       
   502     mContentWidget->header()->bccField()->setPlainText(bccAddressesString);
       
   503 
       
   504     if (ccAddressesString.length() || bccAddressesString.length()) {
       
   505         // Since cc or/and bcc recipients exist, expand the group box to display
       
   506         // the addresses by expanding the group box.
       
   507         mContentWidget->header()->setGroupBoxCollapsed(false);
       
   508     }
       
   509 
       
   510     // Set subject.
       
   511     if (useStartParam) {
       
   512         QString *subject = mStartParam->subject();
       
   513 
       
   514         if (subject) {
       
   515             mContentWidget->header()->subjectField()->setPlainText(*subject);
       
   516         }
       
   517     }
       
   518     else {
       
   519         // If a message is taken from the outbox, no subject formatting is done.
       
   520         NmId notUsed(0);
       
   521 
       
   522         if (mCheckOutboxOperation &&
       
   523             mCheckOutboxOperation->getMessageId(notUsed)) {
       
   524             editorStartMode = NmUiEditorCreateNew;
       
   525         }
       
   526 
       
   527         // Construct the subject field.
       
   528         mContentWidget->header()->subjectField()->setPlainText(
       
   529             addSubjectPrefix(editorStartMode, messageEnvelope.subject()));
       
   530     }
       
   531 
       
   532     // Set priority.
       
   533     mHeaderWidget->setPriority(messageEnvelope.priority());
       
   534     
       
   535     // Set the message body.
       
   536     // Fetch plain text part form message store.
       
   537     NmMessagePart *plainPart = mMessage->plainTextBodyPart();
       
   538 
       
   539     if (plainPart) {
       
   540         mUiEngine.contentToMessagePart(mMessage->mailboxId(),
       
   541                                        mMessage->parentId(),
       
   542                                        mMessage->envelope().id(),
       
   543                                        *plainPart);
       
   544     }
       
   545 
       
   546     // Fetch html part form message store.
       
   547     NmMessagePart *htmlPart = mMessage->htmlBodyPart();
       
   548 
       
   549     if (htmlPart) {
       
   550         mUiEngine.contentToMessagePart(mMessage->mailboxId(),
       
   551                                        mMessage->parentId(),
       
   552                                        mMessage->envelope().id(),
       
   553                                        *htmlPart);
       
   554     }
       
   555 
       
   556     // Fetch attachment.html part form message store if such exists.
       
   557     QList<NmMessagePart*> parts;
       
   558     mMessage->attachmentList(parts);
       
   559     NmMessagePart *attachmentHtml = NULL;
       
   560 
       
   561     foreach(NmMessagePart *part, parts) {
       
   562         if (part->contentDescription().startsWith(NmContentDescrAttachmentHtml)) {
       
   563             attachmentHtml = part;
       
   564         }
       
   565     }
       
   566 
       
   567     if (attachmentHtml) {
       
   568         mUiEngine.contentToMessagePart(mMessage->mailboxId(),
       
   569                                        mMessage->parentId(),
       
   570                                        mMessage->envelope().id(),
       
   571                                        *attachmentHtml);
       
   572     }
       
   573 
       
   574     mContentWidget->setMessageData(mMessage);
       
   575     
       
   576     // Get list of attachments from the message and set those into UI attachment list
       
   577     QList<NmMessagePart*> attachments;
       
   578     mMessage->attachmentList(attachments);
       
   579 
       
   580     for (int i=0; i<attachments.count(); i++) {
       
   581         mHeaderWidget->addAttachment(
       
   582             attachments[i]->attachmentName(),
       
   583             QString::number(attachments[i]->size()),
       
   584             attachments[i]->id());
       
   585     }
       
   586 
       
   587     if (mStartParam) {
       
   588         // Attach passed files to the message.
       
   589         QStringList *fileList = mStartParam->attachmentList();
       
   590 
       
   591         if (fileList) {
       
   592             addAttachments(*fileList);
       
   593         }
       
   594     }
       
   595 
       
   596     // TODO Switch the following arbitrary (magic number) timeout to a
       
   597     // meaningful constant, please!
       
   598     QTimer::singleShot(200, mHeaderWidget, SLOT(sendHeaderHeightChanged()));
       
   599 }
       
   600 
       
   601 
       
   602 /*!
       
   603     createToolBar. Function asks menu commands from extension
       
   604     to be added to toolbar owned by the HbView.
       
   605 */
       
   606 void NmEditorView::createToolBar()
       
   607 {
       
   608     HbToolBar *tb = toolBar();
       
   609     NmUiExtensionManager &extMngr = mApplication.extManager();
       
   610     if (tb && &extMngr && mStartParam) {
       
   611         tb->clearActions();
       
   612         NmActionRequest request(this, NmActionToolbar, NmActionContextViewEditor,
       
   613                 NmActionContextDataNone, mStartParam->mailboxId(), mStartParam->folderId() );
       
   614         QList<NmAction *> list;
       
   615         extMngr.getActions(request, list);
       
   616         for (int i = 0; i < list.count(); i++) {
       
   617             tb->addAction(list[i]);
       
   618             // If action has NmSendable condition, it is shown only when send action
       
   619             // is available, i.e. when at least one recipient field has data.
       
   620             if( list[i]->availabilityCondition() == NmAction::NmSendable ) {
       
   621                 list[i]->setEnabled(false);
       
   622             }
       
   623         }
       
   624     }
       
   625 }
       
   626 
       
   627 /*!
       
   628     createOptionsMenu. Functions asks menu commands from extension
       
   629     to be added to options menu.
       
   630 */
       
   631 void NmEditorView::createOptionsMenu()
       
   632 {
       
   633     if (!mPrioritySubMenu) {
       
   634         mPrioritySubMenu = new HbMenu();
       
   635     }
       
   636     mPrioritySubMenu->clearActions();
       
   637     menu()->clearActions();
       
   638     NmActionRequest request(this, NmActionOptionsMenu, NmActionContextViewEditor,
       
   639             NmActionContextDataMessage, mStartParam->mailboxId(), mStartParam->folderId(),
       
   640             mStartParam->messageId());
       
   641     NmUiExtensionManager &extMngr = mApplication.extManager();
       
   642     QList<NmAction*> list;
       
   643     extMngr.getActions(request, list);
       
   644     for (int i = 0; i < list.count(); i++) {
       
   645         mPrioritySubMenu->addAction(list[i]);
       
   646     }
       
   647     mPrioritySubMenu->setObjectName("editorPrioritySubMenu");
       
   648     mPrioritySubMenu->setTitle(hbTrId("txt_mail_opt_add_priority"));
       
   649     menu()->addMenu(mPrioritySubMenu);
       
   650 }
       
   651 
       
   652 /*!
       
   653     handleActionCommand. From NmActionObserver, extension manager calls this
       
   654     call to handle menu command in the UI.
       
   655 */
       
   656 void NmEditorView::handleActionCommand(NmActionResponse &actionResponse)
       
   657 {
       
   658     NmActionResponseCommand responseCommand = actionResponse.responseCommand();
       
   659     
       
   660     // Handle options menu
       
   661     if (actionResponse.menuType() == NmActionOptionsMenu) {
       
   662         setPriority(responseCommand);
       
   663     }
       
   664     else if (actionResponse.menuType() == NmActionToolbar) {
       
   665         switch (responseCommand) {
       
   666             case NmActionResponseCommandSendMail: {
       
   667                 startSending();
       
   668                 break;
       
   669             }
       
   670             case NmActionResponseCommandAttach : {
       
   671                 // Do nothing if previous addAttachment operation is still ongoing.
       
   672                 if(!mAddAttachmentOperation || !mAddAttachmentOperation->isRunning()) {
       
   673                     //will be replaced by toolbar extension                                
       
   674                     if (!mAttachContextMenu) {
       
   675                         QList<NmAction *> actionList;
       
   676                         NmAction* actionPhoto = new NmAction(0);
       
   677                         actionPhoto->setText(QObject::tr("Photo", "txt_nmailui_photo_attach"));
       
   678                         actionList.append(actionPhoto);
       
   679                         connect(actionPhoto, SIGNAL(triggered()), this, SLOT(attachImage()));
       
   680                                 
       
   681                         mAttachContextMenu = new HbMenu();
       
   682                         mAttachContextMenu->clearActions();
       
   683 
       
   684                         for (int i=0;i<actionList.count();i++) {
       
   685                             mAttachContextMenu->addAction(actionList[i]);
       
   686                         }
       
   687                     }
       
   688                 
       
   689                     QPointF menuPos(qreal(20),qreal(520));
       
   690                     mAttachContextMenu->exec(menuPos);
       
   691                 }
       
   692                 break;
       
   693             }
       
   694             default:
       
   695                 break;
       
   696         }
       
   697     }
       
   698 }
       
   699 
       
   700 /*!
       
   701     This function converts background scroll area coordinate point into
       
   702     body text editor coordinate point.
       
   703  */
       
   704 QPointF NmEditorView::viewCoordinateToEditCoordinate(QPointF orgPoint)
       
   705 {
       
   706     QPointF contentWidgetPos = mScrollAreaContents->pos();
       
   707     qreal y = orgPoint.y() - mHeaderWidget->headerHeight();
       
   708     y -= contentWidgetPos.y();
       
   709     qreal x = orgPoint.x() - contentWidgetPos.x();
       
   710     return QPointF(x, y);
       
   711 }
       
   712 
       
   713 /*!
       
   714    Send mouse press event to body edit widget
       
   715 */
       
   716 void NmEditorView::sendMousePressEventToScroll(QGraphicsSceneMouseEvent *event)
       
   717 {
       
   718     if (event && mEditWidget && mHeaderWidget) {
       
   719         event->setPos(viewCoordinateToEditCoordinate(event->pos()));
       
   720         event->setAccepted(true);
       
   721         mEditWidget->sendMousePressEvent(event);
       
   722     }
       
   723 }
       
   724 
       
   725 /*!
       
   726    Send mouse release event to body edit widget
       
   727 */
       
   728 void NmEditorView::sendMouseReleaseEventToScroll(QGraphicsSceneMouseEvent *event)
       
   729 {
       
   730     if (event&& mEditWidget && mHeaderWidget) {
       
   731         event->setPos(viewCoordinateToEditCoordinate(event->pos()));
       
   732         event->setAccepted(true);
       
   733         mEditWidget->sendMouseReleaseEvent(event);
       
   734     }
       
   735 }
       
   736 
       
   737 /*!
       
   738    Send mouse move event to body edit widget
       
   739 */
       
   740 void NmEditorView::sendMouseMoveEventToScroll(QGraphicsSceneMouseEvent *event)
       
   741 {
       
   742     if (event&& mEditWidget && mHeaderWidget) {
       
   743         event->setPos(viewCoordinateToEditCoordinate(event->pos()));
       
   744         event->setAccepted(true);
       
   745         mEditWidget->sendMouseMoveEvent(event);
       
   746     }
       
   747 }
       
   748 
       
   749 void NmEditorView::sendLongPressGesture(const QPointF &point)
       
   750 {
       
   751     if (mEditWidget && mHeaderWidget) {
       
   752         QPointF scenePos = mEditWidget->scenePos();
       
   753         QPointF newPoint = QPointF(point.x()-scenePos.x(), point.y()-scenePos.y());
       
   754         if(mEditWidget->contains(newPoint)) {
       
   755             mEditWidget->sendLongPressEvent(point);
       
   756         }
       
   757     }
       
   758 }
       
   759 
       
   760 
       
   761 /*!
       
   762    Sets all toolbar and VKB buttons dimmed state. All actions that have the
       
   763    availability condition NmSendable set, will be enabled/disabled.
       
   764 */
       
   765 void NmEditorView::setButtonsDimming(bool enabled)
       
   766 {
       
   767     // Set the toolbar action states
       
   768     HbToolBar *tb = toolBar();
       
   769     if (tb) {
       
   770         QList<QAction *> toolbarList = tb->actions();
       
   771         int count = toolbarList.count();
       
   772         for (int i = 0; i < count; i++) {
       
   773             NmAction *action = static_cast<NmAction *>(toolbarList[i]);
       
   774             if (action->availabilityCondition() == NmAction::NmSendable) {
       
   775                 action->setEnabled(enabled);
       
   776             }
       
   777         }
       
   778 
       
   779         // Set the VKB action states
       
   780         // All editors of the view share the same action, so it is enough to set
       
   781         // this only to one of them.
       
   782         HbEditorInterface editorInterface(mContentWidget->editor());
       
   783         QList<HbAction *> vkbList = editorInterface.actions();
       
   784         count = vkbList.count();
       
   785         for (int i = 0; i < count; i++) {
       
   786             NmAction *action = static_cast<NmAction *>(vkbList[i]);
       
   787             if (action->availabilityCondition() == NmAction::NmSendable) {
       
   788                 action->setEnabled(enabled);
       
   789             }
       
   790         }
       
   791     }
       
   792 }
       
   793 
       
   794 /*!
       
   795     Initialize the Virtual Keyboard to show the "Send" button
       
   796     for all editors of the view.
       
   797 */
       
   798 void NmEditorView::initializeVKB()
       
   799 {
       
   800     NmActionRequest request(this, NmActionVKB, NmActionContextViewEditor,
       
   801          NmActionContextDataNone, mStartParam->mailboxId(), mStartParam->folderId() );
       
   802     NmUiExtensionManager &extMngr = mApplication.extManager();
       
   803     if (&extMngr) {
       
   804         QList<NmAction *> list;
       
   805         extMngr.getActions(request, list);
       
   806 
       
   807         // VKB only supports one application key, but the responsibility of giving only one
       
   808         // action is left to the extension plugin. The rest are still attached to the VKB, but
       
   809         // they are not shown (unless VKB starts supporting more than one).
       
   810         for (int i = 0; i < list.count(); i++) {
       
   811             if( list[i]->availabilityCondition() == NmAction::NmSendable ) {
       
   812                 list[i]->setEnabled(false);
       
   813             }
       
   814             list[i]->setIcon(NmIcons::getIcon(NmIcons::NmIconSend));
       
   815 
       
   816             // Link VKB to the action. This must be done to all
       
   817             // editors that show the button in VKB.
       
   818             HbEditorInterface editorInterface(mContentWidget->editor());
       
   819             editorInterface.addAction(list[i]);
       
   820             HbEditorInterface toEditorInterface(mContentWidget->header()->toField());
       
   821             toEditorInterface.addAction(list[i]);
       
   822             HbEditorInterface ccEditorInterface(mContentWidget->header()->ccField());
       
   823             ccEditorInterface.addAction(list[i]);
       
   824             HbEditorInterface bccEditorInterface(mContentWidget->header()->bccField());
       
   825             bccEditorInterface.addAction(list[i]);
       
   826             HbEditorInterface subjectEditorInterface(mContentWidget->header()->subjectField());
       
   827             subjectEditorInterface.addAction(list[i]);
       
   828         }
       
   829     }
       
   830 }
       
   831 
       
   832 /*!
       
   833     Set mailbox name to title
       
   834 */
       
   835 void NmEditorView::setMailboxName()
       
   836 {
       
   837     if (mStartParam){
       
   838         NmMailboxMetaData *meta = mUiEngine.mailboxById(mStartParam->mailboxId());
       
   839         if (meta){
       
   840             setTitle(meta->name());
       
   841         }
       
   842     }
       
   843 }
       
   844 
       
   845 /*!
       
   846    Adds a prefix to the subject for reply or forward. 
       
   847    Strips other occurrences of the prefix from the beginning.
       
   848  */
       
   849 QString NmEditorView::addSubjectPrefix( NmUiEditorStartMode startMode, const QString &subject )
       
   850 {
       
   851     QString newSubject(subject.trimmed());
       
   852     
       
   853     if (startMode == NmUiEditorReply || startMode == NmUiEditorReplyAll || 
       
   854         startMode == NmUiEditorForward) {
       
   855         QString rePrefix(QObject::tr("Re:", "txt_nmailui_reply_subject_prefix"));
       
   856         QString fwPrefix(QObject::tr("Fw:", "txt_nmailui_forward_subject_prefix"));
       
   857         
       
   858         // strip extra prefixes from beginning
       
   859         int rePrefixLength(rePrefix.length());
       
   860         int fwPrefixLength(fwPrefix.length());
       
   861         
       
   862         bool startswithRe(newSubject.startsWith(rePrefix, Qt::CaseInsensitive));
       
   863         bool startswithFw(newSubject.startsWith(fwPrefix, Qt::CaseInsensitive));
       
   864         
       
   865         while (startswithRe || startswithFw) {            
       
   866             if (startswithRe) {
       
   867                 newSubject.remove(0,rePrefixLength);
       
   868                 newSubject = newSubject.trimmed();
       
   869             }
       
   870             else if (startswithFw) {
       
   871                 newSubject.remove(0,fwPrefixLength);
       
   872                 newSubject = newSubject.trimmed();
       
   873             }
       
   874             startswithRe = newSubject.startsWith(rePrefix, Qt::CaseInsensitive);
       
   875             startswithFw = newSubject.startsWith(fwPrefix, Qt::CaseInsensitive);
       
   876         }
       
   877         
       
   878         if (startMode == NmUiEditorReply || startMode == NmUiEditorReplyAll) {
       
   879             newSubject = rePrefix + " " + newSubject;
       
   880         }
       
   881         else if (startMode == NmUiEditorForward) {
       
   882             newSubject = fwPrefix + " " + newSubject;
       
   883         }
       
   884     }
       
   885     
       
   886     return newSubject;
       
   887 }
       
   888 
       
   889 #ifdef Q_OS_SYMBIAN
       
   890 
       
   891 void NmEditorView::attachImage()
       
   892 {      
       
   893     XQAiwRequest *request;
       
   894     XQApplicationManager mAppmgr;
       
   895     request = mAppmgr.create(IMAGE_FETCHER_INTERFACE, FETCHER_OPERATION, true);
       
   896         
       
   897     if (request) {
       
   898         connect(request, SIGNAL(requestOk(const QVariant&)), this, SLOT(onAttachmentReqCompleted(const QVariant&)));
       
   899     }
       
   900     else {
       
   901         //create request failed
       
   902         NMLOG("appmgr: create request failed");
       
   903         return;
       
   904     }               
       
   905 
       
   906     if (!(request)->send()) {
       
   907         //sending request failed
       
   908         NMLOG("appmgr: send request failed");
       
   909     }
       
   910     delete request;
       
   911 }
       
   912 
       
   913 /*!
       
   914     This slot is called when 'attachment picker' request has been performed succesfully
       
   915     Parameter 'value' contains file currently one file name but later list of the files. 
       
   916 */
       
   917 void NmEditorView::onAttachmentReqCompleted(const QVariant &value)
       
   918 {
       
   919     if (!value.isNull()) {
       
   920         addAttachments(value.toStringList());
       
   921     }
       
   922 }
       
   923 
       
   924 #endif
       
   925 
       
   926 /*!
       
   927     Add list of attachments
       
   928 */
       
   929 void NmEditorView::addAttachments(const QStringList& fileNames) 
       
   930 {
       
   931     NMLOG("NmEditorView::addAttachments");
       
   932 
       
   933     // Add attachment name into UI
       
   934     foreach (QString fileName, fileNames)  {
       
   935         // At this phase attachment size and nmid are not known
       
   936         mHeaderWidget->addAttachment(fileName, QString("0"), NmId(0));
       
   937         NMLOG(fileName);
       
   938     }
       
   939 
       
   940     // Start operation to attach file or list of files into mail message
       
   941     // This will also copy files into message store
       
   942     // Delete previous operation
       
   943     if (mAddAttachmentOperation) {
       
   944         if (!mAddAttachmentOperation->isRunning()) {
       
   945             delete mAddAttachmentOperation;
       
   946             mAddAttachmentOperation = NULL;
       
   947         }
       
   948     }
       
   949     if (!mAddAttachmentOperation) {
       
   950         mAddAttachmentOperation = mUiEngine.addAttachments(*mMessage, fileNames);
       
   951 
       
   952         if (mAddAttachmentOperation) {
       
   953             // Signal to inform completion of one attachment
       
   954             connect(mAddAttachmentOperation,
       
   955                     SIGNAL(operationPartCompleted(const QString &, const NmId &, int)),
       
   956                     this,
       
   957                     SLOT(oneAttachmentAdded(const QString &, const NmId &, int)));
       
   958         
       
   959             // Signal to inform the completion of the whole operation
       
   960             connect(mAddAttachmentOperation,
       
   961                     SIGNAL(operationCompleted(int)),
       
   962                     this,
       
   963                     SLOT(allAttachmentsAdded(int)));
       
   964         }
       
   965     }
       
   966 }
       
   967 
       
   968 /*!
       
   969     This slot is called when attachment has been deleted from UI
       
   970 */
       
   971 void NmEditorView::removeAttachment(const NmId attachmentPartId)
       
   972 {
       
   973     // Delete previous operation
       
   974     if (mRemoveAttachmentOperation) {
       
   975         if (!mRemoveAttachmentOperation->isRunning()) {
       
   976             delete mRemoveAttachmentOperation;
       
   977             mRemoveAttachmentOperation = NULL;
       
   978         }
       
   979     }
       
   980     if (!mRemoveAttachmentOperation) {
       
   981         mRemoveAttachmentOperation = mUiEngine.removeAttachment(*mMessage, attachmentPartId);
       
   982     }
       
   983 }
       
   984 
       
   985 /*!
       
   986     This is signalled by mAddAttachmentOperation when the operation is
       
   987     completed for one attachment.
       
   988  */
       
   989 void NmEditorView::oneAttachmentAdded(const QString &fileName, const NmId &msgPartId, int result)
       
   990 {
       
   991     if (result == NmNoError) {
       
   992         // Get file size from the message when it works
       
   993         mHeaderWidget->setAttachmentParameters(fileName, msgPartId, QString("0"), result);
       
   994     }
       
   995     else {
       
   996         // Attachment adding failed. Show an error note and remove from UI attachment list.
       
   997         NMLOG(QString("nmailui: attachment adding into message failed: %1").arg(fileName));
       
   998         mHeaderWidget->removeAttachment(fileName);
       
   999     }
       
  1000 }
       
  1001 
       
  1002 /*!
       
  1003     This is signalled by mAddAttachmentOperation when the operation is
       
  1004     completed totally.
       
  1005  */
       
  1006 void NmEditorView::allAttachmentsAdded(int result)
       
  1007 {
       
  1008     if (result != NmNoError) {
       
  1009         HbMessageBox::warning(hbTrId("txt_mail_dialog_unable_to_add_attachment"));
       
  1010     }
       
  1011 }
       
  1012 
       
  1013 /*!
       
  1014     This is signalled by mCheckOutboxOperation when the operation is complete.
       
  1015  */
       
  1016 void NmEditorView::outboxChecked(int result)
       
  1017 {
       
  1018     bool messageInOutbox = false;
       
  1019     
       
  1020     if (result == NmNoError && mCheckOutboxOperation) {
       
  1021 
       
  1022         NmId messageId;
       
  1023         messageInOutbox = mCheckOutboxOperation->getMessageId(messageId);
       
  1024         
       
  1025         if (messageInOutbox) {
       
  1026             delete mMessage;
       
  1027             mMessage = NULL;
       
  1028 
       
  1029             mMessage = mUiEngine.message(
       
  1030                 mStartParam->mailboxId(), 
       
  1031                 mUiEngine.standardFolderId(
       
  1032                     mStartParam->mailboxId(), NmFolderOutbox), 
       
  1033                 messageId);
       
  1034             
       
  1035             fillEditorWithMessageContents();
       
  1036             
       
  1037             if (mMessage) {
       
  1038                 HbMessageBox::warning(
       
  1039                     hbTrId("txt_mail_dialog_sending failed").arg(
       
  1040                         NmUtilities::truncate(
       
  1041                             mMessage->envelope().subject(), 20)));
       
  1042             }
       
  1043         }
       
  1044     }
       
  1045 
       
  1046     if (!messageInOutbox) {
       
  1047         startMessageCreation(mStartParam->editorStartMode());
       
  1048     }
       
  1049 }
       
  1050 
       
  1051 /*!
       
  1052    Sets priority for the message object that is being edited 
       
  1053 */
       
  1054 void NmEditorView::setPriority(NmActionResponseCommand priority)
       
  1055 {
       
  1056     mHeaderWidget->setPriority(priority);
       
  1057 
       
  1058     if (mMessage) {
       
  1059         NmMessagePriority messagePriority = NmMessagePriorityNormal;
       
  1060         
       
  1061         if (priority == NmActionResponseCommandPriorityHigh) {
       
  1062             messagePriority = NmMessagePriorityHigh;
       
  1063         }
       
  1064         else if (priority == NmActionResponseCommandPriorityLow) {
       
  1065             messagePriority = NmMessagePriorityLow;
       
  1066         }
       
  1067         mMessage->envelope().setPriority(messagePriority);
       
  1068     }
       
  1069 }
       
  1070 
       
  1071 
       
  1072 /*!
       
  1073     Extracts the addresses from the given list into a string separated with a
       
  1074     delimiter.
       
  1075 
       
  1076     \param list The list containing the addresses.
       
  1077     \return String containing the addresses.
       
  1078 */
       
  1079 QString NmEditorView::addressListToString(const QList<NmAddress*> &list) const
       
  1080 {
       
  1081     QString addressesString;
       
  1082     QList<NmAddress*>::const_iterator i = list.constBegin();
       
  1083     
       
  1084     while (i != list.constEnd() && *i) {
       
  1085         if (i > list.constBegin()) {
       
  1086             // Add the delimiter.
       
  1087             addressesString += Delimiter;
       
  1088         }
       
  1089 
       
  1090         addressesString += (*i)->address();
       
  1091         ++i;
       
  1092     }
       
  1093 
       
  1094     return addressesString;
       
  1095 }
       
  1096 
       
  1097 
       
  1098 /*!
       
  1099     Extracts the addresses from the given list into a string separated with a
       
  1100     delimiter.
       
  1101 
       
  1102     \param list The list containing the addresses.
       
  1103     \return String containing the addresses.
       
  1104 */
       
  1105 QString NmEditorView::addressListToString(const QList<NmAddress> &list) const
       
  1106 {
       
  1107     QString addressesString;
       
  1108     QList<NmAddress>::const_iterator i = list.constBegin();
       
  1109     
       
  1110     while (i != list.constEnd()) {
       
  1111         if (i > list.constBegin()) {
       
  1112             // Add the delimiter.
       
  1113             addressesString += Delimiter;
       
  1114         }
       
  1115 
       
  1116         addressesString += (*i).address();
       
  1117         ++i;
       
  1118     }
       
  1119 
       
  1120     return addressesString;
       
  1121 }
       
  1122 
       
  1123 
       
  1124 // End of file.