#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>
 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:
                 
                 
                 
                 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>