examples/serviceactions/attachmentlistwidget.cpp
changeset 0 876b1a06bc25
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Messaging Framework.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:BSD$
       
    10 ** You may use this file under the terms of the BSD license as follows:
       
    11 **
       
    12 ** "Redistribution and use in source and binary forms, with or without
       
    13 ** modification, are permitted provided that the following conditions are
       
    14 ** met:
       
    15 **   * Redistributions of source code must retain the above copyright
       
    16 **     notice, this list of conditions and the following disclaimer.
       
    17 **   * Redistributions in binary form must reproduce the above copyright
       
    18 **     notice, this list of conditions and the following disclaimer in
       
    19 **     the documentation and/or other materials provided with the
       
    20 **     distribution.
       
    21 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
       
    22 **     the names of its contributors may be used to endorse or promote
       
    23 **     products derived from this software without specific prior written
       
    24 **     permission.
       
    25 **
       
    26 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       
    27 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       
    28 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       
    29 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       
    30 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       
    31 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       
    32 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       
    33 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       
    34 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    35 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    36 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
       
    37 ** $QT_END_LICENSE$
       
    38 **
       
    39 ****************************************************************************/
       
    40 
       
    41 #include "attachmentlistwidget.h"
       
    42 #include <QStringListModel>
       
    43 #include <QListView>
       
    44 #include <QVBoxLayout>
       
    45 #include <QLabel>
       
    46 #include <QDebug>
       
    47 #include <QMessageBox>
       
    48 #include <QDialogButtonBox>
       
    49 #include <QTreeView>
       
    50 #include <QFileInfo>
       
    51 #include <QItemDelegate>
       
    52 #include <QPainter>
       
    53 #include <QPointer>
       
    54 #include <QMouseEvent>
       
    55 #include <QHeaderView>
       
    56 //#include <support/qmailnamespace.h>
       
    57 
       
    58 class AttachmentListWidget;
       
    59 
       
    60 static QString sizeString(uint size)
       
    61 {
       
    62     if(size < 1024)
       
    63         return QObject::tr("%n byte(s)", "", size);
       
    64     else if(size < (1024 * 1024))
       
    65         return QObject::tr("%1 KB").arg(((float)size)/1024.0, 0, 'f', 1);
       
    66     else if(size < (1024 * 1024 * 1024))
       
    67         return QObject::tr("%1 MB").arg(((float)size)/(1024.0 * 1024.0), 0, 'f', 1);
       
    68     else
       
    69         return QObject::tr("%1 GB").arg(((float)size)/(1024.0 * 1024.0 * 1024.0), 0, 'f', 1);
       
    70 }
       
    71 
       
    72 static QStringList headers(QStringList() << "Attachment" << "Size" << "Type" << "");
       
    73 
       
    74 class AttachmentListHeader : public QHeaderView
       
    75 {
       
    76     Q_OBJECT
       
    77 public:
       
    78     AttachmentListHeader(AttachmentListWidget* parent);
       
    79 
       
    80 signals:
       
    81     void clear();
       
    82 
       
    83 protected:
       
    84     void paintSection(QPainter * painter, const QRect & rect, int logicalIndex) const;
       
    85 #ifndef QT_NO_CURSOR    
       
    86     bool viewportEvent(QEvent* e);
       
    87     void mouseMoveEvent(QMouseEvent* e);
       
    88 #endif    
       
    89     void mousePressEvent(QMouseEvent* e);
       
    90     bool overRemoveLink(QMouseEvent* e);
       
    91 
       
    92 
       
    93 private:
       
    94     AttachmentListWidget* m_parent;
       
    95     mutable QRect m_removeButtonRect;
       
    96 
       
    97 };
       
    98 
       
    99 AttachmentListHeader::AttachmentListHeader(AttachmentListWidget* parent)
       
   100 :
       
   101 QHeaderView(Qt::Horizontal,parent),
       
   102 m_parent(parent)
       
   103 {
       
   104 }
       
   105 
       
   106 void AttachmentListHeader::paintSection(QPainter * painter, const QRect & rect, int logicalIndex) const
       
   107 {
       
   108     if(logicalIndex == 3 && m_parent->attachments().count() > 1)
       
   109     {
       
   110         painter->save();
       
   111         QFont font = painter->font();
       
   112         font.setUnderline(true);
       
   113         painter->setFont(font);
       
   114         painter->drawText(rect,Qt::AlignHCenter | Qt::AlignVCenter,"Remove All",&m_removeButtonRect);
       
   115         painter->restore();
       
   116     }
       
   117     else
       
   118         QHeaderView::paintSection(painter,rect,logicalIndex);
       
   119 }
       
   120 
       
   121 #ifndef QT_NO_CURSOR    
       
   122 bool AttachmentListHeader::viewportEvent(QEvent* e)
       
   123 {
       
   124     if(e->type() == QEvent::Leave)
       
   125         setCursor(QCursor());
       
   126     return QAbstractItemView::viewportEvent(e);
       
   127 }
       
   128 
       
   129 void AttachmentListHeader::mouseMoveEvent(QMouseEvent* e)
       
   130 {
       
   131     QHeaderView::mouseMoveEvent(e);
       
   132     if(overRemoveLink(e))
       
   133     {
       
   134         QCursor handCursor(Qt::PointingHandCursor);
       
   135         setCursor(handCursor);
       
   136     }
       
   137     else if(cursor().shape() == Qt::PointingHandCursor)
       
   138         setCursor(QCursor());
       
   139 }
       
   140 #endif
       
   141 
       
   142 void AttachmentListHeader::mousePressEvent(QMouseEvent* e)
       
   143 {
       
   144     if(overRemoveLink(e))
       
   145         emit clear();
       
   146     QHeaderView::mousePressEvent(e);
       
   147 }
       
   148 
       
   149 bool AttachmentListHeader::overRemoveLink(QMouseEvent* e)
       
   150 {
       
   151     return m_removeButtonRect.contains(e->pos());
       
   152 }
       
   153 
       
   154 class AttachmentListDelegate : public QItemDelegate
       
   155 {
       
   156     Q_OBJECT
       
   157 public:
       
   158     AttachmentListDelegate(AttachmentListWidget* parent = 0);
       
   159     void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
       
   160     bool isOverRemoveLink(const QRect& parentRect, const QPoint& pos) const;
       
   161 
       
   162 protected slots:
       
   163     bool helpEvent(QHelpEvent * event, QAbstractItemView * view, const QStyleOptionViewItem & option, const QModelIndex & index);
       
   164 
       
   165 private:
       
   166     QPointer<AttachmentListWidget> m_parent;
       
   167 };
       
   168 
       
   169 AttachmentListDelegate::AttachmentListDelegate(AttachmentListWidget* parent)
       
   170 :
       
   171 QItemDelegate(parent),
       
   172 m_parent(parent)
       
   173 {
       
   174 }
       
   175 
       
   176 void AttachmentListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
       
   177 {
       
   178     if(index.isValid() && index.column() == 3)
       
   179     {
       
   180         painter->save();
       
   181         QFont font = painter->font();
       
   182         QColor c = option.palette.brush(QPalette::Link).color();
       
   183         font.setUnderline(true);
       
   184         painter->setPen(c);
       
   185         painter->setFont(font);
       
   186         painter->drawText(option.rect,Qt::AlignHCenter,"Remove");
       
   187         painter->restore();
       
   188     }
       
   189     else
       
   190         QItemDelegate::paint(painter,option,index);
       
   191 }
       
   192 
       
   193 bool AttachmentListDelegate::isOverRemoveLink(const QRect& parentRect, const QPoint& pos) const
       
   194 {
       
   195     QFont font;
       
   196     font.setUnderline(true);
       
   197     QFontMetrics fm(font);
       
   198     QRect textRect = fm.boundingRect(parentRect,Qt::AlignHCenter,"Remove");
       
   199     return textRect.contains(pos);
       
   200 }
       
   201 
       
   202 bool AttachmentListDelegate::helpEvent(QHelpEvent *, QAbstractItemView *view, const QStyleOptionViewItem &, const QModelIndex &index)
       
   203 {
       
   204     if (!index.isValid()) {
       
   205         view->setToolTip(QString());
       
   206         return false;
       
   207     }
       
   208 
       
   209     QString attachment = m_parent->attachmentAt(index.row());
       
   210     view->setToolTip(attachment);
       
   211     return false;
       
   212 }
       
   213 
       
   214 class AttachmentListView : public QTreeView
       
   215 {
       
   216     Q_OBJECT
       
   217 
       
   218 public:
       
   219     AttachmentListView(QWidget* parent = 0);
       
   220 
       
   221 signals:
       
   222     void removeAttachmentAtIndex(int index);
       
   223 
       
   224 protected:
       
   225 #ifndef QT_NO_CURSOR    
       
   226     bool viewportEvent(QEvent* e);
       
   227     void mouseMoveEvent(QMouseEvent* e);
       
   228 #endif    
       
   229     void mousePressEvent(QMouseEvent* e);
       
   230     bool overRemoveLink(QMouseEvent* e);
       
   231 };
       
   232 
       
   233 AttachmentListView::AttachmentListView(QWidget* parent)
       
   234 :
       
   235 QTreeView(parent)
       
   236 {
       
   237     setMouseTracking(true);
       
   238     installEventFilter(this);
       
   239 }
       
   240 
       
   241 #ifndef QT_NO_CURSOR    
       
   242 bool AttachmentListView::viewportEvent(QEvent* e)
       
   243 {
       
   244     if(e->type() == QEvent::Leave)
       
   245         setCursor(QCursor());
       
   246     return QAbstractItemView::viewportEvent(e);
       
   247 }
       
   248 
       
   249 void AttachmentListView::mouseMoveEvent(QMouseEvent* e)
       
   250 {
       
   251     if(overRemoveLink(e))
       
   252     {
       
   253         QCursor handCursor(Qt::PointingHandCursor);
       
   254         setCursor(handCursor);
       
   255     }
       
   256     else if(cursor().shape() == Qt::PointingHandCursor)
       
   257         setCursor(QCursor());
       
   258     QTreeView::mouseMoveEvent(e);
       
   259 }
       
   260 #endif
       
   261 
       
   262 void AttachmentListView::mousePressEvent(QMouseEvent* e)
       
   263 {
       
   264     if(overRemoveLink(e))
       
   265     {
       
   266         QModelIndex index = indexAt(e->pos());
       
   267         emit removeAttachmentAtIndex(index.row());
       
   268     }
       
   269     QTreeView::mousePressEvent(e);
       
   270 }
       
   271 
       
   272 bool AttachmentListView::overRemoveLink(QMouseEvent* e)
       
   273 {
       
   274     QModelIndex index = indexAt(e->pos());
       
   275     if(index.isValid() && index.column() == 3)
       
   276     {
       
   277         AttachmentListDelegate* delegate = static_cast<AttachmentListDelegate*>(itemDelegate());
       
   278         return delegate->isOverRemoveLink(visualRect(index),e->pos());
       
   279     }
       
   280     return false;
       
   281 }
       
   282 
       
   283 class AttachmentListModel : public QAbstractListModel
       
   284 {
       
   285 public:
       
   286     AttachmentListModel(QWidget* parent );
       
   287     QVariant headerData(int section,Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
       
   288 
       
   289     bool isEmpty() const;
       
   290 
       
   291     int columnCount(const QModelIndex & parent = QModelIndex()) const;
       
   292     int rowCount(const QModelIndex & parent = QModelIndex()) const;
       
   293 
       
   294     QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
       
   295 
       
   296     QStringList attachments() const;
       
   297     void setAttachments(const QStringList& attachments);
       
   298 
       
   299 private:
       
   300     QStringList m_attachments;
       
   301 };
       
   302 
       
   303 AttachmentListModel::AttachmentListModel(QWidget* parent)
       
   304 :
       
   305 QAbstractListModel(parent)
       
   306 {
       
   307 }
       
   308 
       
   309 QVariant AttachmentListModel::headerData(int section, Qt::Orientation o, int role) const
       
   310 {
       
   311     if (role == Qt::DisplayRole)
       
   312     {
       
   313         if(section < headers.count())
       
   314             return headers.at(section);
       
   315     }
       
   316 
       
   317    return QAbstractListModel::headerData(section,o,role);
       
   318 }
       
   319 
       
   320 bool AttachmentListModel::isEmpty() const
       
   321 {
       
   322     return m_attachments.isEmpty();
       
   323 }
       
   324 
       
   325 int AttachmentListModel::columnCount(const QModelIndex & parent ) const
       
   326 {
       
   327     Q_UNUSED(parent);
       
   328     return headers.count();
       
   329 }
       
   330 
       
   331 int AttachmentListModel::rowCount(const QModelIndex& parent) const
       
   332 {
       
   333     Q_UNUSED(parent);
       
   334     return m_attachments.count();
       
   335 }
       
   336 
       
   337 QVariant AttachmentListModel::data( const QModelIndex & index, int role) const
       
   338 {
       
   339     if(index.isValid())
       
   340     {
       
   341         if(role == Qt::DisplayRole && index.isValid())
       
   342         {
       
   343             QString path = m_attachments.at(index.row());
       
   344             QFileInfo fi(path);
       
   345 
       
   346             switch(index.column())
       
   347             {
       
   348             case 0:
       
   349                 return fi.fileName();
       
   350                 break;
       
   351             case 1:
       
   352                 return sizeString(fi.size());
       
   353                 break;
       
   354             case 2:
       
   355                 //QString mimeType = QMail::mimeTypeFromFileName(path);
       
   356                 //if(mimeType.isEmpty()) mimeType = "Unknown";
       
   357                 //return mimeType;
       
   358                 return "Unknown";
       
   359                 break;
       
   360             }
       
   361         }
       
   362         else if((role == Qt::DecorationRole  || role == Qt::CheckStateRole )&& index.column() > 0)
       
   363             return QVariant();
       
   364             else if(role == Qt::DecorationRole)
       
   365         {
       
   366             static QIcon attachIcon( ":icon/attach" );
       
   367             return attachIcon;
       
   368         }
       
   369     }
       
   370     return QVariant();
       
   371 }
       
   372 
       
   373 QStringList AttachmentListModel::attachments() const
       
   374 {
       
   375     return m_attachments;
       
   376 }
       
   377 
       
   378 void AttachmentListModel::setAttachments(const QStringList& attachments)
       
   379 {
       
   380     m_attachments.clear();
       
   381 
       
   382     foreach (const QString &att, attachments) {
       
   383         if (!att.startsWith("ref:") && !att.startsWith("partRef:")) {
       
   384             m_attachments.append(att);
       
   385         }
       
   386     }
       
   387 
       
   388     reset();
       
   389 }
       
   390 
       
   391 AttachmentListWidget::AttachmentListWidget(QWidget* parent)
       
   392 :
       
   393 QWidget(parent),
       
   394 m_listView(new AttachmentListView(this)),
       
   395 m_model(new AttachmentListModel(this)),
       
   396 m_delegate(new AttachmentListDelegate(this)),
       
   397 m_clearLink(new QLabel(this))
       
   398 {
       
   399     m_clearLink->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
       
   400     m_clearLink->setTextFormat(Qt::RichText);
       
   401 
       
   402     m_listView->setModel(m_model);
       
   403     m_listView->setSelectionMode(QAbstractItemView::NoSelection);
       
   404     AttachmentListHeader* header = new AttachmentListHeader(this);
       
   405     connect(header,SIGNAL(clear()),this,SLOT(clearClicked()));
       
   406     m_listView->setHeader(header);
       
   407     m_listView->header()->setStretchLastSection(true);
       
   408     m_listView->header()->setResizeMode(QHeaderView::ResizeToContents);
       
   409     m_listView->header()->setDefaultSectionSize(180);
       
   410     m_listView->setUniformRowHeights(true);
       
   411     m_listView->setRootIsDecorated(false);
       
   412     m_listView->setItemDelegate(m_delegate);
       
   413 
       
   414 
       
   415     QVBoxLayout* layout = new QVBoxLayout(this);
       
   416     layout->setSpacing(0);
       
   417     layout->setContentsMargins(0,0,0,0);
       
   418     layout->addWidget(m_listView);
       
   419 
       
   420     connect(m_clearLink,SIGNAL(linkActivated(QString)),this,SLOT(clearClicked()));
       
   421     connect(m_listView,SIGNAL(removeAttachmentAtIndex(int)),this,SLOT(removeAttachmentAtIndex(int)));
       
   422 }
       
   423 
       
   424 QStringList AttachmentListWidget::attachments() const
       
   425 {
       
   426     return m_attachments;
       
   427 }
       
   428 
       
   429 QString AttachmentListWidget::attachmentAt(int index) const
       
   430 {
       
   431     return m_attachments.at(index);
       
   432 }
       
   433 
       
   434 int AttachmentListWidget::count() const
       
   435 {
       
   436     return m_attachments.count();
       
   437 }
       
   438 
       
   439 bool AttachmentListWidget::isEmpty() const
       
   440 {
       
   441     return m_attachments.isEmpty();
       
   442 }
       
   443 
       
   444 void AttachmentListWidget::addAttachment(const QString& attachment)
       
   445 {
       
   446     if(m_attachments.contains(attachment))
       
   447         return;
       
   448 
       
   449     m_attachments.append(attachment);
       
   450 
       
   451     m_model->setAttachments(m_attachments);
       
   452     setVisible(!m_model->isEmpty());
       
   453 
       
   454     emit attachmentsAdded(QStringList() << attachment);
       
   455 }
       
   456 
       
   457 void AttachmentListWidget::addAttachments(const QStringList& attachments)
       
   458 {
       
   459     QSet<QString> newAttachments = attachments.toSet() - m_attachments.toSet();
       
   460 
       
   461     if (!newAttachments.isEmpty()) {
       
   462         m_attachments += newAttachments.toList();
       
   463 
       
   464         m_model->setAttachments(m_attachments);
       
   465         setVisible(!m_model->isEmpty());
       
   466 
       
   467         emit attachmentsAdded(newAttachments.toList());
       
   468     }
       
   469 }
       
   470 
       
   471 void AttachmentListWidget::removeAttachment(const QString& attachment)
       
   472 {
       
   473     if (!m_attachments.contains(attachment))
       
   474         return;
       
   475 
       
   476     m_attachments.removeAll(attachment);
       
   477 
       
   478     m_model->setAttachments(m_attachments);
       
   479     setVisible(!m_model->isEmpty());
       
   480 
       
   481     emit attachmentsRemoved(attachment);
       
   482 }
       
   483 
       
   484 void AttachmentListWidget::clear()
       
   485 {
       
   486     m_attachments.clear();
       
   487     m_model->setAttachments(m_attachments);
       
   488     setVisible(false);
       
   489 }
       
   490 
       
   491 void AttachmentListWidget::clearClicked()
       
   492 {
       
   493     if(QMessageBox::question(this,
       
   494                              "Remove attachments",
       
   495                              QString("Remove %1 attachments?").arg(m_attachments.count()),
       
   496                              QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
       
   497         clear();
       
   498 }
       
   499 
       
   500 void AttachmentListWidget::removeAttachmentAtIndex(int index)
       
   501 {
       
   502     if(index >= m_attachments.count())
       
   503         return;
       
   504 
       
   505     QString attachment = m_attachments.at(index);
       
   506     m_attachments.removeAt(index);
       
   507 
       
   508     m_model->setAttachments(m_attachments);
       
   509     setVisible(!m_model->isEmpty());
       
   510 
       
   511     emit attachmentsRemoved(attachment);
       
   512 }
       
   513 
       
   514 #include <attachmentlistwidget.moc>
       
   515