diff -r e7aa27f58ae1 -r 578830873419 emailuis/nmailui/src/nmeditorview.cpp --- /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 + (mDocumentLoader->findObject(NMUI_EDITOR_SCROLL_AREA)); + mScrollAreaContents = qobject_cast + (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 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 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 attachments; + mMessage->attachmentList(attachments); + + for (int i=0; iaddAttachment( + 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 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 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 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;iaddAction(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 toolbarList = tb->actions(); + int count = toolbarList.count(); + for (int i = 0; i < count; i++) { + NmAction *action = static_cast(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 vkbList = editorInterface.actions(); + count = vkbList.count(); + for (int i = 0; i < count; i++) { + NmAction *action = static_cast(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 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 &list) const +{ + QString addressesString; + QList::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 &list) const +{ + QString addressesString; + QList::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.