/*
* 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";
// Old sync icon implementation commented out but preserved so it could be put back if need be
// static const char *NMUI_MESSAGE_LIST_SYNC_ICON = "syncIcon";
#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),
mSyncIcon(NULL),
mViewReady(false),
mCurrentFolderType(NmFolderInbox),
mSettingsLaunched(false)
{
NM_FUNCTION;
// Load view layout
loadViewLayout();
// Init tree view
initTreeView();
// set title
setMailboxName();
// Set folder name
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 == true && mWidgetList.count()) {
// Get message list widget
mMessageListWidget = qobject_cast<HbTreeView *>
(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);
// 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<HbLabel *>
(mDocumentLoader->findWidget(NMUI_MESSAGE_LIST_NO_MESSAGES));
if (mNoMessagesLabel) {
mNoMessagesLabel->hide();
}
else{
NM_ERROR(1,"nmailui: (no messages) object loading failed");
}
mFolderLabel = qobject_cast<HbGroupBox *>(mDocumentLoader->findWidget(NMUI_MESSAGE_LIST_FOLDER_LABEL));
// Disable the old sync icon implementation for the time being (commment out loading the icon here)
//mSyncIcon = qobject_cast<HbLabel *>(mDocumentLoader->findWidget(NMUI_MESSAGE_LIST_SYNC_ICON));
if (mSyncIcon) {
mSyncIcon->setIcon(NmIcons::getIcon(NmIcons::NmIconOffline));
}
// 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 &)));
QObject::connect(&mUiEngine, SIGNAL(connectionEvent(NmConnectState, const NmId &)),
this, SLOT(handleConnectionEvent(NmConnectState, const NmId &)));
// Menu needs one dummy item so that aboutToShow signal is emitted.
NmAction *dummy = new NmAction(0);
menu()->addAction(dummy);
}
else {
NM_ERROR(1,"nmailui: resource loading failed");
}
}
/*!
Lazy loading when view layout has been loaded
*/
void NmMessageListView::viewReady()
{
NM_FUNCTION;
if (!mViewReady){
// Set mailbox name to title pane
setMailboxName();
//create toolbar
createToolBar();
// 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();
mItemContextMenu = new HbMenu();
}
}
/*!
Reload view contents with new start parameters
Typically when view is already open and external view activation occurs
for this same 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->folderId()!=0) {
// Delete existing start parameter data
delete mStartParam;
mStartParam=NULL;
// Store new start parameter data
mStartParam=startParam;
// Update the model with new parameters
mMessageListModel = &mUiEngine.messageListModel(startParam->mailboxId(), startParam->folderId());
refreshList();
// Refresh the mailboxname
setMailboxName();
}
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 list
*/
void NmMessageListView::refreshList()
{
NM_FUNCTION;
NmId mailboxId = mMessageListModel->currentMailboxId();
if (mSyncIcon && mailboxId == mMessageListModel->currentMailboxId()) {
if (mUiEngine.syncState(mailboxId) == Synchronizing) {
mSyncIcon->setIcon(NmIcons::getIcon(NmIcons::NmIconSynching));
}
else {
if (mUiEngine.connectionState(mailboxId) == Connected) {
mSyncIcon->setIcon(NmIcons::getIcon(NmIcons::NmIconOnline));
}
else {
mSyncIcon->setIcon(NmIcons::getIcon(NmIcons::NmIconOffline));
}
}
}
// 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());
}
// Set item model to message list widget
if (mMessageListWidget) {
mMessageListWidget->setModel(static_cast<QStandardItemModel*>(mMessageListModel));
QObject::connect(mMessageListModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)),
this, SLOT(itemsAdded(const QModelIndex&,int,int)));
QObject::connect(mMessageListModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)),
this, SLOT(itemsRemoved()));
QObject::connect(mMessageListModel, SIGNAL(setNewParam(NmUiStartParam*)),
this, SLOT(reloadViewContents(NmUiStartParam*)));
if (mMessageListModel->rowCount()==0){
showNoMessagesText();
}
else{
hideNoMessagesText();
}
}
}
/*!
Sync state event handling
*/
void NmMessageListView::handleSyncStateEvent(NmSyncState syncState, const NmId & mailboxId)
{
NM_FUNCTION;
if (mSyncIcon && mailboxId == mMessageListModel->currentMailboxId()) {
if (syncState == Synchronizing) {
mSyncIcon->setIcon(NmIcons::getIcon(NmIcons::NmIconSynching));
// 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);
}
}
else {
if (mUiEngine.connectionState(mailboxId) == Connected) {
mSyncIcon->setIcon(NmIcons::getIcon(NmIcons::NmIconOnline));
}
else {
mSyncIcon->setIcon(NmIcons::getIcon(NmIcons::NmIconOffline));
}
}
}
}
/*!
Connection event handling
*/
void NmMessageListView::handleConnectionEvent(NmConnectState connectState, const NmId &mailboxId)
{
NM_FUNCTION;
if (mSyncIcon && mailboxId == mMessageListModel->currentMailboxId() && mUiEngine.syncState(mailboxId) != Synchronizing) {
if (connectState == Connected) {
mSyncIcon->setIcon(NmIcons::getIcon(NmIcons::NmIconOnline));
}
else {
mSyncIcon->setIcon(NmIcons::getIcon(NmIcons::NmIconOffline));
}
}
}
/*!
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 = 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) {
// Store long press item for later use with response
mLongPressedItem = mMessageListModel->data(
listViewItem->modelIndex(), Qt::DisplayRole).value<NmMessageListModelItem*>();
if (mItemContextMenu && mLongPressedItem && mLongPressedItem->itemType() ==
NmMessageListModelItem::NmMessageItemMessage) {
// Clear previous items from context menu
mItemContextMenu->clearActions();
NmUiExtensionManager &extMngr = mApplication.extManager();
QList<NmAction*> 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;i<list.count();i++) {
mItemContextMenu->addAction(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<NmMessageListModelItem*>();
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<NmAction*> list;
extMngr.getActions(request, list);
for (int i=0;i<list.count();i++) {
menu()->addAction(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){
if (mUiEngine.isSendingMessage()) {
// sending is ongoing so just show a note
QString noteText = hbTrId("txt_mail_dialog_still_sending");
// get message subject from the message being sent
const NmMessage *message = mUiEngine.messageBeingSent();
if (message) {
noteText = noteText.arg(NmUtilities::truncate(message->envelope().subject(), 20));
}
HbMessageBox::warning(noteText);
}
else {
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) {
if (mUiEngine.isSendingMessage()) {
// Sending is ongoing so just show a note.
QString noteText = hbTrId("txt_mail_dialog_still_sending");
// Get the message subject from the message being sent.
const NmMessage *message = mUiEngine.messageBeingSent();
if (message) {
noteText = noteText.arg(
NmUtilities::truncate(message->envelope().subject(), 20));
}
HbMessageBox::warning(noteText);
}
else {
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<NmAction *> 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);
// If "no messages" label is shown, hide it and display the message list
// widget.
if (mNoMessagesLabel && mNoMessagesLabel->isVisible()) {
mNoMessagesLabel->hide();
mMessageListWidget->show();
}
// Make sure the top of the list is kept visible by scrolling back to the
// top if necessary.
if (start == 0 && mMessageListWidget) {
QList<HbAbstractViewItem*> 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;
}
}
}
}
/*!
Observe items removed
*/
void NmMessageListView::itemsRemoved()
{
NM_FUNCTION;
if (mMessageListModel && mMessageListModel->rowCount() == 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();
}
}