diff -r 578830873419 -r ecc8def7944a emailuis/nmailui/src/nmviewerview.cpp --- a/emailuis/nmailui/src/nmviewerview.cpp Fri Apr 16 14:51:52 2010 +0300 +++ b/emailuis/nmailui/src/nmviewerview.cpp Mon May 03 12:23:15 2010 +0300 @@ -23,14 +23,18 @@ 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 nmViewLoadTimer=10; +static const int nmOrientationTimer=100; + +static const QString NmParamTextHeightSecondary = "hb-param-text-height-secondary"; /*! \class NmViewerView \brief Mail viewer class -*/ +*/ /*! Constructor @@ -40,11 +44,13 @@ NmUiStartParam* startParam, NmUiEngine &uiEngine, HbMainWindow *mainWindow, + bool toolbar, QGraphicsItem *parent) :NmBaseView(startParam, parent), mApplication(application), mUiEngine(uiEngine), mMainWindow(mainWindow), +mToolbar(toolbar), mMessage(NULL), mScrollArea(NULL), mViewerContent(NULL), @@ -59,8 +65,11 @@ mScreenSize(QSize(0,0)), mWaitDialog(NULL), loadingCompleted(false), -mLatestLoadingSize(QSize(0,0)) -{ +mLatestLoadingSize(QSize(0,0)), +mFetchOperation(NULL), +mAttaIndexUnderFetch(NmNotFoundError), +mAttaWidget(NULL) + { // Create documentloader mDocumentLoader = new NmUiDocumentLoader(mMainWindow); // Get screensize @@ -87,6 +96,8 @@ mWidgetList.clear(); delete mWaitDialog; mWaitDialog = NULL; + delete mFetchOperation; + mFetchOperation = NULL; } /*! @@ -160,14 +171,31 @@ Qt::ScrollBarAlwaysOff); mWebView->page()->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff); - bool connectOk = connect(mWebView->page()->mainFrame(), SIGNAL(contentsSizeChanged(const QSize&)), + bool connectOk = connect(mWebView->page()->mainFrame(), + SIGNAL(contentsSizeChanged(const QSize&)), this, SLOT(scaleWebViewWhenLoading(const QSize&))); } } } + if(!mToolbar) { + // 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); + } } - // call the createToolBar on load view layout - createToolBar(); + if(mStartParam){ + connect(&mUiEngine.messageListModel(mStartParam->mailboxId(), mStartParam->folderId()), + SIGNAL(removeMessage(const NmId&)), this, SLOT(externalDelete(const NmId &))); + } + + if(mToolbar) { + // call the createToolBar on load view layout + createToolBar(); + } // Set mailbox name to title setMailboxName(); } @@ -204,7 +232,7 @@ NmId mailboxId = mStartParam->mailboxId(); NmId folderId = mStartParam->folderId(); NmId msgId = mStartParam->messageId(); - NmMessagePart *body = mMessage->htmlBodyPart(); + const NmMessagePart *body = mMessage->htmlBodyPart(); if (!body) { // try plain to plain text part body = mMessage->plainTextBodyPart(); @@ -230,11 +258,13 @@ delete mWaitDialog; mWaitDialog = NULL; - + // Create new wait dialog and set it to me modal with dimmed background mWaitDialog = new HbProgressDialog(HbProgressDialog::WaitDialog); 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(); } } @@ -309,11 +339,10 @@ } if (page){ // Set custom network access manager for embedded image handling - NmViewerViewNetManager* netMngr = mApplication.networkAccessManager(); - if (netMngr){ - netMngr->setView(this); - page->setNetworkAccessManager(netMngr); - } + NmViewerViewNetManager &netMngr = mApplication.networkAccessManager(); + netMngr.setView(this); + page->setNetworkAccessManager(&netMngr); + connect(page, SIGNAL(loadFinished(bool)), this, SLOT(webFrameLoaded(bool))); page->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); @@ -331,6 +360,129 @@ QObject::connect(page, SIGNAL(linkClicked(const QUrl&)), this, SLOT(linkClicked(const QUrl&))); changeMessageReadStatus(true); + setAttachmentList(); + } +} + +/*! + +*/ +void NmViewerView::setAttachmentList() +{ + // Load headerwidget + mAttaWidget = qobject_cast( + mDocumentLoader->findObject(NMUI_MESSAGE_VIEWER_ATTALIST)); + if (mMessage && mAttaWidget) { + // 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().compare("inline", Qt::CaseInsensitive) && + !(part->contentType().startsWith("image", Qt::CaseInsensitive))) { + 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->id()); + 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); + } + } +} + +/*! + +*/ +void NmViewerView::openAttachment(int index) +{ + // fetch operation should not be running + if (mAttaIndexUnderFetch == NmNotFoundError) { + NmId attaId = mAttaIdList.at(index); + // reload message to get updates part sizes + loadMessage(); + QList messageParts; + mMessage->attachmentList(messageParts); + for (int i = 0; i < messageParts.count(); i++) { + // if message part found and its fetched size is smaller than size start part fetch + if (messageParts[i]->id() == attaId && + messageParts[i]->size() > messageParts[i]->fetchedSize()) { + // delete old message fetch operation + if (mFetchOperation) { + delete mFetchOperation; + mFetchOperation = NULL; + } + // can return null + mFetchOperation = mUiEngine.fetchMessagePart( + mMessage->mailboxId(), + mMessage->parentId(), + mMessage->envelope().id(), + attaId); + if (mFetchOperation) { + mAttaIndexUnderFetch = index; + QObject::connect(mFetchOperation, SIGNAL(operationCompleted(int)), + this, SLOT(attachmentFetchCompleted(int))); + QObject::connect(mFetchOperation, SIGNAL(operationProgressChanged(int)), + this, SLOT(changeProgress(int))); + QObject::connect(this, SIGNAL(progressValueChanged(int, int)), + mAttaWidget, SLOT(setProgressBarValue(int, int))); + // emit signal, set progress to 5% when started + progressValueChanged(index, 5); + } + } + // attachment is fetched, open file + else if (messageParts[i]->id() == attaId) { + XQSharableFile file = mUiEngine.messagePartFile( + mMessage->mailboxId(), + mMessage->parentId(), + mMessage->envelope().id(), + attaId); + NmUtilities::openFile(file); + file.close(); + } + } + } +} + +/*! + +*/ +void NmViewerView::changeProgress(int progressValue) +{ + // find running + if (mAttaIndexUnderFetch != NmNotFoundError) { + // emit signal + if (mAttaWidget && mAttaWidget->progressValue(mAttaIndexUnderFetch) < progressValue) { + progressValueChanged(mAttaIndexUnderFetch, progressValue); + } + } +} + +/*! + +*/ +void NmViewerView::attachmentFetchCompleted(int result) +{ + Q_UNUSED(result); + if (mAttaWidget && mAttaIndexUnderFetch != NmNotFoundError) { + mAttaWidget->setProgressBarValue(mAttaIndexUnderFetch, 100); + mAttaIndexUnderFetch = NmNotFoundError; } } @@ -340,7 +492,6 @@ QString NmViewerView::formatMessage() { QString msg = ""; - QString body = ""; // null pointer check for mMessage is done before calling this function NmMessagePart *html = mMessage->htmlBodyPart(); if (html) { @@ -350,7 +501,10 @@ NmMessagePart *child = parts[i]; // Browse through embedded image parts and add those // the web view. - if (child->contentType().startsWith("image", Qt::CaseInsensitive)) { + quint32 fetchedSize = child->fetchedSize(); + quint32 size = child->size(); + if (fetchedSize >= size && + child->contentType().startsWith("image", Qt::CaseInsensitive)) { QString contentId = child->contentId(); int ret = mUiEngine.contentToMessagePart( mMessage->mailboxId(), @@ -368,9 +522,8 @@ mMessage->envelope().id(), *html); if (ret == NmNoError) { - body = html->textContent(); + msg = html->textContent(); } - msg = body; } else { NmMessagePart *plain = mMessage->plainTextBodyPart(); @@ -380,21 +533,37 @@ mMessage->parentId(), mMessage->envelope().id(), *plain); - if (ret == NmNoError) { - body += escapeSpecialCharacters(plain->textContent()); - } - // Set plain text to viewer according to layout direction - if (qApp->layoutDirection()==Qt::LeftToRight){ - // Define html start and end tags for plain text - QString start = "

"; - QString end = "

"; - msg = start + body + end; - } - else { - // Define html start and end tags for plain text - QString start = "

"; - QString end = "

"; - msg = start + body + end; + if (ret == NmNoError) { + QTextDocument doku; + // set font + QFont currentFont = doku.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()); + } + doku.setDefaultFont(currentFont); + // convert to html + doku.setPlainText(plain->textContent()); + msg = doku.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; } @@ -524,20 +693,22 @@ /*! - Screen orientation changed. Web view needs to be scaled when - landscape <-> portrait switch occurs because text needs to - be wrapped again. + Set new dimensions after orientation change. */ -void NmViewerView::orientationChanged(Qt::Orientation orientation) +void NmViewerView::adjustViewDimensions() { - Q_UNUSED(orientation); // 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()); + } + // Scale web view and its contens if (mWebView){ if (mDisplayingPlainText){ @@ -562,8 +733,22 @@ } } - // Re-create toolbar in orientation switch - createToolBar(); + if(mToolbar) { + // 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())); } /*! @@ -660,30 +845,6 @@ } /*! - Replace html special characters from plain text content. -*/ -QString NmViewerView::escapeSpecialCharacters(const QString text) -{ - const QString amp("&"); - const QString ampReplace("&"); - const QString lt("<"); - const QString ltReplace("<"); - const QString gt(">"); - const QString gtReplace(">"); - const QString quot("\""); - const QString quotReplace("""); - const QString apos("'"); - const QString aposReplace("'"); - QString ret = text; - ret.replace(amp, ampReplace); - ret.replace(lt, ltReplace); - ret.replace(gt, gtReplace); - ret.replace(quot, quotReplace); - ret.replace(apos, aposReplace); - return ret; -} - -/*! Function to set message read status */ void NmViewerView::changeMessageReadStatus(bool read) @@ -752,6 +913,9 @@ tr.translate(webViewRect.topLeft().x()+leftMovementThreshold ,0); } mHeaderWidget->setTransform(tr); + if (mAttaWidget){ + mAttaWidget->setTransform(tr); + } } mLatestScrollPos = newPosition; } @@ -777,6 +941,27 @@ } /*! + 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. */ @@ -784,10 +969,9 @@ { bool showSendInProgressNote = false; - // Handle options menu - if (actionResponse.menuType() == NmActionOptionsMenu) { - } - else if (actionResponse.menuType() == NmActionToolbar) { + // Handle options menu or toolbar + if (actionResponse.menuType() == NmActionOptionsMenu || + actionResponse.menuType() == NmActionToolbar) { switch (actionResponse.responseCommand()) { case NmActionResponseCommandReply: { if (mUiEngine.isSendingMessage()) { @@ -823,6 +1007,28 @@ } break; case NmActionResponseCommandDeleteMail: { + HbMessageBox *messageBox = new HbMessageBox(HbMessageBox::MessageTypeQuestion); + messageBox->setText(hbTrId("txt_mail_dialog_delete_mail")); + messageBox->setTimeout(HbMessageBox::NoTimeout); + + // Read user selection + HbAction *action = messageBox->exec(); + if((action == messageBox->primaryAction())){ + QList messageList; + messageList.append(mStartParam->messageId()); + + int err = mUiEngine.deleteMessages(mStartParam->mailboxId(), + mStartParam->folderId(), + messageList); + + messageList.clear(); + if (NmNoError != err) { + // Failed to delete the messages! + NMLOG(QString("NmViewerView::handleActionCommand(): failed err=%1").arg(err)); + } + } + delete messageBox; + messageBox = NULL; } break; default: @@ -841,3 +1047,15 @@ HbMessageBox::warning(noteText); } } + +/*! + externalDelete. From NmMessageListModel, handles viewer shutdown when current message is deleted. +*/ +void NmViewerView::externalDelete(const NmId &messageId) +{ + if ((mStartParam->viewId()==NmUiViewMessageViewer) && + (mStartParam->messageId()==messageId)){ + mApplication.popView(); + } +} +