GUI: Restore message upload on drag-and-drop from the file manager
[trojita.git] / src / Gui / MailBoxTreeView.cpp
blob15de8008bd8bfee9cd9d4d9d9138b06a70299a26
1 /* Copyright (C) 2012 Thomas Gahr <thomas.gahr@physik.uni-muenchen.de>
2 Copyright (C) 2006 - 2016 Jan Kundrát <jkt@kde.org>
4 This file is part of the Trojita Qt IMAP e-mail client,
5 http://trojita.flaska.net/
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of
10 the License or (at your option) version 3 or any later version
11 accepted by the membership of KDE e.V. (or its successor approved
12 by the membership of KDE e.V.), which shall act as a proxy
13 defined in Section 14 of version 3 of the license.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include <QDragMoveEvent>
25 #include <QDropEvent>
26 #include <QMenu>
27 #include <QMimeData>
28 #include "Gui/MailBoxTreeView.h"
29 #include "Gui/Util.h"
30 #include "Imap/Model/ItemRoles.h"
31 #include "Imap/Model/MailboxFinder.h"
32 #include "Imap/Model/DragAndDrop.h"
33 #include "UiUtils/IconLoader.h"
35 namespace Gui {
37 MailBoxTreeView::MailBoxTreeView(QWidget *parent)
38 : QTreeView(parent)
39 , m_mailboxFinder(nullptr)
41 setUniformRowHeights(true);
42 setContextMenuPolicy(Qt::CustomContextMenu);
43 setSelectionMode(QAbstractItemView::SingleSelection);
44 setAllColumnsShowFocus(true);
45 setAcceptDrops(true);
46 setDropIndicatorShown(true);
47 setHeaderHidden(true);
48 // I wonder what's the best value to use here. Unfortunately, the default is to disable auto expanding.
49 setAutoExpandDelay(800);
51 // Track expansion/collapsing so that we remember this state despite the asynchronous nature of mailbox loading
52 connect(this, &QTreeView::expanded, this, [this](const QModelIndex &what) {
53 auto name = what.data(Imap::Mailbox::RoleMailboxName).toString();
54 if (!m_desiredExpansionState.contains(name)) {
55 m_desiredExpansionState.insert(name);
56 emit mailboxExpansionChanged(m_desiredExpansionState.toList());
58 });
59 connect(this, &QTreeView::collapsed, this, [this](const QModelIndex &what) {
60 auto name = what.data(Imap::Mailbox::RoleMailboxName).toString();
61 if (m_desiredExpansionState.remove(name)) {
62 emit mailboxExpansionChanged(m_desiredExpansionState.toList());
64 });
67 /** \reimp
69 The MailboxFinder has to be kept up-to-speed about these changes.
71 void MailBoxTreeView::setModel(QAbstractItemModel *model)
73 delete m_mailboxFinder;
74 m_mailboxFinder = nullptr;
76 if (model) {
77 m_mailboxFinder = new Imap::Mailbox::MailboxFinder(this, model);
78 connect(m_mailboxFinder, &Imap::Mailbox::MailboxFinder::mailboxFound,
79 this, [this](const QString &, const QModelIndex &index) {
80 expand(index);
81 });
82 connect(model, &QAbstractItemModel::layoutChanged, this, &MailBoxTreeView::resetWatchedMailboxes);
83 connect(model, &QAbstractItemModel::rowsRemoved, this, &MailBoxTreeView::resetWatchedMailboxes);
84 connect(model, &QAbstractItemModel::modelReset, this, &MailBoxTreeView::resetWatchedMailboxes);
86 QTreeView::setModel(model);
87 resetWatchedMailboxes();
90 /** @short Reimplemented for more consistent handling of modifiers
92 Qt's default behaviour is odd here:
93 If you selected the move-action by pressing shift and you release the shift
94 key while moving the mouse, the action does not change back to copy. But if you
95 then move the mouse over a widget border - i.e. cause dragLeaveEvent, the action
96 WILL change back to copy.
97 This implementation immitates KDE's behaviour: react to a change in modifiers
98 immediately.
100 void MailBoxTreeView::dragMoveEvent(QDragMoveEvent *event)
102 QTreeView::dragMoveEvent(event);
103 if (!event->isAccepted())
104 return;
105 if (event->keyboardModifiers() == Qt::ShiftModifier)
106 event->setDropAction(Qt::MoveAction);
107 else
108 event->setDropAction(Qt::CopyAction);
111 /** @short Reimplemented to present the user with a menu to choose between copy or move.
113 Does not show the menu if either ctrl (copy messages) or shift (move messages)
114 is pressed
116 void MailBoxTreeView::dropEvent(QDropEvent *event)
118 if (Gui::Util::isFromDistinctImapAccount(event)) {
119 event->ignore();
120 return;
122 if (event->keyboardModifiers() == Qt::ControlModifier) {
123 event->setDropAction(Qt::CopyAction);
124 } else if (event->keyboardModifiers() == Qt::ShiftModifier) {
125 event->setDropAction(Qt::MoveAction);
126 } else {
127 QMenu menu;
128 QAction *moveAction = menu.addAction(UiUtils::loadIcon(QStringLiteral("go-jump")), tr("Move here\tShift"));
129 menu.addAction(UiUtils::loadIcon(QStringLiteral("edit-copy")), tr("Copy here\tCtrl"));
130 QAction *cancelAction = menu.addAction(UiUtils::loadIcon(QStringLiteral("process-stop")), tr("Cancel"));
132 QAction *selectedAction = menu.exec(QCursor::pos());
134 // if user closes the menu or selects cancel, ignore the event
135 if (!selectedAction || selectedAction == cancelAction) {
136 event->ignore();
137 return;
140 event->setDropAction(selectedAction == moveAction ? Qt::MoveAction : Qt::CopyAction);
143 QTreeView::dropEvent(event);
146 void MailBoxTreeView::dragEnterEvent(QDragEnterEvent *event)
148 if (Gui::Util::isFromDistinctImapAccount(event)) {
149 event->ignore();
150 return;
152 QTreeView::dragEnterEvent(event);
155 /** @short Specify which mailboxes should be expanded
157 The mailboxes might appear and disappear at any time, so let's make sure that
158 they are properly expanded/collapsed once they pop in.
160 void MailBoxTreeView::setDesiredExpansion(const QStringList &mailboxNames)
162 m_desiredExpansionState = mailboxNames.toSet();
163 resetWatchedMailboxes();
166 /** @short Ensure that we watch stuff that we need to watch */
167 void MailBoxTreeView::resetWatchedMailboxes()
169 if (m_mailboxFinder) {
170 for (const auto &mailbox: m_desiredExpansionState) {
171 m_mailboxFinder->addMailbox(mailbox);