diff -r 000000000000 -r 876b1a06bc25 examples/serviceactions/mainwindow.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/serviceactions/mainwindow.cpp Wed Aug 25 15:49:42 2010 +0300 @@ -0,0 +1,1371 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include "attachmentlistwidget.h" +#include "qmessageservice.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const QSize WindowGeometry(400,300); +static const QString WindowTitle("Service-actions Example"); +static unsigned int RecentMessagesCount = 50; + +class AccountsWidget : public QWidget +{ + Q_OBJECT + +private: + class Loader : public QThread + { + public: + Loader(AccountsWidget* parent); + void run(); + + private: + AccountsWidget* m_parent; + }; + +public: + AccountsWidget(QWidget* parent = 0); + QMessageAccountId currentAccount() const; + QString currentAccountName() const; + bool isEmpty() const; + +signals: + void accountChanged(); + +protected: + void showEvent(QShowEvent* e); + void hideEvent(QHideEvent* e); + +private slots: + void load(); + void loadStarted(); + void loadFinished(); + +private: + void setupUi(); + void setIds(const QMessageAccountIdList& ids); + QMessageAccountIdList ids() const; + +private: + QStackedLayout* m_stackedLayout; + QComboBox* m_accountsCombo; + QLabel* m_busyLabel; + + Loader m_loader; + mutable QMutex m_loadMutex; + QMessageAccountIdList m_ids; +}; + +AccountsWidget::Loader::Loader(AccountsWidget* parent) +: +QThread(parent), +m_parent(parent) +{ +} + +void AccountsWidget::Loader::run() +{ + QMessageManager manager; + m_parent->setIds(manager.queryAccounts()); +} + +AccountsWidget::AccountsWidget(QWidget* parent) +: +QWidget(parent), +m_stackedLayout(0), +m_accountsCombo(0), +m_busyLabel(0), +m_loader(this) +{ + setupUi(); + + connect(&m_loader,SIGNAL(started()),this,SLOT(loadStarted())); + connect(&m_loader,SIGNAL(finished()),this,SLOT(loadFinished())); +} + +QMessageAccountId AccountsWidget::currentAccount() const +{ + QMessageAccountId result; + if(m_loader.isFinished() && m_accountsCombo->count()) + { + int index = m_accountsCombo->currentIndex(); + return ids().at(index); + } + + return result; +} + +QString AccountsWidget::currentAccountName() const +{ + if(m_loader.isFinished() && m_accountsCombo->count()) + return m_accountsCombo->itemData(m_accountsCombo->currentIndex()).toString(); + return QString(); +} + +bool AccountsWidget::isEmpty() const +{ + return m_accountsCombo->count() == 0; +} + +void AccountsWidget::showEvent(QShowEvent* e) +{ + load(); + QWidget::showEvent(e); +} + +void AccountsWidget::hideEvent(QHideEvent* e) +{ + if(m_loader.isRunning()) + m_loader.exit(); + QWidget::hideEvent(e); +} + +void AccountsWidget::load() +{ + static bool runonce = false; + //#define NOTHREAD +#ifdef NOTHREAD + QMessageManager manager; + if(!runonce) + setIds(manager.queryAccounts()); + // m_loader.start(); + +#else + // if(!runonce) + m_loader.start(); +#endif + runonce = true; +} + +void AccountsWidget::loadStarted() +{ +#ifndef _WIN32_WCE + setCursor(Qt::BusyCursor); +#endif + m_stackedLayout->setCurrentWidget(m_busyLabel); +} + +void AccountsWidget::loadFinished() +{ + m_accountsCombo->clear(); + + QMessageAccountIdList accountIds = ids(); + + if(!accountIds.isEmpty()) + { + for(int i = 0; i < accountIds.count(); ++i) + { + QMessageAccount account(accountIds[i]); + m_accountsCombo->addItem(QString("%1 - %2").arg(i+1).arg(account.name()),account.name()); + } + + m_stackedLayout->setCurrentWidget(m_accountsCombo); + } + else + m_busyLabel->setText("No accounts!"); + +#ifndef _WIN32_WCE + setCursor(Qt::ArrowCursor); +#endif +} + +void AccountsWidget::setupUi() +{ + m_stackedLayout = new QStackedLayout(this); + + m_accountsCombo = new QComboBox(this); + m_stackedLayout->addWidget(m_accountsCombo); + connect(m_accountsCombo,SIGNAL(currentIndexChanged(int)),this,SIGNAL(accountChanged())); + + m_busyLabel = new QLabel("Loading..."); + m_stackedLayout->addWidget(m_busyLabel); + + setSizePolicy(m_accountsCombo->sizePolicy()); + +} + +void AccountsWidget::setIds(const QMessageAccountIdList& ids) +{ + QMutexLocker mutex(&m_loadMutex); + + m_ids = ids; +} + +QMessageAccountIdList AccountsWidget::ids() const +{ + QMutexLocker mutex(&m_loadMutex); + return m_ids; +} + +class RecentMessagesWidget : public QWidget +{ + Q_OBJECT + +public: + RecentMessagesWidget(QWidget* parent = 0, unsigned int maxRecent = 10); + ~RecentMessagesWidget(); + QMessageId currentMessage() const; + +signals: + void selected(const QMessageId& messageId); + +protected: + void showEvent(QShowEvent* e); + void hideEvent(QHideEvent* e); + +private slots: + void currentItemChanged(QListWidgetItem* current, QListWidgetItem* previous); + void messagesFound(const QMessageIdList& result); + void stateChanged(QMessageService::State s); + void messageUpdated(const QMessageId& id, const QMessageManager::NotificationFilterIdSet& filter); + void messageRemoved(const QMessageId& id, const QMessageManager::NotificationFilterIdSet& filter); + void processResults(); + +private: + void setupUi(); + void updateState(); + void load(); + +private: + enum State { Unloaded, Loading, LoadFinished, Processing, LoadFailed, Done }; + static const int MessageIdRole = Qt::UserRole + 1; + +private: + QListWidget* m_messageListWidget; + QLabel* m_statusLabel; + QStackedLayout* m_layout; + QMessageIdList m_ids; + QMap m_indexMap; + unsigned int m_maxRecent; + QMessageService* m_service; + State m_state; + QMessageManager::NotificationFilterId m_storeFilterId; + QMessageManager m_manager; +}; + +RecentMessagesWidget::RecentMessagesWidget(QWidget* parent, unsigned int maxRecent) +: +QWidget(parent), +m_messageListWidget(0), +m_statusLabel(0), +m_layout(0), +m_maxRecent(maxRecent), +m_service(new QMessageService(this)), +m_state(Unloaded) +{ + setupUi(); + connect(m_service,SIGNAL(messagesFound(const QMessageIdList&)),this,SLOT(messagesFound(const QMessageIdList&))); + connect(m_service,SIGNAL(stateChanged(QMessageService::State)),this,SLOT(stateChanged(QMessageService::State))); + + //register for message update notifications + + connect(&m_manager, SIGNAL(messageUpdated(const QMessageId&, const QMessageManager::NotificationFilterIdSet&)), + this, SLOT(messageUpdated(const QMessageId&, const QMessageManager::NotificationFilterIdSet&))); + connect(&m_manager, SIGNAL(messageRemoved(const QMessageId&, const QMessageManager::NotificationFilterIdSet&)), + this, SLOT(messageRemoved(const QMessageId&, const QMessageManager::NotificationFilterIdSet&))); + + m_storeFilterId = m_manager.registerNotificationFilter(QMessageFilter()); +} + +RecentMessagesWidget::~RecentMessagesWidget() +{ + m_manager.unregisterNotificationFilter(m_storeFilterId); +} + +QMessageId RecentMessagesWidget::currentMessage() const +{ + QMessageId result; + + if(QListWidgetItem* currentItem = m_messageListWidget->currentItem()) + result = QMessageId(currentItem->data(MessageIdRole).toString()); + + return result; +} + +void RecentMessagesWidget::showEvent(QShowEvent* e) +{ + if(m_state == Unloaded) + load(); + + updateState(); + + QWidget::showEvent(e); +} + +void RecentMessagesWidget::hideEvent(QHideEvent* e) +{ + if(m_state == Loading || m_state == Processing) + { + m_service->cancel(); + m_state = Unloaded; + m_ids.clear(); + } + + QWidget::hideEvent(e); +} + +void RecentMessagesWidget::currentItemChanged(QListWidgetItem*, QListWidgetItem*) +{ + if(m_state != Processing || m_state != Loading) + emit selected(currentMessage()); +} + +//! [process-results] +void RecentMessagesWidget::messagesFound(const QMessageIdList& ids) +{ + m_ids.append(ids); +} +//! [process-results] + +void RecentMessagesWidget::stateChanged(QMessageService::State newState) +{ + if (newState == QMessageService::FinishedState) { + if ((m_state != LoadFailed) && (m_service->error() == QMessageManager::NoError)) { + m_state = LoadFinished; + } else { + m_state = LoadFailed; + } + } + + updateState(); +} + + +void RecentMessagesWidget::messageUpdated(const QMessageId& id, const QMessageManager::NotificationFilterIdSet& filter) +{ + if(!filter.contains(m_storeFilterId) || m_state == Loading || !id.isValid() || !m_indexMap.contains(id)) + return; + + //update the pertinent entry to reflect completeness + + QListWidgetItem* item = m_indexMap.value(id); + if(item) + { + + QMessage message(id); + bool partialMessage = !message.find(message.bodyId()).isContentAvailable(); + QFont itemFont = item->font(); + itemFont.setItalic(partialMessage); + item->setFont(itemFont); + } +} + +void RecentMessagesWidget::messageRemoved(const QMessageId& id, const QMessageManager::NotificationFilterIdSet& filter) +{ + if(!filter.contains(m_storeFilterId) || m_state == Loading || !id.isValid() || !m_indexMap.contains(id)) + return; + + QListWidgetItem* item = m_indexMap.value(id); + if(item) + { + int row = m_messageListWidget->row(item); + QListWidgetItem* item = m_messageListWidget->takeItem(row); + m_indexMap.remove(id); + delete item; + } + m_ids.removeAll(id); +} + +void RecentMessagesWidget::setupUi() +{ + m_layout = new QStackedLayout(this); + + m_messageListWidget = new QListWidget(this); + m_layout->addWidget(m_messageListWidget); + connect(m_messageListWidget,SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this,SLOT(currentItemChanged(QListWidgetItem*,QListWidgetItem*))); + + m_statusLabel = new QLabel(this); + m_statusLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + m_statusLabel->setFrameStyle(QFrame::Box); + m_layout->addWidget(m_statusLabel); + +} + +void RecentMessagesWidget::updateState() +{ + switch(m_state) + { + case Unloaded: + { + m_statusLabel->setText(QString()); + m_layout->setCurrentWidget(m_statusLabel); + } + break; + case Loading: + { + m_statusLabel->setText("Loading..."); + m_layout->setCurrentWidget(m_statusLabel); + } + break; + case LoadFinished: + { + if(m_ids.isEmpty()) + { + m_statusLabel->setText("Finished. No messages."); + m_layout->setCurrentWidget(m_statusLabel); + } + else + { + m_state = Processing; + updateState(); + processResults(); + } + } + break; + case Processing: + m_layout->setCurrentWidget(m_messageListWidget); + break; + case LoadFailed: + { + m_statusLabel->setText("Load failed!"); + m_layout->setCurrentWidget(m_statusLabel); + } + break; + } + +#ifndef _WIN32_WCE + if(m_state == Loading || m_state == Processing) + setCursor(Qt::BusyCursor); + else + setCursor(Qt::ArrowCursor); +#endif + +} + +//! [load-message] +void RecentMessagesWidget::load() +{ + m_ids.clear(); + m_state = Loading; + bool b; + + b=m_service->queryMessages(QMessageFilter(),QMessageSortOrder::byReceptionTimeStamp(Qt::DescendingOrder),m_maxRecent); +//! [load-message] +}; + +//! [process-results2] +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(); + } +} +//! [process-results2] + +class ComposeSendWidget : public QWidget +{ + Q_OBJECT + +public: + ComposeSendWidget(QMessageService* service, QWidget* parent = 0); + +signals: + void actionsChanged(); + +private slots: + void composeButtonClicked(); + void sendButtonClicked(); + void addAttachmentButtonClicked(); + void accountChanged(); + +private: + void setupUi(); + QMessage constructQMessage(bool asHtml = false) const; + +private: + QStackedLayout* m_layoutStack; + QMessageService* m_service; + AccountsWidget* m_accountsWidget; + QLineEdit* m_toEdit; + QLineEdit* m_ccEdit; + QLabel* m_ccLabel; + QLineEdit* m_bccEdit; + QLabel* m_bccLabel; + QLineEdit* m_subjectEdit; + QLabel* m_subjectLabel; + QTextEdit* m_bodyEdit; + AttachmentListWidget* m_attachmentList; + QAction* m_attachmentsAction; + QAction* m_sendAsHTMLAction; +}; + +ComposeSendWidget::ComposeSendWidget(QMessageService* service, QWidget* parent) +: +QWidget(parent), +m_layoutStack(0), +m_service(service), +m_accountsWidget(0), +m_toEdit(0), +m_ccEdit(0), +m_ccLabel(0), +m_bccEdit(0), +m_bccLabel(0), +m_subjectEdit(0), +m_subjectLabel(0), +m_bodyEdit(0), +m_attachmentList(0), +m_attachmentsAction(0), +m_sendAsHTMLAction(0) +{ + setupUi(); +} + +static void notifyResult(bool result, const QString& description) +{ +#ifndef _WIN32_WCE + if(result) QMessageBox::information(0,description,"Succeeded!"); + else QMessageBox::critical(0,description,"Failed."); +#else + Q_UNUSED(result); + Q_UNUSED(description); +#endif +} + +//! [send-compose-message] +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"); +} +//! [send-compose-message] + +void ComposeSendWidget::addAttachmentButtonClicked() +{ + QStringList filenames = QFileDialog::getOpenFileNames(this,tr("Select attachments")); + m_attachmentList->addAttachments(filenames); +} + +void ComposeSendWidget::accountChanged() +{ + QMessageAccount currentAccount(m_accountsWidget->currentAccount()); + + bool isSmsAccount = (currentAccount.messageTypes() & QMessage::Sms) > 0; + + foreach(QWidget* emailSpecificWidget , QList() << m_bccEdit << m_bccLabel << + m_ccEdit << m_ccLabel << + m_subjectEdit << m_subjectLabel) { + emailSpecificWidget->setVisible(!isSmsAccount); + } + + m_attachmentsAction->setEnabled(!isSmsAccount); + m_sendAsHTMLAction->setEnabled(!isSmsAccount); +} + +void ComposeSendWidget::setupUi() +{ + QGridLayout* gl = new QGridLayout(this); + + QLabel* accountLabel = new QLabel("Account:",this); + gl->addWidget(accountLabel,0,0); + + m_accountsWidget = new AccountsWidget(this); + gl->addWidget(m_accountsWidget,0,1); + + connect(m_accountsWidget,SIGNAL(accountChanged()),this,SLOT(accountChanged())); + + QLabel* toLabel = new QLabel("To:",this); + gl->addWidget(toLabel,1,0); + + m_toEdit = new QLineEdit(this); + gl->addWidget(m_toEdit,1,1); + + m_ccLabel = new QLabel("Cc:",this); + gl->addWidget(m_ccLabel,2,0); + + m_ccEdit = new QLineEdit(this); + gl->addWidget(m_ccEdit,2,1); + + m_bccLabel = new QLabel("Bcc",this); + gl->addWidget(m_bccLabel,3,0); + + m_bccEdit = new QLineEdit(this); + gl->addWidget(m_bccEdit,3,1); + + m_subjectLabel = new QLabel("Subject:",this); + gl->addWidget(m_subjectLabel,4,0); + + m_subjectEdit = new QLineEdit(this); + gl->addWidget(m_subjectEdit,4,1); + + m_bodyEdit = new QTextEdit(this); + gl->addWidget(m_bodyEdit,5,0,1,2); + + m_attachmentList = new AttachmentListWidget(this); + gl->addWidget(m_attachmentList,6,0,1,2); + m_attachmentList->hide(); + + QAction* composeAction = new QAction("Compose",this); + connect(composeAction,SIGNAL(triggered()),this,SLOT(composeButtonClicked())); + addAction(composeAction); + + QAction* sendAction = new QAction("Send",this); + connect(sendAction,SIGNAL(triggered()),this,SLOT(sendButtonClicked())); + addAction(sendAction); + + m_sendAsHTMLAction = new QAction("Send as HTML",this); + connect(m_sendAsHTMLAction,SIGNAL(triggered()),this,SLOT(sendButtonClicked())); + addAction(m_sendAsHTMLAction); + + QAction* separator = new QAction(this); + separator->setSeparator(true); + addAction(separator); + + m_attachmentsAction = new QAction("Add attachment",this); + connect(m_attachmentsAction,SIGNAL(triggered()),this,SLOT(addAttachmentButtonClicked())); + addAction(m_attachmentsAction); +} + + +//! [construct-message] +QMessage ComposeSendWidget::constructQMessage(bool asHtml) const +{ + QMessage message; + + if(m_accountsWidget->isEmpty()) + { + QMessageBox::critical(const_cast(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("

