1 /* Copyright (C) 2012 Thomas Lübking <thomas.luebking@gmail.com>
2
3 This file is part of the Trojita Qt IMAP e-mail client,
4 http://trojita.flaska.net/
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of
9 the License or (at your option) version 3 or any later version
10 accepted by the membership of KDE e.V. (or its successor approved
11 by the membership of KDE e.V.), which shall act as a proxy
12 defined in Section 14 of version 3 of the license.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include <QAction>
24 #include <QDragEnterEvent>
25 #include <QDebug>
26 #include <QInputDialog>
27 #include <QMenu>
28 #include "Composer/MessageComposer.h"
29 #include "Gui/ComposerAttachmentsList.h"
30 #include "Imap/Model/ItemRoles.h"
31 #include "UiUtils/IconLoader.h"
32
ComposerAttachmentsList(QWidget * parent)33 ComposerAttachmentsList::ComposerAttachmentsList(QWidget *parent):
34 QListView(parent), m_dragging(false), m_dragInside(false), m_composer(0)
35 {
36 setMouseTracking( true );
37 setAcceptDrops(true);
38 setDragDropMode( DragDrop );
39 setDragDropOverwriteMode( false );
40 setDragEnabled(true);
41 setDropIndicatorShown(false);
42 setContextMenuPolicy(Qt::CustomContextMenu);
43 connect(this, &QWidget::customContextMenuRequested, this, &ComposerAttachmentsList::showContextMenu);
44
45 m_actionSendInline = new QAction(UiUtils::loadIcon(QStringLiteral("insert-image")), tr("Send Inline"), this);
46 m_actionSendInline->setCheckable(true);
47 connect(m_actionSendInline, &QAction::triggered, this, &ComposerAttachmentsList::slotToggledContentDispositionInline);
48 addAction(m_actionSendInline);
49
50 m_actionRename = new QAction(UiUtils::loadIcon(QStringLiteral("edit-rename")), tr("Rename..."), this);
51 connect(m_actionRename, &QAction::triggered, this, &ComposerAttachmentsList::slotRenameAttachment);
52 addAction(m_actionRename);
53
54 m_actionRemoveAttachment = new QAction(UiUtils::loadIcon(QStringLiteral("list-remove")), tr("Remove"), this);
55 connect(m_actionRemoveAttachment, &QAction::triggered, this, &ComposerAttachmentsList::slotRemoveAttachment);
56 addAction(m_actionRemoveAttachment);
57
58 connect(this, &ComposerAttachmentsList::itemDroppedOut, this, &ComposerAttachmentsList::slotRemoveAttachment);
59 connect(this, &QAbstractItemView::clicked, this, &ComposerAttachmentsList::onCurrentChanged);
60 connect(this, &QAbstractItemView::activated, this, &ComposerAttachmentsList::onCurrentChanged);
61 }
62
setComposer(Composer::MessageComposer * composer)63 void ComposerAttachmentsList::setComposer(Composer::MessageComposer *composer)
64 {
65 // prevent double connections etc
66 Q_ASSERT(!m_composer);
67
68 m_composer = composer;
69 setModel(m_composer);
70 connect(model(), &QAbstractItemModel::rowsRemoved, this, &ComposerAttachmentsList::onAttachmentNumberChanged);
71 connect(model(), &QAbstractItemModel::rowsInserted, this, &ComposerAttachmentsList::onAttachmentNumberChanged);
72 connect(model(), &QAbstractItemModel::layoutChanged, this, &ComposerAttachmentsList::onAttachmentNumberChanged);
73 connect(model(), &QAbstractItemModel::modelReset, this, &ComposerAttachmentsList::onAttachmentNumberChanged);
74
75 onAttachmentNumberChanged();
76 }
77
startDrag(Qt::DropActions da)78 void ComposerAttachmentsList::startDrag(Qt::DropActions da)
79 {
80 m_dragging = true;
81 m_dragInside = true;
82 const QModelIndex idx = indexAt(mapFromGlobal(QCursor::pos()));
83 if (!idx.isValid())
84 setCurrentIndex(idx);
85 QListView::startDrag(da);
86 m_dragging = false;
87 if (!m_dragInside) {
88 emit itemDroppedOut();
89 }
90 }
91
92
dragEnterEvent(QDragEnterEvent * de)93 void ComposerAttachmentsList::dragEnterEvent(QDragEnterEvent *de)
94 {
95 if (m_dragging)
96 m_dragInside = true;
97 QListView::dragEnterEvent(de);
98 }
99
dragLeaveEvent(QDragLeaveEvent * de)100 void ComposerAttachmentsList::dragLeaveEvent(QDragLeaveEvent *de)
101 {
102 if (m_dragging)
103 m_dragInside = false;
104 QListView::dragLeaveEvent(de);
105 }
106
slotRemoveAttachment()107 void ComposerAttachmentsList::slotRemoveAttachment()
108 {
109 m_composer->removeAttachment(currentIndex());
110 }
111
slotToggledContentDispositionInline(bool checked)112 void ComposerAttachmentsList::slotToggledContentDispositionInline(bool checked)
113 {
114 m_composer->setAttachmentContentDisposition(currentIndex(), checked ? Composer::CDN_INLINE : Composer::CDN_ATTACHMENT);
115 }
116
slotRenameAttachment()117 void ComposerAttachmentsList::slotRenameAttachment()
118 {
119 bool ok;
120 QString newName = QInputDialog::getText(this, tr("Rename Attachment"), tr("New Name"), QLineEdit::Normal,
121 currentIndex().data().toString(), &ok);
122 if (ok) {
123 m_composer->setAttachmentName(currentIndex(), newName);
124 }
125 }
126
onAttachmentNumberChanged()127 void ComposerAttachmentsList::onAttachmentNumberChanged()
128 {
129 Q_ASSERT(model());
130 bool current = currentIndex().isValid();
131 m_actionRemoveAttachment->setEnabled(current);
132 m_actionSendInline->setEnabled(current);
133 m_actionRename->setEnabled(current);
134 onCurrentChanged();
135 }
136
onCurrentChanged()137 void ComposerAttachmentsList::onCurrentChanged()
138 {
139 m_actionSendInline->setChecked(false);
140
141 // This is needed because the QVariant::toInt returns zero when faced with null QVariant
142 bool ok;
143 int res = currentIndex().data(Imap::Mailbox::RoleAttachmentContentDispositionMode).toInt(&ok);
144 if (!ok)
145 return;
146
147 switch (static_cast<Composer::ContentDisposition>(res)) {
148 case Composer::CDN_INLINE:
149 m_actionSendInline->setChecked(true);
150 break;
151 case Composer::CDN_ATTACHMENT:
152 // nothing is needed here
153 break;
154 }
155 }
156
showContextMenu(const QPoint & pos)157 void ComposerAttachmentsList::showContextMenu(const QPoint &pos)
158 {
159 // Sometimes currentChanged() is not enough -- we really want to to have these actions to reflect the current selection, if any
160 onAttachmentNumberChanged();
161 QMenu::exec(actions(), mapToGlobal(pos), 0, this);
162 }
163