mainwindow.cpp Example File
serviceactions/mainwindow.cpp
#include "mainwindow.h"
#include "attachmentlistwidget.h"
#include "qmessageservice.h"
#include <qmessagemanager.h>
#include <QComboBox>
#include <QListWidget>
#include <QVBoxLayout>
#include <QLabel>
#include <QTabWidget>
#include <QPointer>
#include <QPushButton>
#include <QDebug>
#include <QLineEdit>
#include <QTextEdit>
#include <QTextBrowser>
#include <QFileDialog>
#include <QTimer>
#include <QMessageBox>
#include <QThread>
#include <QStackedLayout>
#include <QPair>
#include <QScrollArea>
#include <QMenuBar>
#include <QApplication>
#include <QStackedWidget>
#include <QMutex>
#include <QKeyEvent>
#include <QDesktopServices>
#include <QInputDialog>
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 ;
#ifdef NOTHREAD
QMessageManager manager;
if (! runonce)
setIds(manager. queryAccounts());
#else
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 < QMessageId , QListWidgetItem * > 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)));
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());
}
void RecentMessagesWidget:: messagesFound(const QMessageIdList & ids)
{
m_ids. append(ids);
}
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;
}
} else if (newState = = QMessageService :: CanceledState) {
m_state = LoadFinished;
}
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 ;
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
}
void RecentMessagesWidget:: load()
{
m_ids. clear();
m_state = Loading;
bool b;
b= m_service- > queryMessages(QMessageFilter (), QMessageSortOrder :: byReceptionTimeStamp(Qt :: DescendingOrder), m_maxRecent);
};
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();
}
}
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
}
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" );
}
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 < QWidget * > () < < 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);
}
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) {
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;
}
class MessageViewWidget : public QWidget
{
Q_OBJECT
static const unsigned int LoadTimeLimit = 20 ;
static QString changeBetweenBodyAndAttachmentsLinkURL()
{
static const QString changeViewUrl("MessageViewWidget://changeview" );
return changeViewUrl;
};
static QString downloadAttachmentLinkURL()
{
static const QString downloadAttachmentUrl("MessageViewWidget://downloadattachment" );
return downloadAttachmentUrl;
};
static QString openAttachmentLinkURL()
{
static const QString downloadAttachmentUrl("MessageViewWidget://openattachment" );
return downloadAttachmentUrl;
};
static QString downloadLinkURL()
{
static const QString url("MessageViewWidget://download" );
return url;
};
public :
MessageViewWidget(QWidget * parent = 0 );
~ MessageViewWidget();
QMessageId viewing() const ;
signals :
void bodyShown();
void attachmentsShown();
void downloadStarted();
void downloadFinished();
void downloadFailed();
public slots :
void view(const QMessageId & messageId);
void showBodyOrAttachments();
bool retrieveBody();
bool retrieveAttachment(QMessageContentContainerId attachmentId);
bool cancelRetrieve();
bool openAttachment(QMessageContentContainerId attachmentId);
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, LoadCanceled };
void setupUi();
void updateState();
void loadMessage();
void resetService();
public :
bool m_showAttachmentsActivated;
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),
m_showAttachmentsActivated(false )
{
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();
}
void MessageViewWidget:: showBodyOrAttachments()
{
m_showAttachmentsActivated = ! m_showAttachmentsActivated;
if (m_showAttachmentsActivated) {
emit attachmentsShown();
} else {
emit bodyShown();
}
loadMessage();
}
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 ;
}
bool MessageViewWidget:: retrieveAttachment(QMessageContentContainerId attachmentId)
{
if (m_state ! = Loading & & ! m_loadTimer. isActive())
{
m_loadTimer. setSingleShot(true );
m_loadTimer. start(LoadTimeLimit * 1000 );
m_state = Unloaded;
return m_service- > retrieve(m_messageId, attachmentId);
}
return false ;
}
bool MessageViewWidget:: cancelRetrieve()
{
m_service- > cancel();
m_state = LoadCanceled;
updateState();
return true ;
}
bool MessageViewWidget:: openAttachment(QMessageContentContainerId attachmentId)
{
QMessage message(m_messageId);
QMessageContentContainer attachment(message. find(attachmentId));
QString tempFolder = QDesktopServices :: storageLocation(QDesktopServices :: TempLocation);
QString filePath = tempFolder+ "/" + attachment. suggestedFileName();
QFile file(filePath);
if (! file. open(QIODevice :: WriteOnly))
return false ;
QByteArray content = attachment. content();
file. write(content);
file. close();
QDesktopServices :: openUrl(QUrl (QString ("file:///" )+ filePath));
return true ;
}
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)
{
QString urlString = url. toString();
if (urlString = = changeBetweenBodyAndAttachmentsLinkURL()) {
showBodyOrAttachments();
} else if (urlString = = downloadLinkURL()) {
retrieveBody();
} else if (urlString. startsWith(downloadAttachmentLinkURL())) {
retrieveAttachment(QMessageContentContainerId (urlString. remove(0 , downloadAttachmentLinkURL(). length()+ 1 )));
} else if (urlString. startsWith(openAttachmentLinkURL())) {
openAttachment(QMessageContentContainerId (urlString. remove(0 , openAttachmentLinkURL(). length()+ 1 )));
}
}
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)
{
Q_UNUSED(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:
{
emit downloadStarted();
m_statusLabel- > setText("Downloading..." );
m_layoutStack- > setCurrentWidget(m_statusLabel);
} break ;
case Loaded:
{
emit downloadFinished();
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:
{
emit downloadFailed();
m_statusLabel- > setText("Download failed!" );
m_layoutStack- > setCurrentWidget(m_statusLabel);
} break ;
case LoadCanceled:
{
emit downloadFinished();
loadMessage();
m_layoutStack- > setCurrentWidget(m_messageBrowser);
}
}
}
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;
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));
}
}
}
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);
void showBodyOrAttachments();
void retrieveAttachment();
void openAttachment();
void bodyShown();
void attachmentsShown();
void downloadStarted();
void downloadFinished();
void downloadFailed();
private :
void setupUi();
private :
QMessageService * m_service;
RecentMessagesWidget* m_recentMessagesWidget;
MessageViewWidget* m_messageViewWidget;
QAction * m_retrieveAction;
QAction * m_showBodyOrAttachmentsAction;
QAction * m_retrieveAttachmentAction;
QAction * m_openAttachmentAction;
QAction * m_cancelRetrieveAction;
QMap < QString , QString > m_availableAttachments;
QMap < QString , QString > m_notAvailableAttachments;
};
RetrieveWidget:: RetrieveWidget(QWidget * parent)
:
QWidget (parent),
m_recentMessagesWidget(0 ),
m_messageViewWidget(0 ),
m_retrieveAction(0 ),
m_showBodyOrAttachmentsAction(0 ),
m_retrieveAttachmentAction(0 ),
m_openAttachmentAction(0 )
{
setupUi();
connect(m_messageViewWidget, SIGNAL(bodyShown()), this , SLOT(bodyShown()));
connect(m_messageViewWidget, SIGNAL(attachmentsShown()), this , SLOT(attachmentsShown()));
connect(m_messageViewWidget, SIGNAL(downloadStarted()), this , SLOT(downloadStarted()));
connect(m_messageViewWidget, SIGNAL(downloadFinished()), this , SLOT(downloadFinished()));
connect(m_messageViewWidget, SIGNAL(downloadFailed()), this , SLOT(downloadFailed()));
}
void RetrieveWidget:: messageSelected(const QMessageId & messageId)
{
QMessage message(messageId);
m_availableAttachments. clear();
m_notAvailableAttachments. clear();
QMessageContentContainerIdList attachmentIds(message. attachmentIds());
if (attachmentIds. count() > 0 ) {
m_showBodyOrAttachmentsAction- > setEnabled(true );
bool retrieveAttachment = false ;
bool openAttachment = false ;
for (int i = 0 ; i < attachmentIds. count(); + + i) {
QMessageContentContainer attachment(message. find(attachmentIds[ i] ));
QString attachmentName = attachment. suggestedFileName();
if (attachment. isContentAvailable()) {
openAttachment = true ;
m_availableAttachments. insert(attachmentName, attachmentIds[ i] . toString());
} else {
retrieveAttachment = true ;
m_notAvailableAttachments. insert(attachmentName, attachmentIds[ i] . toString());
}
}
if (openAttachment) {
m_openAttachmentAction- > setEnabled(true );
} else {
m_openAttachmentAction- > setEnabled(false );
}
if (retrieveAttachment) {
m_retrieveAttachmentAction- > setEnabled(true );
} else {
m_retrieveAttachmentAction- > setEnabled(false );
}
} else {
m_showBodyOrAttachmentsAction- > setEnabled(false );
m_retrieveAttachmentAction- > setEnabled(false );
m_openAttachmentAction- > setEnabled(false );
}
if (m_messageViewWidget- > m_showAttachmentsActivated) {
m_messageViewWidget- > showBodyOrAttachments();
}
bool partialMessage = ! message. find(message. bodyId()). isContentAvailable();
m_retrieveAction- > setEnabled(partialMessage & & messageId. isValid());
}
void RetrieveWidget:: showBodyOrAttachments()
{
m_messageViewWidget- > showBodyOrAttachments();
}
void RetrieveWidget:: bodyShown()
{
m_showBodyOrAttachmentsAction- > setText("Show Attachments" );
}
void RetrieveWidget:: attachmentsShown()
{
m_showBodyOrAttachmentsAction- > setText("Show Body" );
}
void RetrieveWidget:: downloadStarted()
{
m_showBodyOrAttachmentsAction- > setEnabled(false );
m_retrieveAttachmentAction- > setEnabled(false );
m_openAttachmentAction- > setEnabled(false );
m_cancelRetrieveAction- > setEnabled(true );
}
void RetrieveWidget:: downloadFinished()
{
messageSelected(m_recentMessagesWidget- > currentMessage());
}
void RetrieveWidget:: downloadFailed()
{
messageSelected(m_recentMessagesWidget- > currentMessage());
}
void RetrieveWidget:: retrieveAttachment()
{
if (m_notAvailableAttachments. count() > 1 ) {
QInputDialog inputDialog;
inputDialog. setOptions(QInputDialog :: UseListViewForComboBoxItems);
inputDialog. setComboBoxItems(m_notAvailableAttachments. keys());
inputDialog. setComboBoxEditable(false );
inputDialog. setLabelText("Select attachment" );
inputDialog. exec();
if (inputDialog. result() = = QDialog :: Accepted) {
m_messageViewWidget- > retrieveAttachment(m_notAvailableAttachments. value(inputDialog. textValue()));
}
} else {
m_messageViewWidget- > retrieveAttachment(m_notAvailableAttachments. values(). first());
}
}
void RetrieveWidget:: openAttachment()
{
if (m_availableAttachments. count() > 1 ) {
QInputDialog inputDialog;
inputDialog. setOptions(QInputDialog :: UseListViewForComboBoxItems);
inputDialog. setComboBoxItems(m_availableAttachments. keys());
inputDialog. setComboBoxEditable(false );
inputDialog. setLabelText("Select attachment" );
inputDialog. exec();
if (inputDialog. result() = = QDialog :: Accepted) {
m_messageViewWidget- > openAttachment(m_availableAttachments. value(inputDialog. textValue()));
}
} else {
m_messageViewWidget- > openAttachment(m_availableAttachments. values(). first());
}
}
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_showBodyOrAttachmentsAction = new QAction ("Show Attachments" , this );
connect(m_showBodyOrAttachmentsAction, SIGNAL(triggered(bool )), this , SLOT(showBodyOrAttachments()));
addAction(m_showBodyOrAttachmentsAction);
m_showBodyOrAttachmentsAction- > setEnabled(false );
m_retrieveAction = new QAction ("Retrieve" , this );
connect(m_retrieveAction, SIGNAL(triggered(bool )), m_messageViewWidget, SLOT(retrieveBody()));
addAction(m_retrieveAction);
m_retrieveAction- > setEnabled(false );
m_retrieveAttachmentAction = new QAction ("Retrieve attachment" , this );
connect(m_retrieveAttachmentAction, SIGNAL(triggered(bool )), this , SLOT(retrieveAttachment()));
addAction(m_retrieveAttachmentAction);
m_retrieveAttachmentAction- > setEnabled(false );
m_openAttachmentAction = new QAction ("Open attachment" , this );
connect(m_openAttachmentAction, SIGNAL(triggered(bool )), this , SLOT(openAttachment()));
addAction(m_openAttachmentAction);
m_openAttachmentAction- > setEnabled(false );
m_cancelRetrieveAction = new QAction ("Cancel retrieve" , this );
connect(m_cancelRetrieveAction, SIGNAL(triggered(bool )), m_messageViewWidget, SLOT(cancelRetrieve()));
addAction(m_cancelRetrieveAction);
m_cancelRetrieveAction- > setEnabled(false );
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();
}
void ShowWidget:: showButtonClicked()
{
QMessageId id = m_recentMessagesWidget- > currentMessage();
if (id. isValid())
m_service- > show(id);
}
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();
}
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);
}
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)));
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
}
#ifndef _WIN32_WCE
QMenu * fileMenu = new QMenu ("File" , this );
#endif
int index = 0 ;
foreach(QAction * viewAction, QList < QAction * > () < < 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()));
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();
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< QAction * > (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 <mainwindow.moc>
Best Of
Actualités les plus lues
Le Qt Developer Network au hasard
Le Qt Developer Network est un réseau de développeurs Qt anglophone, où ils peuvent partager leur expérience sur le framework.
Lire l'article.
Communauté
Ressources
Liens utiles
Contact
Vous souhaitez rejoindre la rédaction ou proposer un tutoriel, une traduction, une question... ? Postez dans le forum Contribuez ou contactez-nous par MP ou par email (voir en bas de page).
Qt dans le magazine