MeeGo 1.2 Harmattan Developer Documentation Develop for the Nokia N9

Service Actions Example

Files:

This simple example demonstrates how to compose, send, show, query and retrieve messages, and also react to message store events using the QtMobility Messaging API.

Each of these actions is demonstrated in a separate sub example accessible from the "File" menu of each platform.

Send and Compose

Messages are sent and composed from a composition widget under the "Compose/Send" menu. Relevant message details such as sending account, recipients and message bodies (attachments for email accounts) can be entered by the user via corresponding UI elements. A QMessage is constructed using these details:

 QMessage ComposeSendWidget::constructQMessage(bool asHtml) const
 {
     QMessage message;

     if(m_accountsWidget->isEmpty())
     {
         QMessageBox::critical(const_cast<ComposeSendWidget*>(this),"No Accounts","Cannot send a message without any available accounts");
         return message;
     }

     QMessageAccountId selectedAccountId = m_accountsWidget->currentAccount();
     QMessageAccount selectedAccount(selectedAccountId);

     bool composingSms = (selectedAccount.messageTypes() & QMessage::Sms) > 0;

     QMessageAddressList toList;
     QMessageAddressList ccList;
     QMessageAddressList bccList;

     QMessageAddress::Type addressType = QMessageAddress::Email;
     if(composingSms)
     {
         addressType = QMessageAddress::Phone;
         message.setType(QMessage::Sms);
     }

     foreach(QString s, m_toEdit->text().split(QRegExp("\\s"),QString::SkipEmptyParts))
         toList.append(QMessageAddress(addressType, s));
     message.setTo(toList);

     if(!composingSms)
     {
         foreach(QString s, m_ccEdit->text().split(QRegExp("\\s"),QString::SkipEmptyParts))
             ccList.append(QMessageAddress(QMessageAddress::Email, s));
         message.setCc(ccList);

         foreach(QString s, m_bccEdit->text().split(QRegExp("\\s"),QString::SkipEmptyParts))
             bccList.append(QMessageAddress(QMessageAddress::Email, s));
         message.setBcc(bccList);
         message.setSubject(m_subjectEdit->text());

         message.setType(QMessage::Email);

         message.appendAttachments(m_attachmentList->attachments());
     }

     message.setParentAccountId(selectedAccountId);

     if(!composingSms && asHtml) {
         //create html body
         QString htmlBody("<html><head><title></title></head><body><h2 align=center>%1</h2><hr>%2</body></html>");
         message.setBody(htmlBody.arg(message.subject()).arg(m_bodyEdit->toPlainText()),"text/html");
     }
     else
         message.setBody(m_bodyEdit->toPlainText());

     return message;
 }

The message is then passed to the QMessageService::compose() or QMessageService::send() service actions to initiate sending of the message by the platform, or trigger display by the platforms' message composer with the QMessage contents:

 void ComposeSendWidget::composeButtonClicked()
 {
     QMessage message(constructQMessage());
     m_service->compose(message);
 }

 void ComposeSendWidget::sendButtonClicked()
 {
     bool asHtml = (sender() == m_sendAsHTMLAction);
     QMessage message(constructQMessage(asHtml));
     notifyResult(m_service->send(message),"Send message");
 }

Show

Messages are displayed by a show widget under the "Show" menu. This widget displays the users last 50 messages. (Ensure the platform has one or more messages in its mail accounts).