%1


%2"); + message.setBody(htmlBody.arg(message.subject()).arg(m_bodyEdit->toPlainText()),"text/html"); + } + else + message.setBody(m_bodyEdit->toPlainText()); + + return message; +} +//! [construct-message] + +class MessageViewWidget : public QWidget +{ + Q_OBJECT + + static const unsigned int LoadTimeLimit = 20; //seconds + + static QString downloadLinkURL() + { + static const QString url("MessageViewWidget://download"); + return url; + }; + +public: + MessageViewWidget(QWidget* parent = 0); + ~MessageViewWidget(); + + QMessageId viewing() const; + +public slots: + void view(const QMessageId& messageId); + bool retrieveBody(); + +protected: + void showEvent(QShowEvent* e); + void hideEvent(QHideEvent* e); + +private slots: + void stateChanged(QMessageService::State s); + void loadTimeout(); + void linkClicked(const QUrl&); + void messageUpdated(const QMessageId&, const QMessageManager::NotificationFilterIdSet& filterSet); + void messageRemoved(const QMessageId&, const QMessageManager::NotificationFilterIdSet& filterSet); + + +private: + enum State { Unloaded , Loaded, Loading, LoadFailed }; + void setupUi(); + void updateState(); + void loadMessage(); + void resetService(); + +private: + QStackedLayout* m_layoutStack; + QLabel* m_statusLabel; + QMessageService* m_service; + QLineEdit* m_fromLabel; + QLineEdit* m_subjectLabel; + QTextBrowser* m_messageBrowser; + QMessageId m_messageId; + State m_state; + QTimer m_loadTimer; + QMessageManager::NotificationFilterId m_storeFilterId; + QMessageManager m_manager; +}; + +MessageViewWidget::MessageViewWidget(QWidget* parent) +: +QWidget(parent), +m_layoutStack(0), +m_statusLabel(0), +m_service(new QMessageService(this)), +m_messageBrowser(0), +m_state(Unloaded) +{ + setupUi(); + resetService(); + connect(&m_loadTimer,SIGNAL(timeout()),this,SLOT(loadTimeout())); + connect(&m_manager, SIGNAL(messageUpdated(const QMessageId&,const QMessageManager::NotificationFilterIdSet&)), + this,SLOT(messageUpdated(const QMessageId&,const QMessageManager::NotificationFilterIdSet&))); + connect(&m_manager, SIGNAL(messageRemoved(const QMessageId&,const QMessageManager::NotificationFilterIdSet&)), + this,SLOT(messageRemoved(const QMessageId&,const QMessageManager::NotificationFilterIdSet&))); + m_storeFilterId = m_manager.registerNotificationFilter(QMessageFilter()); +} + +MessageViewWidget::~MessageViewWidget() +{ + m_manager.unregisterNotificationFilter(m_storeFilterId); +} + +void MessageViewWidget::view(const QMessageId& messageId) +{ + m_messageId = messageId; + m_state = m_messageId.isValid() ? Loaded : Unloaded; + + updateState(); +} + +//! [retrieve-message-body] +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; +} + +//! [retrieve-message-body] + +void MessageViewWidget::showEvent(QShowEvent* e) +{ + updateState(); + QWidget::showEvent(e); +} + +void MessageViewWidget::hideEvent(QHideEvent* e) +{ + if(m_state == Loading) + { + m_service->cancel(); + m_state = Unloaded; + } + + QWidget::hideEvent(e); +} + +void MessageViewWidget::stateChanged(QMessageService::State newState) +{ + if (m_state == LoadFailed) + return; + + if (newState == QMessageService::ActiveState) { + m_state = Loading; + } else if (newState == QMessageService::FinishedState) { + m_state = (m_service->error() == QMessageManager::NoError ? Loaded : LoadFailed); + } + + updateState(); +} + +void MessageViewWidget::loadTimeout() +{ + qWarning() << "Load timeout"; + m_service->cancel(); + m_state = LoadFailed; + updateState(); +} + +void MessageViewWidget::linkClicked(const QUrl& url) +{ + bool downloadLinkClicked = url.toString() == downloadLinkURL(); + + if(downloadLinkClicked) + retrieveBody(); +} + +void MessageViewWidget::messageUpdated(const QMessageId& id, const QMessageManager::NotificationFilterIdSet& filterSet) +{ + if(!filterSet.contains(m_storeFilterId) || m_state == Loading || !id.isValid() || id != m_messageId) + return; + + view(id); +} + +void MessageViewWidget::messageRemoved(const QMessageId& id, const QMessageManager::NotificationFilterIdSet& filterSet) +{ + if(id == m_messageId) + { + m_state = Unloaded; + m_loadTimer.stop(); + m_messageId = QMessageId(); + view(QMessageId()); + } +} + +QMessageId MessageViewWidget::viewing() const +{ + return m_messageId; +} + +void MessageViewWidget::setupUi() +{ + m_layoutStack = new QStackedLayout(this); + + m_statusLabel = new QLabel(this); + m_statusLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + m_layoutStack->addWidget(m_statusLabel); + + m_messageBrowser = new QTextBrowser(this); + m_messageBrowser->setOpenLinks(false); + connect(m_messageBrowser,SIGNAL(anchorClicked(const QUrl&)),this,SLOT(linkClicked(const QUrl&))); + m_layoutStack->addWidget(m_messageBrowser); +} + +void MessageViewWidget::updateState() +{ + switch(m_state) + { + case Unloaded: + { + m_messageBrowser->clear(); + m_layoutStack->setCurrentWidget(m_messageBrowser); + } break; + case Loading: + { + m_statusLabel->setText("Downloading..."); + m_layoutStack->setCurrentWidget(m_statusLabel); + } break; + case Loaded: + { + if(m_loadTimer.isActive()) + { + m_loadTimer.stop(); + if(m_service->state() == QMessageService::ActiveState) + m_service->cancel(); + } + + loadMessage(); + m_layoutStack->setCurrentWidget(m_messageBrowser); + } break; + case LoadFailed: + { + m_statusLabel->setText("Download failed!"); + m_layoutStack->setCurrentWidget(m_statusLabel); + } break; + } +} + +//! [partial-message-check] +void MessageViewWidget::loadMessage() +{ + m_messageBrowser->clear(); + + static const QString htmlTemplate("\ + \ + \ + \ + \ + \ + \ + \ + \ +
From: %1
Subject: %2
Date: %3
\ +
%4\ + <\body>\ + \ + "); + + if(m_messageId.isValid()) + { + QMessage message(m_messageId); + + 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 = ""; + } + else + bodyText = QString("

