emailuis/nmailui/src/nmmessagesearchlistview.cpp
changeset 23 2dc6caa42ec3
child 27 9ba4404ef423
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emailuis/nmailui/src/nmmessagesearchlistview.cpp	Fri May 14 15:41:10 2010 +0300
@@ -0,0 +1,673 @@
+/*
+* Copyright (c) 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_SEARCH_LIST_VIEW_XML = ":/docml/nmmessagesearchlistview.docml";
+static const char *NMUI_MESSAGE_SEARCH_LIST_VIEW = "NmMessageListView";
+static const char *NMUI_MESSAGE_SEARCH_LIST_TREE_LIST = "MessageTreeList";
+static const char *NMUI_MESSAGE_SEARCH_LIST_NO_MESSAGES = "MessageListNoMessages";
+static const char *NMUI_MESSAGE_SEARCH_LIST_INFO_LABEL = "InfoLabel";
+static const char *NMUI_MESSAGE_SEARCH_LIST_LINE_EDIT = "LineEdit";
+static const char *NMUI_MESSAGE_SEARCH_LIST_PUSH_BUTTON = "PushButton";
+
+
+#include "nmuiheaders.h"
+
+
+/*!
+    \class NmMessageSearchListView
+    \brief The view for searching messages.
+*/
+
+
+/*!
+    Class constructor.
+*/
+NmMessageSearchListView::NmMessageSearchListView(
+    NmApplication &application,
+    NmUiStartParam* startParam,
+    NmUiEngine &uiEngine,
+    NmMessageSearchListModel &searchListModel,
+    HbDocumentLoader *documentLoader,
+    QGraphicsItem *parent)
+: NmBaseView(startParam, parent),
+  mApplication(application),
+  mUiEngine(uiEngine),
+  mSearchListModel(searchListModel),
+  mDocumentLoader(documentLoader),
+  mItemContextMenu(NULL),
+  mMessageListWidget(NULL),
+  mNoMessagesLabel(NULL),
+  mInfoLabel(NULL),
+  mLineEdit(NULL),
+  mPushButton(NULL),
+  mLongPressedItem(NULL),
+  mViewReady(false),
+  mSearchInProgress(false)
+{
+    loadViewLayout();
+    initTreeView();
+}
+
+
+/*!
+    Class destructor.
+*/
+NmMessageSearchListView::~NmMessageSearchListView()
+{
+    delete mDocumentLoader;
+
+    mWidgetList.clear();
+
+    if (mItemContextMenu){
+        mItemContextMenu->clearActions();
+    }
+
+    delete mItemContextMenu;
+}
+
+
+/*!
+    From NmBaseView.
+
+    Returns the view ID.
+
+    \return The view ID.
+*/
+NmUiViewId NmMessageSearchListView::nmailViewId() const
+{
+    return NmUiViewMessageSearchList;
+}
+
+
+/*!
+    From NmBaseView.
+
+    Does the lazy loading after the view layout has been loaded.
+*/
+void NmMessageSearchListView::viewReady()
+{
+    if (!mViewReady){
+        // Set the mailbox name to the title pane.
+        setViewTitle();
+
+        // Refresh the list.
+        QMetaObject::invokeMethod(this, "refreshList", Qt::QueuedConnection);
+
+        // Highlight the search input.
+        setSearchInputMode(NmHighlightedMode);
+
+        mViewReady = true;
+    }
+}
+
+
+/*!
+    From NmMenuObserver.
+
+    Handles action commands which are usually given by the user by selecting
+    menu items.
+
+    \param actionResponse The command details.
+*/
+void NmMessageSearchListView::handleActionCommand(NmActionResponse &actionResponse)
+{
+    // Handle options menu commands here.
+    if (actionResponse.menuType() == NmActionOptionsMenu) {
+        switch (actionResponse.responseCommand()) {
+            case NmActionResponseCommandUpdateMailboxName: {
+                setViewTitle();
+                break;
+            }
+            case NmActionResponseCommandMailboxDeleted: {
+                mApplication.popView();
+                break;
+            }
+            default: {
+                break;
+            }
+        }
+    }
+}
+
+
+/*!
+    From NmBaseView.
+
+    Loads the view layout from the XML file.
+*/
+void NmMessageSearchListView::loadViewLayout()
+{
+    // Use the document loader to load the view layout.
+    bool ok(false);
+    setObjectName(QString(NMUI_MESSAGE_SEARCH_LIST_VIEW));
+    QObjectList objectList;
+    objectList.append(this);
+
+    // Pass the view to the document loader. Instead of creating a new view, the
+    // document loader uses this view when the docml file is parsed.
+    if (mDocumentLoader) {
+        mDocumentLoader->setObjectTree(objectList);
+        mWidgetList = mDocumentLoader->load(NMUI_MESSAGE_SEARCH_LIST_VIEW_XML, &ok);
+    }
+
+    if (ok && mWidgetList.count()) {
+        // Get the message list widget.
+        mMessageListWidget = qobject_cast<HbTreeView *>(
+            mDocumentLoader->findWidget(NMUI_MESSAGE_SEARCH_LIST_TREE_LIST));
+
+        if (mMessageListWidget) {
+            NMLOG("NmMessageSearchListView: Message list widget loaded.");
+
+            // Set the item prototype.
+            mMessageListWidget->setItemPrototype(new NmMessageListViewItem());
+            mMessageListWidget->setItemRecycling(true);
+            mMessageListWidget->contentWidget()->setProperty("indentation", 0);
+            mMessageListWidget->setScrollDirections(Qt::Vertical);
+            mMessageListWidget->setClampingStyle(HbScrollArea::BounceBackClamping);
+            mMessageListWidget->setFrictionEnabled(true);
+        }
+
+        // Load the "no messages" label.
+        mNoMessagesLabel = qobject_cast<HbLabel *>(
+            mDocumentLoader->findWidget(NMUI_MESSAGE_SEARCH_LIST_NO_MESSAGES));
+
+        if (mNoMessagesLabel) {
+            NMLOG("NmMessageSearchListView: \"No messages\" label loaded.");
+            mNoMessagesLabel->hide();
+        }
+
+        // Load the info label.
+        mInfoLabel = qobject_cast<HbLabel *>(
+            mDocumentLoader->findWidget(NMUI_MESSAGE_SEARCH_LIST_INFO_LABEL));
+
+        if (mInfoLabel) {
+            NMLOG("NmMessageSearchListView: Info label loaded.");
+            mInfoLabel->setPlainText(hbTrId("txt_mail_subhead_inbox"));
+            mInfoLabel->hide();
+        }
+
+        // Load the search panel.
+        mLineEdit = qobject_cast<HbLineEdit *>(
+            mDocumentLoader->findWidget(NMUI_MESSAGE_SEARCH_LIST_LINE_EDIT));
+        if (mLineEdit) {
+            connect(mLineEdit, SIGNAL(textChanged(QString)), 
+                this, SLOT(criteriaChanged(QString)));
+        }
+        
+        mPushButton = qobject_cast<HbPushButton *>(
+            mDocumentLoader->findWidget(NMUI_MESSAGE_SEARCH_LIST_PUSH_BUTTON));
+        if (mPushButton) {
+			// button is disabled when line edit is empty
+			mPushButton->setEnabled(false);
+            // The push button both starts and stops the search.
+            connect(mPushButton, SIGNAL(clicked()), this, SLOT(toggleSearch()));
+            mPushButton->setIcon(HbIcon("qtg_mono_search"));
+        }
+    }
+    else {
+        NMLOG("NmMessageSearchListView: Failed to load widgets from XML!");
+    }
+}
+
+
+/*!
+    Initializes the tree view.
+*/
+void NmMessageSearchListView::initTreeView()
+{
+    // Get the mailbox widget pointer and set the parameters.
+    if (mMessageListWidget) {
+        connect(mMessageListWidget, SIGNAL(activated(const QModelIndex &)),
+                this, SLOT(itemActivated(const QModelIndex &)));
+
+        connect(mMessageListWidget, SIGNAL(longPressed(HbAbstractViewItem*, QPointF)),
+                this, SLOT(showItemContextMenu(HbAbstractViewItem*, QPointF)));
+
+        mMessageListWidget->setFocus();
+        mItemContextMenu = new HbMenu();
+    }
+
+    // Clear the previous content if any.
+    mSearchListModel.clearSearchResults();
+}
+
+
+/*!
+    Sets the title according to the name of the current mailbox.
+*/
+void NmMessageSearchListView::setViewTitle()
+{
+    if (mStartParam){
+        NmMailboxMetaData *meta = mUiEngine.mailboxById(mStartParam->mailboxId());
+
+        if (meta){
+            setTitle(meta->name());
+        }
+    }
+}
+
+
+/*!
+    Toggles the visiblity between the message list widget and the "no messages"
+    label.
+
+    \param visible If true, will display the "no messages" label. If false,
+                   will display the message list widget.
+*/
+void NmMessageSearchListView::noMessagesLabelVisibility(bool visible)
+{
+    if (visible) {
+        // Hide the message list widget and display the "no messages" label.
+        if (mMessageListWidget) {
+            mMessageListWidget->hide();
+        }
+
+        if (mNoMessagesLabel && !mNoMessagesLabel->isVisible()) {
+            mNoMessagesLabel->show();
+        }
+    }
+    else {
+        // Hide the "no messages" label and display the message list widget.
+        if (mNoMessagesLabel && mNoMessagesLabel->isVisible()) {
+            mNoMessagesLabel->hide();
+        }
+
+        if (mMessageListWidget) {
+            mMessageListWidget->show();
+        }
+    }
+}
+
+
+/*!
+    Sets the mode for the search input.
+
+    \param mode The mode to set.
+*/
+void NmMessageSearchListView::setSearchInputMode(NmSearchInputMode mode)
+{
+    if (!mLineEdit) {
+        // No line edit widget!
+        return;
+    }
+
+    switch (mode) {
+        case NmNormalMode: {
+            mLineEdit->setEnabled(true);
+            break;
+        }
+        case NmHighlightedMode: {
+            mLineEdit->setEnabled(true);
+            mLineEdit->setFocus();
+            break;
+        }
+        case NmDimmedMode: {
+            mLineEdit->setEnabled(false);
+            break;
+        }
+    }
+}
+
+
+/*!
+    From NmBaseView.
+
+    Reloads the view contents with new start parameters. This method is
+    typically used when the view is already open and an external view activation
+    occurs for this same view.
+*/
+void NmMessageSearchListView::reloadViewContents(NmUiStartParam *startParam)
+{
+    // Check the start parameter's validity; message view cannot be updated if
+    // the given parameter is zero.
+    if (startParam&&startParam->viewId() == NmUiViewMessageSearchList &&
+        startParam->folderId() != 0) {
+        // Delete the existing start parameter data.
+        delete mStartParam;
+        mStartParam = NULL;
+
+        // Store the new start parameter data.
+        mStartParam = startParam;
+
+        // Update the model with new parameters.
+        NmMessageListModel &messageListModel =
+            mUiEngine.messageListModel(startParam->mailboxId(),
+                                       startParam->folderId());
+        mSearchListModel.setSourceModel(&messageListModel);
+        refreshList();
+
+        // Refresh the mailbox name.
+        setViewTitle();
+    }
+    else {
+        // Invalid start parameter data! Unused start parameter needs to be
+        // deleted.
+        NMLOG("NmMessageSearchListView: Invalid message list start parameter!");
+        delete startParam;
+    }
+}
+
+
+/*!
+    Displays the item context menu. This method gets called if an item on the
+    list is long pressed.
+*/
+void NmMessageSearchListView::showItemContextMenu(
+    HbAbstractViewItem *listViewItem, const QPointF &coords)
+{
+    // Store long press item for later use with response.
+    mLongPressedItem = 
+        mSearchListModel.data(listViewItem->modelIndex(),
+                              Qt::DisplayRole).value<NmMessageListModelItem*>();
+
+    if (mItemContextMenu && mLongPressedItem && mLongPressedItem->itemType() ==
+        NmMessageListModelItem::NmMessageItemMessage) {
+        // Clear the previous menu actions.
+        mItemContextMenu->clearActions();
+        NmUiExtensionManager &extMngr = mApplication.extManager();
+        QList<NmAction*> list;
+
+        // Fetch the menu actions based on the selected 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);
+        }
+        else{
+            NmActionRequest request(this, NmActionContextMenu, NmActionContextViewMessageList,
+                NmActionContextDataMessage, mStartParam->mailboxId(), mStartParam->folderId(),
+                envelope->messageId());
+
+            extMngr.getActions(request, list);
+        }
+
+        for (int i(0); i < list.count(); ++i) {
+            mItemContextMenu->addAction(list[i]);
+        }
+        mItemContextMenu->setPreferredPos(coords);
+        mItemContextMenu->open(this, SLOT(contextButton(NmActionResponse&)));
+    }
+}
+
+/*!
+    Slot. Signaled when menu option is selected
+*/
+void NmMessageSearchListView::contextButton(NmActionResponse &result)
+{
+// Handle context menu commands here.
+    if (result.menuType() == NmActionContextMenu){
+        switch (result.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;
+           }
+        }
+    }
+}
+
+/*!
+    Stores the given index and forwards the call to handleSelection(). This
+    method gets called when an item on the list is selected.  
+
+    \param index The index of the activated item.
+*/
+void NmMessageSearchListView::itemActivated(const QModelIndex &index)
+{
+    mActivatedIndex = index;
+    QMetaObject::invokeMethod(this, "handleSelection", Qt::QueuedConnection);
+}
+
+/*!
+    Called when text is changed in the edit field
+    
+    \param text new text entered in the field
+ */
+void NmMessageSearchListView::criteriaChanged(QString text) 
+{
+    NMLOG(QString("NmMessageSearchListView::criteriaChanged %1").arg(text));
+    
+    // Check when button should be disabled/enabled
+    bool enabled = mPushButton->isEnabled();
+    if (!enabled && !text.isEmpty()) {
+		mPushButton->setEnabled(true);
+    }
+    else if (enabled && text.isEmpty()) {
+		mPushButton->setEnabled(false);
+    }
+}
+
+/*!
+    If the selected item is a message, will open the message.
+*/
+void NmMessageSearchListView::handleSelection()
+{
+    // Do expand/collapse for title divider items
+    NmMessageListModelItem* modelItem = mSearchListModel.data(
+        mActivatedIndex, Qt::DisplayRole).value<NmMessageListModelItem*>();
+
+    if (modelItem &&
+        modelItem->itemType() == NmMessageListModelItem::NmMessageItemMessage)
+    {
+        if (mSearchInProgress) {
+            // Stop the search.
+            toggleSearch();
+        }
+
+        // Open the message.
+        NmUiStartParam *startParam = new NmUiStartParam(NmUiViewMessageViewer,
+            mStartParam->mailboxId(), mStartParam->folderId(),
+            modelItem->envelope().messageId());
+
+        mApplication.enterNmUiView(startParam);
+    }
+}
+
+
+/*!
+    Displays the message list widtet if not visible and scrolls to the
+    appropriate point on the list.
+*/
+void NmMessageSearchListView::itemsAdded(const QModelIndex &parent, int start, int end)
+{
+    NMLOG("nmailui: NmMessageSearchListView::itemsAdded()");
+
+    Q_UNUSED(parent);
+    Q_UNUSED(end);
+
+    // Display the message list widget if not visible.
+    noMessagesLabelVisibility(false);
+
+    if (!start && mMessageListWidget) {
+        QList<HbAbstractViewItem*> items = mMessageListWidget->visibleItems();
+
+        if (items.count()) {
+            QModelIndex index = items.at(0)->modelIndex();
+
+            if (1 == index.row()) {
+                QModelIndex previous = mMessageListWidget->modelIterator()->previousIndex(index);
+
+                if (previous.isValid()) {
+                    mMessageListWidget->scrollTo(previous);
+                }
+            }
+        }
+    }
+}
+
+
+/*!
+    This method gets called when an item is removed from the list. If the list
+    contains no items, "no messages" label is displayed.
+*/
+void NmMessageSearchListView::itemsRemoved()
+{
+    if (mSearchListModel.searchResultCount() == 0) {
+        noMessagesLabelVisibility(true);
+    }
+}
+
+
+/*!
+    Refreshes the search list.
+*/
+void NmMessageSearchListView::refreshList()
+{
+    if (mMessageListWidget) {
+        // Set the model.
+        NmMessageListModel &messageListModel =
+            mUiEngine.messageListModel(mStartParam->mailboxId(),
+                                       mStartParam->folderId());
+        mSearchListModel.setSourceModel(&messageListModel);
+        mMessageListWidget->setModel(
+            static_cast<QSortFilterProxyModel*>(&mSearchListModel));
+
+        // Connect the signals.
+        connect(&mSearchListModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
+                this, SLOT(itemsAdded(const QModelIndex&, int, int)), Qt::UniqueConnection);
+
+        connect(&mSearchListModel, SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
+                this, SLOT(itemsRemoved()), Qt::UniqueConnection);
+
+        connect(&messageListModel, SIGNAL(setNewParam(NmUiStartParam*)),
+                this, SLOT(reloadViewContents(NmUiStartParam*)), Qt::UniqueConnection);
+
+    }
+}
+
+
+/*!
+    Starts and stops the search according to the current status.
+
+    Starts search: Uses the input given by the user as a search string and
+    starts an asynchronous search. Any previous search results are removed from
+    the search list.
+
+    Stops search: Sets the number of search results into the info label.
+*/
+void NmMessageSearchListView::toggleSearch()
+{
+    if (mSearchInProgress) {
+        // Search is in progress - do cancel.
+        mUiEngine.cancelSearch(mStartParam->mailboxId());
+        handleSearchComplete();
+    }
+    else {
+        // Do start the search.
+        mSearchInProgress = true;
+    
+        // Clear previous results if any.
+        mSearchListModel.clearSearchResults();
+
+        connect(&mUiEngine, SIGNAL(searchComplete()),
+                this, SLOT(handleSearchComplete()), Qt::UniqueConnection);
+    
+        // Get the search input and start the search.
+        QStringList searchStrings;
+
+        if (mLineEdit) {
+            searchStrings.append(mLineEdit->text());
+        }
+
+        mUiEngine.search(mStartParam->mailboxId(), searchStrings);
+
+        // Hide the "no messages" label if visible and dim the search input.
+        noMessagesLabelVisibility(false);
+        setSearchInputMode(NmDimmedMode);
+
+        // Display the info label.
+        if (mInfoLabel) {
+            mInfoLabel->setPlainText(hbTrId("txt_mail_list_searching"));
+            mInfoLabel->show();
+        }
+
+        // Change the push button text.
+        if (mPushButton) {
+            mPushButton->setIcon(HbIcon("qtg_mono_search_stop"));
+        }
+    }
+}
+
+
+/*!
+    If the search matched any messages, displays the search result count in the
+    info label. If no messages were found, the method displays the "no messages"
+    label. In either case, the search panel is updated.
+*/
+void NmMessageSearchListView::handleSearchComplete()
+{
+    NMLOG("NmMessageSearchListView::handleSearchComplete()");
+    mSearchInProgress = false;
+    
+    // Change the push button text.
+    if (mPushButton) {
+        mPushButton->setIcon(HbIcon("qtg_mono_search"));
+    }
+
+    const int resultCount = mSearchListModel.searchResultCount();
+
+    if (resultCount == 1) {
+        // For some reason when the result count is only 1, the search list
+        // will not display the found message. Until the underlying reason for
+        // this bug is found, let us use the following solution to fix this
+        // issue.
+        refreshList();
+    }
+
+    if (resultCount) {
+        if (mInfoLabel) {
+            // Display the result count on the info label.
+            QString resultsString(hbTrId("txt_mail_list_search_results"));
+            resultsString.arg(resultCount);
+            mInfoLabel->setPlainText(resultsString);
+
+            if (!mInfoLabel->isVisible()) {
+                mInfoLabel->show();
+            }
+        }
+
+        // Undim the search input.
+        setSearchInputMode(NmNormalMode);
+    }
+    else {
+        // No search results!
+        if (mInfoLabel && mInfoLabel->isVisible()) {
+            mInfoLabel->hide();
+        }
+
+        // Display the "no messags" label and highlight the search term.
+        noMessagesLabelVisibility(true);
+        setSearchInputMode(NmHighlightedMode);
+    }
+}
+
+
+// End of file.