examples/serviceactions/attachmentlistwidget.cpp
changeset 0 876b1a06bc25
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/serviceactions/attachmentlistwidget.cpp	Wed Aug 25 15:49:42 2010 +0300
@@ -0,0 +1,515 @@
+/****************************************************************************
+**
+** 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 Messaging Framework.
+**
+** $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 "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>
+//#include <support/qmailnamespace.h>
+
+class AttachmentListWidget;
+
+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" << "Type" << "");
+
+class AttachmentListHeader : public QHeaderView
+{
+    Q_OBJECT
+public:
+    AttachmentListHeader(AttachmentListWidget* parent);
+
+signals:
+    void clear();
+
+protected:
+    void paintSection(QPainter * painter, const QRect & rect, int logicalIndex) const;
+#ifndef QT_NO_CURSOR    
+    bool viewportEvent(QEvent* e);
+    void mouseMoveEvent(QMouseEvent* e);
+#endif    
+    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 == 3 && 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);
+}
+
+#ifndef QT_NO_CURSOR    
+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());
+}
+#endif
+
+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
+{
+    Q_OBJECT
+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;
+
+protected slots:
+    bool helpEvent(QHelpEvent * event, QAbstractItemView * view, const QStyleOptionViewItem & option, const QModelIndex & index);
+
+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
+{
+    if(index.isValid() && index.column() == 3)
+    {
+        painter->save();
+        QFont font = painter->font();
+        QColor c = option.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);
+}
+
+bool AttachmentListDelegate::helpEvent(QHelpEvent *, QAbstractItemView *view, const QStyleOptionViewItem &, const QModelIndex &index)
+{
+    if (!index.isValid()) {
+        view->setToolTip(QString());
+        return false;
+    }
+
+    QString attachment = m_parent->attachmentAt(index.row());
+    view->setToolTip(attachment);
+    return false;
+}
+
+class AttachmentListView : public QTreeView
+{
+    Q_OBJECT
+
+public:
+    AttachmentListView(QWidget* parent = 0);
+
+signals:
+    void removeAttachmentAtIndex(int index);
+
+protected:
+#ifndef QT_NO_CURSOR    
+    bool viewportEvent(QEvent* e);
+    void mouseMoveEvent(QMouseEvent* e);
+#endif    
+    void mousePressEvent(QMouseEvent* e);
+    bool overRemoveLink(QMouseEvent* e);
+};
+
+AttachmentListView::AttachmentListView(QWidget* parent)
+:
+QTreeView(parent)
+{
+    setMouseTracking(true);
+    installEventFilter(this);
+}
+
+#ifndef QT_NO_CURSOR    
+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);
+}
+#endif
+
+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() == 3)
+    {
+        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;
+
+    bool isEmpty() 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);
+}
+
+bool AttachmentListModel::isEmpty() const
+{
+    return m_attachments.isEmpty();
+}
+
+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;
+            case 2:
+                //QString mimeType = QMail::mimeTypeFromFileName(path);
+                //if(mimeType.isEmpty()) mimeType = "Unknown";
+                //return mimeType;
+                return "Unknown";
+                break;
+            }
+        }
+        else if((role == Qt::DecorationRole  || role == Qt::CheckStateRole )&& index.column() > 0)
+            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.clear();
+
+    foreach (const QString &att, attachments) {
+        if (!att.startsWith("ref:") && !att.startsWith("partRef:")) {
+            m_attachments.append(att);
+        }
+    }
+
+    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);
+
+    connect(m_clearLink,SIGNAL(linkActivated(QString)),this,SLOT(clearClicked()));
+    connect(m_listView,SIGNAL(removeAttachmentAtIndex(int)),this,SLOT(removeAttachmentAtIndex(int)));
+}
+
+QStringList AttachmentListWidget::attachments() const
+{
+    return m_attachments;
+}
+
+QString AttachmentListWidget::attachmentAt(int index) const
+{
+    return m_attachments.at(index);
+}
+
+int AttachmentListWidget::count() const
+{
+    return m_attachments.count();
+}
+
+bool AttachmentListWidget::isEmpty() const
+{
+    return m_attachments.isEmpty();
+}
+
+void AttachmentListWidget::addAttachment(const QString& attachment)
+{
+    if(m_attachments.contains(attachment))
+        return;
+
+    m_attachments.append(attachment);
+
+    m_model->setAttachments(m_attachments);
+    setVisible(!m_model->isEmpty());
+
+    emit attachmentsAdded(QStringList() << attachment);
+}
+
+void AttachmentListWidget::addAttachments(const QStringList& attachments)
+{
+    QSet<QString> newAttachments = attachments.toSet() - m_attachments.toSet();
+
+    if (!newAttachments.isEmpty()) {
+        m_attachments += newAttachments.toList();
+
+        m_model->setAttachments(m_attachments);
+        setVisible(!m_model->isEmpty());
+
+        emit attachmentsAdded(newAttachments.toList());
+    }
+}
+
+void AttachmentListWidget::removeAttachment(const QString& attachment)
+{
+    if (!m_attachments.contains(attachment))
+        return;
+
+    m_attachments.removeAll(attachment);
+
+    m_model->setAttachments(m_attachments);
+    setVisible(!m_model->isEmpty());
+
+    emit attachmentsRemoved(attachment);
+}
+
+void AttachmentListWidget::clear()
+{
+    m_attachments.clear();
+    m_model->setAttachments(m_attachments);
+    setVisible(false);
+}
+
+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_model->isEmpty());
+
+    emit attachmentsRemoved(attachment);
+}
+
+#include <attachmentlistwidget.moc>
+