Download

").arg(downloadLinkURL()); + m_messageBrowser->setHtml(htmlTemplate\ + .arg(message.from().addressee())\ + .arg(message.subject())\ + .arg(message.receivedDate().toString())\ + .arg(bodyText)); + } +} +//! [partial-message-check] + +void MessageViewWidget::resetService() +{ + if(m_service) + m_service->deleteLater(); + m_service = new QMessageService(this); + connect(m_service,SIGNAL(stateChanged(QMessageService::State)),this,SLOT(stateChanged(QMessageService::State))); +} + +class RetrieveWidget : public QWidget +{ + Q_OBJECT + +public: + RetrieveWidget(QWidget* parent = 0); + +private slots: + void messageSelected(const QMessageId& messageId); + +private: + void setupUi(); + +private: + QMessageService* m_service; + RecentMessagesWidget* m_recentMessagesWidget; + MessageViewWidget* m_messageViewWidget; + QAction* m_retrieveAction; +}; + +RetrieveWidget::RetrieveWidget(QWidget* parent) +: +QWidget(parent), +m_recentMessagesWidget(0), +m_messageViewWidget(0), +m_retrieveAction(0) +{ + setupUi(); +} + +void RetrieveWidget::messageSelected(const QMessageId& messageId) +{ + QMessage message(messageId); + bool partialMessage = !message.find(message.bodyId()).isContentAvailable(); + + m_retrieveAction->setEnabled(partialMessage && messageId.isValid()); +} + +void RetrieveWidget::setupUi() +{ + QVBoxLayout* l = new QVBoxLayout(this); + l->addWidget(new QLabel(QString("Last %1 messages:").arg(RecentMessagesCount),this)); + + m_recentMessagesWidget = new RecentMessagesWidget(this,RecentMessagesCount); + l->addWidget(m_recentMessagesWidget); + + m_messageViewWidget = new MessageViewWidget(this); + l->addWidget(m_messageViewWidget); + + m_retrieveAction = new QAction("Retrieve",this); + connect(m_retrieveAction,SIGNAL(triggered(bool)),m_messageViewWidget,SLOT(retrieveBody())); + addAction(m_retrieveAction); + + connect(m_recentMessagesWidget,SIGNAL(selected(const QMessageId&)),m_messageViewWidget,SLOT(view(const QMessageId&))); + connect(m_recentMessagesWidget,SIGNAL(selected(const QMessageId&)),this,SLOT(messageSelected(const QMessageId&))); +} + +class ShowWidget : public QWidget +{ + Q_OBJECT + +public: + ShowWidget(QMessageService* service, QWidget* parent = 0); + +private slots: + void showButtonClicked(); + +private: + void setupUi(); + +private: + QMessageService* m_service; + RecentMessagesWidget* m_recentMessagesWidget; +}; + +ShowWidget::ShowWidget(QMessageService* service, QWidget* parent) +: +QWidget(parent), +m_service(service), +m_recentMessagesWidget(0) +{ + setupUi(); +} + +//! [show-message] +void ShowWidget::showButtonClicked() +{ + + QMessageId id = m_recentMessagesWidget->currentMessage(); + + if(id.isValid()) + m_service->show(id); +} +//! [show-message] + +void ShowWidget::setupUi() +{ + QVBoxLayout* vbl = new QVBoxLayout(this); + + QString labelText("Last %1 messages:"); + vbl->addWidget(new QLabel(labelText.arg(RecentMessagesCount),this)); + + m_recentMessagesWidget = new RecentMessagesWidget(this,RecentMessagesCount); + vbl->addWidget(m_recentMessagesWidget); + + QAction* showAction = new QAction("Show",this); + connect(showAction,SIGNAL(triggered()),this,SLOT(showButtonClicked())); + addAction(showAction); +} + +class StoreSignalsWidget : public QWidget +{ + Q_OBJECT + +public: + StoreSignalsWidget(QWidget* parent = 0); + +private slots: + void messageAdded(const QMessageId&, const QMessageManager::NotificationFilterIdSet&); + void messageUpdated(const QMessageId&, const QMessageManager::NotificationFilterIdSet&); + void messageRemoved(const QMessageId&, const QMessageManager::NotificationFilterIdSet&); + +private: + void setupUi(); + void appendString(const QString& message); + +private: + QListWidget* m_activityListWidget; + QMessageManager::NotificationFilterId m_notificationFilterId; + QMessageManager m_manager; +}; + +StoreSignalsWidget::StoreSignalsWidget(QWidget* parent) +: +QWidget(parent), +m_activityListWidget(0) +{ + setupUi(); +} + +//! [store-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); +} +//! [store-signals] + +void StoreSignalsWidget::setupUi() +{ + m_activityListWidget = new QListWidget(this); + QVBoxLayout* l = new QVBoxLayout(this); + l->setSpacing(0); + l->setContentsMargins(0,0,0,0); + l->addWidget(m_activityListWidget); + + connect(&m_manager, + SIGNAL(messageAdded(const QMessageId&,const QMessageManager::NotificationFilterIdSet&)), + this, + SLOT(messageAdded(const QMessageId&,const QMessageManager::NotificationFilterIdSet&))); + + connect(&m_manager, + SIGNAL(messageRemoved(const QMessageId&,const QMessageManager::NotificationFilterIdSet&)), + this, + SLOT(messageRemoved(const QMessageId&,const QMessageManager::NotificationFilterIdSet&))); + + connect(&m_manager, + SIGNAL(messageUpdated(const QMessageId&,const QMessageManager::NotificationFilterIdSet&)), + this, + SLOT(messageUpdated(const QMessageId&,const QMessageManager::NotificationFilterIdSet&))); + + m_notificationFilterId = m_manager.registerNotificationFilter(QMessageFilter()); + + QAction* clearAction = new QAction("Clear",this); + connect(clearAction,SIGNAL(triggered(bool)),m_activityListWidget,SLOT(clear())); + addAction(clearAction); +} + +MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags f) +: +QMainWindow(parent,f), +m_tabWidget(0) +{ + + m_service = new QMessageService(this); + + connect(m_service,SIGNAL(stateChanged(QMessageService::State)), + this,SLOT(serviceStateChanged(QMessageService::State))); + + //example widgets + + m_widgetStack = new QStackedWidget(this); + setCentralWidget(m_widgetStack); + + foreach(QWidget* exampleWidget, QWidgetList() << new ComposeSendWidget(m_service,this) + << new ShowWidget(m_service,this) + << new RetrieveWidget(this) + << new StoreSignalsWidget(this)) { + + m_widgetStack->addWidget(exampleWidget); +#ifdef _WIN32_WCE + exampleWidget->installEventFilter(this); +#endif + } + + //main menu +#ifndef _WIN32_WCE + QMenu* fileMenu = new QMenu("File",this); +#endif + + int index = 0; + foreach(QAction* viewAction, QList() << new QAction("Compose\\Send",this) + << new QAction("Show",this) + << new QAction("Retrieve/Query",this) + << new QAction("Store Signals",this)) + { + connect(viewAction,SIGNAL(triggered()),this,SLOT(viewSelected())); +#ifndef _WIN32_WCE + fileMenu->addAction(viewAction); +#else + menuBar()->addAction(viewAction); +#endif + viewAction->setData(index); + index++; + } +#ifndef _WIN32_WCE + fileMenu->addSeparator(); +#else + menuBar()->addSeparator(); +#endif + + QAction* quitAction = new QAction("Quit",this); + connect(quitAction,SIGNAL(triggered()),qApp,SLOT(quit())); +#ifndef _WIN32_WCE + fileMenu->addAction(quitAction); + menuBar()->addMenu(fileMenu); +#else + menuBar()->addAction(quitAction); +#endif + + QTimer::singleShot(0,this,SLOT(viewSelected())); + + //window properties + + setWindowTitle(WindowTitle); + resize(WindowGeometry); + +} + +#ifdef _WIN32_WCE +bool MainWindow::eventFilter(QObject* source, QEvent* e) +{ + bool actionChanged = (m_widgetStack->currentWidget() == source) && e->type() == QEvent::ActionChanged; + if(actionChanged) + viewSelected(); //update the menu items + return false; +} +#endif + +void MainWindow::serviceStateChanged(QMessageService::State newState) +{ + if ((newState == QMessageService::FinishedState) && (m_service->error() != QMessageManager::NoError)) + QMessageBox::critical(this,"Error","One or more service actions failed"); +} + +void MainWindow::viewSelected() +{ + static QMenu* actionMenu = 0; + + if(!actionMenu) + { + actionMenu = new QMenu("Action",this); +#ifndef _WIN32_WCE + menuBar()->addMenu(actionMenu); +#endif + } + QAction* senderAction = qobject_cast(sender()); + if(senderAction) + m_widgetStack->setCurrentIndex(senderAction->data().toInt()); + + bool currentViewHasActions = m_widgetStack->currentWidget() && !m_widgetStack->currentWidget()->actions().isEmpty(); + actionMenu->clear(); + if(currentViewHasActions) + { + foreach(QAction* a, m_widgetStack->currentWidget()->actions()) + actionMenu->addAction(a); + } +#ifdef _WIN32_WCE + static QAction* leftSoftButton = new QAction("Action",this); + leftSoftButton->setMenu(actionMenu); + menuBar()->setDefaultAction(leftSoftButton); +#endif +} + +#include +