diff -r 238255e8b033 -r 84d9eb65b26f messagingapp/msgui/conversationview/src/msgconversationview.cpp --- a/messagingapp/msgui/conversationview/src/msgconversationview.cpp Fri Apr 16 14:56:15 2010 +0300 +++ b/messagingapp/msgui/conversationview/src/msgconversationview.cpp Mon May 03 12:29:07 2010 +0300 @@ -20,29 +20,29 @@ // SYSTEM INCLUDES #include #include -#include -#include -#include -#include -#include #include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include -#include -#include #include #include #include +#include +#include +#include +#include + // USER INCLUDES -#include "msguiutilsmanager.h" +#include "msgsendutil.h" #include "msgconversationviewitem.h" #include "conversationsengine.h" #include "convergedmessageid.h" -#include "convergedmessage.h" #include "conversationsenginedefines.h" #include "msgcontactcardwidget.h" #include "msgeditorwidget.h" @@ -51,38 +51,40 @@ #include "unidatamodelloader.h" #include "unidatamodelplugininterface.h" #include "ringbc.h" +#include "mmsconformancecheck.h" -// LOCAL CONSTANTS -const QString M_SERVER("mserver"); -const QString SMS("sms"); +//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_SAVE hbTrId("txt_common_menu_save") +#define LOC_COMMON_DOWNLOAD hbTrId("txt_messaging_menu_download") +#define LOC_COMMON_SEND hbTrId("txt_common_menu_send") -#define LOC_DELETE_CONVERSATION hbTrId("txt_messaging_dialog_delete_conversation") #define LOC_BUTTON_DELETE hbTrId("txt_common_button_delete") #define LOC_BUTTON_CANCEL hbTrId("txt_common_button_cancel") +#define LOC_BUTTON_OK hbTrId("txt_common_button_ok") #define LOC_DELETE_MESSAGE hbTrId("txt_messaging_dialog_delete_message") -#define LOC_DELETE_POPINFO hbTrId("txt_messaging_dpopinfo_message_deleted") - -const QString HELP(QObject::tr("Help")); -#define LOC_ADD hbTrId("txt_messaging_opt_add") -#define LOC_RECIPIENTS hbTrId("txt_messaging_opt_sub_recipients") -#define LOC_SUBJECT hbTrId("txt_messaging_opt_sub_subject") +//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_ATTACH hbTrId("txt_messaging_opt_attach") -#define LOC_PHOTO hbTrId("txt_messaging_opt_attach_sub_photo") -#define LOC_VIDEO hbTrId("txt_messaging_opt_attach_sub_video") -#define LOC_SOUND hbTrId("txt_messaging_opt_attach_sub_sound") -#define LOC_MORE hbTrId("txt_messaging_opt_attach_sub_more") +#define LOC_MSG_SEND_FAILED hbTrId("txt_messaging_dpopinfo_sending_failed") + const QString PLUGINPATH("conversationviewplugin.dll"); 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 @@ -94,25 +96,16 @@ mMessageModel(NULL), mEditorWidget(NULL), mContactCardWidget(contactCardWidget), - mUiUtilsManager(NULL) + mSendUtil(NULL), + mItemLongPressed(false), + mVkbHost(NULL), + mVkbopened(false) { - // Initialize the Utils manager - mUiUtilsManager = new MsgUiUtilsManager(this); - // connect the error signal from UtilsManager to the slot - // in the conversation view. - connect(mUiUtilsManager, - SIGNAL(serviceError(const QString&)), - this, - SLOT(serviceError(const QString&))); - - connect(mUiUtilsManager, SIGNAL(imagesFetched(const QVariant&)), - this, SLOT(imagesFetched(const QVariant&))); - connect(mUiUtilsManager, SIGNAL(audiosFetched(const QVariant&)), - this, SLOT(audiosFetched(const QVariant&))); - + //create send utils + mSendUtil = new MsgSendUtil(this); //initialize view setupView(); - addMenu(); + setupMenu(); } //--------------------------------------------------------------- @@ -121,7 +114,7 @@ //--------------------------------------------------------------- MsgConversationView::~MsgConversationView() { -mConversationList->setModel(NULL); + } //--------------------------------------------------------------- // MsgConversationView::setupView @@ -140,83 +133,61 @@ mConversationList->setClampingStyle(HbScrollArea::BounceBackClamping); mConversationList->setScrollingStyle(HbScrollArea::PanOrFlick); - mMessageModel = ConversationsEngine::instance()->getConversationsModel(); connect(ConversationsEngine::instance(), - SIGNAL(conversationModelPopulated()), - this, - SLOT(populateConversationsView())); + SIGNAL(conversationModelPopulated()), + this, + SLOT(populateConversationsView())); connect(mConversationList, SIGNAL(activated(QModelIndex)), - this, SLOT(openItem(QModelIndex))); + this, SLOT(openItem(QModelIndex))); // Long tap list item connect(mConversationList, SIGNAL(longPressed(HbAbstractViewItem*, QPointF)), - this, SLOT(longPressed(HbAbstractViewItem*, QPointF))); + this, SLOT(longPressed(HbAbstractViewItem*, QPointF))); - // Create message editor widget. - mEditorWidget = new MsgEditorWidget(); + // 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())); - QGraphicsLinearLayout *mainLayout = new QGraphicsLinearLayout(Qt::Vertical); - mainLayout->setContentsMargins(CONTENT_MARGIN, CONTENT_MARGIN, - CONTENT_MARGIN, CONTENT_MARGIN); - mainLayout->setSpacing(CONTENT_SPACING); - mainLayout->addItem(mConversationList); - mainLayout->addItem(mEditorWidget); - setLayout(mainLayout); + 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(); - - HbEffect::add(QString("ConversationView"), - QString(":/xml/conversationview_effect.fxml"), - QString("show") ); } //--------------------------------------------------------------- // MsgConversationView::addMenu // @see header file //--------------------------------------------------------------- -void MsgConversationView::addMenu() +void MsgConversationView::setupMenu() { - HbMenu *mainMenu = new HbMenu(); - - // Clear conversation - HbAction* clearConversation = mainMenu->addAction(LOC_COMMON_DELETE); - connect(clearConversation, SIGNAL(triggered()), this, SLOT(deleteAll())); - - // Attach sub-menu - HbMenu *attachSubMenu = mainMenu->addMenu(LOC_ATTACH); - - HbAction *addPhoto = attachSubMenu->addAction(LOC_PHOTO); - connect(addPhoto, SIGNAL(triggered()),mUiUtilsManager, SLOT(fetchImages())); - - HbAction *addVideo = attachSubMenu->addAction(LOC_VIDEO); - connect(addVideo, SIGNAL(triggered()),mUiUtilsManager, SLOT(fetchVideo())); - - HbAction *addSound = attachSubMenu->addAction(LOC_SOUND); - connect(addSound, SIGNAL(triggered()),mUiUtilsManager, SLOT(fetchAudio())); - - HbAction *addOther = attachSubMenu->addAction(LOC_MORE); - connect(addOther, SIGNAL(triggered()),mUiUtilsManager, SLOT(fetchOther())); - - HbMenu *addSubMenu = mainMenu->addMenu(LOC_ADD); - - HbAction *addRecipients = addSubMenu->addAction(LOC_RECIPIENTS); - connect(addRecipients, SIGNAL(triggered()), this, SLOT(addRecipients())); - - HbAction *addSubject = addSubMenu->addAction(LOC_SUBJECT); - connect(addSubject, SIGNAL(triggered()),this, SLOT(addSubject())); - - // Help - HbAction* help = mainMenu->addAction(HELP); - connect(help, SIGNAL(triggered()),this, SLOT(launchHelp())); - - setMenu(mainMenu); + // 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())); } //--------------------------------------------------------------- @@ -225,9 +196,21 @@ //--------------------------------------------------------------- void MsgConversationView::refreshView() { - mContactCardWidget->updateContents(); - mContactCardWidget->resize(mContactCardWidget->boundingRect().size()); - scrollToBottom(); + // 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); + mEditorWidget->setEncodingSettings(); + mEditorWidget->show(); + } + mContactCardWidget->updateContents(); + } } //--------------------------------------------------------------- @@ -247,70 +230,185 @@ //--------------------------------------------------------------- void MsgConversationView::longPressed(HbAbstractViewItem* viewItem, const QPointF& point) -{ +{ + mItemLongPressed = true; + MsgConversationViewItem* item = qgraphicsitem_cast< MsgConversationViewItem *> (viewItem); - bool inSide = false; - - if (item) - { - inSide = item->containsPoint(point); - } - - //If point is within the item then show the item-specific menu - if (this->isVisible() && inSide) + // 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::Suspended || - sendingState == ConvergedMessage::Resend || - sendingState == ConvergedMessage::Scheduled || - sendingState == ConvergedMessage::Sending || - sendingState == ConvergedMessage::Waiting) - { - return; - } - // Create new menu - HbMenu *contextMenu = new HbMenu(); + HbMenu* contextMenu = new HbMenu(); + setContextMenu(item, contextMenu, sendingState); - int messageType = item->modelIndex().data(MessageType).toInt(); - - // Add the menu items - HbAction *contextItem4 = contextMenu->addAction(LOC_COMMON_OPEN); - connect(contextItem4, SIGNAL(triggered()), - this, SLOT(openItem())); - - HbAction *contextItem3 = contextMenu->addAction(LOC_COMMON_DELETE); - connect(contextItem3, SIGNAL(triggered()), - this, SLOT(deleteItem())); - - // for provisioning messages don't add forward option - if(messageType != ConvergedMessage::Provisioning && - messageType != ConvergedMessage::RingingTone) - { - HbAction *contextItem2 = contextMenu->addAction(LOC_COMMON_FORWARD); - connect(contextItem2, SIGNAL(triggered()), - this, SLOT(forwardMessage())); - } - - + //Before showing menu reset the flag + mItemLongPressed = false; contextMenu->exec(point); - // Cleanup delete contextMenu; + + } + else + { + // For cases where the long tap check failed + mItemLongPressed = false; } } //--------------------------------------------------------------- +// 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); + addDeleteItemToContextMenu(item, contextMenu, sendingState); +} + +//--------------------------------------------------------------- +// 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( (sendingState == ConvergedMessage::SentState ) || + (sendingState == ConvergedMessage::Resend ) || + (sendingState == ConvergedMessage::Failed ) || + (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(); + + if( (direction == ConvergedMessage::Outgoing)&& + ((sendingState == ConvergedMessage::Resend ) || + (sendingState == ConvergedMessage::Suspended )|| + (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(); + + if( ((sendingState == ConvergedMessage::SentState) || + (sendingState == ConvergedMessage::Resend) || + (sendingState == ConvergedMessage::Failed) || + (direction == ConvergedMessage::Incoming) ) && + (validateMsgForForward(messageType,messageId)) ) + { + 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() { - mUiUtilsManager->activateInputBlocker(this); + activateInputBlocker(); ConvergedMessageAddressList addresses; addresses = mContactCardWidget->address(); int sendResult = KErrNone; @@ -323,48 +421,197 @@ msg.addToRecipients(addresses); // Send - sendResult = mUiUtilsManager->send(msg); + sendResult = mSendUtil->send(msg); + if( sendResult == KErrNone) { mEditorWidget->clear(); } } - mUiUtilsManager->deactivateInputBlocker(); + deactivateInputBlocker(); if( sendResult == KErrNotFound) { - //switch to settings view - QVariantList param; - param << MsgBaseView::MSGSETTINGS; - param << MsgBaseView::CV; - emit switchView(param); + bool result = HbMessageBox::question("SMS Settings not defined\nDefine now ?", + LOC_BUTTON_OK, + LOC_BUTTON_CANCEL); + if (result) + { + //switch to settings view + QVariantList param; + param << MsgBaseView::MSGSETTINGS; + param << MsgBaseView::CV; + emit switchView(param); + } + } +} + +//--------------------------------------------------------------- +// MsgConversationView::contactsFetchedForVCards +// @see header file +//--------------------------------------------------------------- +void MsgConversationView::contactsFetchedForVCards(const QVariant& value) +{ + // get received contact-list and launch unieditor + CntServicesContactList contactList = + qVariantValue(value); + int cntCount = contactList.count(); + if(cntCount > 0) + { + QVariantList params; + params << MsgBaseView::ADD_VCARD; + params << value; + launchUniEditor(params); } } //--------------------------------------------------------------- -// MsgConversationView::deleteAll -// Deletes all the conversations +// MsgConversationView::fetchContacts +// @see header file //--------------------------------------------------------------- -void MsgConversationView::deleteAll() +void MsgConversationView::fetchContacts() +{ + HbAction* action = qobject_cast(sender()); + + if(!action) + return; + + QList 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 { - bool result = HbMessageBox::question(LOC_DELETE_CONVERSATION, - LOC_BUTTON_DELETE, - LOC_BUTTON_CANCEL); - if(result) - { - ConversationsEngine* engine = ConversationsEngine::instance(); - engine->deleteConversations(engine->getCurrentConversationId()); - //show dialog - HbNotificationDialog::launchDialog("Conversation Deleted"); - //switch to CLV - QVariantList param; - param << MsgBaseView::CLV; // target view - param << MsgBaseView::CV; // source view - emit switchView(param); - } + 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 interface("Image"); + QString operation("fetch(QVariantMap,QVariant)"); + XQAiwRequest* request = NULL; + XQApplicationManager appManager; + request = appManager.create(interface, operation, true);//embedded + 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::addPhoto() +// MsgConversationView::fetchAudio +// @see header file +//--------------------------------------------------------------- +void MsgConversationView::fetchAudio() +{ + QString service("Music Fetcher"); + QString interface("com.nokia.services.media.Music"); + QString operation("fetch(QString)"); + XQAiwRequest* request = NULL; + XQApplicationManager appManager; + request = appManager.create(service, interface, operation, true); //embedded + if(!request) + { + QDEBUG_WRITE("AIW-ERROR: NULL request"); + return; + } + + connect(request, SIGNAL(requestOk(const QVariant&)), + this, SLOT(audiosFetched(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::contactsFetched +// @see header file +//--------------------------------------------------------------- +void MsgConversationView::contactsFetched(const QVariant& value) +{ + CntServicesContactList contactList; + contactList = qVariantValue(value); + ConvergedMessageAddressList addresses; + int count = contactList.count(); + if(count > 0) + { + ConvergedMessageAddress* address = new ConvergedMessageAddress; + address->setAlias(mContactCardWidget->address().at(0)->alias()); + address->setAddress(mContactCardWidget->address().at(0)->address()); + addresses.append(address); + for(int i = 0; i < contactList.count(); i++ ) + { + ConvergedMessageAddress* address = new ConvergedMessageAddress; + address->setAlias(contactList[i].mDisplayName); + address->setAddress(contactList[i].mPhoneNumber); + addresses.append(address); + } + + ConvergedMessage message; + message.setBodyText(mEditorWidget->content()); + message.addToRecipients(addresses);//takes the ownership of list elements + QByteArray dataArray; + QDataStream messageStream + (&dataArray, QIODevice::WriteOnly | QIODevice::Append); + message.serialize(messageStream); + QVariantList params; + params << MsgBaseView::UNIEDITOR; // target view + params << MsgBaseView::CV; // source view + params << dataArray; + clearEditors(); + emit switchView(params); + } +} + +//--------------------------------------------------------------- +// MsgConversationView::imagesFetched() // @see header file //--------------------------------------------------------------- void MsgConversationView::imagesFetched(const QVariant& result ) @@ -374,8 +621,11 @@ QStringList fileList = result.value(); if ( fileList.size()>0 ) { - QString filepath(fileList.at(0)); - launchUniEditor(MsgBaseView::ADD_PHOTO, filepath); + QString filepath(QDir::toNativeSeparators(fileList.at(0))); + QVariantList params; + params << MsgBaseView::ADD_PHOTO; + params << filepath; + launchUniEditor(params); } } } @@ -392,22 +642,15 @@ if ( fileList.size()>0 && !fileList.at(0).isEmpty()) { QString filepath(QDir::toNativeSeparators(fileList.at(0))); - launchUniEditor(MsgBaseView::ADD_AUDIO, filepath); + QVariantList params; + params << MsgBaseView::ADD_AUDIO; + params << filepath; + launchUniEditor(params); } } } //--------------------------------------------------------------- -// MsgConversationView::addRecipients() -// @see header file -//--------------------------------------------------------------- -void MsgConversationView::addRecipients() -{ - QString filepath; - launchUniEditor(MsgBaseView::ADD_RECIPIENTS, filepath); -} - -//--------------------------------------------------------------- // MsgConversationView::addSubject() // @see header file //--------------------------------------------------------------- @@ -415,24 +658,9 @@ { QString filepath; - launchUniEditor(MsgBaseView::ADD_SUBJECT, filepath); -} - -//--------------------------------------------------------------- -// MsgConversationView::launchHelp() -// Launches the help content -//--------------------------------------------------------------- -void MsgConversationView::launchHelp() -{ -} - -//--------------------------------------------------------------- -// MsgConversationView::exitApp() -// Exits the application -//--------------------------------------------------------------- -void MsgConversationView::exitApp() -{ - HbApplication::quit(); + QVariantList params; + params << MsgBaseView::ADD_SUBJECT; + launchUniEditor(params); } //--------------------------------------------------------------- @@ -441,6 +669,60 @@ //--------------------------------------------------------------- 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 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); + } + } + +} + +//--------------------------------------------------------------- +// 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("Message Retrieval Failed!"); //TODO: use logical str name + } + } + } //--------------------------------------------------------------- @@ -464,7 +746,6 @@ QList msgIdList; msgIdList.append(messageId); ConversationsEngine::instance()->deleteMessages(msgIdList); - HbNotificationDialog::launchDialog(LOC_DELETE_POPINFO); //switch view if (count == 1) { @@ -488,15 +769,6 @@ } //--------------------------------------------------------------- -// MsgConversationView::setMessageData() -// Set message data -//--------------------------------------------------------------- -void MsgConversationView::setMessageData(const ConvergedMessage &message) -{ - mEditorWidget->setContent(message.bodyText()); -} - -//--------------------------------------------------------------- // MsgConversationView::clearEditors() // @See header //--------------------------------------------------------------- @@ -516,7 +788,7 @@ int msgId = INVALID_MSGID; if(!mEditorWidget->content().isEmpty()) { - mUiUtilsManager->activateInputBlocker(this); + activateInputBlocker(); ConvergedMessageAddressList addresses; addresses = mContactCardWidget->address(); @@ -526,119 +798,78 @@ ConvergedMessage msg; populateForSending(msg); msg.addToRecipients(addresses); - - // Send - msgId = mUiUtilsManager->saveToDrafts(msg); - + + // save to drafts + msgId = mSendUtil->saveToDrafts(msg); + mEditorWidget->clear(); } - mUiUtilsManager->deactivateInputBlocker(); + deactivateInputBlocker(); } return ((msgId > INVALID_MSGID)? true : false); } //--------------------------------------------------------------- -// MsgConversationView::loadCommandPlugin() -// @See header -//--------------------------------------------------------------- -bool MsgConversationView::loadCommandPlugin() -{ - /* -#ifdef _DEBUG - QDir dir(QLibraryInfo::location(QLibraryInfo::PluginsPath)); - dir.cd("messaging"); -#else - QDir dir("Z:/resource/qt/plugins/messaging"); -#endif -#ifdef _DEBUG_TRACES_ - qDebug() << "MsgConversationView::plugins path" << dir.path(); -#endif - - // load the plugins - QFileInfoList entries = dir.entryInfoList(QDir::Files | QDir::Readable); - foreach (QFileInfo entry, entries) - { - QPluginLoader loader(entry.absoluteFilePath()); -#ifdef _DEBUG_TRACES_ - qDebug() << "MsgConversationView::absolute path" - << entry.absoluteFilePath(); -#endif - mMsgCmdPlugin = qobject_cast ( - loader.instance()); - if (mMsgCmdPlugin) - { - return true; - } - }*/ - return false; -} - -//--------------------------------------------------------------- -//MsgConversationView::parseServiceId() -//@see header -//--------------------------------------------------------------- -QString MsgConversationView::parseServiceId(const QString &serviceId) -{ - QStringList services = serviceId.split('.'); - // the service id is in the form "messaging.mserver.mms" - // split the string by '.' and compare the middle part - // by the server names. - return services[1]; -} - -//--------------------------------------------------------------- -//MsgConversationView::currentMessageType() -//@see header -//--------------------------------------------------------------- -int MsgConversationView::currentMessageType() -{ - QString serviceId = mEditorWidget->serviceId(); - QString sendClientType = parseServiceId(serviceId); - - ConvergedMessage::MessageType messageType = ConvergedMessage::None; - if ( (M_SERVER == sendClientType) && serviceId.contains(SMS)) - { - messageType = ConvergedMessage::Sms; - } - return messageType; -} -//--------------------------------------------------------------- //MsgConversationView::populateForSending() //@see header //--------------------------------------------------------------- void MsgConversationView::populateForSending(ConvergedMessage &message) { - ConvergedMessage::MessageType messageType = - static_cast (currentMessageType()); + message.setMessageType(ConvergedMessage::Sms); + message.setBodyText(mEditorWidget->content()); + message.setDirection(ConvergedMessage::Outgoing); + QDateTime time = QDateTime::currentDateTime(); + message.setTimeStamp(time.toTime_t()); +} - if (ConvergedMessage::Sms == messageType) - { - message.setMessageType(messageType); - 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(); + + QString interface("com.nokia.services.btmsgdispservices.displaymsg"); + QString operation("displaymsg(int)"); + + XQServiceRequest request(interface, operation, false); + + request << messageId; + + bool result = request.send(); } //--------------------------------------------------------------- -// MsgConversationView::serviceError() +// MsgConversationView::menuAboutToShow() // @See header //--------------------------------------------------------------- -void MsgConversationView::serviceError(const QString& error) +void MsgConversationView::menuAboutToShow() { - Q_UNUSED(error) -// HbDialog popup; -// -// popup.setDismissPolicy(HbDialog::TapAnywhere); -// popup.setHeadingWidget(new HbLabel(tr("Error Notification"))); -// -// /// set a label as the content widget in the popup. -// HbLabel contentLabel(error); -// popup.setContentWidget(&contentLabel); -// -// popup.setPrimaryAction(new HbAction(tr("Ok"), &popup)); -// popup.exec(); + // 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())); + } } //--------------------------------------------------------------- @@ -647,23 +878,61 @@ //--------------------------------------------------------------- void MsgConversationView::openItem(const QModelIndex & index) { - int messageType = index.data(MessageType).toInt(); - if(messageType == ConvergedMessage::RingingTone ) + // Return if invalid index. + if (!index.isValid() || mVkbopened) { - if(RingBc::askSaveQuery()) - { - saveRingingTone(); - } return; } - - /// smart messages hardcoded due to common handling - if (messageType == ConvergedMessage::BioMsg - || messageType >= ConvergedMessage::VCard) - { - return; - } - + + if(mItemLongPressed) + return; + + int messageType = index.data(MessageType).toInt(); + int messageSubType = index.data(MessageSubType).toInt(); + + if (ConvergedMessage::BioMsg == messageType) { + if (ConvergedMessage::RingingTone == messageSubType) { + if (RingBc::askSaveQuery()) { + saveRingingTone(); + } + return; + } + // Unsupported messages + else if (ConvergedMessage::VCard == messageSubType + || ConvergedMessage::VCal == messageSubType + || ConvergedMessage::Provisioning == messageSubType) { + return; + } + } + else if (ConvergedMessage::BT == messageType) { + launchBtDisplayService(index); + 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 + if(HbMessageBox::question("Download Message?", + LOC_COMMON_DOWNLOAD, + LOC_BUTTON_CANCEL)) + { + downloadMessage(); + } + return; + } + } + ConvergedMessage message; // check whether message is in sending progress, then donot launch viewer. int location = index.data(MessageLocation).toInt(); @@ -672,7 +941,6 @@ //If message is in Sending state or is Scheduled to be sent later, //do not open the message if(sendingState == ConvergedMessage::Suspended || - sendingState == ConvergedMessage::Resend || sendingState == ConvergedMessage::Scheduled || sendingState == ConvergedMessage::Sending || sendingState == ConvergedMessage::Waiting) @@ -684,7 +952,9 @@ // movement lock issue is resolved from mw if( !((location == ConvergedMessage::Inbox) || (location == ConvergedMessage::Sent) || - (sendingState == ConvergedMessage::SentState)) ) + (sendingState == ConvergedMessage::SentState)|| + (sendingState == ConvergedMessage::Failed) || + (sendingState == ConvergedMessage::Resend))) {// do not launch viewer, show a note HbNotificationDialog* dlg = new HbNotificationDialog(); dlg->setFocusPolicy(Qt::NoFocus); @@ -707,6 +977,7 @@ // message type message.setMessageType((ConvergedMessage::MessageType) messageType); + message.setMessageSubType((ConvergedMessage::MessageSubType) messageSubType); if (messageType == ConvergedMessage::Mms) { @@ -762,35 +1033,67 @@ // MsgConversationView::launchUniEditor // @see header file //--------------------------------------------------------------- -void MsgConversationView::launchUniEditor(const int editorFields, QString& filepath) +void MsgConversationView::launchUniEditor(const QVariantList& data) { - ConvergedMessage message; - message.setBodyText(mEditorWidget->content()); - - ConvergedMessageAddress address; - address.setAlias(mContactCardWidget->address().at(0)->alias()); - address.setAddress(mContactCardWidget->address().at(0)->address()); - message.addToRecipient(address); - - if(!filepath.isEmpty()) - { - ConvergedMessageAttachment* attachment = new ConvergedMessageAttachment(filepath); - ConvergedMessageAttachmentList attachmentList; - attachmentList.append(attachment); - message.addAttachments(attachmentList); - } - + // param list for switching to editor view + QVariantList params; QByteArray dataArray; QDataStream messageStream (&dataArray, QIODevice::WriteOnly | QIODevice::Append); - message.serialize(messageStream); + + // 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()); + + ConvergedMessageAddress address; + address.setAlias(mContactCardWidget->address().at(0)->alias()); + address.setAddress(mContactCardWidget->address().at(0)->address()); + message.addToRecipient(address); - QVariantList params; - params << MsgBaseView::UNIEDITOR; // target view - params << MsgBaseView::CV; // source view + 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 + { + 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 << editorFields; + params << editorOperation; + if(!data2.isNull()) + params << data2; clearEditors(); emit switchView(params); @@ -802,58 +1105,154 @@ //--------------------------------------------------------------- void MsgConversationView::populateConversationsView() { - connect(mMessageModel, SIGNAL(conversationModelUpdated()), - this, SLOT(refreshView())); + bool b = connect(ConversationsEngine::instance(), + SIGNAL(conversationModelUpdated()), + this, + SLOT(scrollToBottom())); mConversationList->setModel(mMessageModel); refreshView(); - - HbEffect::start(this,QString("ConversationView"), - QString("show"),this,"effectFinished"); + scrollToBottom(); } //--------------------------------------------------------------- -// MsgConversationView::effectFinished -// @see header file -//--------------------------------------------------------------- -void MsgConversationView::effectFinished( - const HbEffect::EffectStatus& /*status*/) - { - // Effect is finished. Start fetching remaing conversations - ConversationsEngine::instance()->fetchMoreConversations(); - } - -//--------------------------------------------------------------- // MsgConversationView::saveRingingTone // @see header file //--------------------------------------------------------------- void MsgConversationView::saveRingingTone() - { +{ QModelIndex index = mConversationList->currentIndex(); int messageId = index.data(ConvergedMsgId).toInt(); - + UniDataModelLoader* pluginLoader = new UniDataModelLoader(); - pluginLoader->loadPlugins(); UniDataModelPluginInterface* pluginInterface = - pluginLoader->getDataModelPlugin("bio:vcal"); + pluginLoader->getDataModelPlugin(ConvergedMessage::BioMsg); pluginInterface->setMessageId(messageId); UniMessageInfoList attachments = pluginInterface->attachmentList(); - - QString attachmentPath = attachments[0]->path(); - - RingBc* ringBc = new RingBc(); - - ringBc->saveTone(attachmentPath); - - // clear attachement list : its allocated at data model - while(!attachments.isEmpty()) + 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 attachments.takeFirst(); } - delete ringBc; + delete ringBc; + } delete pluginLoader; +} + +//--------------------------------------------------------------- +// MsgConversationView::handleSmsCharLimitReached +// @see header file +//--------------------------------------------------------------- +void MsgConversationView::handleSmsCharLimitReached() +{ + QString filepath; + QVariantList params; + params << MsgBaseView::ADD_OTHERS; + launchUniEditor(params); +} + +//--------------------------------------------------------------- +// MsgConversationView::validateMsgForForward +// @see header file +//--------------------------------------------------------------- +bool MsgConversationView::validateMsgForForward(int &messageType, + qint32 &messageId) +{ + bool retValue = true; + if (messageType == ConvergedMessage::Mms) + { + //Validate if the mms msg can be forwarded or not + MmsConformanceCheck* mmsConformanceCheck = new MmsConformanceCheck; + retValue = mmsConformanceCheck->validateMsgForForward(messageId); + + delete mmsConformanceCheck; } + return retValue; +} + +//--------------------------------------------------------------- +// MsgConversationView::vkbOpened +// @see header file +//--------------------------------------------------------------- +void MsgConversationView::vkbOpened() +{ + mVkbopened = true; + + mContactCardWidget->connectSignals(false); + + emit hideChrome(true); + + 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); + + disconnect(mVkbHost,SIGNAL(keypadOpened()),this,SLOT(vkbOpened())); + + scrollToBottom(); +} + +//--------------------------------------------------------------- +// MsgConversationView::vkbClosed +// @see header file +//--------------------------------------------------------------- +void MsgConversationView::vkbClosed() +{ + mVkbopened = false; + + mContactCardWidget->connectSignals(true); + + emit hideChrome(false); + + this->setMaximumHeight(-1); + 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() + { + this->grabMouse(); + this->grabKeyboard(); + } + +//--------------------------------------------------------------- +// MsgConversationView::deactivateInputBlocker +// @see header file +//-------------------------------------------------------------- +void MsgConversationView::deactivateInputBlocker() + { + this->ungrabKeyboard(); + this->ungrabMouse(); + } + + // EOF