emailuis/nmailui/src/nmviewerview.cpp
branchRCL_3
changeset 63 d189ee25cf9d
equal deleted inserted replaced
61:dcf0eedfc1a3 63:d189ee25cf9d
       
     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: Mail viewer implementation.
       
    15  *
       
    16  */
       
    17 
       
    18 #include "nmuiheaders.h"
       
    19 
       
    20 static const char *NMUI_MESSAGE_VIEWER_XML = ":/docml/nmmailviewer.docml";
       
    21 static const char *NMUI_MESSAGE_VIEWER_VIEW = "nmailViewerView";
       
    22 static const char *NMUI_MESSAGE_VIEWER_CONTENT = "content";
       
    23 static const char *NMUI_MESSAGE_VIEWER_SCROLL_AREA = "viewerScrollArea";
       
    24 static const char *NMUI_MESSAGE_VIEWER_SCROLL_AREA_CONTENTS = "viewerScrollAreaContents";
       
    25 static const char *NMUI_MESSAGE_VIEWER_HEADER = "viewerHeader";
       
    26 static const char *NMUI_MESSAGE_VIEWER_ATTALIST = "viewerAttaList";
       
    27 static const char *NMUI_MESSAGE_VIEWER_SCROLL_WEB_VIEW = "viewerWebView";
       
    28 static const int NmOrientationTimer = 100;
       
    29 static const int NmHeaderMargin = 3;
       
    30 static const int NmWhitePixmapSize = 10;
       
    31 static const int NmProgressValueComplete = 100;
       
    32 static const QString NmParamTextHeightSecondary = "hb-param-text-height-secondary";
       
    33 static const QString NmHttpLinkScheme = "http";
       
    34 static const QString NmHttpsLinkScheme = "https";
       
    35 static const QString NmMailtoLinkScheme = "mailto";
       
    36 
       
    37 // Local constants
       
    38 const qreal NmZoomFactor = 1.5;
       
    39 
       
    40 /*!
       
    41 	\class NmViewerView
       
    42 	\brief Mail viewer class
       
    43 */
       
    44 
       
    45 /*!
       
    46     Constructor
       
    47 */
       
    48 NmViewerView::NmViewerView(
       
    49     NmApplication &application,
       
    50     NmUiStartParam* startParam,
       
    51     NmUiEngine &uiEngine,
       
    52     HbMainWindow *mainWindow,
       
    53     NmAttachmentManager &attaManager,
       
    54     bool toolbarEnabled,
       
    55     QGraphicsItem *parent)
       
    56 :NmBaseView(startParam, application, parent),
       
    57 mApplication(application),
       
    58 mUiEngine(uiEngine),
       
    59 mMainWindow(mainWindow),
       
    60 mAttaManager(attaManager),
       
    61 mToolbarEnabled(toolbarEnabled),
       
    62 mMessage(NULL),
       
    63 mScrollArea(NULL),
       
    64 mViewerContent(NULL),
       
    65 mWebView(NULL),
       
    66 mHeaderWidget(NULL),
       
    67 mMessageFetchingOperation(NULL),
       
    68 mDisplayingPlainText(false),
       
    69 mDocumentLoader(NULL),
       
    70 mScrollAreaContents(NULL),
       
    71 mScreenSize(QSize(0,0)),
       
    72 mWaitDialog(NULL),
       
    73 webFrameloadingCompleted(false),
       
    74 mLatestLoadingSize(QSize(0,0)),
       
    75 mAttaIndexUnderFetch(NmNotFoundError),
       
    76 mAttaWidget(NULL),
       
    77 mViewReady(false),
       
    78 mWaitNoteCancelled(false),
       
    79 mErrorNote(NULL)
       
    80 {
       
    81     // Create documentloader
       
    82     mDocumentLoader = new NmUiDocumentLoader(mMainWindow);
       
    83     // Get screensize
       
    84     mScreenSize = mApplication.screenSize();
       
    85     // Connect external delete handling to uiengine signal
       
    86     connect(&mUiEngine,
       
    87             SIGNAL(messageDeleted(const NmId &, const NmId &, const NmId &)),
       
    88             this, SLOT(messageDeleted(const NmId &, const NmId &, const NmId &)),
       
    89             Qt::UniqueConnection);
       
    90     // Fetch message
       
    91     loadMessage();
       
    92     // Load view layout
       
    93     loadViewLayout();
       
    94 }
       
    95 
       
    96 /*!
       
    97     Destructor
       
    98 */
       
    99 NmViewerView::~NmViewerView()
       
   100 {
       
   101     delete mErrorNote;
       
   102     mErrorNote=NULL;
       
   103     delete mWebView;
       
   104     mWebView = NULL;
       
   105     delete mMessage;
       
   106     mMessage = NULL;
       
   107     delete mDocumentLoader;
       
   108     mDocumentLoader = NULL;
       
   109     mWidgetList.clear();
       
   110     delete mWaitDialog;
       
   111     mWaitDialog = NULL;
       
   112     // remove view from osbserving atta manager events
       
   113     mAttaManager.clearObserver();
       
   114     mAttaManager.cancelFetch();
       
   115 }
       
   116 
       
   117 /*!
       
   118     View is about to exit
       
   119 */
       
   120 void NmViewerView::aboutToExitView()
       
   121 {
       
   122     // View is about to exit, for safety, stop 
       
   123     // loading of content before closing the view
       
   124     if (mWebView){
       
   125         mAttaManager.cancelFetch();
       
   126         mWebView->stop();
       
   127         if (mWebView->page()){
       
   128             mWebView->page()->deleteLater();
       
   129         }
       
   130     }
       
   131 }
       
   132 
       
   133 /*!
       
   134     View layout loading from XML
       
   135 */
       
   136 void NmViewerView::loadViewLayout()
       
   137 {
       
   138     NM_FUNCTION;
       
   139     
       
   140     // Use document loader to load the view
       
   141     bool ok(false);
       
   142     setObjectName(QString(NMUI_MESSAGE_VIEWER_VIEW));
       
   143    QObjectList objectList;
       
   144    objectList.append(this);
       
   145    // Pass the view to documentloader. Document loader uses this view
       
   146    // when docml is parsed, instead of creating new view.
       
   147    // documentloader is created in constructor
       
   148    mDocumentLoader->setObjectTree(objectList);
       
   149    mWidgetList = mDocumentLoader->load(NMUI_MESSAGE_VIEWER_XML, &ok);
       
   150 
       
   151    if (ok)
       
   152    {
       
   153         // Create content and content layout
       
   154         // qobject_cast not work in this case, using reinterpret_cast
       
   155         mViewerContent = reinterpret_cast<HbWidget *>(
       
   156                 mDocumentLoader->findObject(NMUI_MESSAGE_VIEWER_CONTENT));
       
   157         // Find scroll area
       
   158         mScrollArea = reinterpret_cast<HbScrollArea *>(
       
   159                 mDocumentLoader->findObject(NMUI_MESSAGE_VIEWER_SCROLL_AREA));
       
   160         if (mScrollArea) {
       
   161             mScrollArea->setParentItem(this);
       
   162             mScrollArea->setScrollDirections(Qt::Vertical | Qt::Horizontal);
       
   163             connect(mScrollArea, SIGNAL(scrollPositionChanged(QPointF)),
       
   164                 this, SLOT(contentScrollPositionChanged(QPointF)));
       
   165 
       
   166             // Get scroll area contents and set layout margins
       
   167             mScrollAreaContents = qobject_cast<HbWidget *>(
       
   168                     mDocumentLoader->findObject(NMUI_MESSAGE_VIEWER_SCROLL_AREA_CONTENTS));
       
   169             if (mScrollAreaContents) {
       
   170                 QGraphicsLayout *layout = mScrollAreaContents->layout();
       
   171                 if (layout){
       
   172                     layout->setContentsMargins(0,0,0,0);
       
   173                 }
       
   174                 // Set white pixmap to backgrounditem 
       
   175                 QPixmap whitePixmap(NmWhitePixmapSize,NmWhitePixmapSize);
       
   176                 whitePixmap.fill(Qt::white);
       
   177                 QGraphicsPixmapItem *pixmapItem = new QGraphicsPixmapItem(whitePixmap);
       
   178                 mScrollAreaContents->setBackgroundItem(pixmapItem);
       
   179             }
       
   180 
       
   181             // Load headerwidget
       
   182             mHeaderWidget = qobject_cast<NmViewerHeader *>(
       
   183                     mDocumentLoader->findObject(NMUI_MESSAGE_VIEWER_HEADER));
       
   184             if (mHeaderWidget) {
       
   185                 mHeaderWidget->setView(this);
       
   186                 mHeaderWidget->rescaleHeader(mScreenSize);
       
   187                 mHeaderWidget->setMessage(mMessage);
       
   188                 QPointF headerStartPos = mHeaderWidget->scenePos();
       
   189                 mHeaderStartScenePos = QPointF(0,headerStartPos.y());
       
   190             }
       
   191 
       
   192             // Load webview
       
   193             mWebView = reinterpret_cast<NmMailViewerWK *>(
       
   194                     mDocumentLoader->findObject(QString(NMUI_MESSAGE_VIEWER_SCROLL_WEB_VIEW)));
       
   195             if (mWebView) {
       
   196                 // Set auto load images and private browsing(no history) attributes
       
   197                 QWebSettings *settings = mWebView->settings();
       
   198                 if (settings) {
       
   199                     settings->setAttribute(QWebSettings::AutoLoadImages, true);
       
   200                     settings->setAttribute(QWebSettings::PrivateBrowsingEnabled, true);
       
   201                 }
       
   202                 QWebPage *page = mWebView->page();
       
   203                 if (page) {
       
   204                     QWebFrame *frame = page->mainFrame();
       
   205                     if (frame) {
       
   206                         frame->setScrollBarPolicy(Qt::Vertical,Qt::ScrollBarAlwaysOff);
       
   207                         frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
       
   208                         frame->setTextSizeMultiplier(NmZoomFactor);
       
   209                         connect(mWebView->page()->mainFrame(),
       
   210                                 SIGNAL(contentsSizeChanged(const QSize&)),
       
   211                             this, SLOT(scaleWebViewWhenLoading(const QSize&)));  
       
   212                     }
       
   213                 }
       
   214             }
       
   215         }
       
   216     }
       
   217 }
       
   218  
       
   219 /*!
       
   220     Lazy loading when view layout has been loaded
       
   221 */
       
   222 void NmViewerView::viewReady()
       
   223 {
       
   224     if (!mViewReady){
       
   225         // Set mailbox name to title
       
   226         setMailboxName();
       
   227         // Create toolbar if needed
       
   228         if (mToolbarEnabled) {
       
   229             createToolBar();
       
   230         } else {
       
   231             // Connect options menu about to show to create options menu function
       
   232             QObject::connect(menu(), SIGNAL(aboutToShow()),
       
   233                     this, SLOT(createOptionsMenu())); 
       
   234             // Menu needs one dummy item so that aboutToShow signal is emitted.
       
   235             NmAction *dummy = new NmAction(0);
       
   236             menu()->addAction(dummy);
       
   237         }
       
   238                 
       
   239         if (mHeaderWidget) {
       
   240             QPointF contentWidgetPos = mScrollArea->pos();
       
   241             qreal headerHeight = mHeaderWidget->geometry().height();
       
   242             if (mMainWindow->orientation() == Qt::Horizontal) {
       
   243                 const QPointF pointToWebView(contentWidgetPos.x(), headerHeight+NmHeaderMargin);
       
   244                 mScrollArea->scrollContentsTo(pointToWebView,0);
       
   245             }
       
   246         }
       
   247         
       
   248         // Run fetchmessage in queue
       
   249         QMetaObject::invokeMethod(this, "fetchMessage", Qt::QueuedConnection);
       
   250         // Set view ready
       
   251         mViewReady = true;
       
   252     }
       
   253 }
       
   254 
       
   255 /*!
       
   256     Function fecthes message data based on parameters
       
   257 */
       
   258 void NmViewerView::loadMessage()
       
   259 {
       
   260     NM_FUNCTION;
       
   261     
       
   262     if (mMessage) {
       
   263         delete mMessage;
       
   264         mMessage = NULL;
       
   265     }
       
   266     // Read start params and message object
       
   267     if (mStartParam){
       
   268         NmId mailboxId = mStartParam->mailboxId();
       
   269         NmId folderId = mStartParam->folderId();
       
   270         NmId msgId = mStartParam->messageId();
       
   271         mMessage = mUiEngine.message(mailboxId, folderId, msgId);
       
   272     }
       
   273 }
       
   274 
       
   275 /*!
       
   276     Function fecthes message data based on parameters. Returns false if message is available,
       
   277     true if message have to be fetched
       
   278 */
       
   279 void NmViewerView::fetchMessage()
       
   280 {
       
   281     NM_FUNCTION;
       
   282     
       
   283     if (mMessage) {
       
   284         NmId mailboxId = mStartParam->mailboxId();
       
   285         NmId folderId = mStartParam->folderId();
       
   286         NmId msgId = mStartParam->messageId();
       
   287         const NmMessagePart *body = mMessage->htmlBodyPart();
       
   288         if (!body) {
       
   289             // try plain to plain text part
       
   290             body = mMessage->plainTextBodyPart();
       
   291         }
       
   292         // try to fetch if body missing or fetched size is smaller than content size
       
   293         // if body missing it might mean that only header is fetched or message has no body
       
   294         if (!body || (body && (body->fetchedSize() < body->size()))) {
       
   295             // start fetching operation
       
   296             if (mMessageFetchingOperation && mMessageFetchingOperation->isRunning()) { 
       
   297                 mMessageFetchingOperation->cancelOperation();
       
   298             }
       
   299             mMessageFetchingOperation = mUiEngine.fetchMessage(mailboxId, folderId, msgId);
       
   300 
       
   301             if (mMessageFetchingOperation) {
       
   302                 connect(mMessageFetchingOperation,
       
   303                         SIGNAL(operationCompleted(int)),
       
   304                         this,
       
   305                         SLOT(messageFetched(int)));
       
   306                 createAndShowWaitDialog();
       
   307             }
       
   308         } else {
       
   309             // message is fetched
       
   310             setMessageData();
       
   311         }
       
   312     }
       
   313 }
       
   314 
       
   315 /*!
       
   316     This is signalled by mMessageFetchingOperation when the original message is fetched.
       
   317  */
       
   318 void NmViewerView::messageFetched(int result)
       
   319 {
       
   320     mWaitDialog->close();
       
   321     disconnect(mWaitDialog->mainWindow(), SIGNAL(orientationChanged(Qt::Orientation)),
       
   322                 this, SLOT(orientationChanged(Qt::Orientation)));
       
   323     
       
   324     if (result == NmNoError && mMessageFetchingOperation) {
       
   325         if (mMessage) {
       
   326             delete mMessage;
       
   327             mMessage = NULL;
       
   328         }
       
   329         // Read start params and message object
       
   330         if (mStartParam) {
       
   331             NmId mailboxId = mStartParam->mailboxId();
       
   332             NmId folderId = mStartParam->folderId();
       
   333             NmId msgId = mStartParam->messageId();
       
   334             mMessage = mUiEngine.message(mailboxId, folderId, msgId);
       
   335         }
       
   336         setMessageData();
       
   337         // Update header message data
       
   338 		if (mHeaderWidget){
       
   339         	mHeaderWidget->updateMessageData(mMessage);
       
   340 		}
       
   341     }
       
   342 }
       
   343 
       
   344 
       
   345 /*!
       
   346     This is signalled by mWaitDialog when the note is cancelled
       
   347  */
       
   348 void NmViewerView::waitNoteCancelled()
       
   349 {
       
   350     if (!mWaitNoteCancelled) {
       
   351         if (mMessageFetchingOperation && mMessageFetchingOperation->isRunning()) { 
       
   352 	        mMessageFetchingOperation->cancelOperation();
       
   353         }
       
   354         mWaitNoteCancelled = true;
       
   355         QMetaObject::invokeMethod(&mApplication, "prepareForPopView", Qt::QueuedConnection);
       
   356     }
       
   357 }
       
   358 
       
   359 
       
   360 /*!
       
   361     Function sets message data to web view and header
       
   362 */
       
   363 void NmViewerView::setMessageData()
       
   364 {
       
   365     NM_FUNCTION;
       
   366     
       
   367     // Connect to observe orientation change events
       
   368     connect(mApplication.mainWindow(), SIGNAL(orientationChanged(Qt::Orientation)),
       
   369                 this, SLOT(orientationChanged(Qt::Orientation)));
       
   370 
       
   371     // Set page parameters
       
   372     QWebPage *page(NULL);
       
   373     if (mWebView){
       
   374        page = mWebView->page();
       
   375     }
       
   376     if (page){
       
   377         // Set custom network access manager for embedded image handling
       
   378         NmViewerViewNetManager &netMngr = mApplication.networkAccessManager();
       
   379         netMngr.setView(this);
       
   380         page->setNetworkAccessManager(&netMngr);
       
   381         QWebSettings *webSettings = page->settings();
       
   382         if (webSettings) {
       
   383             webSettings->setObjectCacheCapacities(0,0,0);
       
   384         }
       
   385 
       
   386         connect(page, SIGNAL(loadFinished(bool)),
       
   387                     this, SLOT(webFrameLoaded(bool)));
       
   388         page->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
       
   389         page->setContentEditable(false);
       
   390     }
       
   391 
       
   392   	// if everything is ok, set message to html viewer
       
   393     if (mMessage && mWebView && page) {
       
   394         // Set initial size of component and content before loading data
       
   395         mWebView->setPreferredWidth(mScreenSize.width());
       
   396         QRectF myGeometry = geometry();
       
   397         page->setViewportSize(myGeometry.size().toSize());
       
   398         //Set message data to html viewer.
       
   399         mWebView->setHtml(formatMessage());
       
   400         // Connect to link clicked
       
   401         QObject::connect(page, SIGNAL(linkClicked(const QUrl&)),
       
   402                 this, SLOT(linkClicked(const QUrl&)));
       
   403         changeMessageReadStatus(true);
       
   404         setAttachmentList();
       
   405     }
       
   406 }
       
   407 
       
   408 /*!
       
   409 
       
   410 */
       
   411 void NmViewerView::setAttachmentList()
       
   412 {
       
   413     NM_FUNCTION;
       
   414     
       
   415     // Load headerwidget
       
   416     mAttaWidget = qobject_cast<NmAttachmentListWidget *>(
       
   417             mDocumentLoader->findObject(NMUI_MESSAGE_VIEWER_ATTALIST));
       
   418     if (mMessage && mAttaWidget) {
       
   419         // connect atta widget to listen progress value events
       
   420         QObject::connect(this, SIGNAL(progressValueChanged(int, int)),
       
   421                 mAttaWidget, SLOT(setProgressBarValue(int, int)));
       
   422         // Set atta widget text color black since header has static white bg.
       
   423         mAttaWidget->setTextColor(Qt::black);
       
   424         // Set attawidget minimum & maximum size
       
   425         mAttaWidget->setMinimumWidth(mScreenSize.width());
       
   426         mAttaWidget->setMaximumWidth(mScreenSize.width());
       
   427         bool inserted(false);
       
   428         QList<NmMessagePart*> messageParts;
       
   429         mMessage->attachmentList(messageParts);
       
   430         for (int i = 0; i < messageParts.count();i++) {
       
   431             NmMessagePart *part = messageParts[i];
       
   432             if (part &&
       
   433                 ((part->contentDisposition().trimmed().startsWith("inline", Qt::CaseInsensitive)==false) ||
       
   434                  (part->contentType().trimmed().startsWith("image", Qt::CaseInsensitive)==false))) {
       
   435                 QString fileName = part->attachmentName();
       
   436                 // index starts from zero, next index is same as count
       
   437                 int attaIndex = mAttaWidget->count();
       
   438                 mAttaWidget->insertAttachment(attaIndex, fileName,
       
   439                                               NmUtilities::attachmentSizeString(part->size()));
       
   440                 mAttaIdList.insert(attaIndex, part->partId());
       
   441                 // check is part under fetch, add progress value to attachment widget
       
   442                 if (mAttaManager.isFetching() && 
       
   443                         mAttaManager.partIdUnderFetch() == part->partId()) {
       
   444                     mAttaIndexUnderFetch = attaIndex;
       
   445                 }
       
   446                 inserted = true;
       
   447             }
       
   448         }
       
   449         if (inserted) {
       
   450             QObject::connect(mAttaWidget, SIGNAL(itemActivated(int)),
       
   451                     this, SLOT(openAttachment(int)));
       
   452         }
       
   453         else {
       
   454             // No attachments, set height to 0
       
   455             mAttaWidget->setMinimumHeight(0);
       
   456             mAttaWidget->setMaximumHeight(0);
       
   457         }
       
   458         // set this as a observer for attachment manager
       
   459         mAttaManager.setObserver(this);
       
   460     }
       
   461 }
       
   462 
       
   463 /*!
       
   464 
       
   465 */
       
   466 void NmViewerView::openAttachment(int index)
       
   467 {
       
   468     NM_FUNCTION;
       
   469     if (index >= 0) {
       
   470         NmId attaId = mAttaIdList.at(index);
       
   471         // reload message to get updates part sizes
       
   472         loadMessage();
       
   473         QList<NmMessagePart*> messageParts;
       
   474         if (mMessage) {
       
   475             mMessage->attachmentList(messageParts);
       
   476              NmId mailboxId = mMessage->envelope().mailboxId();
       
   477              NmId folderId = mMessage->envelope().folderId();
       
   478              NmId messageId = mMessage->envelope().messageId();
       
   479              for (int i = 0; i < messageParts.count(); i++) {
       
   480                  // message part found have to found
       
   481                  // and its fetched size is smaller than size, then start part fetch
       
   482                  if (messageParts[i]->partId() == attaId &&
       
   483                      messageParts[i]->size() > messageParts[i]->fetchedSize()) {
       
   484                      // do not start if there's already ongoing fetch
       
   485                      if (mAttaIndexUnderFetch == NmNotFoundError) {
       
   486                          mAttaIndexUnderFetch = index;
       
   487                          mAttaManager.fetchAttachment(mailboxId, folderId,
       
   488                                                       messageId, attaId);
       
   489                      }
       
   490                  }
       
   491                  // attachment is fetched, open file
       
   492                  else if (messageParts[i]->partId() == attaId) {
       
   493                      mAttaManager.cancelFetch();
       
   494                      XQSharableFile file = mUiEngine.messagePartFile(mailboxId, folderId,
       
   495                                                                      messageId, attaId);
       
   496                      int error = NmUtilities::openFile(file);
       
   497                      file.close();
       
   498                      if (error==NmNotFoundError){
       
   499                          delete mErrorNote;
       
   500                          mErrorNote=NULL;
       
   501                          mErrorNote = NmUtilities::displayWarningNote(
       
   502                                  hbTrId("txt_mail_dialog_unable_to_open_attachment_file_ty"));
       
   503                      }
       
   504                  }
       
   505              }            
       
   506          }
       
   507     }
       
   508 }
       
   509 
       
   510 /*!
       
   511     Function formats message based on actual data
       
   512 */
       
   513 QString NmViewerView::formatMessage()
       
   514 {
       
   515     NM_FUNCTION;
       
   516     
       
   517     QString msg = "";
       
   518     if (mMessage) {
       
   519         NmMessagePart *html = mMessage->htmlBodyPart();
       
   520         if (html) {
       
   521             msg += formatHtmlMessage(html);
       
   522         }
       
   523         else {
       
   524             NmMessagePart *plain = mMessage->plainTextBodyPart();
       
   525             if (plain) {
       
   526                 msg += formatPlainTextMessage(plain);
       
   527             }
       
   528         }    
       
   529     }
       
   530     return msg;
       
   531 }
       
   532 
       
   533 /*!
       
   534     Function formats html message
       
   535 */
       
   536 QString NmViewerView::formatHtmlMessage(NmMessagePart *html)
       
   537 {    
       
   538     NM_FUNCTION;
       
   539 
       
   540     QString msg = "";
       
   541     if (html && mMessage) {
       
   542         NmId mailboxId = mMessage->envelope().mailboxId();
       
   543         NmId folderId = mMessage->envelope().folderId();
       
   544         NmId messageId = mMessage->envelope().messageId();
       
   545         QList<NmMessagePart*> parts;
       
   546         mMessage->attachmentList(parts);
       
   547         for (int i=0; i < parts.count(); i++) {
       
   548             NmMessagePart *child = parts[i];
       
   549             // Browse through embedded image parts and add those
       
   550             // the web view.
       
   551             bool isFetched = child->fetchedSize() >= child->size();
       
   552             if (child->contentType().startsWith("image", Qt::CaseInsensitive)) {
       
   553                 QString contentId = child->contentId();
       
   554                 if (isFetched) {
       
   555                     int ret = mUiEngine.contentToMessagePart(
       
   556                             mailboxId, folderId, messageId, *child);
       
   557                     if (ret == NmNoError) {
       
   558                       mWebView->addContent(contentId, QVariant::fromValue(child->binaryContent()), 
       
   559                               child->partId(), isFetched);
       
   560                     }
       
   561                 }
       
   562                 else {
       
   563                     mWebView->addContent(contentId, QVariant::fromValue(QByteArray()), 
       
   564                             child->partId(), isFetched);
       
   565                 }
       
   566             }
       
   567         }
       
   568         int ret = mUiEngine.contentToMessagePart(mailboxId, folderId, messageId, *html);
       
   569         if (ret == NmNoError) {
       
   570          msg = html->textContent();
       
   571         }    
       
   572     }
       
   573     return msg;
       
   574 }
       
   575 
       
   576 /*!
       
   577     Function formats plain text message message
       
   578 */
       
   579 QString NmViewerView::formatPlainTextMessage(NmMessagePart *plain)
       
   580 {
       
   581     NM_FUNCTION;
       
   582       
       
   583     QString msg = "";
       
   584     if (plain && mMessage) {
       
   585         NmId mailboxId = mMessage->envelope().mailboxId();
       
   586         NmId folderId = mMessage->envelope().folderId();
       
   587         NmId messageId = mMessage->envelope().messageId();
       
   588         int ret = mUiEngine.contentToMessagePart(mailboxId, folderId,
       
   589                                                  messageId, *plain);
       
   590         if (ret == NmNoError) {
       
   591             QTextDocument document;
       
   592             // set font
       
   593             QFont currentFont = document.defaultFont();
       
   594             currentFont.setWeight(QFont::Normal);
       
   595             qreal secondarySize;
       
   596             HbStyle myStyle;
       
   597             bool found = myStyle.parameter(NmParamTextHeightSecondary, secondarySize);
       
   598             if (found) {
       
   599                 HbFontSpec fontSpec(HbFontSpec::Secondary);
       
   600                 fontSpec.setTextHeight(secondarySize);
       
   601                 currentFont.setPixelSize(fontSpec.font().pixelSize());
       
   602             }
       
   603             document.setDefaultFont(currentFont);
       
   604             // convert to html
       
   605             document.setPlainText(plain->textContent());
       
   606             msg = document.toHtml();
       
   607     
       
   608             if (qApp->layoutDirection()==Qt::RightToLeft){
       
   609                 // add right alignment to document css section
       
   610                 QRegExp rx("(<style type=\"text/css\">)(.+)(</style>)", Qt::CaseInsensitive);
       
   611                 rx.setMinimal(true);
       
   612                 int pos = rx.indexIn(msg);
       
   613                 if (pos > -1) {
       
   614                     QString newStr = rx.cap(1);
       
   615                     newStr.append(rx.cap(2));
       
   616                     newStr.append("p { text-align: right } ");
       
   617                     newStr.append(rx.cap(3));
       
   618                     msg.replace(rx, newStr);
       
   619                 }
       
   620             }
       
   621         }    
       
   622     }
       
   623     mDisplayingPlainText=true;  
       
   624     return msg;
       
   625 }
       
   626 
       
   627 /*!
       
   628     Reload view contents with new start parameters
       
   629     Typically when view is already open and external view activation occurs
       
   630     for this same view
       
   631 */
       
   632 void NmViewerView::reloadViewContents(NmUiStartParam* startParam)
       
   633 {
       
   634     // Check start parameter validity, message view cannot
       
   635     // be updated if given parameter is zero.
       
   636     if (startParam && startParam->viewId() == NmUiViewMessageViewer &&
       
   637         startParam->messageId()!= 0) {
       
   638         // Delete existing start parameter data
       
   639         delete mStartParam;
       
   640         mStartParam = NULL;
       
   641         // Store new start parameter data
       
   642         mStartParam = startParam;
       
   643         // Reload viewer with new message information
       
   644         setMessageData();
       
   645     }
       
   646     else {
       
   647         NMLOG("nmailui: Invalid viewer start parameter");
       
   648         // Unused start parameter needs to be deleted
       
   649         delete startParam;
       
   650     }
       
   651 }
       
   652 
       
   653 /*!
       
   654     nmailViewId
       
   655 */
       
   656 NmUiViewId NmViewerView::nmailViewId() const
       
   657 {
       
   658     return NmUiViewMessageViewer;
       
   659 }
       
   660 
       
   661 /*!
       
   662     Scale web view width
       
   663 */
       
   664 void NmViewerView::webFrameLoaded(bool loaded)
       
   665 {
       
   666     if (loaded){
       
   667         webFrameloadingCompleted = true;
       
   668         // Scale web view after loading the
       
   669         // complete contents, including images
       
   670         QMetaObject::invokeMethod(this, "scaleWebViewWhenLoaded", Qt::QueuedConnection);       
       
   671     }
       
   672 }
       
   673 
       
   674 /*!
       
   675     Scale web view width when loading is ongoing
       
   676 */
       
   677 void NmViewerView::scaleWebViewWhenLoading(const QSize &size)
       
   678 {
       
   679     // Try to scale web view while mainframe is being loaded.
       
   680     // So that screen is scrollable even before images are fully loaded
       
   681     // First check that new size is different than previous, no need to react if
       
   682     // same size value is received more than once.
       
   683     if (size != mLatestLoadingSize) {
       
   684         if (!webFrameloadingCompleted && mWebView && mWebView->page() &&
       
   685             (size.width() > mScreenSize.width() || size.height() > geometry().height())) {
       
   686             int width = (int)size.width();
       
   687             int height = (int)size.height();
       
   688             // Set content (webview) width
       
   689             if (mDisplayingPlainText){
       
   690                 mWebView->setPreferredWidth(geometry().width());           
       
   691             }
       
   692             else {
       
   693                 mWebView->setPreferredWidth(width);
       
   694             }
       
   695             mWebView->setMinimumHeight(height);
       
   696         }
       
   697     }
       
   698     mLatestLoadingSize = size;
       
   699 }
       
   700 
       
   701 /*!
       
   702     Scale web view width when loading is completed
       
   703 */
       
   704 void NmViewerView::scaleWebViewWhenLoaded()
       
   705 {
       
   706     QRectF myGeometry = geometry();
       
   707     QWebPage *page = mWebView->page();
       
   708     if (mWebView && page) {
       
   709         page->setPreferredContentsSize(myGeometry.size().toSize());
       
   710         QSizeF contentSize = page->mainFrame()->contentsSize();
       
   711         mWebView->setPreferredSize(contentSize);
       
   712     }
       
   713     // Workaround for scrolling problem
       
   714     scene()->setProperty("overridingGesture",QVariant());
       
   715 }
       
   716 
       
   717 /*!
       
   718     Set new dimensions after orientation change.
       
   719 */
       
   720 void NmViewerView::adjustViewDimensions()
       
   721 {
       
   722     // Update current screensize
       
   723     mScreenSize = mApplication.screenSize();
       
   724     // Scale header to screen width
       
   725     if (mHeaderWidget){
       
   726         mHeaderWidget->rescaleHeader(mScreenSize);
       
   727     }
       
   728     if (mAttaWidget){
       
   729         // Set attawidget minimum & maximum size
       
   730         mAttaWidget->setMinimumWidth(mScreenSize.width());
       
   731         mAttaWidget->setMaximumWidth(mScreenSize.width());
       
   732     }    
       
   733     scaleWebViewWhenLoaded();
       
   734 
       
   735     if (mToolbarEnabled) {
       
   736 		// Re-create toolbar in orientation switch
       
   737 		createToolBar();
       
   738     }
       
   739 }
       
   740 
       
   741 /*!
       
   742    Screen orientation changed. Web view needs to be scaled when
       
   743    landscape <-> portrait switch occurs because text needs to
       
   744    be wrapped again.
       
   745 */
       
   746 void NmViewerView::orientationChanged(Qt::Orientation orientation)
       
   747 {
       
   748     Q_UNUSED(orientation);
       
   749     QTimer::singleShot(NmOrientationTimer, this, SLOT(adjustViewDimensions()));
       
   750 }
       
   751 
       
   752 /*!
       
   753    Link clicked callback
       
   754 */
       
   755 void NmViewerView::linkClicked(const QUrl& link)
       
   756 {
       
   757     NM_FUNCTION;
       
   758     
       
   759     if (link.scheme() == NmHttpLinkScheme ||
       
   760         link.scheme() == NmHttpsLinkScheme) {
       
   761         mAttaManager.cancelFetch();
       
   762         QDesktopServices::openUrl(link);
       
   763     } else if (link.scheme() == NmMailtoLinkScheme){
       
   764         mAttaManager.cancelFetch();
       
   765         QList<NmAddress*> *addrList = new QList<NmAddress*>();
       
   766         NmAddress *mailtoAddr = new NmAddress();
       
   767         QString address = link.toString(QUrl::RemoveScheme);
       
   768         mailtoAddr->setAddress(address);
       
   769         mailtoAddr->setDisplayName(address);
       
   770         addrList->append(mailtoAddr);
       
   771         // Create start parameters. Address list ownership
       
   772         // is transferred to startparam object
       
   773         NmUiStartParam* param = new NmUiStartParam(NmUiViewMessageEditor,
       
   774                                                    mStartParam->mailboxId(),
       
   775                                                    mStartParam->folderId(),
       
   776                                                    0,
       
   777                                                    NmUiEditorMailto,
       
   778                                                    addrList);
       
   779         mApplication.enterNmUiView(param);
       
   780     }    
       
   781 }
       
   782 
       
   783 /*!
       
   784    Function can be used to check whether mouse event has
       
   785    occured on top of header area.
       
   786 */
       
   787 bool NmViewerView::eventOnTopOfHeaderArea(QGraphicsSceneMouseEvent *event)
       
   788 {
       
   789     bool ret(false);
       
   790     if (event && mHeaderWidget) {
       
   791         QPointF lastReleasePoint = event->lastPos();
       
   792         QPointF contentWidgetPos = mScrollAreaContents->pos();
       
   793         int headerHeight = (int)mHeaderWidget->geometry().height();
       
   794         if (lastReleasePoint.y()<headerHeight+contentWidgetPos.y()) {
       
   795             ret=true;
       
   796         }
       
   797     }
       
   798     return ret;
       
   799 }
       
   800 
       
   801 /*!
       
   802     Get function for content widget web view.
       
   803 */
       
   804 NmMailViewerWK* NmViewerView::webView()
       
   805 {
       
   806     return mWebView;
       
   807 }
       
   808 
       
   809 /*!
       
   810     Get function for message being viewed
       
   811 */
       
   812 NmMessage* NmViewerView::message()
       
   813 {
       
   814     return mMessage;
       
   815 }
       
   816 
       
   817 /*!
       
   818    Function to set message read status
       
   819 */
       
   820 void NmViewerView::changeMessageReadStatus(bool read)
       
   821 {
       
   822     NM_FUNCTION;
       
   823     
       
   824     QList<const NmMessageEnvelope*> envelopeList;
       
   825     NmMessageEnvelope *envelope = &mMessage->envelope();
       
   826     QPointer<NmStoreEnvelopesOperation> op(NULL);
       
   827     if (envelope) {
       
   828         if ( read != envelope->isRead() ){
       
   829             if (read){
       
   830                 envelope->setRead(true);
       
   831                 envelopeList.append(envelope);
       
   832                 op = mUiEngine.setEnvelopes(
       
   833                     mStartParam->mailboxId(),
       
   834                     mStartParam->folderId(),
       
   835                     MarkAsRead,
       
   836                     envelopeList);
       
   837             }
       
   838             else {
       
   839                 envelope->setRead(false);
       
   840                 envelopeList.append(envelope);
       
   841                 op = mUiEngine.setEnvelopes(
       
   842                     mStartParam->mailboxId(),
       
   843                     mStartParam->folderId(),
       
   844                     MarkAsUnread,
       
   845                     envelopeList);
       
   846             }
       
   847         }
       
   848     }
       
   849 }
       
   850 
       
   851 /*!
       
   852     Set mailbox name to title
       
   853 */
       
   854 void NmViewerView::setMailboxName()
       
   855 {
       
   856     if (mStartParam){
       
   857         NmMailboxMetaData *meta = mUiEngine.mailboxById(mStartParam->mailboxId());
       
   858         if (meta) {
       
   859             setTitle(meta->name());
       
   860         }
       
   861     }
       
   862 }
       
   863 
       
   864 /*!
       
   865     contentScrollPositionChanged.
       
   866     Function reacts to scroll position change events and sets
       
   867     header to correct position
       
   868 */
       
   869 void NmViewerView::contentScrollPositionChanged(const QPointF &newPosition)
       
   870 {
       
   871     if (mWebView&&mHeaderWidget){
       
   872         QRectF webViewRect = mWebView->geometry();
       
   873         QTransform tr;
       
   874         qreal leftMovementThreshold(webViewRect.width()-mHeaderWidget->geometry().width());
       
   875         if (newPosition.x()<0) {
       
   876             tr.translate(webViewRect.topLeft().x() ,0);
       
   877         }
       
   878         else if (newPosition.x()>=0 && newPosition.x()<leftMovementThreshold) {
       
   879             tr.translate(mHeaderStartScenePos.x()+newPosition.x() ,0);
       
   880         }
       
   881         else {
       
   882             tr.translate(webViewRect.topLeft().x()+leftMovementThreshold ,0);
       
   883         }
       
   884         mHeaderWidget->setTransform(tr);
       
   885         if (mAttaWidget) {
       
   886             mAttaWidget->setTransform(tr);
       
   887         }
       
   888     }
       
   889     mLatestScrollPos = newPosition;
       
   890 }
       
   891 
       
   892 /*!
       
   893     createToolBar. Function asks menu commands from extension
       
   894     to be added to toolbar owned by the HbView.
       
   895 */
       
   896 void NmViewerView::createToolBar()
       
   897 {
       
   898     HbToolBar *tb = toolBar();
       
   899     NmUiExtensionManager &extMngr = mApplication.extManager();
       
   900     if (tb && &extMngr && mStartParam) {
       
   901         tb->clearActions();
       
   902         NmActionRequest request(this, NmActionToolbar, NmActionContextViewViewer,
       
   903                 NmActionContextDataNone, mStartParam->mailboxId(), mStartParam->folderId() );
       
   904         QList<NmAction *> list;
       
   905         extMngr.getActions(request, list);
       
   906         for (int i = 0; i < list.count(); i++) {
       
   907             tb->addAction(list[i]);
       
   908         }
       
   909     }
       
   910 }
       
   911 
       
   912 /*!
       
   913     createOptionsMenu. Functions asks menu commands from extension
       
   914     to be added to options menu.
       
   915 */
       
   916 void NmViewerView::createOptionsMenu()
       
   917 {
       
   918 	HbMenu *optionsMenu = menu();
       
   919 	NmUiExtensionManager &extMngr = mApplication.extManager();
       
   920 	if (optionsMenu && &extMngr && mStartParam) {
       
   921 		optionsMenu->clearActions();
       
   922 		NmActionRequest request(this, NmActionOptionsMenu, NmActionContextViewViewer,
       
   923 				NmActionContextDataNone, mStartParam->mailboxId(), mStartParam->folderId() );
       
   924 
       
   925 		QList<NmAction*> list;
       
   926 		extMngr.getActions(request, list);
       
   927 		for (int i=0;i<list.count();i++) {
       
   928 			optionsMenu->addAction(list[i]);
       
   929 		}
       
   930 	}
       
   931 }
       
   932 
       
   933 /*!
       
   934     handleActionCommand. From NmActionObserver, extension manager calls this
       
   935     call to handle menu command in the UI.
       
   936 */
       
   937 void NmViewerView::handleActionCommand(NmActionResponse &actionResponse)
       
   938 {
       
   939     // Handle options menu or toolbar
       
   940     if (actionResponse.menuType() == NmActionOptionsMenu ||
       
   941     	actionResponse.menuType() == NmActionToolbar) {
       
   942         switch (actionResponse.responseCommand()) {
       
   943             case NmActionResponseCommandReply: {
       
   944                 mAttaManager.cancelFetch();
       
   945                 NmUiStartParam *startParam = new NmUiStartParam(NmUiViewMessageEditor,
       
   946                     mStartParam->mailboxId(), mStartParam->folderId(),
       
   947                     mStartParam->messageId(), NmUiEditorReply);
       
   948                 mApplication.enterNmUiView(startParam);
       
   949             }
       
   950             break;
       
   951             case NmActionResponseCommandReplyAll: {
       
   952                 mAttaManager.cancelFetch();
       
   953                 NmUiStartParam *startParam = new NmUiStartParam(NmUiViewMessageEditor,
       
   954                     mStartParam->mailboxId(), mStartParam->folderId(),
       
   955                     mStartParam->messageId(), NmUiEditorReplyAll);
       
   956                 mApplication.enterNmUiView(startParam);
       
   957             }
       
   958             break;
       
   959             case NmActionResponseCommandForward: {
       
   960                 mAttaManager.cancelFetch();
       
   961                 NmUiStartParam *startParam = new NmUiStartParam(NmUiViewMessageEditor,
       
   962                     mStartParam->mailboxId(), mStartParam->folderId(),
       
   963                     mStartParam->messageId(), NmUiEditorForward);
       
   964                 mApplication.enterNmUiView(startParam);
       
   965             }
       
   966             break;
       
   967             case NmActionResponseCommandDeleteMail: {
       
   968                 mAttaManager.cancelFetch();
       
   969                 deleteMessage();
       
   970                 }
       
   971             break;
       
   972             default:
       
   973                 break;
       
   974         }
       
   975     }
       
   976 }
       
   977 
       
   978 /*!
       
   979     Deletes the currently open message
       
   980 */
       
   981 void NmViewerView::deleteMessage()
       
   982 {
       
   983     NM_FUNCTION;
       
   984     
       
   985     QList<NmId> messageList;
       
   986     messageList.append(mStartParam->messageId());  
       
   987     int err = mUiEngine.deleteMessages(mStartParam->mailboxId(),
       
   988                                        mStartParam->folderId(),
       
   989                                        messageList);
       
   990     messageList.clear();
       
   991 }
       
   992 
       
   993 
       
   994 /*!
       
   995     This is called when attachment fetch progress changes
       
   996 */
       
   997 void NmViewerView::progressChanged(int value)
       
   998 {
       
   999     if (mAttaIndexUnderFetch != NmNotFoundError) {
       
  1000         // emit signal
       
  1001         if (mAttaWidget && mAttaWidget->progressValue(mAttaIndexUnderFetch) < value) {
       
  1002             progressValueChanged(mAttaIndexUnderFetch, value);
       
  1003         }
       
  1004     }
       
  1005 }
       
  1006 
       
  1007 /*!
       
  1008     This is called when attachment fetch is completed
       
  1009 */
       
  1010 void NmViewerView::fetchCompleted(int result)
       
  1011 {
       
  1012     if (mAttaWidget && mAttaIndexUnderFetch != NmNotFoundError) {
       
  1013         if (result == NmNoError) {
       
  1014             progressValueChanged(mAttaIndexUnderFetch, NmProgressValueComplete);
       
  1015             openAttachment(mAttaIndexUnderFetch);
       
  1016         } else {
       
  1017             mAttaWidget->hideProgressBar(mAttaIndexUnderFetch);
       
  1018         }
       
  1019     }
       
  1020     mAttaIndexUnderFetch = NmNotFoundError;
       
  1021 }
       
  1022 
       
  1023 /*!
       
  1024     externalDelete. From NmUiEngine, handles viewer shutdown when current message is deleted.
       
  1025 */
       
  1026 void NmViewerView::messageDeleted(const NmId &mailboxId, const NmId &folderId, const NmId &messageId)
       
  1027 {
       
  1028     if ((mStartParam->viewId() == NmUiViewMessageViewer)
       
  1029         && (mStartParam->mailboxId()== mailboxId)
       
  1030         && (mStartParam->folderId()== folderId)
       
  1031         && (mStartParam->messageId()== messageId)) {
       
  1032         mApplication.prepareForPopView();
       
  1033     }
       
  1034 }
       
  1035 
       
  1036 /*!
       
  1037     Helper function for wait dialog creation.
       
  1038 */
       
  1039 void NmViewerView::createAndShowWaitDialog()
       
  1040 {
       
  1041     delete mWaitDialog;
       
  1042     mWaitDialog = NULL;
       
  1043     // Create new wait dialog and set it to me modal with dimmed background
       
  1044     mWaitDialog = new HbProgressDialog(HbProgressDialog::WaitDialog);
       
  1045     // Connect to observe orientation change events
       
  1046     connect(mWaitDialog->mainWindow(), SIGNAL(orientationChanged(Qt::Orientation)),
       
  1047                 this, SLOT(orientationChanged(Qt::Orientation)));
       
  1048     mWaitDialog->setModal(true);
       
  1049     mWaitDialog->setBackgroundFaded(true);
       
  1050     connect(mWaitDialog, SIGNAL(cancelled()), this, SLOT(waitNoteCancelled()));
       
  1051     mWaitDialog->setText(hbTrId("txt_mail_dialog_loading_mail_content"));
       
  1052     // Display wait dialog
       
  1053     mWaitDialog->show(); 
       
  1054 }