diff -r dcf0eedfc1a3 -r d189ee25cf9d emailuis/nmailui/src/nmviewerview.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emailuis/nmailui/src/nmviewerview.cpp Tue Aug 31 15:04:17 2010 +0300 @@ -0,0 +1,1054 @@ +/* + * 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: Mail viewer implementation. + * + */ + +#include "nmuiheaders.h" + +static const char *NMUI_MESSAGE_VIEWER_XML = ":/docml/nmmailviewer.docml"; +static const char *NMUI_MESSAGE_VIEWER_VIEW = "nmailViewerView"; +static const char *NMUI_MESSAGE_VIEWER_CONTENT = "content"; +static const char *NMUI_MESSAGE_VIEWER_SCROLL_AREA = "viewerScrollArea"; +static const char *NMUI_MESSAGE_VIEWER_SCROLL_AREA_CONTENTS = "viewerScrollAreaContents"; +static const char *NMUI_MESSAGE_VIEWER_HEADER = "viewerHeader"; +static const char *NMUI_MESSAGE_VIEWER_ATTALIST = "viewerAttaList"; +static const char *NMUI_MESSAGE_VIEWER_SCROLL_WEB_VIEW = "viewerWebView"; +static const int NmOrientationTimer = 100; +static const int NmHeaderMargin = 3; +static const int NmWhitePixmapSize = 10; +static const int NmProgressValueComplete = 100; +static const QString NmParamTextHeightSecondary = "hb-param-text-height-secondary"; +static const QString NmHttpLinkScheme = "http"; +static const QString NmHttpsLinkScheme = "https"; +static const QString NmMailtoLinkScheme = "mailto"; + +// Local constants +const qreal NmZoomFactor = 1.5; + +/*! + \class NmViewerView + \brief Mail viewer class +*/ + +/*! + Constructor +*/ +NmViewerView::NmViewerView( + NmApplication &application, + NmUiStartParam* startParam, + NmUiEngine &uiEngine, + HbMainWindow *mainWindow, + NmAttachmentManager &attaManager, + bool toolbarEnabled, + QGraphicsItem *parent) +:NmBaseView(startParam, application, parent), +mApplication(application), +mUiEngine(uiEngine), +mMainWindow(mainWindow), +mAttaManager(attaManager), +mToolbarEnabled(toolbarEnabled), +mMessage(NULL), +mScrollArea(NULL), +mViewerContent(NULL), +mWebView(NULL), +mHeaderWidget(NULL), +mMessageFetchingOperation(NULL), +mDisplayingPlainText(false), +mDocumentLoader(NULL), +mScrollAreaContents(NULL), +mScreenSize(QSize(0,0)), +mWaitDialog(NULL), +webFrameloadingCompleted(false), +mLatestLoadingSize(QSize(0,0)), +mAttaIndexUnderFetch(NmNotFoundError), +mAttaWidget(NULL), +mViewReady(false), +mWaitNoteCancelled(false), +mErrorNote(NULL) +{ + // Create documentloader + mDocumentLoader = new NmUiDocumentLoader(mMainWindow); + // Get screensize + mScreenSize = mApplication.screenSize(); + // Connect external delete handling to uiengine signal + connect(&mUiEngine, + SIGNAL(messageDeleted(const NmId &, const NmId &, const NmId &)), + this, SLOT(messageDeleted(const NmId &, const NmId &, const NmId &)), + Qt::UniqueConnection); + // Fetch message + loadMessage(); + // Load view layout + loadViewLayout(); +} + +/*! + Destructor +*/ +NmViewerView::~NmViewerView() +{ + delete mErrorNote; + mErrorNote=NULL; + delete mWebView; + mWebView = NULL; + delete mMessage; + mMessage = NULL; + delete mDocumentLoader; + mDocumentLoader = NULL; + mWidgetList.clear(); + delete mWaitDialog; + mWaitDialog = NULL; + // remove view from osbserving atta manager events + mAttaManager.clearObserver(); + mAttaManager.cancelFetch(); +} + +/*! + View is about to exit +*/ +void NmViewerView::aboutToExitView() +{ + // View is about to exit, for safety, stop + // loading of content before closing the view + if (mWebView){ + mAttaManager.cancelFetch(); + mWebView->stop(); + if (mWebView->page()){ + mWebView->page()->deleteLater(); + } + } +} + +/*! + View layout loading from XML +*/ +void NmViewerView::loadViewLayout() +{ + NM_FUNCTION; + + // Use document loader to load the view + bool ok(false); + setObjectName(QString(NMUI_MESSAGE_VIEWER_VIEW)); + QObjectList objectList; + objectList.append(this); + // Pass the view to documentloader. Document loader uses this view + // when docml is parsed, instead of creating new view. + // documentloader is created in constructor + mDocumentLoader->setObjectTree(objectList); + mWidgetList = mDocumentLoader->load(NMUI_MESSAGE_VIEWER_XML, &ok); + + if (ok) + { + // Create content and content layout + // qobject_cast not work in this case, using reinterpret_cast + mViewerContent = reinterpret_cast( + mDocumentLoader->findObject(NMUI_MESSAGE_VIEWER_CONTENT)); + // Find scroll area + mScrollArea = reinterpret_cast( + mDocumentLoader->findObject(NMUI_MESSAGE_VIEWER_SCROLL_AREA)); + if (mScrollArea) { + mScrollArea->setParentItem(this); + mScrollArea->setScrollDirections(Qt::Vertical | Qt::Horizontal); + connect(mScrollArea, SIGNAL(scrollPositionChanged(QPointF)), + this, SLOT(contentScrollPositionChanged(QPointF))); + + // Get scroll area contents and set layout margins + mScrollAreaContents = qobject_cast( + mDocumentLoader->findObject(NMUI_MESSAGE_VIEWER_SCROLL_AREA_CONTENTS)); + if (mScrollAreaContents) { + QGraphicsLayout *layout = mScrollAreaContents->layout(); + if (layout){ + layout->setContentsMargins(0,0,0,0); + } + // Set white pixmap to backgrounditem + QPixmap whitePixmap(NmWhitePixmapSize,NmWhitePixmapSize); + whitePixmap.fill(Qt::white); + QGraphicsPixmapItem *pixmapItem = new QGraphicsPixmapItem(whitePixmap); + mScrollAreaContents->setBackgroundItem(pixmapItem); + } + + // Load headerwidget + mHeaderWidget = qobject_cast( + mDocumentLoader->findObject(NMUI_MESSAGE_VIEWER_HEADER)); + if (mHeaderWidget) { + mHeaderWidget->setView(this); + mHeaderWidget->rescaleHeader(mScreenSize); + mHeaderWidget->setMessage(mMessage); + QPointF headerStartPos = mHeaderWidget->scenePos(); + mHeaderStartScenePos = QPointF(0,headerStartPos.y()); + } + + // Load webview + mWebView = reinterpret_cast( + mDocumentLoader->findObject(QString(NMUI_MESSAGE_VIEWER_SCROLL_WEB_VIEW))); + if (mWebView) { + // Set auto load images and private browsing(no history) attributes + QWebSettings *settings = mWebView->settings(); + if (settings) { + settings->setAttribute(QWebSettings::AutoLoadImages, true); + settings->setAttribute(QWebSettings::PrivateBrowsingEnabled, true); + } + QWebPage *page = mWebView->page(); + if (page) { + QWebFrame *frame = page->mainFrame(); + if (frame) { + frame->setScrollBarPolicy(Qt::Vertical,Qt::ScrollBarAlwaysOff); + frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff); + frame->setTextSizeMultiplier(NmZoomFactor); + connect(mWebView->page()->mainFrame(), + SIGNAL(contentsSizeChanged(const QSize&)), + this, SLOT(scaleWebViewWhenLoading(const QSize&))); + } + } + } + } + } +} + +/*! + Lazy loading when view layout has been loaded +*/ +void NmViewerView::viewReady() +{ + if (!mViewReady){ + // Set mailbox name to title + setMailboxName(); + // Create toolbar if needed + if (mToolbarEnabled) { + createToolBar(); + } else { + // Connect options menu about to show to create options menu function + QObject::connect(menu(), SIGNAL(aboutToShow()), + this, SLOT(createOptionsMenu())); + // Menu needs one dummy item so that aboutToShow signal is emitted. + NmAction *dummy = new NmAction(0); + menu()->addAction(dummy); + } + + if (mHeaderWidget) { + QPointF contentWidgetPos = mScrollArea->pos(); + qreal headerHeight = mHeaderWidget->geometry().height(); + if (mMainWindow->orientation() == Qt::Horizontal) { + const QPointF pointToWebView(contentWidgetPos.x(), headerHeight+NmHeaderMargin); + mScrollArea->scrollContentsTo(pointToWebView,0); + } + } + + // Run fetchmessage in queue + QMetaObject::invokeMethod(this, "fetchMessage", Qt::QueuedConnection); + // Set view ready + mViewReady = true; + } +} + +/*! + Function fecthes message data based on parameters +*/ +void NmViewerView::loadMessage() +{ + NM_FUNCTION; + + if (mMessage) { + delete mMessage; + mMessage = NULL; + } + // Read start params and message object + if (mStartParam){ + NmId mailboxId = mStartParam->mailboxId(); + NmId folderId = mStartParam->folderId(); + NmId msgId = mStartParam->messageId(); + mMessage = mUiEngine.message(mailboxId, folderId, msgId); + } +} + +/*! + Function fecthes message data based on parameters. Returns false if message is available, + true if message have to be fetched +*/ +void NmViewerView::fetchMessage() +{ + NM_FUNCTION; + + if (mMessage) { + NmId mailboxId = mStartParam->mailboxId(); + NmId folderId = mStartParam->folderId(); + NmId msgId = mStartParam->messageId(); + const NmMessagePart *body = mMessage->htmlBodyPart(); + if (!body) { + // try plain to plain text part + body = mMessage->plainTextBodyPart(); + } + // try to fetch if body missing or fetched size is smaller than content size + // if body missing it might mean that only header is fetched or message has no body + if (!body || (body && (body->fetchedSize() < body->size()))) { + // start fetching operation + if (mMessageFetchingOperation && mMessageFetchingOperation->isRunning()) { + mMessageFetchingOperation->cancelOperation(); + } + mMessageFetchingOperation = mUiEngine.fetchMessage(mailboxId, folderId, msgId); + + if (mMessageFetchingOperation) { + connect(mMessageFetchingOperation, + SIGNAL(operationCompleted(int)), + this, + SLOT(messageFetched(int))); + createAndShowWaitDialog(); + } + } else { + // message is fetched + setMessageData(); + } + } +} + +/*! + This is signalled by mMessageFetchingOperation when the original message is fetched. + */ +void NmViewerView::messageFetched(int result) +{ + mWaitDialog->close(); + disconnect(mWaitDialog->mainWindow(), SIGNAL(orientationChanged(Qt::Orientation)), + this, SLOT(orientationChanged(Qt::Orientation))); + + if (result == NmNoError && mMessageFetchingOperation) { + if (mMessage) { + delete mMessage; + mMessage = NULL; + } + // Read start params and message object + if (mStartParam) { + NmId mailboxId = mStartParam->mailboxId(); + NmId folderId = mStartParam->folderId(); + NmId msgId = mStartParam->messageId(); + mMessage = mUiEngine.message(mailboxId, folderId, msgId); + } + setMessageData(); + // Update header message data + if (mHeaderWidget){ + mHeaderWidget->updateMessageData(mMessage); + } + } +} + + +/*! + This is signalled by mWaitDialog when the note is cancelled + */ +void NmViewerView::waitNoteCancelled() +{ + if (!mWaitNoteCancelled) { + if (mMessageFetchingOperation && mMessageFetchingOperation->isRunning()) { + mMessageFetchingOperation->cancelOperation(); + } + mWaitNoteCancelled = true; + QMetaObject::invokeMethod(&mApplication, "prepareForPopView", Qt::QueuedConnection); + } +} + + +/*! + Function sets message data to web view and header +*/ +void NmViewerView::setMessageData() +{ + NM_FUNCTION; + + // Connect to observe orientation change events + connect(mApplication.mainWindow(), SIGNAL(orientationChanged(Qt::Orientation)), + this, SLOT(orientationChanged(Qt::Orientation))); + + // Set page parameters + QWebPage *page(NULL); + if (mWebView){ + page = mWebView->page(); + } + if (page){ + // Set custom network access manager for embedded image handling + NmViewerViewNetManager &netMngr = mApplication.networkAccessManager(); + netMngr.setView(this); + page->setNetworkAccessManager(&netMngr); + QWebSettings *webSettings = page->settings(); + if (webSettings) { + webSettings->setObjectCacheCapacities(0,0,0); + } + + connect(page, SIGNAL(loadFinished(bool)), + this, SLOT(webFrameLoaded(bool))); + page->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); + page->setContentEditable(false); + } + + // if everything is ok, set message to html viewer + if (mMessage && mWebView && page) { + // Set initial size of component and content before loading data + mWebView->setPreferredWidth(mScreenSize.width()); + QRectF myGeometry = geometry(); + page->setViewportSize(myGeometry.size().toSize()); + //Set message data to html viewer. + mWebView->setHtml(formatMessage()); + // Connect to link clicked + QObject::connect(page, SIGNAL(linkClicked(const QUrl&)), + this, SLOT(linkClicked(const QUrl&))); + changeMessageReadStatus(true); + setAttachmentList(); + } +} + +/*! + +*/ +void NmViewerView::setAttachmentList() +{ + NM_FUNCTION; + + // Load headerwidget + mAttaWidget = qobject_cast( + mDocumentLoader->findObject(NMUI_MESSAGE_VIEWER_ATTALIST)); + if (mMessage && mAttaWidget) { + // connect atta widget to listen progress value events + QObject::connect(this, SIGNAL(progressValueChanged(int, int)), + mAttaWidget, SLOT(setProgressBarValue(int, int))); + // Set atta widget text color black since header has static white bg. + mAttaWidget->setTextColor(Qt::black); + // Set attawidget minimum & maximum size + mAttaWidget->setMinimumWidth(mScreenSize.width()); + mAttaWidget->setMaximumWidth(mScreenSize.width()); + bool inserted(false); + QList messageParts; + mMessage->attachmentList(messageParts); + for (int i = 0; i < messageParts.count();i++) { + NmMessagePart *part = messageParts[i]; + if (part && + ((part->contentDisposition().trimmed().startsWith("inline", Qt::CaseInsensitive)==false) || + (part->contentType().trimmed().startsWith("image", Qt::CaseInsensitive)==false))) { + QString fileName = part->attachmentName(); + // index starts from zero, next index is same as count + int attaIndex = mAttaWidget->count(); + mAttaWidget->insertAttachment(attaIndex, fileName, + NmUtilities::attachmentSizeString(part->size())); + mAttaIdList.insert(attaIndex, part->partId()); + // check is part under fetch, add progress value to attachment widget + if (mAttaManager.isFetching() && + mAttaManager.partIdUnderFetch() == part->partId()) { + mAttaIndexUnderFetch = attaIndex; + } + inserted = true; + } + } + if (inserted) { + QObject::connect(mAttaWidget, SIGNAL(itemActivated(int)), + this, SLOT(openAttachment(int))); + } + else { + // No attachments, set height to 0 + mAttaWidget->setMinimumHeight(0); + mAttaWidget->setMaximumHeight(0); + } + // set this as a observer for attachment manager + mAttaManager.setObserver(this); + } +} + +/*! + +*/ +void NmViewerView::openAttachment(int index) +{ + NM_FUNCTION; + if (index >= 0) { + NmId attaId = mAttaIdList.at(index); + // reload message to get updates part sizes + loadMessage(); + QList messageParts; + if (mMessage) { + mMessage->attachmentList(messageParts); + NmId mailboxId = mMessage->envelope().mailboxId(); + NmId folderId = mMessage->envelope().folderId(); + NmId messageId = mMessage->envelope().messageId(); + for (int i = 0; i < messageParts.count(); i++) { + // message part found have to found + // and its fetched size is smaller than size, then start part fetch + if (messageParts[i]->partId() == attaId && + messageParts[i]->size() > messageParts[i]->fetchedSize()) { + // do not start if there's already ongoing fetch + if (mAttaIndexUnderFetch == NmNotFoundError) { + mAttaIndexUnderFetch = index; + mAttaManager.fetchAttachment(mailboxId, folderId, + messageId, attaId); + } + } + // attachment is fetched, open file + else if (messageParts[i]->partId() == attaId) { + mAttaManager.cancelFetch(); + XQSharableFile file = mUiEngine.messagePartFile(mailboxId, folderId, + messageId, attaId); + int error = NmUtilities::openFile(file); + file.close(); + if (error==NmNotFoundError){ + delete mErrorNote; + mErrorNote=NULL; + mErrorNote = NmUtilities::displayWarningNote( + hbTrId("txt_mail_dialog_unable_to_open_attachment_file_ty")); + } + } + } + } + } +} + +/*! + Function formats message based on actual data +*/ +QString NmViewerView::formatMessage() +{ + NM_FUNCTION; + + QString msg = ""; + if (mMessage) { + NmMessagePart *html = mMessage->htmlBodyPart(); + if (html) { + msg += formatHtmlMessage(html); + } + else { + NmMessagePart *plain = mMessage->plainTextBodyPart(); + if (plain) { + msg += formatPlainTextMessage(plain); + } + } + } + return msg; +} + +/*! + Function formats html message +*/ +QString NmViewerView::formatHtmlMessage(NmMessagePart *html) +{ + NM_FUNCTION; + + QString msg = ""; + if (html && mMessage) { + NmId mailboxId = mMessage->envelope().mailboxId(); + NmId folderId = mMessage->envelope().folderId(); + NmId messageId = mMessage->envelope().messageId(); + QList parts; + mMessage->attachmentList(parts); + for (int i=0; i < parts.count(); i++) { + NmMessagePart *child = parts[i]; + // Browse through embedded image parts and add those + // the web view. + bool isFetched = child->fetchedSize() >= child->size(); + if (child->contentType().startsWith("image", Qt::CaseInsensitive)) { + QString contentId = child->contentId(); + if (isFetched) { + int ret = mUiEngine.contentToMessagePart( + mailboxId, folderId, messageId, *child); + if (ret == NmNoError) { + mWebView->addContent(contentId, QVariant::fromValue(child->binaryContent()), + child->partId(), isFetched); + } + } + else { + mWebView->addContent(contentId, QVariant::fromValue(QByteArray()), + child->partId(), isFetched); + } + } + } + int ret = mUiEngine.contentToMessagePart(mailboxId, folderId, messageId, *html); + if (ret == NmNoError) { + msg = html->textContent(); + } + } + return msg; +} + +/*! + Function formats plain text message message +*/ +QString NmViewerView::formatPlainTextMessage(NmMessagePart *plain) +{ + NM_FUNCTION; + + QString msg = ""; + if (plain && mMessage) { + NmId mailboxId = mMessage->envelope().mailboxId(); + NmId folderId = mMessage->envelope().folderId(); + NmId messageId = mMessage->envelope().messageId(); + int ret = mUiEngine.contentToMessagePart(mailboxId, folderId, + messageId, *plain); + if (ret == NmNoError) { + QTextDocument document; + // set font + QFont currentFont = document.defaultFont(); + currentFont.setWeight(QFont::Normal); + qreal secondarySize; + HbStyle myStyle; + bool found = myStyle.parameter(NmParamTextHeightSecondary, secondarySize); + if (found) { + HbFontSpec fontSpec(HbFontSpec::Secondary); + fontSpec.setTextHeight(secondarySize); + currentFont.setPixelSize(fontSpec.font().pixelSize()); + } + document.setDefaultFont(currentFont); + // convert to html + document.setPlainText(plain->textContent()); + msg = document.toHtml(); + + if (qApp->layoutDirection()==Qt::RightToLeft){ + // add right alignment to document css section + QRegExp rx("()", Qt::CaseInsensitive); + rx.setMinimal(true); + int pos = rx.indexIn(msg); + if (pos > -1) { + QString newStr = rx.cap(1); + newStr.append(rx.cap(2)); + newStr.append("p { text-align: right } "); + newStr.append(rx.cap(3)); + msg.replace(rx, newStr); + } + } + } + } + mDisplayingPlainText=true; + return msg; +} + +/*! + Reload view contents with new start parameters + Typically when view is already open and external view activation occurs + for this same view +*/ +void NmViewerView::reloadViewContents(NmUiStartParam* startParam) +{ + // Check start parameter validity, message view cannot + // be updated if given parameter is zero. + if (startParam && startParam->viewId() == NmUiViewMessageViewer && + startParam->messageId()!= 0) { + // Delete existing start parameter data + delete mStartParam; + mStartParam = NULL; + // Store new start parameter data + mStartParam = startParam; + // Reload viewer with new message information + setMessageData(); + } + else { + NMLOG("nmailui: Invalid viewer start parameter"); + // Unused start parameter needs to be deleted + delete startParam; + } +} + +/*! + nmailViewId +*/ +NmUiViewId NmViewerView::nmailViewId() const +{ + return NmUiViewMessageViewer; +} + +/*! + Scale web view width +*/ +void NmViewerView::webFrameLoaded(bool loaded) +{ + if (loaded){ + webFrameloadingCompleted = true; + // Scale web view after loading the + // complete contents, including images + QMetaObject::invokeMethod(this, "scaleWebViewWhenLoaded", Qt::QueuedConnection); + } +} + +/*! + Scale web view width when loading is ongoing +*/ +void NmViewerView::scaleWebViewWhenLoading(const QSize &size) +{ + // Try to scale web view while mainframe is being loaded. + // So that screen is scrollable even before images are fully loaded + // First check that new size is different than previous, no need to react if + // same size value is received more than once. + if (size != mLatestLoadingSize) { + if (!webFrameloadingCompleted && mWebView && mWebView->page() && + (size.width() > mScreenSize.width() || size.height() > geometry().height())) { + int width = (int)size.width(); + int height = (int)size.height(); + // Set content (webview) width + if (mDisplayingPlainText){ + mWebView->setPreferredWidth(geometry().width()); + } + else { + mWebView->setPreferredWidth(width); + } + mWebView->setMinimumHeight(height); + } + } + mLatestLoadingSize = size; +} + +/*! + Scale web view width when loading is completed +*/ +void NmViewerView::scaleWebViewWhenLoaded() +{ + QRectF myGeometry = geometry(); + QWebPage *page = mWebView->page(); + if (mWebView && page) { + page->setPreferredContentsSize(myGeometry.size().toSize()); + QSizeF contentSize = page->mainFrame()->contentsSize(); + mWebView->setPreferredSize(contentSize); + } + // Workaround for scrolling problem + scene()->setProperty("overridingGesture",QVariant()); +} + +/*! + Set new dimensions after orientation change. +*/ +void NmViewerView::adjustViewDimensions() +{ + // Update current screensize + mScreenSize = mApplication.screenSize(); + // Scale header to screen width + if (mHeaderWidget){ + mHeaderWidget->rescaleHeader(mScreenSize); + } + if (mAttaWidget){ + // Set attawidget minimum & maximum size + mAttaWidget->setMinimumWidth(mScreenSize.width()); + mAttaWidget->setMaximumWidth(mScreenSize.width()); + } + scaleWebViewWhenLoaded(); + + if (mToolbarEnabled) { + // Re-create toolbar in orientation switch + createToolBar(); + } +} + +/*! + Screen orientation changed. Web view needs to be scaled when + landscape <-> portrait switch occurs because text needs to + be wrapped again. +*/ +void NmViewerView::orientationChanged(Qt::Orientation orientation) +{ + Q_UNUSED(orientation); + QTimer::singleShot(NmOrientationTimer, this, SLOT(adjustViewDimensions())); +} + +/*! + Link clicked callback +*/ +void NmViewerView::linkClicked(const QUrl& link) +{ + NM_FUNCTION; + + if (link.scheme() == NmHttpLinkScheme || + link.scheme() == NmHttpsLinkScheme) { + mAttaManager.cancelFetch(); + QDesktopServices::openUrl(link); + } else if (link.scheme() == NmMailtoLinkScheme){ + mAttaManager.cancelFetch(); + QList *addrList = new QList(); + NmAddress *mailtoAddr = new NmAddress(); + QString address = link.toString(QUrl::RemoveScheme); + mailtoAddr->setAddress(address); + mailtoAddr->setDisplayName(address); + addrList->append(mailtoAddr); + // Create start parameters. Address list ownership + // is transferred to startparam object + NmUiStartParam* param = new NmUiStartParam(NmUiViewMessageEditor, + mStartParam->mailboxId(), + mStartParam->folderId(), + 0, + NmUiEditorMailto, + addrList); + mApplication.enterNmUiView(param); + } +} + +/*! + Function can be used to check whether mouse event has + occured on top of header area. +*/ +bool NmViewerView::eventOnTopOfHeaderArea(QGraphicsSceneMouseEvent *event) +{ + bool ret(false); + if (event && mHeaderWidget) { + QPointF lastReleasePoint = event->lastPos(); + QPointF contentWidgetPos = mScrollAreaContents->pos(); + int headerHeight = (int)mHeaderWidget->geometry().height(); + if (lastReleasePoint.y() envelopeList; + NmMessageEnvelope *envelope = &mMessage->envelope(); + QPointer op(NULL); + if (envelope) { + if ( read != envelope->isRead() ){ + if (read){ + envelope->setRead(true); + envelopeList.append(envelope); + op = mUiEngine.setEnvelopes( + mStartParam->mailboxId(), + mStartParam->folderId(), + MarkAsRead, + envelopeList); + } + else { + envelope->setRead(false); + envelopeList.append(envelope); + op = mUiEngine.setEnvelopes( + mStartParam->mailboxId(), + mStartParam->folderId(), + MarkAsUnread, + envelopeList); + } + } + } +} + +/*! + Set mailbox name to title +*/ +void NmViewerView::setMailboxName() +{ + if (mStartParam){ + NmMailboxMetaData *meta = mUiEngine.mailboxById(mStartParam->mailboxId()); + if (meta) { + setTitle(meta->name()); + } + } +} + +/*! + contentScrollPositionChanged. + Function reacts to scroll position change events and sets + header to correct position +*/ +void NmViewerView::contentScrollPositionChanged(const QPointF &newPosition) +{ + if (mWebView&&mHeaderWidget){ + QRectF webViewRect = mWebView->geometry(); + QTransform tr; + qreal leftMovementThreshold(webViewRect.width()-mHeaderWidget->geometry().width()); + if (newPosition.x()<0) { + tr.translate(webViewRect.topLeft().x() ,0); + } + else if (newPosition.x()>=0 && newPosition.x()setTransform(tr); + if (mAttaWidget) { + mAttaWidget->setTransform(tr); + } + } + mLatestScrollPos = newPosition; +} + +/*! + createToolBar. Function asks menu commands from extension + to be added to toolbar owned by the HbView. +*/ +void NmViewerView::createToolBar() +{ + HbToolBar *tb = toolBar(); + NmUiExtensionManager &extMngr = mApplication.extManager(); + if (tb && &extMngr && mStartParam) { + tb->clearActions(); + NmActionRequest request(this, NmActionToolbar, NmActionContextViewViewer, + NmActionContextDataNone, mStartParam->mailboxId(), mStartParam->folderId() ); + QList list; + extMngr.getActions(request, list); + for (int i = 0; i < list.count(); i++) { + tb->addAction(list[i]); + } + } +} + +/*! + createOptionsMenu. Functions asks menu commands from extension + to be added to options menu. +*/ +void NmViewerView::createOptionsMenu() +{ + HbMenu *optionsMenu = menu(); + NmUiExtensionManager &extMngr = mApplication.extManager(); + if (optionsMenu && &extMngr && mStartParam) { + optionsMenu->clearActions(); + NmActionRequest request(this, NmActionOptionsMenu, NmActionContextViewViewer, + NmActionContextDataNone, mStartParam->mailboxId(), mStartParam->folderId() ); + + QList list; + extMngr.getActions(request, list); + for (int i=0;iaddAction(list[i]); + } + } +} + +/*! + handleActionCommand. From NmActionObserver, extension manager calls this + call to handle menu command in the UI. +*/ +void NmViewerView::handleActionCommand(NmActionResponse &actionResponse) +{ + // Handle options menu or toolbar + if (actionResponse.menuType() == NmActionOptionsMenu || + actionResponse.menuType() == NmActionToolbar) { + switch (actionResponse.responseCommand()) { + case NmActionResponseCommandReply: { + mAttaManager.cancelFetch(); + NmUiStartParam *startParam = new NmUiStartParam(NmUiViewMessageEditor, + mStartParam->mailboxId(), mStartParam->folderId(), + mStartParam->messageId(), NmUiEditorReply); + mApplication.enterNmUiView(startParam); + } + break; + case NmActionResponseCommandReplyAll: { + mAttaManager.cancelFetch(); + NmUiStartParam *startParam = new NmUiStartParam(NmUiViewMessageEditor, + mStartParam->mailboxId(), mStartParam->folderId(), + mStartParam->messageId(), NmUiEditorReplyAll); + mApplication.enterNmUiView(startParam); + } + break; + case NmActionResponseCommandForward: { + mAttaManager.cancelFetch(); + NmUiStartParam *startParam = new NmUiStartParam(NmUiViewMessageEditor, + mStartParam->mailboxId(), mStartParam->folderId(), + mStartParam->messageId(), NmUiEditorForward); + mApplication.enterNmUiView(startParam); + } + break; + case NmActionResponseCommandDeleteMail: { + mAttaManager.cancelFetch(); + deleteMessage(); + } + break; + default: + break; + } + } +} + +/*! + Deletes the currently open message +*/ +void NmViewerView::deleteMessage() +{ + NM_FUNCTION; + + QList messageList; + messageList.append(mStartParam->messageId()); + int err = mUiEngine.deleteMessages(mStartParam->mailboxId(), + mStartParam->folderId(), + messageList); + messageList.clear(); +} + + +/*! + This is called when attachment fetch progress changes +*/ +void NmViewerView::progressChanged(int value) +{ + if (mAttaIndexUnderFetch != NmNotFoundError) { + // emit signal + if (mAttaWidget && mAttaWidget->progressValue(mAttaIndexUnderFetch) < value) { + progressValueChanged(mAttaIndexUnderFetch, value); + } + } +} + +/*! + This is called when attachment fetch is completed +*/ +void NmViewerView::fetchCompleted(int result) +{ + if (mAttaWidget && mAttaIndexUnderFetch != NmNotFoundError) { + if (result == NmNoError) { + progressValueChanged(mAttaIndexUnderFetch, NmProgressValueComplete); + openAttachment(mAttaIndexUnderFetch); + } else { + mAttaWidget->hideProgressBar(mAttaIndexUnderFetch); + } + } + mAttaIndexUnderFetch = NmNotFoundError; +} + +/*! + externalDelete. From NmUiEngine, handles viewer shutdown when current message is deleted. +*/ +void NmViewerView::messageDeleted(const NmId &mailboxId, const NmId &folderId, const NmId &messageId) +{ + if ((mStartParam->viewId() == NmUiViewMessageViewer) + && (mStartParam->mailboxId()== mailboxId) + && (mStartParam->folderId()== folderId) + && (mStartParam->messageId()== messageId)) { + mApplication.prepareForPopView(); + } +} + +/*! + Helper function for wait dialog creation. +*/ +void NmViewerView::createAndShowWaitDialog() +{ + delete mWaitDialog; + mWaitDialog = NULL; + // Create new wait dialog and set it to me modal with dimmed background + mWaitDialog = new HbProgressDialog(HbProgressDialog::WaitDialog); + // Connect to observe orientation change events + connect(mWaitDialog->mainWindow(), SIGNAL(orientationChanged(Qt::Orientation)), + this, SLOT(orientationChanged(Qt::Orientation))); + mWaitDialog->setModal(true); + mWaitDialog->setBackgroundFaded(true); + connect(mWaitDialog, SIGNAL(cancelled()), this, SLOT(waitNoteCancelled())); + mWaitDialog->setText(hbTrId("txt_mail_dialog_loading_mail_content")); + // Display wait dialog + mWaitDialog->show(); +}