messagingapp/msgui/conversationview/src/msgconversationview.cpp
branchRCL_3
changeset 57 ebe688cedc25
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingapp/msgui/conversationview/src/msgconversationview.cpp	Tue Aug 31 15:11:31 2010 +0300
@@ -0,0 +1,1491 @@
+/*
+ * Copyright (c) 2009 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:Conversation (chat) view for messaging application.
+ *
+ */
+
+#include "msgconversationview.h"
+
+// SYSTEM INCLUDES
+#include <HbMenu>
+#include <HbAction>
+#include <HbListView>
+#include <HbMessageBox>
+#include <HbNotificationDialog>
+#include <HbFrameBackground>
+#include <xqservicerequest.h>
+#include <HbStaticVkbHost>
+#include <HbStyleLoader>
+#include <xqaiwrequest.h>
+#include <xqappmgr.h>
+#include <HbMainWindow>
+
+#include <QDir>
+#include <QDateTime>
+#include <QGraphicsLinearLayout>
+#include <QStandardItemModel>
+
+#include <cntservicescontact.h>
+#include <ccsdefs.h>
+#include <centralrepository.h>
+#include <MmsEngineDomainCRKeys.h>
+
+// USER INCLUDES
+#include "msgcontactsutil.h"
+#include "msgsendutil.h"
+#include "msgconversationviewitem.h"
+#include "conversationsengine.h"
+#include "convergedmessageid.h"
+#include "conversationsenginedefines.h"
+#include "msgcontactcardwidget.h"
+#include "msgeditorwidget.h"
+#include "msgviewdefines.h"
+#include "debugtraces.h"
+#include "unidatamodelloader.h"
+#include "unidatamodelplugininterface.h"
+#include "ringbc.h"
+#include "mmsconformancecheck.h"
+#include "msgsettingsview.h"
+#include "msgaudiofetcherview.h"
+#include "unieditorpluginloader.h"
+#include "unieditorplugininterface.h"
+
+//Item specific menu.
+
+#define LOC_COMMON_OPEN hbTrId("txt_common_menu_open")
+#define LOC_COMMON_DELETE hbTrId("txt_common_menu_delete")
+#define LOC_COMMON_FORWARD hbTrId("txt_common_menu_forward")
+#define LOC_COMMON_DOWNLOAD hbTrId("txt_messaging_menu_download")
+#define LOC_COMMON_SEND  hbTrId("txt_common_button_send") 
+#define LOC_COMMON_SAVE  hbTrId("txt_common_menu_save")
+
+#define LOC_DELETE_MESSAGE hbTrId("txt_messaging_dialog_delete_message")
+#define LOC_DELETE_SHARED_MESSAGE hbTrId("txt_messaging_dialog_same_message_exists_in_multip")
+#define LOC_SAVE_TO_CONTACTS hbTrId("txt_messaging_menu_save_to_contacts")
+
+//main menu
+#define LOC_ATTACH          hbTrId("txt_messaging_opt_attach")
+#define LOC_PHOTO           hbTrId("txt_messaging_opt_attach_sub_photo")
+#define LOC_SOUND           hbTrId("txt_messaging_opt_attach_sub_sound")
+#define LOC_VCARD           hbTrId("txt_messaging_list_business_card")
+#define LOC_ADD_RECIPIENTS  hbTrId("txt_messaging_opt_add_recipients")
+#define LOC_ADD_SUBJECT     hbTrId("txt_messaging_opt_add_subject")
+
+#define LOC_MSG_SEND_FAILED hbTrId("txt_messaging_dialog_message_sending_failed")
+#define LOC_DIALOG_SMS_SETTINGS_INCOMPLETE hbTrId("txt_messaging_dialog_sms_message_centre_does_not_e")
+#define LOC_DIALOG_SAVE_RINGTONE hbTrId("txt_conversations_dialog_save_ringing_tone")
+#define LOC_MMS_RETRIEVAL_FAILED hbTrId("txt_messaging_dialog_mms_retrieval_failed")
+
+
+const int INVALID_MSGID = -1;
+const int INVALID_CONVID = -1;
+const int CONTACT_INSERTION_MODE = 1;
+const int VCARD_INSERTION_MODE = 0;
+
+//---------------------------------------------------------------
+// MsgConversationView::MsgConversationView
+// @see header file
+//---------------------------------------------------------------
+MsgConversationView::MsgConversationView(MsgContactCardWidget *contactCardWidget,
+    QGraphicsItem *parent) :
+    MsgBaseView(parent),
+    mConversationList(NULL),
+    mMessageModel(NULL),
+    mEditorWidget(NULL),
+    mContactCardWidget(contactCardWidget),
+    mSendUtil(NULL),
+    mVkbHost(NULL),
+    mVisibleIndex(),
+    mModelPopulated(false),
+    mViewReady(false)
+{
+    //create send utils
+    mSendUtil = new MsgSendUtil(this);
+    //initialize view
+    setupView();
+    setupMenu();
+    
+    connect(ConversationsEngine::instance(), 
+                     SIGNAL(conversationModelUpdated()),
+                     this, 
+                     SLOT(scrollToBottom()));
+
+    connect(ConversationsEngine::instance(), 
+                         SIGNAL(conversationViewEmpty()),
+                         this, 
+                         SLOT(onConversationViewEmpty()));
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::~MsgConversationView
+// @see header file
+//---------------------------------------------------------------
+MsgConversationView::~MsgConversationView()
+{
+    
+}
+//---------------------------------------------------------------
+// MsgConversationView::setupView
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::setupView()
+{
+    // Create HbListView and set properties
+    mConversationList = new HbListView();
+    if (!HbStyleLoader::registerFilePath(":/layouts")) {
+        QDEBUG_WRITE("ERROR: ConversationView -> HbStyleLoader::registerFilePath");
+    }
+    mConversationList->setLayoutName("custom");
+    mConversationList->setItemRecycling(true);
+    MsgConversationViewItem *item = new MsgConversationViewItem(this);
+    HbFrameBackground defaultBackground;
+    defaultBackground.setFrameGraphicsName(QString(""));
+    item->setDefaultFrame(defaultBackground);
+    mConversationList->setItemPrototype(item);
+    mConversationList->setSelectionMode(HbListView::NoSelection);
+    mConversationList->setClampingStyle(HbScrollArea::BounceBackClamping);
+    mConversationList->setScrollingStyle(HbScrollArea::PanOrFlick);
+
+    mMessageModel = ConversationsEngine::instance()->getConversationsModel();
+    
+    connect(ConversationsEngine::instance(), 
+            SIGNAL(conversationModelPopulated()), 
+            this, 
+            SLOT(populateConversationsView()));
+    
+    connect(mConversationList, SIGNAL(activated(QModelIndex)),
+            this, SLOT(openItem(QModelIndex)));
+    connect(this->mainWindow(), SIGNAL(aboutToChangeOrientation()),
+                this, SLOT(onOrientationAboutToBeChanged()));
+    
+    connect(this->mainWindow(), SIGNAL(orientationChanged(Qt::Orientation)),
+                    this, SLOT(onOrientationChanged(Qt::Orientation)));
+
+    // Long tap list item
+    connect(mConversationList, SIGNAL(longPressed(HbAbstractViewItem*, QPointF)),
+            this, SLOT(longPressed(HbAbstractViewItem*, QPointF)));
+
+    // Create message editor widget, will be displayed based on msg type.
+    mEditorWidget = new MsgEditorWidget(this);
+    mEditorWidget->hide();
+
+    connect(mEditorWidget, SIGNAL(sendMessage()), this, SLOT(send()));
+    connect(mEditorWidget, SIGNAL(smsCharLimitReached()), 
+        this, SLOT(handleSmsCharLimitReached()));
+    connect(mEditorWidget, SIGNAL(replyStarted()), this, SIGNAL(replyStarted()));
+
+    qreal spacing = HbDeviceProfile::profile(mConversationList).unitValue();
+    
+    mMainLayout = new QGraphicsLinearLayout(Qt::Vertical,this); 
+    
+    mMainLayout->setContentsMargins(CONTENT_MARGIN, CONTENT_MARGIN,
+                                    CONTENT_MARGIN, CONTENT_MARGIN);   
+    mMainLayout->setSpacing(spacing);
+
+    mMainLayout->addItem(mConversationList);
+
+    setLayout(mMainLayout);
+
+    //Create VKB instance and listen to VKB open and close signals for resizing the view.
+    mVkbHost = new HbStaticVkbHost(this);
+	connect(mVkbHost, SIGNAL(keypadOpened()), this, SLOT(vkbOpened()));
+	connect(mVkbHost, SIGNAL(keypadClosed()), this, SLOT(vkbClosed()));
+
+    // Refresh view to show the header details
+    refreshView();
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::addMenu
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::setupMenu()
+{
+    // Just create dummy menu.
+    // Actual menu will be created in menuAboutToShow()
+    HbMenu *mainMenu = this->menu();
+    HbAction* clearConversation = mainMenu->addAction(QString());
+    connect(mainMenu, SIGNAL(aboutToShow()), this, SLOT(menuAboutToShow()));
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::fetchMoreConversations
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::fetchMoreConversations()
+{
+    if (mViewReady && mModelPopulated) {
+        ConversationsEngine::instance()->fetchMoreConversations();
+        mViewReady = mModelPopulated = false;
+    }
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::refreshView()
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::refreshView()
+{
+    // Hide editor in case of BT conversations.
+    qint64 convId = ConversationsEngine::instance()->getCurrentConversationId();
+    if (INVALID_CONVID != convId) {
+        if (KBluetoothMsgsConversationId == convId) {
+            mMainLayout->removeItem(mEditorWidget);
+            mEditorWidget->hide();
+            mEditorWidget->setParent(this);
+        }
+        else {
+            mMainLayout->addItem(mEditorWidget);
+            TRAP_IGNORE(mEditorWidget->setEncodingSettingsL());
+            mEditorWidget->show();
+        }
+        mContactCardWidget->updateContents();
+    }
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::scrollToBottom()
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::scrollToBottom()
+{
+    const int rowCnt = mMessageModel->rowCount();
+    mConversationList->scrollTo(
+            mMessageModel->index(rowCnt - 1, 0));
+}
+
+void MsgConversationView::onConversationViewEmpty()
+{
+    QVariantList param;
+    param << MsgBaseView::CLV; // target view
+    param << MsgBaseView::CV; // source view
+    emit switchView(param);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::longPressed
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::longPressed(HbAbstractViewItem* viewItem, const QPointF& point)
+{ 
+    showContextMenu(viewItem,point,HbPopup::TopLeftCorner);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::setContextMenu
+// @see header
+//---------------------------------------------------------------
+void MsgConversationView::setContextMenu(MsgConversationViewItem* item, HbMenu* contextMenu, int sendingState)
+{
+    addOpenItemToContextMenu(item , contextMenu,sendingState);
+    addResendItemToContextMenu(item, contextMenu, sendingState);
+    addForwardItemToContextMenu(item, contextMenu, sendingState);
+    addDownloadItemToContextMenu(item, contextMenu);
+    addSaveItemToContextMenu(item , contextMenu,sendingState);
+    addDeleteItemToContextMenu(item, contextMenu, sendingState);
+}
+
+
+//---------------------------------------------------------------
+// MsgEditorPrivate::addSaveItemToContextMenu
+// @see header
+//---------------------------------------------------------------
+void MsgConversationView::addSaveItemToContextMenu(MsgConversationViewItem* item,
+    HbMenu* contextMenu, int sendingState)
+{
+    Q_UNUSED(sendingState)
+
+    int messageSubType = item->modelIndex().data(MessageSubType).toInt();
+    int direction =  item->modelIndex().data(Direction).toInt();
+    if ((messageSubType == ConvergedMessage::RingingTone) && 
+        (direction == ConvergedMessage::Incoming)) {
+        HbAction *contextItem = contextMenu->addAction(LOC_COMMON_SAVE);
+        connect(contextItem, SIGNAL(triggered()), this, SLOT(saveRingingTone()));
+    }
+}
+
+//---------------------------------------------------------------
+// MsgEditorPrivate::addOpenItemToContextMenu
+// @see header
+//---------------------------------------------------------------
+
+void MsgConversationView::addOpenItemToContextMenu(MsgConversationViewItem* item, HbMenu* contextMenu, int sendingState)
+{
+    int direction = item->modelIndex().data(Direction).toInt();
+    int messageType = item->modelIndex().data(MessageType).toInt();
+    int messageSubType = item->modelIndex().data(MessageSubType).toInt();
+    
+    if((messageSubType == ConvergedMessage::VCal) ||
+        (messageSubType == ConvergedMessage::RingingTone) ||
+        (messageType == ConvergedMessage::MmsNotification))
+        {
+        return;
+        }
+    if ((messageSubType == ConvergedMessage::VCard) &&
+        (direction == ConvergedMessage::Incoming))
+        {
+        HbAction *contextItem = contextMenu->addAction(LOC_SAVE_TO_CONTACTS);
+        connect(contextItem, SIGNAL(triggered()),this, SLOT(saveVCard()));
+        return;
+        }
+    if( (sendingState == ConvergedMessage::SentState &&
+         messageSubType != ConvergedMessage::VCard) ||
+        (direction == ConvergedMessage::Incoming))
+    {
+        HbAction *contextItem = contextMenu->addAction(LOC_COMMON_OPEN);
+        connect(contextItem, SIGNAL(triggered()),this, SLOT(openItem()));
+    }
+    
+}
+
+//---------------------------------------------------------------
+// MsgEditorPrivate::addResendItemToContextMenu
+// @see header
+//---------------------------------------------------------------
+
+void MsgConversationView::addResendItemToContextMenu(MsgConversationViewItem* item, HbMenu* contextMenu, int sendingState)
+{
+    Q_UNUSED(item)
+    int direction = item->modelIndex().data(Direction).toInt();
+    int messageSubType = item->modelIndex().data(MessageSubType).toInt();
+    
+    
+    if( ((direction == ConvergedMessage::Outgoing) &&
+        (messageSubType != ConvergedMessage::VCard))&&
+        ((sendingState == ConvergedMessage::Resend ) ||
+        
+        (sendingState == ConvergedMessage::Failed )))
+    {
+        HbAction *contextItem = contextMenu->addAction(LOC_COMMON_SEND);
+        connect(contextItem, SIGNAL(triggered()),this, SLOT(resendMessage()));
+    }
+}
+
+//---------------------------------------------------------------
+// MsgEditorPrivate::addForwardItemToContextMenu
+// @see header
+//---------------------------------------------------------------
+void MsgConversationView::addForwardItemToContextMenu(MsgConversationViewItem* item, HbMenu* contextMenu, int sendingState)
+{
+    int messageType = item->modelIndex().data(MessageType).toInt();
+    int direction = item->modelIndex().data(Direction).toInt();
+    int messageSubType = item->modelIndex().data(MessageSubType).toInt();
+    
+    if( (messageType == ConvergedMessage::BT) ||
+        (messageType == ConvergedMessage::MmsNotification) ||
+        (messageSubType == ConvergedMessage::Provisioning ) ||
+        (messageSubType == ConvergedMessage::RingingTone) ||
+        (messageSubType == ConvergedMessage::VCal))
+    {
+        return;
+    }
+    
+    qint32 messageId = item->modelIndex().data(ConvergedMsgId).toInt();
+    qint32 messageProperty = item->modelIndex().data(MessageProperty).toInt();
+    
+    bool canForwardMessage  = true;
+    if (messageType == ConvergedMessage::Mms){
+        canForwardMessage = (messageProperty & EPreviewForward)? true:false;
+    }            
+
+    if( ((sendingState == ConvergedMessage::SentState) ||
+        (sendingState == ConvergedMessage::Resend) ||
+        (sendingState == ConvergedMessage::Failed) ||
+        (sendingState == ConvergedMessage::Suspended )||
+        (direction == ConvergedMessage::Incoming) ) &&
+        canForwardMessage)
+    {
+        HbAction *contextItem = contextMenu->addAction(LOC_COMMON_FORWARD);
+        connect(contextItem, SIGNAL(triggered()),this, SLOT(forwardMessage()));
+    }
+
+}
+
+//---------------------------------------------------------------
+// MsgEditorPrivate::addDeleteItemToContextMenu
+// @see header
+//---------------------------------------------------------------
+void MsgConversationView::addDeleteItemToContextMenu(MsgConversationViewItem* item, HbMenu* contextMenu, int sendingState)
+{
+    int direction = item->modelIndex().data(Direction).toInt();
+    int messageType = item->modelIndex().data(MessageType).toInt();
+    int notificationState = item->modelIndex().data(NotificationStatus).toInt();
+    
+    if( (messageType == ConvergedMessage::MmsNotification) && 
+        ((notificationState == ConvergedMessage::NotifNull) || 
+         (notificationState ==  ConvergedMessage::NotifRetrieving) ||
+         (notificationState == ConvergedMessage::NotifWaiting)))
+    {
+        return;
+    }
+    
+    if( (sendingState == ConvergedMessage::SentState) ||
+        (sendingState == ConvergedMessage::Resend) ||
+        (sendingState == ConvergedMessage::Suspended) ||
+        (sendingState == ConvergedMessage::Failed) ||
+        (direction == ConvergedMessage::Incoming))
+    {
+        HbAction *contextItem = contextMenu->addAction(LOC_COMMON_DELETE);
+        connect(contextItem, SIGNAL(triggered()),this, SLOT(deleteItem()));
+    }  
+}
+
+//---------------------------------------------------------------
+// MsgEditorPrivate::addDownloadItemToContextMenu
+// @see header
+//---------------------------------------------------------------
+void MsgConversationView::addDownloadItemToContextMenu(MsgConversationViewItem* item, HbMenu* contextMenu)
+{
+    int notificationState = item->modelIndex().data(NotificationStatus).toInt();
+    int messageType = item->modelIndex().data(MessageType).toInt();
+    qint32 messageId = item->modelIndex().data(ConvergedMsgId).toLongLong();
+        
+    if( messageType == ConvergedMessage::MmsNotification &&
+        ConversationsEngine::instance()->downloadOperationSupported(messageId))
+    {            
+        HbAction *contextItem = contextMenu->addAction(LOC_COMMON_DOWNLOAD);
+        connect(contextItem, SIGNAL(triggered()),this, SLOT(downloadMessage()));
+    }
+}
+//---------------------------------------------------------------
+// MsgEditorPrivate::send
+// @see header
+//---------------------------------------------------------------
+void MsgConversationView::send()
+{
+    activateInputBlocker();
+    ConvergedMessageAddressList addresses;
+    addresses = mContactCardWidget->address();
+    int sendResult = KErrNone;
+
+    // Populate the ConvergedMessage.
+    if (!addresses.isEmpty())
+    {
+        ConvergedMessage msg;
+        populateForSending(msg);
+        msg.addToRecipients(addresses);
+
+        // Send
+        sendResult = mSendUtil->send(msg);
+                   
+        if( sendResult == KErrNone)
+        {
+            mEditorWidget->clear();
+        }
+    }
+    deactivateInputBlocker();
+    if( sendResult == KErrNotFound)
+    {
+    HbMessageBox::question(LOC_DIALOG_SMS_SETTINGS_INCOMPLETE, this,
+                           SLOT(onDialogSettingsLaunch(HbAction*)), 
+                           HbMessageBox::Ok | HbMessageBox::Cancel);
+    }
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::contactsFetchedForVCards
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::contactsFetchedForVCards(const QVariant& value)
+{
+    // get received contact-list and launch unieditor
+    CntServicesContactList contactList = 
+            qVariantValue<CntServicesContactList>(value);
+    int cntCount = contactList.count();
+    if(cntCount > 0)
+    {
+        QVariantList params;
+        params << MsgBaseView::ADD_VCARD;
+        params << value;
+        launchUniEditor(params);        
+    }
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::fetchContacts
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::fetchContacts()
+{
+    HbAction* action = qobject_cast<HbAction*>(sender());
+
+    if(!action)
+        return;
+
+    QList<QVariant> args;
+    QString serviceName("com.nokia.services.phonebookservices");
+    QString operation("fetch(QString,QString,QString)");
+    XQAiwRequest* request;
+    XQApplicationManager appManager;
+    request = appManager.create(serviceName, "Fetch", operation, true); //embedded
+    if ( request == NULL )
+    {
+        return;       
+    }
+
+    int mode = action->data().toInt();
+    
+    if( VCARD_INSERTION_MODE == mode) //vcard-insert mode
+    {
+        connect(request, SIGNAL(requestOk(const QVariant&)),
+            this, SLOT(contactsFetchedForVCards(const QVariant&)));      
+    }
+    else  //contact-insert mode
+    {
+        connect(request, SIGNAL(requestOk(const QVariant&)),
+            this, SLOT(contactsFetched(const QVariant&)));
+    }
+    connect (request, SIGNAL(requestError(int,const QString&)), 
+        this, SLOT(serviceRequestError(int,const QString&)));
+
+    args << QString(tr("Phonebook")); 
+    args << KCntActionAll;
+    args << KCntFilterDisplayAll;
+
+    request->setArguments(args);
+    request->send();
+    delete request;
+}
+//---------------------------------------------------------------
+// MsgConversationView::fetchImages
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::fetchImages()
+{
+    QString service("photos");
+    QString interface("com.nokia.symbian.IImageFetch");
+    QString operation("fetch()");
+    XQAiwRequest* request = NULL;
+    XQApplicationManager appManager;
+    request = appManager.create(service,interface, operation, true); // embedded
+    request->setSynchronous(true); // synchronous
+    if(!request)
+    {
+        QDEBUG_WRITE("AIW-ERROR: NULL request");
+        return;
+    }
+
+    connect(request, SIGNAL(requestOk(const QVariant&)),
+        this, SLOT(imagesFetched(const QVariant&)));
+    connect(request, SIGNAL(requestError(int,const QString&)),
+        this, SLOT(serviceRequestError(int,const QString&)));
+
+    // Make the request
+    if (!request->send())
+    {
+        QDEBUG_WRITE_FORMAT("AIW-ERROR: Request Send failed:" , request->lastError());
+    }  
+    delete request;
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::fetchAudio
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::fetchAudio()
+{
+    // Launch Audio fetcher view
+    QVariantList params;
+    QByteArray dataArray;
+    QDataStream messageStream
+    (&dataArray, QIODevice::WriteOnly | QIODevice::Append);
+
+    ConvergedMessage message;
+    message.setBodyText(mEditorWidget->content());
+    // add address from contact-card to to-field
+    ConvergedMessageAddress address;
+    address.setAlias(mContactCardWidget->address().at(0)->alias());
+    address.setAddress(mContactCardWidget->address().at(0)->address());
+    message.addToRecipient(address);
+    message.serialize(messageStream);
+
+    params << MsgBaseView::AUDIOFETCHER; // target view
+    params << MsgBaseView::CV; // source view
+    params << dataArray;
+    emit switchView(params);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::contactsFetched
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::contactsFetched(const QVariant& value)
+{
+    //switch to editor.
+    QVariantList params;
+    params << MsgBaseView::ADD_RECIPIENTS;
+    params << value;
+    launchUniEditor(params);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::imagesFetched()
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::imagesFetched(const QVariant& result )
+{
+    if(result.canConvert<QStringList>())
+    {
+        QStringList fileList = result.value<QStringList>();
+        if ( fileList.size()>0 )
+        {
+            QString filepath(QDir::toNativeSeparators(fileList.at(0)));
+            QVariantList params;
+            params << MsgBaseView::ADD_PHOTO;
+            params << filepath;
+            launchUniEditor(params);
+        }
+    }
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::addSubject()
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::addSubject()
+{
+
+    QString filepath;
+    QVariantList params;
+    params << MsgBaseView::ADD_SUBJECT;
+    launchUniEditor(params);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::forwardMessage()
+// Forwards the message
+//---------------------------------------------------------------
+void MsgConversationView::forwardMessage()
+{
+    QModelIndex index = mConversationList->currentIndex();
+    //messageId & messageType to be forwarded
+    qint32 messageId = index.data(ConvergedMsgId).toLongLong();
+    int messageType = index.data(MessageType).toInt();
+ 
+    //Mark the message to read before forwarding.
+    if(index.data(UnReadStatus).toBool())
+    {
+        QList<int> msgIdList;
+        msgIdList.append(messageId);
+        ConversationsEngine::instance()->markMessagesRead(msgIdList);
+    }
+    // populate params and launch editor 
+    QVariantList params;
+    params << MsgBaseView::FORWARD_MSG;
+    params << messageId;
+    params << messageType;
+    launchUniEditor(params);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::resendMessage()
+// Resends the message in the failed messages case
+//---------------------------------------------------------------
+void MsgConversationView::resendMessage()
+{
+    QModelIndex index = mConversationList->currentIndex();
+    if(index.isValid())
+    {
+        qint32 messageId = index.data(ConvergedMsgId).toLongLong();    
+        if(!(ConversationsEngine::instance()->resendMessage(messageId)))
+        {
+            HbMessageBox::warning(LOC_MSG_SEND_FAILED, 0, 0, HbMessageBox::Ok);
+        }
+    }
+    
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::downloadMessage()
+// @see header
+//---------------------------------------------------------------
+void MsgConversationView::downloadMessage()
+{
+    QModelIndex index = mConversationList->currentIndex();
+    if(index.isValid())
+    {
+        qint32 messageId = index.data(ConvergedMsgId).toLongLong();
+        if(ConversationsEngine::instance()->downloadMessage(messageId)!=KErrNone)
+        {
+            HbMessageBox::warning(LOC_MMS_RETRIEVAL_FAILED, 0, 0, HbMessageBox::Ok);
+        }
+    }
+    
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::deleteItem()
+// Deletes the message
+//---------------------------------------------------------------
+void MsgConversationView::deleteItem()
+{
+    QString str = LOC_DELETE_MESSAGE;
+
+    QModelIndex index = mConversationList->currentIndex();
+    if(index.isValid())
+    {
+        int messageType = index.data(MessageType).toInt();        
+        int direction = index.data(Direction).toInt();
+
+        if ( direction == ConvergedMessage::Outgoing &&
+            messageType == ConvergedMessage::Mms )
+        {
+            qint32 messageId = index.data(ConvergedMsgId).toLongLong();
+
+            if(isSharedMessage(messageId))
+            {
+                str = LOC_DELETE_SHARED_MESSAGE;  
+            }
+        }
+    }
+
+
+    HbMessageBox::question(str,this,SLOT(onDialogdeleteMsg(HbAction*)),
+                           HbMessageBox::Delete | HbMessageBox::Cancel);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::openItem()
+// Opens the message
+//---------------------------------------------------------------
+void MsgConversationView::openItem()
+{
+    QModelIndex index = mConversationList->currentIndex();
+    openItem(index);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::clearEditors()
+// @See header
+//---------------------------------------------------------------
+void MsgConversationView::clearEditors()
+{
+    mEditorWidget->clear();
+    mConversationList->setModel(NULL);
+    mContactCardWidget->clearContent();
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::saveContentToDrafts()
+// @See header
+//---------------------------------------------------------------
+int MsgConversationView::saveContentToDrafts()
+{
+    int msgId = INVALID_MSGID;
+    if(!mEditorWidget->content().isEmpty())
+    {
+        activateInputBlocker();
+        ConvergedMessageAddressList addresses;
+        addresses = mContactCardWidget->address();
+
+        // Populate the ConvergedMessage.
+        if (!addresses.isEmpty())
+        {
+            ConvergedMessage msg;
+            populateForSending(msg);
+            msg.addToRecipients(addresses);
+            
+            // save to drafts
+            msgId = mSendUtil->saveToDrafts(msg);
+                     
+            mEditorWidget->clear();
+        }
+        deactivateInputBlocker();
+    }
+    return msgId;
+}
+
+//---------------------------------------------------------------
+//MsgConversationView::populateForSending()
+//@see header
+//---------------------------------------------------------------
+void MsgConversationView::populateForSending(ConvergedMessage &message)
+{
+    message.setMessageType(ConvergedMessage::Sms);
+    message.setBodyText(mEditorWidget->content());
+    message.setDirection(ConvergedMessage::Outgoing);
+    QDateTime time = QDateTime::currentDateTime();
+    message.setTimeStamp(time.toTime_t());
+}
+
+//---------------------------------------------------------------
+//MsgConversationView::launchBtDisplayService()
+//@see header
+//---------------------------------------------------------------
+void MsgConversationView::launchBtDisplayService(const QModelIndex & index)
+{
+    qint32 messageId = index.data(ConvergedMsgId).toLongLong();
+
+    QList<QVariant> args;
+    QString serviceName("com.nokia.services.btmsgdispservices");
+    QString operation("displaymsg(int)");
+    XQAiwRequest* request;
+    XQApplicationManager appManager;
+    request = appManager.create(serviceName, "displaymsg", operation, false); // embedded
+    
+    if ( request == NULL )
+        {
+        return;
+        }
+
+    args << QVariant(messageId);
+    request->setSynchronous(true);
+    
+    request->setArguments(args);
+    request->send();
+    delete request;    
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::menuAboutToShow()
+// @See header
+//---------------------------------------------------------------
+void MsgConversationView::menuAboutToShow()
+{
+    // Clear all the previously added actions.
+    HbMenu *mainMenu = this->menu();
+    mainMenu->clearActions();
+
+    // Message type specific menu items
+    QModelIndex index = ConversationsEngine::instance()->getConversationsModel()->index(0, 0);
+    if (ConvergedMessage::BT != index.data(MessageType).toInt())
+    {
+        // Attach sub-menu
+        HbMenu *attachSubMenu = mainMenu->addMenu(LOC_ATTACH);
+        
+        attachSubMenu->addAction(LOC_PHOTO,this, SLOT(fetchImages()));
+        attachSubMenu->addAction(LOC_SOUND,this, SLOT(fetchAudio()));
+		
+        HbAction* addVCard = attachSubMenu->addAction(LOC_VCARD);
+        addVCard->setData(VCARD_INSERTION_MODE);        
+        connect(addVCard, SIGNAL(triggered()),this,SLOT(fetchContacts()));
+
+        HbAction *addRecipients = mainMenu->addAction(LOC_ADD_RECIPIENTS);
+        addRecipients->setData(CONTACT_INSERTION_MODE);        
+        connect(addRecipients, SIGNAL(triggered()), this, SLOT(fetchContacts()));
+
+        mainMenu->addAction(LOC_ADD_SUBJECT,this, SLOT(addSubject()));
+    }
+}
+
+//---------------------------------------------------------------
+//MsgConversationView::openItem
+//@see header
+//---------------------------------------------------------------
+void MsgConversationView::openItem(const QModelIndex & index)
+{
+    // Return if invalid index.
+    if (!index.isValid())
+    {
+        return;
+    }
+    
+    int messageType = index.data(MessageType).toInt();
+    int messageSubType = index.data(MessageSubType).toInt();
+    int messageId = index.data(ConvergedMsgId).toInt();
+    
+    if (ConvergedMessage::BioMsg == messageType)
+    {
+        if (ConvergedMessage::RingingTone == messageSubType)
+        {
+            HbMessageBox::question(LOC_DIALOG_SAVE_RINGTONE, this,
+                                   SLOT(onDialogSaveTone(HbAction*)), 
+                                   HbMessageBox::Save | HbMessageBox::Cancel);
+            return;
+        }
+        else if(ConvergedMessage::Provisioning == messageSubType)
+        {
+            int messageId = index.data(ConvergedMsgId).toInt();
+            handleProvisoningMsg(messageId);
+            QList<int> msgIdList;
+            if(index.data(UnReadStatus).toInt())
+            {
+                msgIdList.clear();
+                msgIdList << messageId;
+                ConversationsEngine::instance()->markMessagesRead(msgIdList);
+            }
+            return;
+        }
+        else if(ConvergedMessage::VCard == messageSubType)
+        {
+            handleShortTap();
+            return;
+        }
+        else if(ConvergedMessage::VCal == messageSubType)
+        {
+            return;
+        }
+    }
+    else if (ConvergedMessage::BT == messageType)
+    {
+        launchBtDisplayService(index);
+        QList<int> msgIdList;
+        if(index.data(UnReadStatus).toInt())
+            {
+            msgIdList.clear();
+            msgIdList << messageId;
+            ConversationsEngine::instance()->markMessagesRead(msgIdList);
+            }
+        return;
+    }
+    else if(ConvergedMessage::MmsNotification == messageType)
+    {
+        qint32 messageId = index.data(ConvergedMsgId).toLongLong();
+        if(!ConversationsEngine::instance()->downloadOperationSupported(messageId))           
+        {
+           int notificationState = index.data(NotificationStatus).toInt();
+           if( notificationState == ConvergedMessage::NotifExpired)
+           {
+               deleteItem();
+           }
+           return;
+        }
+        else
+        {
+            //TODO: use logical str name
+            HbMessageBox::question("Download Message?",this,
+                                   SLOT(onDialogDownLoadMsg(HbAction*)),
+                                   HbMessageBox::Yes | HbMessageBox::Cancel);
+            return;
+        }
+    }
+
+    int direction = index.data(Direction).toInt();
+
+    if (direction == ConvergedMessage::Outgoing && ConvergedMessage::Sms == messageType
+        && ConversationsEngine::instance()->getMsgSubType(messageId)== ConvergedMessage::NokiaService)
+    {
+        return;
+    }
+    
+    // check whether message is in sending progress, then donot launch viewer.
+    int location = index.data(MessageLocation).toInt();
+    int sendingState = index.data(SendingState).toInt();
+    
+    // For suspended message both short tap and long tap needs to show the same
+    // context menu.....
+    if(direction == ConvergedMessage::Outgoing 
+        	&&sendingState == ConvergedMessage::Suspended )
+    {
+        handleShortTap();
+        return;
+    }
+    
+    //If message is in any other state other than 'Sent'
+    //do not open the message
+    if(direction == ConvergedMessage::Outgoing 
+            && sendingState != ConvergedMessage::SentState )
+           
+    {
+        return;
+    }
+
+   
+    
+    // contact Id
+    qint32 contactId = index.data(ContactId).toLongLong();  
+	    
+    //if message unread, mark as read before opening view
+    QList<int> msgIdList;
+    if(index.data(UnReadStatus).toInt())
+    {
+        msgIdList.clear();
+        msgIdList << messageId;
+        ConversationsEngine::instance()->markMessagesRead(msgIdList);
+    }
+
+    //switch view
+    QVariantList param;
+    param << MsgBaseView::UNIVIEWER;  // target view
+    param << MsgBaseView::CV; // source view
+
+    param << contactId;
+    param << messageId;
+    param << mMessageModel->rowCount();
+    emit switchView(param);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::launchUniEditor
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::launchUniEditor(const QVariantList& data)
+{
+    // param list for switching to editor view
+    QVariantList params;
+    QByteArray dataArray;
+    QDataStream messageStream
+    (&dataArray, QIODevice::WriteOnly | QIODevice::Append);
+
+    // first arg is always the editor operation
+    int editorOperation = data.at(0).toInt();
+    
+    ConvergedMessage message;
+    QVariant data2;
+    if( editorOperation != MsgBaseView::FORWARD_MSG )
+    {
+        message.setBodyText(mEditorWidget->content());
+
+        // add address from contact-card to to-field
+        ConvergedMessageAddress address;
+        address.setAlias(mContactCardWidget->address().at(0)->alias());
+        address.setAddress(mContactCardWidget->address().at(0)->address());
+        message.addToRecipient(address);
+
+        if(editorOperation == MsgBaseView::ADD_PHOTO ||
+           editorOperation == MsgBaseView::ADD_AUDIO ||
+           editorOperation == MsgBaseView::ADD_VIDEO )
+        {
+            // filepath is sent in cases like ADD_PHOTO, ADD_AUDIO etc.
+            QString filepath;
+            filepath = data.at(1).toString();
+            if(!filepath.isEmpty())
+            {
+                ConvergedMessageAttachment* attachment = 
+                        new ConvergedMessageAttachment(filepath);
+                ConvergedMessageAttachmentList attachmentList;
+                attachmentList.append(attachment);
+                message.addAttachments(attachmentList);
+            }            
+        }
+        else if(editorOperation == MsgBaseView::ADD_VCARD)
+        {
+            // filepath is not sent in cases like VCards & recipients
+            // instead, we will get a list of contacts. Pass it as it is.
+            data2 = data.at(1);
+        }
+        else if(editorOperation == MsgBaseView::ADD_RECIPIENTS)
+        {
+            ConvergedMessageAddressList addresses;
+            CntServicesContactList contactList = 
+                    qVariantValue<CntServicesContactList>(data.at(1));
+            // now add fetched contacts from contact selection dialog
+            for(int i = 0; i < contactList.count(); i++ )
+            {
+                ConvergedMessageAddress* address = new ConvergedMessageAddress;
+                address->setAlias(contactList[i].mDisplayName);
+                if(!contactList[i].mPhoneNumber.isEmpty())
+                {
+                    address->setAddress(contactList[i].mPhoneNumber);
+                }
+                else
+                {
+                    address->setAddress(contactList[i].mEmailAddress);
+                }
+                addresses.append(address);
+            }
+            message.addToRecipients(addresses);
+        }
+    }
+    else
+    {
+        qint32 msgId = (qint32)data.at(1).toInt();
+        int msgType = data.at(2).toInt();
+        ConvergedMessageId id(msgId);
+        message.setMessageId(id);
+        message.setMessageType((ConvergedMessage::MessageType)msgType);
+    }
+
+    message.serialize(messageStream);
+    params << MsgBaseView::UNIEDITOR;
+    params << MsgBaseView::CV;
+    params << dataArray;
+    params << editorOperation;
+    if(!data2.isNull())
+        params << data2;
+
+    clearEditors();
+    emit switchView(params);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::populateConversationsView
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::populateConversationsView()
+{    
+    mModelPopulated = true;
+    mConversationList->setModel(mMessageModel);
+    
+    refreshView();
+    scrollToBottom();
+    fetchMoreConversations();
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::saveRingingTone
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::saveRingingTone()
+{
+    QModelIndex index = mConversationList->currentIndex();
+    int messageId = index.data(ConvergedMsgId).toInt();
+
+    UniDataModelLoader* pluginLoader = new UniDataModelLoader();
+    UniDataModelPluginInterface* pluginInterface = 
+    pluginLoader->getDataModelPlugin(ConvergedMessage::BioMsg);
+    pluginInterface->setMessageId(messageId);
+    UniMessageInfoList attachments = pluginInterface->attachmentList();
+    if(attachments.count() > 0)
+    {
+        QString attachmentPath = attachments[0]->path();
+
+        RingBc* ringBc = new RingBc();
+
+        ringBc->saveTone(attachmentPath);
+
+        // clear attachement list : its allocated at data model
+        while(!attachments.isEmpty())
+        {
+            delete attachments.takeFirst();
+        }
+
+        delete ringBc;
+    }
+    delete pluginLoader;
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::handleSmsCharLimitReached
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::handleSmsCharLimitReached()   
+{
+    QString filepath;
+    QVariantList params;
+    params << MsgBaseView::ADD_OTHERS;
+    launchUniEditor(params);   
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::vkbOpened
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::vkbOpened()
+{
+    emit vkbOpened(true);
+    
+    scrollToBottom();
+    
+    QRectF appRect = mVkbHost->applicationArea();    
+    qreal spacing = 0.0;
+    qreal cardHeight = 0.0;
+    if(mContactCardWidget->isVisible())
+        {
+        cardHeight = mContactCardWidget->rect().height();
+        spacing = HbDeviceProfile::profile(this).unitValue();
+        }
+    
+    this->setMaximumHeight(appRect.height()- cardHeight - spacing);
+    mConversationList->adjustSize();
+    
+    disconnect(mVkbHost,SIGNAL(keypadOpened()),this,SLOT(vkbOpened()));
+
+}
+	  
+//---------------------------------------------------------------
+// MsgConversationView::vkbClosed
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::vkbClosed()
+{
+    emit vkbOpened(false);
+    
+    scrollToBottom();
+    
+    this->setMaximumHeight(-1);
+    mConversationList->adjustSize();    
+    
+    connect(mVkbHost,SIGNAL(keypadOpened()),this,SLOT(vkbOpened()));
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::serviceRequestError
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::serviceRequestError(int errorCode, const QString& errorMessage)
+{
+    QDEBUG_WRITE_FORMAT(errorMessage,errorCode);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::activateInputBlocker
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::activateInputBlocker()
+{
+    mainWindow()->setInteractive(false);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::deactivateInputBlocker
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::deactivateInputBlocker()
+{
+    mainWindow()->setInteractive(true);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::handleProvisoningMsg
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::handleProvisoningMsg(int msgId)
+	{
+		QString messageId;
+    messageId.setNum(msgId);
+
+    XQApplicationManager* aiwMgr = new XQApplicationManager();
+
+    XQAiwRequest* request = aiwMgr->create("com.nokia.services.MDM", 
+            "Provisioning",
+            "ProcessMessage(QString)", true); // embedded
+
+    if (request) {
+    QList<QVariant> args;
+    args << QVariant(messageId);
+    request->setArguments(args);
+
+    // Send the request
+    bool res = request->send();
+
+    // Cleanup
+    delete request;
+    }
+
+    delete aiwMgr;
+	}
+
+//---------------------------------------------------------------
+// MsgConversationView::onDialogSettingsLaunch
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::onDialogSettingsLaunch(HbAction* action)
+{
+    HbMessageBox *dlg = qobject_cast<HbMessageBox*> (sender());
+    if (action == dlg->actions().at(0)) {
+        //switch to settings view
+         QVariantList param;
+         param << MsgBaseView::MSGSETTINGS;
+         param << MsgBaseView::CV;
+         param << MsgSettingsView::SMSView;
+         emit switchView(param);
+    }
+
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::onDialogdeleteMsg
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::onDialogdeleteMsg(HbAction* action)
+{
+    HbMessageBox *dlg = qobject_cast<HbMessageBox*> (sender());
+    if (action == dlg->actions().at(0)) {
+        QModelIndex index = mConversationList->currentIndex();
+        if (index.isValid()) {
+            int count = mMessageModel->rowCount();
+            //delete message
+            qint32 messageId = index.data(ConvergedMsgId).toLongLong();
+            if (messageId) {
+                QList<int> msgIdList;
+                msgIdList.append(messageId);
+                ConversationsEngine::instance()->deleteMessages(msgIdList);
+                //switch view               
+                if (count == 1) {
+                    QVariantList param;
+                    param << MsgBaseView::CLV; // target view
+                    param << MsgBaseView::CV; // source view
+                    emit switchView(param);
+                }
+            }
+        }
+
+    }
+
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::onDialogDownLoadMsg
+// @see header file
+//--------------------------------------------------------------
+void MsgConversationView::onDialogDownLoadMsg(HbAction* action)
+{
+    HbMessageBox *dlg = qobject_cast<HbMessageBox*> (sender());
+    if (action == dlg->actions().at(0)) {
+        downloadMessage();
+    }
+    
+    //if message unread, mark as read now
+    QModelIndex index = mConversationList->currentIndex();
+    qint32 messageId = index.data(ConvergedMsgId).toLongLong();
+    QList<int> msgIdList;
+    if(index.data(UnReadStatus).toInt())
+    {
+        msgIdList.clear();
+        msgIdList << messageId;
+        ConversationsEngine::instance()->markMessagesRead(msgIdList);
+    }
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::onDialogSaveTone
+// @see header file
+//--------------------------------------------------------------
+void MsgConversationView::onDialogSaveTone(HbAction* action)
+    {
+    HbMessageBox *dlg = qobject_cast<HbMessageBox*> (sender());
+    if (action == dlg->actions().at(0)) {
+        saveRingingTone();
+    }
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::onOrientationChanged
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::onOrientationChanged(Qt::Orientation newOrientation)
+{
+    Q_UNUSED(newOrientation)
+
+    // On orientation change always make the preserved index(last visible item) to be visible
+    if(mVisibleIndex.isValid())
+    {
+    mConversationList->scrollTo(mVisibleIndex, HbAbstractItemView::PositionAtBottom);
+    mVisibleIndex = QModelIndex();
+    }
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::onOrientationAboutToBeChanged
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::onOrientationAboutToBeChanged()
+{
+    // Preserve the model index of the last visible item to be scrolled on orientation change
+    QList<HbAbstractViewItem *>items = mConversationList->visibleItems();
+    if (items.count() > 0) {
+        mVisibleIndex = items.last()->modelIndex();
+    }
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::onViewReady
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::onViewReady()
+{
+    mViewReady = true;
+    //Disconnect list View's signals, for avoiding execution of the default implementaion
+    disconnect(mainWindow(), SIGNAL(aboutToChangeOrientation()), mConversationList, 0);
+    disconnect(mainWindow(), SIGNAL(orientationChanged(Qt: rientation)), mConversationList, 0);
+    
+   fetchMoreConversations();
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::handleShortTap
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::handleShortTap()
+{
+    HbAbstractViewItem* item = mConversationList->currentViewItem();
+    QRectF rc = item->rect();
+    QPointF p = item->mapToScene(rc.center());
+    
+    showContextMenu(item,p,HbPopup::TopEdgeCenter);
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::handleShortTap
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::showContextMenu(HbAbstractViewItem* viewItem,const QPointF& point, int placement)
+{    
+    MsgConversationViewItem* item = qgraphicsitem_cast<MsgConversationViewItem *>(viewItem);
+
+    // Show the item-specific menu
+    if (this->isVisible())
+    {
+        //If message is in Sending state or is Scheduled to be sent later,
+        //do not allow any operations on the message
+        int sendingState = item->modelIndex().data(SendingState).toInt();
+        
+        if(sendingState == ConvergedMessage::Scheduled ||
+            sendingState == ConvergedMessage::Sending ||
+            sendingState == ConvergedMessage::Waiting)
+            {
+                return;
+            }
+        // Create new menu
+        HbMenu* contextMenu = new HbMenu();
+        contextMenu->setAttribute(Qt::WA_DeleteOnClose);
+        contextMenu->setPreferredPos(point,HbPopup::Placement(placement));
+        setContextMenu(item, contextMenu, sendingState);
+        contextMenu->show();
+    }
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::saveVCard
+// @see header file
+//---------------------------------------------------------------
+void MsgConversationView::saveVCard()
+{
+    QModelIndex index = mConversationList->currentIndex();
+    
+    QString filepath = index.data(Attachments).toStringList().at(0);
+    bool result = MsgContactsUtil::launchVCardViewer(filepath);
+    if(result)
+    {
+        int messageId = index.data(ConvergedMsgId).toInt();
+        QList<int> msgIdList;
+        if(index.data(UnReadStatus).toInt())
+        {
+            msgIdList.clear();
+            msgIdList << messageId;
+            ConversationsEngine::instance()->markMessagesRead(msgIdList);
+        }
+    } 
+}
+
+//---------------------------------------------------------------
+// MsgConversationView::isSharedMessage
+// @see header file
+//---------------------------------------------------------------
+bool MsgConversationView::isSharedMessage(qint32 messageId)
+{
+    bool shared = false;
+
+    UniDataModelLoader* pluginLoader = new UniDataModelLoader();
+    
+    UniDataModelPluginInterface* pluginInterface =
+        pluginLoader->getDataModelPlugin(ConvergedMessage::Mms);
+    
+    CMsvSession* session = pluginInterface->session();
+
+    TMsvEntry entry; 
+    TMsvId service;
+    session->GetEntry(messageId, service, entry);
+    
+    if(entry.MultipleRecipients())
+    {
+        shared = true;
+    }
+    delete pluginLoader;    
+
+    return shared;
+}
+
+// EOF