diff -r dcf0eedfc1a3 -r d189ee25cf9d emailuis/nmailui/src/nmmessagelistview.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emailuis/nmailui/src/nmmessagelistview.cpp Tue Aug 31 15:04:17 2010 +0300 @@ -0,0 +1,798 @@ +/* +* 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: +* +*/ + +static const char *NMUI_MESSAGE_LIST_VIEW_XML = ":/docml/nmmessagelistview.docml"; +static const char *NMUI_MESSAGE_LIST_VIEW = "NmMessageListView"; +static const char *NMUI_MESSAGE_LIST_TREE_LIST = "MessageTreeList"; +static const char *NMUI_MESSAGE_LIST_NO_MESSAGES = "MessageListNoMessages"; +static const char *NMUI_MESSAGE_LIST_FOLDER_LABEL = "labelGroupBox"; + +#include "nmuiheaders.h" + +/*! + \class NmMessageListView + \brief Message list view +*/ + +/*! + Constructor +*/ +NmMessageListView::NmMessageListView( + NmApplication &application, + NmUiStartParam* startParam, + NmUiEngine &uiEngine, + NmMailboxListModel &mailboxListModel, + NmMessageListModel *messageListModel, + HbDocumentLoader *documentLoader, + QGraphicsItem *parent) +: NmBaseView(startParam, application, parent), +mApplication(application), +mMessageListWidget(NULL), +mUiEngine(uiEngine), +mMailboxListModel(mailboxListModel), +mMessageListModel(messageListModel), +mDocumentLoader(documentLoader), +mItemContextMenu(NULL), +mLongPressedItem(NULL), +mNoMessagesLabel(NULL), +mFolderLabel(NULL), +mViewReady(false), +mCurrentFolderType(NmFolderInbox), +mSettingsLaunched(false), +mPreviousModelCount(0), +mIsFirstSyncInMessageList(true) +{ + NM_FUNCTION; + + loadViewLayout(); + createToolBar(); + initTreeView(); + setMailboxName(); + setFolderName(); +} + +/*! + Destructor +*/ +NmMessageListView::~NmMessageListView() +{ + NM_FUNCTION; + + delete mDocumentLoader; + mWidgetList.clear(); + if (mItemContextMenu){ + mItemContextMenu->clearActions(); + } + delete mItemContextMenu; +} + +/*! + View layout loading from XML +*/ +void NmMessageListView::loadViewLayout() +{ + NM_FUNCTION; + + // Use document loader to load the view + bool ok(false); + setObjectName(QString(NMUI_MESSAGE_LIST_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. + if (mDocumentLoader) { + mDocumentLoader->setObjectTree(objectList); + mWidgetList = mDocumentLoader->load(NMUI_MESSAGE_LIST_VIEW_XML, &ok); + } + + if (ok) { + // Get message list widget + mMessageListWidget = qobject_cast + (mDocumentLoader->findWidget(NMUI_MESSAGE_LIST_TREE_LIST)); + + if (mMessageListWidget) { + NM_COMMENT("nmailui: list object loaded"); + + // Set item prototype. + mMessageListWidget->setItemPrototype(new NmMessageListViewItem()); + + // Set the list widget properties. + mMessageListWidget->setItemRecycling(true); + mMessageListWidget->contentWidget()->setProperty("indentation", 0); + mMessageListWidget->setScrollDirections(Qt::Vertical); + mMessageListWidget->setClampingStyle(HbScrollArea::BounceBackClamping); + mMessageListWidget->setFrictionEnabled(true); + mMessageListWidget->setItemPixmapCacheEnabled(true); + + // Enable animations to display an email as soon as it is added to + // the list. + mMessageListWidget->setEnabledAnimations(HbAbstractItemView::Appear & + HbAbstractItemView::Expand); + } + else { + NM_ERROR(1,"nmailui: list object loading failed"); + } + + mNoMessagesLabel = qobject_cast + (mDocumentLoader->findWidget(NMUI_MESSAGE_LIST_NO_MESSAGES)); + if (mNoMessagesLabel) { + mNoMessagesLabel->hide(); + } + else{ + NM_ERROR(1,"nmailui: (no messages) object loading failed"); + } + + mFolderLabel = qobject_cast(mDocumentLoader->findWidget(NMUI_MESSAGE_LIST_FOLDER_LABEL)); + + // Connect options menu about to show to create options menu function + QObject::connect(menu(), SIGNAL(aboutToShow()), + this, SLOT(createOptionsMenu())); + QObject::connect(&mUiEngine, SIGNAL(syncStateEvent(NmSyncState, const NmId &)), + this, SLOT(handleSyncStateEvent(NmSyncState, const NmId &))); + + // Menu needs one dummy item so that aboutToShow signal is emitted. + NmAction *dummy = new NmAction(0); + menu()->addAction(dummy); + // Set sync icon if needed + updateSyncIcon(); + } + else { + NM_ERROR(1,"nmailui: resource loading failed"); + } +} + +/*! + Lazy loading when view layout has been loaded +*/ +void NmMessageListView::viewReady() +{ + NM_FUNCTION; + + if (!mViewReady){ + // Refresh list + QMetaObject::invokeMethod(this, "refreshList", Qt::QueuedConnection); + mViewReady=true; + } + mSettingsLaunched = false; +} + +/*! + Getter for currently displayed folder type +*/ +NmFolderType NmMessageListView::folderType() +{ + NM_FUNCTION; + + return mCurrentFolderType; +} + +/*! + okToExitView. Message list view determines whether it is + ok to exit view and calls mapplication popview. +*/ +void NmMessageListView::okToExitView() +{ + NM_FUNCTION; + + // Close view if current folder is inbox + if (mCurrentFolderType==NmFolderInbox){ + mApplication.popView(); + } + // Switch to inbox + else{ + mSelectedMailboxId=mStartParam->mailboxId(); + mSelectedFolderId=mUiEngine.standardFolderId(mSelectedMailboxId,NmFolderInbox); + QMetaObject::invokeMethod(this, "folderSelected", Qt::QueuedConnection); + } +} + +/*! + initTreeView +*/ +void NmMessageListView::initTreeView() +{ + NM_FUNCTION; + + // Get mailbox widget pointer and set parameters + if (mMessageListWidget){ + QObject::connect(mMessageListWidget, + SIGNAL(activated(const QModelIndex &)), this, + SLOT(itemActivated(const QModelIndex &))); + QObject::connect(mMessageListWidget, + SIGNAL(longPressed(HbAbstractViewItem*, QPointF)), this, + SLOT(showItemContextMenu(HbAbstractViewItem*, QPointF))); + mMessageListWidget->setFocus(); + } +} + + +/*! + Reload view contents with new start parameters + Typically when view is already open and external view activation occurs + for this same view. Startparam ownership is transferred to this view +*/ +void NmMessageListView::reloadViewContents(NmUiStartParam* startParam) +{ + NM_FUNCTION; + + // Check start parameter validity, message view cannot + // be updated if given parameter is zero. + if (startParam&&startParam->viewId()==NmUiViewMessageList && + startParam->mailboxId() != 0 ) { + // Delete existing start parameter data + delete mStartParam; + mStartParam = NULL; + // Store new start parameter data + mStartParam = startParam; + // Disconnect signals from previous model + QObject::disconnect(mMessageListModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), + this, SLOT(itemsAdded(const QModelIndex&,int,int))); + QObject::disconnect(mMessageListModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), + this, SLOT(itemsRemoved())); + QObject::disconnect(mMessageListModel, SIGNAL(setNewParam(NmUiStartParam*)), + this, SLOT(reloadViewContents(NmUiStartParam*))); + // Update model pointer and refresh mailbox with new model + mMessageListModel = &mUiEngine.messageListModel(startParam->mailboxId(), startParam->folderId()); + + refreshList(); + + // Refresh the mailbox name + setMailboxName(); + + // Store active folder type + mCurrentFolderType=NmFolderInbox; + if (startParam->folderId()!=0){ + mCurrentFolderType = mUiEngine.folderTypeById(startParam->mailboxId(),startParam->folderId()); + } + + // Update folder name + setFolderName(); + + // Set sync icon if needed + updateSyncIcon(); + + // Reconstruct the tool bar. This needed because, for example, the + // search button needs the new mailbox ID. + createToolBar(); + } + else { + NM_ERROR(1,"nmailui: invalid message list start parameter"); + // Unused start parameter needs to be deleted + delete startParam; + } +} + + +/*! + Return view id +*/ +NmUiViewId NmMessageListView::nmailViewId() const +{ + NM_FUNCTION; + + return NmUiViewMessageList; +} + + +/*! + Refresh the message list. +*/ +void NmMessageListView::refreshList() +{ + NM_FUNCTION; + + if (mMessageListModel) { + NmId mailboxId = mStartParam->mailboxId(); + + // In each refresh, e.g. in folder change the UI signals lower layer + // about the folder that has been opened. + if (mStartParam){ + mUiEngine.updateActiveFolder(mailboxId, mStartParam->folderId()); + + NmFolderType folderType(NmFolderInbox); + if (mStartParam->folderId()!= 0){ + folderType = mUiEngine.folderTypeById(mStartParam->mailboxId(), + mStartParam->folderId()); + } + + // If the new folder is an inbox, first automatic sync should be shown + if (folderType == NmFolderInbox) { + mIsFirstSyncInMessageList = true; + } + } + + // Set item model to message list widget + if (mMessageListWidget) { + mMessageListWidget->setModel(static_cast(mMessageListModel)); + + QObject::connect(mMessageListModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), + this, SLOT(itemsAdded(const QModelIndex&,int,int)),Qt::UniqueConnection); + QObject::connect(mMessageListModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), + this, SLOT(itemsRemoved()),Qt::UniqueConnection); + QObject::connect(mMessageListModel, SIGNAL(setNewParam(NmUiStartParam*)), + this, SLOT(reloadViewContents(NmUiStartParam*)),Qt::UniqueConnection); + + mPreviousModelCount=mMessageListModel->rowCount(); + + if (mPreviousModelCount == 0) { + showNoMessagesText(); + } + else { + hideNoMessagesText(); + } + } + + // Notify the mail agent. + NmUiEventsNotifier::notifyViewStateChanged(NmUiEventsNotifier::NmViewShownEvent, + NmUiViewMessageList, + mStartParam->mailboxId()); + } +} + + +/*! + Sync state event handling +*/ +void NmMessageListView::handleSyncStateEvent(NmSyncState syncState, const NmId &mailboxId) +{ + NM_FUNCTION; + if (mMessageListModel && mailboxId == mMessageListModel->currentMailboxId()) { + if (syncState == Synchronizing) { + // before first sync inbox id might be zero + if (mStartParam->folderId() == 0) { + // after sync inbox id should be updated to correct value + NmId folderId = mUiEngine.standardFolderId( + mStartParam->mailboxId(), + NmFolderInbox); + mStartParam->setFolderId(folderId); + } + // Show sync icon only for the first automatic sync after opening message list. + // Sync icon for manual sync is shown in NmUiEngine::refreshMailbox, not here. + if (mIsFirstSyncInMessageList) { + // Show the indicator only if the application is in the foreground + if (mApplication.isForeground()) { + mUiEngine.enableSyncIndicator(true); + } + mIsFirstSyncInMessageList = false; + } + } + } +} + +/*! + folder selection handling within current mailbox +*/ +void NmMessageListView::folderSelected() +{ + NM_FUNCTION; + + // Reload view contents with new startparams if mailbox or folder + // id is different than current values. + if (mStartParam && (mStartParam->mailboxId()!=mSelectedMailboxId|| + mStartParam->folderId()!=mSelectedFolderId)){ + // Create start params + NmUiStartParam* startParam = new NmUiStartParam(NmUiViewMessageList, + mSelectedMailboxId, + mSelectedFolderId); + // Store active folder type + mCurrentFolderType=NmFolderInbox; + if (startParam->folderId()!=0){ + mCurrentFolderType = mUiEngine.folderTypeById(startParam->mailboxId(),startParam->folderId()); + } + // Reload view, ownership of the startparams is passed and old startparams + // are deleted within reloadViewContents function + reloadViewContents(startParam); + // Set folder text to status bar + setFolderName(); + } +} + + +/*! + Long keypress handling +*/ +void NmMessageListView::showItemContextMenu(HbAbstractViewItem *listViewItem, const QPointF &coords) +{ + NM_FUNCTION; + + if (listViewItem) { + // Recreate item context menu each time it is called + if (mItemContextMenu){ + mItemContextMenu->clearActions(); + delete mItemContextMenu; + mItemContextMenu=NULL; + } + mItemContextMenu = new HbMenu(); + // Store long press item for later use with response + mLongPressedItem = mMessageListModel->data( + listViewItem->modelIndex(), Qt::DisplayRole).value(); + if (mItemContextMenu && mLongPressedItem && mLongPressedItem->itemType() == + NmMessageListModelItem::NmMessageItemMessage) { + + // Clear previous items from context menu + mItemContextMenu->clearActions(); + NmUiExtensionManager &extMngr = mApplication.extManager(); + QList list; + // Fetch items from extension based on item + NmMessageEnvelope *envelope = mLongPressedItem->envelopePtr(); + if (envelope){ + NmActionRequest request(this, NmActionContextMenu, NmActionContextViewMessageList, + NmActionContextDataMessage, mStartParam->mailboxId(), mStartParam->folderId(), + envelope->messageId(),QVariant::fromValue(envelope)); + extMngr.getActions(request, list); + for (int i=0;iaddAction(list[i]); + } + mItemContextMenu->setPreferredPos(coords); + mItemContextMenu->open(); + } + } + } +} + +/*! + Item activation handling. Expand/collapse for title dividers + opening for mail items +*/ +void NmMessageListView::itemActivated(const QModelIndex &index) +{ + NM_FUNCTION; + + mActivatedIndex = index; + QMetaObject::invokeMethod(this, "handleSelection", Qt::QueuedConnection); +} + +/*! + Item activation handling. Expand/collapse for title dividers + opening for mail items +*/ +void NmMessageListView::handleSelection() +{ + NM_FUNCTION; + + // Do expand/collapse for title divider items + NmMessageListModelItem* modelItem = mMessageListModel->data( + mActivatedIndex, Qt::DisplayRole).value(); + if (modelItem && modelItem->itemType()== + NmMessageListModelItem::NmMessageItemTitleDivider) { + if (!mMessageListWidget->isExpanded(mActivatedIndex)) { + mMessageListWidget->setExpanded(mActivatedIndex, true); + modelItem->setExpanded(true); + } + else { + mMessageListWidget->setExpanded(mActivatedIndex, false); + modelItem->setExpanded(false); + } + } + if (modelItem && modelItem->itemType() == NmMessageListModelItem::NmMessageItemMessage + && !mSettingsLaunched) + { + NmFolderType folderType = mUiEngine.folderTypeById(mStartParam->mailboxId(), + mStartParam->folderId()); + if (folderType==NmFolderDrafts){ + NmUiStartParam *startParam = new NmUiStartParam(NmUiViewMessageEditor, + mStartParam->mailboxId(), mStartParam->folderId(), + modelItem->envelope().messageId(),NmUiEditorFromDrafts); + mApplication.enterNmUiView(startParam); + } + else if (folderType!=NmFolderOutbox){ + NmUiStartParam *startParam = new NmUiStartParam(NmUiViewMessageViewer, + mStartParam->mailboxId(), mStartParam->folderId(), + modelItem->envelope().messageId()); + mApplication.enterNmUiView(startParam); + } + } +} + + + +/*! + createOptionsMenu. Functions asks menu commands from extension + to be added to options menu. +*/ +void NmMessageListView::createOptionsMenu() +{ + NM_FUNCTION; + + menu()->clearActions(); + NmActionRequest request(this, NmActionOptionsMenu, NmActionContextViewMessageList, + NmActionContextDataNone, mStartParam->mailboxId(), mStartParam->folderId() ); + NmUiExtensionManager &extMngr = mApplication.extManager(); + QList list; + extMngr.getActions(request, list); + for (int i=0;iaddAction(list[i]); + } +} + +/*! + handleActionCommand. From NmMenuObserver, extension manager calls this + call to handle menu command in the UI. +*/ +void NmMessageListView::handleActionCommand(NmActionResponse &actionResponse) +{ + NM_FUNCTION; + + // Handle context menu commands here + if (actionResponse.menuType() == NmActionOptionsMenu) { + switch (actionResponse.responseCommand()) { + case NmActionResponseCommandNewMail: { + // Check that given start response has mailbox and folder id's + if (actionResponse.mailboxId()!=0){ + NmUiStartParam *startParam = new NmUiStartParam(NmUiViewMessageEditor, + actionResponse.mailboxId(), mStartParam->folderId()); + // startParam ownerhips transfers + mApplication.enterNmUiView(startParam); + } + break; + } + case NmActionResponseCommandUpdateMailboxName: { + setMailboxName(); + break; + } + case NmActionResponseCommandMailboxDeleted: { + mApplication.prepareForPopView(); + break; + } + case NmActionResponseCommandSwitchFolder: { + mSelectedFolderId=actionResponse.folderId(); + mSelectedMailboxId=actionResponse.mailboxId(); + QMetaObject::invokeMethod(this, "folderSelected", Qt::QueuedConnection); + break; + } + case NmActionResponseCommandSettings: { + mSettingsLaunched = true; + break; + } + default: { + break; + } + } + } + + // Handle context menu commands here + else if (actionResponse.menuType()==NmActionContextMenu){ + switch (actionResponse.responseCommand()){ + case NmActionResponseCommandOpen:{ + if (mLongPressedItem){ + NmUiStartParam *startParam = new NmUiStartParam(NmUiViewMessageViewer, + mStartParam->mailboxId(), mStartParam->folderId(), + mLongPressedItem->envelope().messageId()); + mApplication.enterNmUiView(startParam); + mLongPressedItem=NULL; + } + } + break; + default: + break; + } + } + + // Handle toolbar commands here + else if ( actionResponse.menuType() == NmActionToolbar ) { + if ( actionResponse.responseCommand() == NmActionResponseCommandNewMail ) { + // Check that given start response has mailbox and folder id's + if (actionResponse.mailboxId()!=0){ + NmUiStartParam *startParam = new NmUiStartParam(NmUiViewMessageEditor, + actionResponse.mailboxId(), mStartParam->folderId()); + // startParam ownerhips transfers + mApplication.enterNmUiView(startParam); + } + } + if (actionResponse.responseCommand() == NmActionResponseCommandSearch) { + // Check that the given start response has mailbox and folder IDs. + if (actionResponse.mailboxId() != 0) { + NmUiStartParam *startParam = + new NmUiStartParam(NmUiViewMessageSearchList, + actionResponse.mailboxId(), + mStartParam->folderId()); + + // startParam ownership transfers. + mApplication.enterNmUiView(startParam); + } + } + } +} + + +/*! + Set mailbox name to title +*/ +void NmMessageListView::setMailboxName() +{ + NM_FUNCTION; + + if (mStartParam){ + NmMailboxMetaData *meta = mUiEngine.mailboxById(mStartParam->mailboxId()); + if (meta){ + setTitle(meta->name()); + } + } +} + +/*! + createToolBar. Function asks menu commands from extension + to be added to toolbar owned by the HbView. Also toolbar + specific icons are added in this function. +*/ +void NmMessageListView::createToolBar() +{ + NM_FUNCTION; + + HbToolBar *tb = toolBar(); + if (!tb) { + return; + } + tb->clearActions(); + NmActionRequest request(this, NmActionToolbar, NmActionContextViewMessageList, + NmActionContextDataNone, mStartParam->mailboxId(), mStartParam->folderId() ); + NmUiExtensionManager &extMngr = mApplication.extManager(); + if (!&extMngr) { + return; + } + QList list; + extMngr.getActions(request, list); + for (int i = 0; i < list.count(); i++) { + tb->addAction(list[i]); + } +} + +/*! + setFolderName. Function sets folder name to status bar +*/ +void NmMessageListView::setFolderName() +{ + NM_FUNCTION; + + if (mStartParam && mFolderLabel){ + switch (mCurrentFolderType) { + case NmFolderOutbox: + { + mFolderLabel->setHeading(hbTrId("txt_mail_subhead_outbox")); + } + break; + case NmFolderDrafts: + { + mFolderLabel->setHeading(hbTrId("txt_mail_subhead_drafts")); + } + break; + case NmFolderSent: + { + mFolderLabel->setHeading(hbTrId("txt_mail_subhead_sent_items")); + } + break; + case NmFolderDeleted: + { + mFolderLabel->setHeading(hbTrId("txt_mail_subhead_deleted_items")); + } + break; + case NmFolderInbox: + default: + { + mFolderLabel->setHeading(hbTrId("txt_mail_subhead_inbox")); + } + break; + } + } +} + + +/*! + Handles the addition of a new item. Makes sure the message list widget is + visible and keeps the scroll position on the top of the list. + + \param parent Not used. + \param start + \param end Not used. +*/ +void NmMessageListView::itemsAdded(const QModelIndex &parent, int start, int end) +{ + NM_FUNCTION; + + Q_UNUSED(parent); + Q_UNUSED(end); + + // Hide no messages if previous model count has been zero + // and new items have been added to the list + if (mPreviousModelCount==0) { + hideNoMessagesText(); + } + + // Make sure the top of the list is kept visible by scrolling back to the + // top if necessary. + if (start == 0 && mMessageListWidget) { + QList items = mMessageListWidget->visibleItems(); + + if (items.count()) { + QModelIndex index = items.at(0)->modelIndex(); + + while (index.row() > 0) { + QModelIndex previous = + mMessageListWidget->modelIterator()->previousIndex(index); + + if (previous.isValid()) { + mMessageListWidget->scrollTo(previous); + } + + index = previous; + } + } + } + // Store model count + if (mMessageListModel){ + mPreviousModelCount=mMessageListModel->rowCount(); + } +} + + +/*! + Observe items removed +*/ +void NmMessageListView::itemsRemoved() +{ + NM_FUNCTION; + // Store model count + if (mMessageListModel){ + mPreviousModelCount=mMessageListModel->rowCount(); + } + if (mPreviousModelCount == 0){ + showNoMessagesText(); + } +} + +/*! + Show "(no messages)" text at the middle of the screen. +*/ +void NmMessageListView::showNoMessagesText() +{ + NM_FUNCTION; + + if (mNoMessagesLabel&&mMessageListWidget) { + mMessageListWidget->hide(); + mNoMessagesLabel->show(); + } +} + +/*! + Hide "(no messages)" text at the middle of the screen. +*/ +void NmMessageListView::hideNoMessagesText() +{ + NM_FUNCTION; + + if (mNoMessagesLabel&&mMessageListWidget) { + mNoMessagesLabel->hide(); + mMessageListWidget->show(); + } +} + +/*! + Updates sync icon based on sync status from the plugin. +*/ +void NmMessageListView::updateSyncIcon() +{ + if (mStartParam) { + NmSyncState syncState = mUiEngine.syncState(mStartParam->mailboxId()); + if (syncState==Synchronizing) { + mUiEngine.enableSyncIndicator(true); + } + else { + mUiEngine.enableSyncIndicator(false); + } + } +} +