Merge "persistent color scheme selection"
[trojita.git] / src / Gui / MailBoxTreeView.cpp
blobf75b11a44123c5ad4fba12ff2c1ad1aa1dd74167
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 "Common/SettingsNames.h"
29 #include "Gui/MailBoxTreeView.h"
30 #include "Gui/Util.h"
31 #include "Imap/Model/ItemRoles.h"
32 #include "Imap/Model/MailboxFinder.h"
33 #include "Imap/Model/DragAndDrop.h"
34 #include "UiUtils/IconLoader.h"
36 namespace Gui {
38 MailBoxTreeView::MailBoxTreeView(QWidget *parent, QSettings *settings)
39 : QTreeView(parent)
40 , m_mailboxFinder(nullptr), m_settings(settings)
42 setUniformRowHeights(true);
43 setContextMenuPolicy(Qt::CustomContextMenu);
44 setSelectionMode(QAbstractItemView::SingleSelection);
45 setAllColumnsShowFocus(true);
46 setAcceptDrops(true);
47 setDropIndicatorShown(true);
48 setHeaderHidden(true);
49 // I wonder what's the best value to use here. Unfortunately, the default is to disable auto expanding.
50 setAutoExpandDelay(800);
52 // Track expansion/collapsing so that we remember this state despite the asynchronous nature of mailbox loading
53 connect(this, &QTreeView::expanded, this, [this](const QModelIndex &what) {
54 auto name = what.data(Imap::Mailbox::RoleMailboxName).toString();
55 if (!m_desiredExpansionState.contains(name)) {
56 m_desiredExpansionState.insert(name);
57 emit mailboxExpansionChanged(m_desiredExpansionState.toList());
59 });
60 connect(this, &QTreeView::collapsed, this, [this](const QModelIndex &what) {
61 auto name = what.data(Imap::Mailbox::RoleMailboxName).toString();
62 if (m_desiredExpansionState.remove(name)) {
63 emit mailboxExpansionChanged(m_desiredExpansionState.toList());
65 });
68 /** \reimp
70 The MailboxFinder has to be kept up-to-speed about these changes.
72 void MailBoxTreeView::setModel(QAbstractItemModel *model)
74 delete m_mailboxFinder;
75 m_mailboxFinder = nullptr;
77 if (model) {
78 m_mailboxFinder = new Imap::Mailbox::MailboxFinder(this, model);
79 connect(m_mailboxFinder, &Imap::Mailbox::MailboxFinder::mailboxFound,
80 this, [this](const QString &, const QModelIndex &index) {
81 expand(index);
82 });
83 connect(model, &QAbstractItemModel::layoutChanged, this, &MailBoxTreeView::resetWatchedMailboxes);
84 connect(model, &QAbstractItemModel::rowsRemoved, this, &MailBoxTreeView::resetWatchedMailboxes);
85 connect(model, &QAbstractItemModel::modelReset, this, &MailBoxTreeView::resetWatchedMailboxes);
87 QTreeView::setModel(model);
88 resetWatchedMailboxes();
90 /** @short Returns the user's default action from Qt::DropAction or Qt::IgnoreAction if not set */
91 Qt::DropAction MailBoxTreeView::defaultDropAction()
93 auto mboxDropAction = m_settings->value(Common::SettingsNames::mboxDropAction, QVariant(QStringLiteral("ask"))).toString();
94 if (mboxDropAction == QStringLiteral("move")) {
95 return Qt::MoveAction;
96 } else if (mboxDropAction == QStringLiteral("copy")) {
97 return Qt::CopyAction;
98 } else {
99 return Qt::IgnoreAction;
103 /** @short Reimplemented for more consistent handling of modifiers
105 Qt's default behaviour is odd here:
106 If you selected the move-action by pressing shift and you release the shift
107 key while moving the mouse, the action does not change back to copy. But if you
108 then move the mouse over a widget border - i.e. cause dragLeaveEvent, the action
109 WILL change back to copy.
110 This implementation immitates KDE's behaviour: react to a change in modifiers
111 immediately.
113 void MailBoxTreeView::dragMoveEvent(QDragMoveEvent *event)
115 QTreeView::dragMoveEvent(event);
116 if (!event->isAccepted())
117 return;
118 if (event->keyboardModifiers() == Qt::ShiftModifier)
119 event->setDropAction(Qt::MoveAction);
120 else
121 event->setDropAction(Qt::CopyAction);
124 /** @short Reimplemented to present the user with a menu to choose between copy or move.
126 Does not show the menu if either ctrl (copy messages) or shift (move messages)
127 is pressed
129 void MailBoxTreeView::dropEvent(QDropEvent *event)
131 if (Gui::Util::isFromDistinctImapAccount(event)) {
132 event->ignore();
133 return;
135 if (event->keyboardModifiers() == Qt::ControlModifier) {
136 event->setDropAction(Qt::CopyAction);
137 } else if (event->keyboardModifiers() == Qt::ShiftModifier) {
138 event->setDropAction(Qt::MoveAction);
139 } else if (defaultDropAction() != Qt::IgnoreAction) {
140 event->setDropAction(defaultDropAction());
141 } else {
142 QMenu menu(this);
143 QAction *moveAction = menu.addAction(UiUtils::loadIcon(QStringLiteral("go-jump")), tr("Move here\tShift"));
144 menu.addAction(UiUtils::loadIcon(QStringLiteral("edit-copy")), tr("Copy here\tCtrl"));
145 QAction *cancelAction = menu.addAction(UiUtils::loadIcon(QStringLiteral("process-stop")), tr("Cancel"));
147 QAction *selectedAction = menu.exec(mapToGlobal(event->pos()));
149 // if user closes the menu or selects cancel, ignore the event
150 if (!selectedAction || selectedAction == cancelAction) {
151 event->ignore();
152 return;
155 event->setDropAction(selectedAction == moveAction ? Qt::MoveAction : Qt::CopyAction);
158 QTreeView::dropEvent(event);
161 void MailBoxTreeView::dragEnterEvent(QDragEnterEvent *event)
163 if (Gui::Util::isFromDistinctImapAccount(event)) {
164 event->ignore();
165 return;
167 QTreeView::dragEnterEvent(event);
170 /** @short Specify which mailboxes should be expanded
172 The mailboxes might appear and disappear at any time, so let's make sure that
173 they are properly expanded/collapsed once they pop in.
175 void MailBoxTreeView::setDesiredExpansion(const QStringList &mailboxNames)
177 m_desiredExpansionState = mailboxNames.toSet();
178 resetWatchedMailboxes();
181 /** @short Ensure that we watch stuff that we need to watch */
182 void MailBoxTreeView::resetWatchedMailboxes()
184 if (m_mailboxFinder) {
185 for (const auto &mailbox: m_desiredExpansionState) {
186 m_mailboxFinder->addMailbox(mailbox);