diff options
author | AleksW <qt-info@nokia.com> | 2009-05-07 18:06:28 +1000 |
---|---|---|
committer | AleksW <qt-info@nokia.com> | 2009-05-07 18:06:28 +1000 |
commit | 871d75f382edf04840fc805f9ba26896642cbc29 (patch) | |
tree | e76e0b6b57caf4f9309d6e4582f293dab9e25551 | |
parent | 9887907dd98df020c12dc64f8d58ae1ff18bb8df (diff) |
Improve attachment handling widget in email composer.2009W19
-rw-r--r-- | src/plugins/composers/email/attachmentlistwidget.cpp | 422 | ||||
-rw-r--r-- | src/plugins/composers/email/attachmentlistwidget.h | 46 | ||||
-rw-r--r-- | src/plugins/composers/email/email.pro | 6 | ||||
-rw-r--r-- | src/plugins/composers/email/emailcomposer.cpp | 13 | ||||
-rw-r--r-- | src/plugins/composers/email/emailcomposer.h | 8 |
5 files changed, 489 insertions, 6 deletions
diff --git a/src/plugins/composers/email/attachmentlistwidget.cpp b/src/plugins/composers/email/attachmentlistwidget.cpp new file mode 100644 index 00000000..ab519686 --- /dev/null +++ b/src/plugins/composers/email/attachmentlistwidget.cpp @@ -0,0 +1,422 @@ +#include "attachmentlistwidget.h" +#include <QStringListModel> +#include <QListView> +#include <QVBoxLayout> +#include <QLabel> +#include <QDebug> +#include <QMessageBox> +#include <QDialogButtonBox> +#include <QTreeView> +#include <QFileInfo> +#include <QItemDelegate> +#include <QPainter> +#include <QPointer> +#include <QMouseEvent> +#include <QHeaderView> + +static QString sizeString(uint size) +{ + if(size < 1024) + return QObject::tr("%n byte(s)", "", size); + else if(size < (1024 * 1024)) + return QObject::tr("%1 KB").arg(((float)size)/1024.0, 0, 'f', 1); + else if(size < (1024 * 1024 * 1024)) + return QObject::tr("%1 MB").arg(((float)size)/(1024.0 * 1024.0), 0, 'f', 1); + else + return QObject::tr("%1 GB").arg(((float)size)/(1024.0 * 1024.0 * 1024.0), 0, 'f', 1); +} + +static QStringList headers(QStringList() << "Attachment" << "Size" << ""); +class AttachmentListWidget; + +class AttachmentListHeader : public QHeaderView +{ + Q_OBJECT +public: + AttachmentListHeader(AttachmentListWidget* parent); + +signals: + void clear(); + +protected: + void paintSection(QPainter * painter, const QRect & rect, int logicalIndex) const; + bool viewportEvent(QEvent* e); + void mouseMoveEvent(QMouseEvent* e); + void mousePressEvent(QMouseEvent* e); + bool overRemoveLink(QMouseEvent* e); + +private: + AttachmentListWidget* m_parent; + mutable QRect m_removeButtonRect; + +}; + +AttachmentListHeader::AttachmentListHeader(AttachmentListWidget* parent) +: +QHeaderView(Qt::Horizontal,parent), +m_parent(parent) +{ +} + +void AttachmentListHeader::paintSection(QPainter * painter, const QRect & rect, int logicalIndex) const +{ + if(logicalIndex == 2 && m_parent->attachments().count() > 1) + { + painter->save(); + QFont font = painter->font(); + font.setUnderline(true); + painter->setFont(font); + painter->drawText(rect,Qt::AlignHCenter | Qt::AlignVCenter,"Remove All",&m_removeButtonRect); + painter->restore(); + } + else + QHeaderView::paintSection(painter,rect,logicalIndex); +} + +bool AttachmentListHeader::viewportEvent(QEvent* e) +{ + if(e->type() == QEvent::Leave) + setCursor(QCursor()); + return QAbstractItemView::viewportEvent(e); +} + +void AttachmentListHeader::mouseMoveEvent(QMouseEvent* e) +{ + QHeaderView::mouseMoveEvent(e); + if(overRemoveLink(e)) + { + QCursor handCursor(Qt::PointingHandCursor); + setCursor(handCursor); + } + else if(cursor().shape() == Qt::PointingHandCursor) + setCursor(QCursor()); +} + +void AttachmentListHeader::mousePressEvent(QMouseEvent* e) +{ + if(overRemoveLink(e)) + emit clear(); + QHeaderView::mousePressEvent(e); +} + +bool AttachmentListHeader::overRemoveLink(QMouseEvent* e) +{ + return m_removeButtonRect.contains(e->pos()); +} + +class AttachmentListDelegate : public QItemDelegate +{ +public: + AttachmentListDelegate(AttachmentListWidget* parent = 0); + void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; + bool isOverRemoveLink(const QRect& parentRect, const QPoint& pos) const; + +private: + QPointer<AttachmentListWidget> m_parent; +}; + +AttachmentListDelegate::AttachmentListDelegate(AttachmentListWidget* parent) +: +QItemDelegate(parent), +m_parent(parent) +{ +} + +void AttachmentListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ +// QStyleOptionViewItem myStyle(option); +// myStyle.state &= ~QStyle::State_HasFocus; + if(index.isValid() && index.column() == 2) + { + painter->save(); + QFont font = painter->font(); + QColor c = m_parent->palette().brush(QPalette::Link).color(); + font.setUnderline(true); + painter->setPen(c); + painter->setFont(font); + painter->drawText(option.rect,Qt::AlignHCenter,"Remove"); + painter->restore(); + } + else + QItemDelegate::paint(painter,option,index); +} + +bool AttachmentListDelegate::isOverRemoveLink(const QRect& parentRect, const QPoint& pos) const +{ + QFont font; + font.setUnderline(true); + QFontMetrics fm(font); + QRect textRect = fm.boundingRect(parentRect,Qt::AlignHCenter,"Remove"); + return textRect.contains(pos); +} + +class AttachmentListView : public QTreeView +{ + Q_OBJECT + +public: + AttachmentListView(QWidget* parent = 0); + +signals: + void removeAttachmentAtIndex(int index); + +protected: + bool viewportEvent(QEvent* e); + void mouseMoveEvent(QMouseEvent* e); + void mousePressEvent(QMouseEvent* e); + bool overRemoveLink(QMouseEvent* e); +}; + +AttachmentListView::AttachmentListView(QWidget* parent) +: +QTreeView(parent) +{ + setMouseTracking(true); + installEventFilter(this); +} + +bool AttachmentListView::viewportEvent(QEvent* e) +{ + if(e->type() == QEvent::Leave) + setCursor(QCursor()); + return QAbstractItemView::viewportEvent(e); +} + +void AttachmentListView::mouseMoveEvent(QMouseEvent* e) +{ + if(overRemoveLink(e)) + { + QCursor handCursor(Qt::PointingHandCursor); + setCursor(handCursor); + } + else if(cursor().shape() == Qt::PointingHandCursor) + setCursor(QCursor()); + QTreeView::mouseMoveEvent(e); +} + +void AttachmentListView::mousePressEvent(QMouseEvent* e) +{ + if(overRemoveLink(e)) + { + QModelIndex index = indexAt(e->pos()); + emit removeAttachmentAtIndex(index.row()); + } + QTreeView::mousePressEvent(e); +} + +bool AttachmentListView::overRemoveLink(QMouseEvent* e) +{ + QModelIndex index = indexAt(e->pos()); + if(index.isValid() && index.column() == 2) + { + AttachmentListDelegate* delegate = static_cast<AttachmentListDelegate*>(itemDelegate()); + return delegate->isOverRemoveLink(visualRect(index),e->pos()); + } + return false; +} + +class AttachmentListModel : public QAbstractListModel +{ +public: + AttachmentListModel(QWidget* parent ); + QVariant headerData(int section,Qt::Orientation orientation, int role = Qt::DisplayRole ) const; + int columnCount(const QModelIndex & parent = QModelIndex()) const; + int rowCount(const QModelIndex & parent = QModelIndex()) const; + QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const; + + QStringList attachments() const; + void setAttachments(const QStringList& attachments); + +private: + QStringList m_attachments; +}; + +AttachmentListModel::AttachmentListModel(QWidget* parent) +: +QAbstractListModel(parent) +{ +} + +QVariant AttachmentListModel::headerData(int section, Qt::Orientation o, int role) const +{ + if (role == Qt::DisplayRole) + { + if(section < headers.count()) + return headers.at(section); + } + + return QAbstractListModel::headerData(section,o,role); +} + +int AttachmentListModel::columnCount(const QModelIndex & parent ) const +{ + Q_UNUSED(parent); + return headers.count(); +} + +int AttachmentListModel::rowCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + return m_attachments.count(); +} + +QVariant AttachmentListModel::data( const QModelIndex & index, int role) const +{ + if(index.isValid()) + { + if(role == Qt::DisplayRole && index.isValid()) + { + QString path = m_attachments.at(index.row()); + QFileInfo fi(path); + + switch(index.column()) + { + case 0: + return fi.fileName(); + break; + case 1: + return sizeString(fi.size()); + break; + } + } + else if((role == Qt::DecorationRole || role == Qt::CheckStateRole )&& index.column() > 0) + return QVariant(); + else if(role == Qt::CheckStateRole) + { + /* + Qt::CheckState state = static_cast<Qt::CheckState>(QMailAttachmentListModel::data(index,role).toInt()); + if(state == Qt::Unchecked) + */ + return QVariant(); + } + else if(role == Qt::DecorationRole) + { + static QIcon attachIcon( ":icon/attach" ); + return attachIcon; + } + } + return QVariant(); +} + +QStringList AttachmentListModel::attachments() const +{ + return m_attachments; +} + +void AttachmentListModel::setAttachments(const QStringList& attachments) +{ + m_attachments = attachments; + reset(); +} + +AttachmentListWidget::AttachmentListWidget(QWidget* parent) +: +QWidget(parent), +m_listView(new AttachmentListView(this)), +m_model(new AttachmentListModel(this)), +m_delegate(new AttachmentListDelegate(this)), +m_clearLink(new QLabel(this)) +{ + m_clearLink->setTextInteractionFlags(Qt::LinksAccessibleByMouse); + m_clearLink->setTextFormat(Qt::RichText); + + m_listView->setModel(m_model); + m_listView->setSelectionMode(QAbstractItemView::NoSelection); + AttachmentListHeader* header = new AttachmentListHeader(this); + connect(header,SIGNAL(clear()),this,SLOT(clearClicked())); + m_listView->setHeader(header); + m_listView->header()->setStretchLastSection(true); + m_listView->header()->setResizeMode(QHeaderView::ResizeToContents); + m_listView->header()->setDefaultSectionSize(180); + m_listView->setUniformRowHeights(true); + m_listView->setRootIsDecorated(false); + m_listView->setItemDelegate(m_delegate); + + + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setSpacing(0); + layout->setContentsMargins(0,0,0,0); + layout->addWidget(m_listView); + +// m_clearLink->setAlignment(Qt::AlignHCenter); +// layout->addWidget(m_clearLink); +// connect(this,SIGNAL(attachmentsAdded(QStringList)),this,SLOT(updateClearLabel())); +// connect(this,SIGNAL(attachmentsRemoved(QString)),this,SLOT(updateClearLabel())); + connect(m_clearLink,SIGNAL(linkActivated(QString)),this,SLOT(clearClicked())); + connect(m_listView,SIGNAL(removeAttachmentAtIndex(int)),this,SLOT(removeAttachmentAtIndex(int))); + + + // updateClearLabel(); +} + +QStringList AttachmentListWidget::attachments() const +{ + return m_attachments; +} + +void AttachmentListWidget::addAttachment(const QString& attachment) +{ + if(m_attachments.contains(attachment)) + return; + m_attachments.append(attachment); + m_model->setAttachments(m_attachments); + setVisible(!m_attachments.isEmpty()); + emit attachmentsAdded(QStringList() << attachment); +} + +void AttachmentListWidget::addAttachments(const QStringList& attachments) +{ + QSet<QString> result = attachments.toSet() - m_attachments.toSet(); + m_attachments += result.toList(); + m_model->setAttachments(m_attachments); + setVisible(!m_attachments.isEmpty()); + emit attachmentsAdded(result.toList()); +} + +void AttachmentListWidget::removeAttachment(const QString& attachment) +{ + if(!m_attachments.contains(attachment)) + return; + + m_attachments.removeAll(attachment); + m_model->setAttachments(m_attachments); + setVisible(!m_attachments.isEmpty()); + emit attachmentsRemoved(attachment); +} + +void AttachmentListWidget::clear() +{ + m_attachments.clear(); + m_model->setAttachments(m_attachments); + setVisible(false); +} + +void AttachmentListWidget::updateClearLabel() +{ + int attachmentCount = m_attachments.count(); + if(attachmentCount) + m_clearLink->setText("<b><a href=\"http://foo\">Clear " + QString::number(attachmentCount) + " attachment(s)</a></b>"); +} + +void AttachmentListWidget::clearClicked() +{ + if(QMessageBox::question(this, + "Remove attachments", + QString("Remove %1 attachments?").arg(m_attachments.count()), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + clear(); +} + +void AttachmentListWidget::removeAttachmentAtIndex(int index) +{ + if(index >= m_attachments.count()) + return; + QString attachment = m_attachments.at(index); + m_attachments.removeAt(index); + m_model->setAttachments(m_attachments); + setVisible(!m_attachments.isEmpty()); + emit attachmentsRemoved(attachment); +} + +#include <attachmentlistwidget.moc> + diff --git a/src/plugins/composers/email/attachmentlistwidget.h b/src/plugins/composers/email/attachmentlistwidget.h new file mode 100644 index 00000000..0aa30e36 --- /dev/null +++ b/src/plugins/composers/email/attachmentlistwidget.h @@ -0,0 +1,46 @@ +#ifndef ATTACHMENTLISTWIDGET_H +#define ATTACHMENTLISTWIDGET_H + +#include <QWidget> + +class QListView; +class QStringListModel; +class QLabel; +class QTreeView; +class AttachmentListView; +class AttachmentListModel; +class AttachmentListDelegate; +class QModelIndex; + +class AttachmentListWidget : public QWidget +{ + Q_OBJECT + +public: + AttachmentListWidget(QWidget* parent = 0); + QStringList attachments() const; + +public slots: + void clear(); + void addAttachment(const QString& attachment); + void addAttachments(const QStringList& attachments); + void removeAttachment(const QString& attachment); + +signals: + void attachmentsAdded(const QStringList& attachments); + void attachmentsRemoved(const QString& attachment); + +private slots: + void updateClearLabel(); + void clearClicked(); + void removeAttachmentAtIndex(int); + +private: + AttachmentListView* m_listView; + AttachmentListModel* m_model; + AttachmentListDelegate* m_delegate; + QStringList m_attachments; + QLabel* m_clearLink; +}; + +#endif diff --git a/src/plugins/composers/email/email.pro b/src/plugins/composers/email/email.pro index 74a6776a..f65a515e 100644 --- a/src/plugins/composers/email/email.pro +++ b/src/plugins/composers/email/email.pro @@ -13,9 +13,11 @@ INCLUDEPATH += . ../../../libraries/qmfutil \ LIBS += -L../../../libraries/qtopiamail -lqtopiamail \ -L../../../libraries/qmfutil -lqmfutil -HEADERS += emailcomposer.h +HEADERS += emailcomposer.h \ + attachmentlistwidget.h -SOURCES += emailcomposer.cpp +SOURCES += emailcomposer.cpp \ + attachmentlistwidget.cpp TRANSLATIONS += libemailcomposer-ar.ts \ libemailcomposer-de.ts \ diff --git a/src/plugins/composers/email/emailcomposer.cpp b/src/plugins/composers/email/emailcomposer.cpp index 9cb875c7..205c95c3 100644 --- a/src/plugins/composers/email/emailcomposer.cpp +++ b/src/plugins/composers/email/emailcomposer.cpp @@ -33,6 +33,11 @@ #include <QToolButton> #include <qmailaccountkey.h> #include <qmailstore.h> +#include <QListWidget> +#include <QPushButton> +#include <QStringListModel> +#include <QFileDialog> +#include "attachmentlistwidget.h" static int minimumLeftWidth = 65; static const QString placeholder("(no subject)"); @@ -474,6 +479,9 @@ void EmailComposerInterface::updateAttachmentsLabel() void EmailComposerInterface::selectAttachment() { + QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select attachments")); + m_attachmentListWidget->addAttachments(fileNames); + /* if (m_attachments.isEmpty() && m_addAttDialog->documentSelector()->documents().isEmpty()) { QMessageBox::warning(this, @@ -504,7 +512,8 @@ EmailComposerInterface::EmailComposerInterface( QWidget *parent ) m_recipientListWidget(0), m_subjectEdit(0), m_attachmentAction(0), - m_title(QString()) + m_title(QString()), + m_attachmentListWidget(0) { init(); } @@ -558,6 +567,7 @@ void EmailComposerInterface::init() m_attachmentsLabel = new QLabel(this); layout->addWidget(m_attachmentsLabel); m_attachmentsLabel->hide(); + layout->addWidget(m_attachmentListWidget = new AttachmentListWidget(this)); // m_addAttDialog = new AddAttDialog(this, "attachmentDialog"); // connect(m_addAttDialog,SIGNAL(attachmentsChanged()),this,SLOT(updateAttachmentsLabel())); @@ -724,6 +734,7 @@ void EmailComposerInterface::clear() m_recipientListWidget->clear(); m_bodyEdit->clear(); + m_attachmentListWidget->clear(); //m_addAttDialog->clear(); // Delete any temporary files we don't need diff --git a/src/plugins/composers/email/emailcomposer.h b/src/plugins/composers/email/emailcomposer.h index b3d79848..41d807a0 100644 --- a/src/plugins/composers/email/emailcomposer.h +++ b/src/plugins/composers/email/emailcomposer.h @@ -21,6 +21,7 @@ class QStackedWidget; class DetailsPage; class RecipientListWidget; class QLineEdit; +class AttachmentListWidget; class EmailComposerInterface : public QMailComposerInterface { @@ -49,10 +50,8 @@ public: public slots: void clear(); -// void attach( const QContent &lnk, QMailMessage::AttachmentsAction = QMailMessage::LinkToAttachments ); + //void attach( const QContent &lnk, QMailMessage::AttachmentsAction = QMailMessage::LinkToAttachments ); void setSignature( const QString &sig ); - void create(const QMailMessage& source); - void reply(const QMailMessage& source, int action); protected slots: void selectAttachment(); @@ -61,6 +60,8 @@ protected slots: void updateAttachmentsLabel(); private: + void create(const QMailMessage& source); + void reply(const QMailMessage& source, int action); void init(); void setPlainText( const QString& text, const QString& signature ); void getDetails(QMailMessage& message) const; @@ -75,6 +76,7 @@ private: QStackedWidget* m_widgetStack; QAction* m_attachmentAction; RecipientListWidget* m_recipientListWidget; + AttachmentListWidget* m_attachmentListWidget; QLineEdit* m_subjectEdit; // typedef QPair<QContent, QMailMessage::AttachmentsAction> AttachmentDetail; |