The last 50 messages (incoming/outgoing) are queried from the store using the QMessageService::queryMessages() service request:

 void RecentMessagesWidget::load()
 {
     m_ids.clear();
     m_state = Loading;
     bool b;

     b=m_service->queryMessages(QMessageFilter(),QMessageSortOrder::byReceptionTimeStamp(Qt::DescendingOrder),m_maxRecent);

Once the results of the query are returned via the QMessageService::messagesFound() signal, the widget loads each of the returned messages in turn and populates it's list with message subjects.

 void RecentMessagesWidget::messagesFound(const QMessageIdList& ids)
 {
     m_ids.append(ids);
 }
 void RecentMessagesWidget::processResults()
 {
     if(!m_ids.isEmpty())
     {
         QMessageId id = m_ids.takeFirst();
         QMessage message(id);

         QListWidgetItem* newItem = new QListWidgetItem(message.from().addressee()+QString(":")+message.subject());
         newItem->setData(MessageIdRole,id.toString());
         QFont itemFont = newItem->font();
         bool isPartialMessage = !message.find(message.bodyId()).isContentAvailable();
         itemFont.setItalic(isPartialMessage);
         newItem->setFont(itemFont);
         m_messageListWidget->addItem(newItem);
         m_indexMap.insert(id,newItem);
         m_messageListWidget->update();
         QTimer::singleShot(100,this,SLOT(processResults()));
     }
     else
     {
         m_state = Done;
         updateState();
     }
 }

Selecting "Show" from the action menu will display the selected message using the platforms' message viewer via the QMessageService::show() service action.

 void ShowWidget::showButtonClicked()
 {

     QMessageId id = m_recentMessagesWidget->currentMessage();

     if(id.isValid())
         m_service->show(id);
 }

Query and Retrieve

Message contents are displayed/retrieved by a retrieve widget under the "Query/Retrieve" menu. This example displays the last 50 messages, as in the "Show" example, but also displays message content in a QTextBrowser widget and provides the option to download messages that are incomplete.

After the message list is populated, the message display widget will attempt to load and display the currently selected message. The completeness of the message body is checked using the QMessageContentContainer::isContentAvailable function. If the message body is partially downloaded, a download link is displayed.

 void MessageViewWidget::loadMessage()
 {
     m_messageBrowser->clear();

     static const QString htmlTemplate("\
     <html>\
     <head>\
     </head>\
     <body>\
     <table border=\"0\" cellspacing=\"0\">\
         <tr><td><b>From: </b></td><td>%1</td></tr>\
         <tr><td><b>Subject: </b></td><td>%2</td></tr>\
         <tr><td><b>Date: </b></td><td>%3</td></tr>\
         %4\
     </table>\
     <hr>%5\
     <\body>\
     </html>\
     ");

     if(m_messageId.isValid())
     {
         QMessage message(m_messageId);

         QString changeViewTypeLink;
         if (m_showAttachmentsActivated) {
             QString attachments;
             QString changeViewTypeLink = QString("<tr><td></td><td><b><a href=\"%1\">Body</a></b></td></tr>")\
                                          .arg(changeBetweenBodyAndAttachmentsLinkURL());
             QMessageContentContainerIdList attachmentIds(message.attachmentIds());
             for (int i = 0; i < attachmentIds.count(); ++i) {
                 QMessageContentContainer attachment(message.find(attachmentIds[i]));
                 QString attachmentName = attachment.suggestedFileName();
                 if (attachment.isContentAvailable()) {
                     attachments += QString("<b>%1 </b><a href=\"%2\">Open</a><br>")\
                                    .arg(attachmentName)\
                                    .arg(openAttachmentLinkURL()+"/"+attachmentIds[i].toString());
                 } else {
                     attachments += QString("<b>%1 </b><a href=\"%2\">Download</a><br>")\
                                    .arg(attachmentName)\
                                    .arg(downloadAttachmentLinkURL()+"/"+attachmentIds[i].toString());
                 }
             }
             m_messageBrowser->setHtml(htmlTemplate\
                                      .arg(message.from().addressee())\
                                      .arg(message.subject())\
                                      .arg(message.receivedDate().toString())\
                                      .arg(changeViewTypeLink)\
                                      .arg(attachments));
         } else {
             QString changeViewTypeLink;
             QMessageContentContainerIdList attachmentIds(message.attachmentIds());
             if (attachmentIds.count() > 0) {
                 changeViewTypeLink = QString("<tr><td></td><td><b><a href=\"%1\">Attachments (%2)</a></b></td></tr>")\
                                      .arg(changeBetweenBodyAndAttachmentsLinkURL())\
                                      .arg(attachmentIds.count());
             }
             QMessageContentContainer bodyPart = message.find(message.bodyId());

             QString bodyText;

             //for partial message display a download link instead

             bool bodyAvailable = bodyPart.isContentAvailable();

             if (bodyAvailable)
             {
                 if (bodyPart.contentType() == "text")
                     bodyText = bodyPart.textContent();
                 else bodyText = "<Non-text content>";
             }
             else
                 bodyText = QString("<p align=\"center\"><a href=\"%1\">Download</a></p>").arg(downloadLinkURL());
             m_messageBrowser->setHtml(htmlTemplate\
                                      .arg(message.from().addressee())\
                                      .arg(message.subject())\
                                      .arg(message.receivedDate().toString())\
                                      .arg(changeViewTypeLink)\
                                      .arg(bodyText));
         }
     }
 }

When the download link is clicked, the message body is retrieved using the QMessageService::retrieveBody() service action.

 bool MessageViewWidget::retrieveBody()
 {
     if(m_state != Loading && !m_loadTimer.isActive())
     {
         m_loadTimer.setSingleShot(true);
         m_loadTimer.start(LoadTimeLimit * 1000);
         m_state = Unloaded;

         return m_service->retrieveBody(m_messageId);
     }

     return false;
 }

Store Signals

This example displays the activities of the QMessageManager in a QListWidget by connecting to QMessageManager::message(Added/Updated/Removed) signals.

 void StoreSignalsWidget::messageAdded(const QMessageId& id, const QMessageManager::NotificationFilterIdSet& filterSet)
 {
     if(!filterSet.contains(m_notificationFilterId))
         return;

     QMessage message(id);

     QString msg = QString("Added: %1").arg(message.subject());
     m_activityListWidget->addItem(msg);
 }

 void StoreSignalsWidget::messageUpdated(const QMessageId& id, const QMessageManager::NotificationFilterIdSet& filterSet)
 {
     if(!filterSet.contains(m_notificationFilterId))
         return;

     QMessage message(id);

     QString msg = QString("Updated: %1").arg(message.subject());
     m_activityListWidget->addItem(msg);
 }

 void StoreSignalsWidget::messageRemoved(const QMessageId& id, const QMessageManager::NotificationFilterIdSet& filterSet)
 {
     if(!filterSet.contains(m_notificationFilterId))
         return;

     QString idString(id.toString());
     idString.truncate(10);

     QString msg = QString("Removed ID: %1 ...").arg(idString);
     m_activityListWidget->addItem(msg);
 }