1 /* Copyright (C) 2014 - 2015 Stephan Platz <trojita@paalsteek.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 "Cryptography/MessageModel.h"
25 #include "Cryptography/MessagePart.h"
26 #include "Cryptography/PartReplacer.h"
27 #include "Common/MetaTypes.h"
28 #include "Imap/Model/ItemRoles.h"
29 #include "Imap/Model/MailboxTree.h"
31 namespace Cryptography
{
33 MessageModel::MessageModel(QObject
*parent
, const QModelIndex
&message
)
34 : QAbstractItemModel(parent
)
36 , m_rootPart(std::move(new TopLevelMessage(m_message
, this)))
38 Q_ASSERT(m_message
.isValid());
39 connect(m_message
.model(), &QAbstractItemModel::dataChanged
, this, &MessageModel::mapDataChanged
);
42 void MessageModel::mapDataChanged(const QModelIndex
&topLeft
, const QModelIndex
&bottomRight
)
44 if (!m_message
.isValid()) {
48 Q_ASSERT(m_message
.model());
49 Q_ASSERT(topLeft
.parent() == bottomRight
.parent());
51 QModelIndex root
= index(0,0);
55 auto topLeftIt
= m_map
.constFind(topLeft
);
56 auto bottomRightIt
= m_map
.constFind(bottomRight
);
57 if (topLeftIt
!= m_map
.constEnd() && bottomRightIt
!= m_map
.constEnd()) {
59 createIndex(topLeft
.row(), topLeft
.column(), *topLeftIt
),
60 createIndex(bottomRight
.row(), bottomRight
.column(), *bottomRightIt
)
65 QModelIndex
MessageModel::index(int row
, int column
, const QModelIndex
&parent
) const
67 Q_ASSERT(!parent
.isValid() || parent
.model() == this);
68 auto parentPart
= translatePtr(parent
);
70 auto childPtr
= parentPart
->child(const_cast<MessageModel
*>(this), row
, column
);
74 return createIndex(row
, column
, childPtr
);
78 QModelIndex
MessageModel::parent(const QModelIndex
&child
) const
82 Q_ASSERT(child
.model() == this);
83 auto childPart
= translatePtr(child
);
85 auto parentPart
= childPart
->parent();
86 return (parentPart
&& parentPart
!= m_rootPart
.get()) ? createIndex(parentPart
->row(), 0, parentPart
) : QModelIndex();
89 QVariant
MessageModel::data(const QModelIndex
&index
, int role
) const
91 if (!index
.isValid()) {
95 Q_ASSERT(index
.model() == this);
97 return translatePtr(index
)->data(role
);
100 QModelIndex
MessageModel::message() const
105 void MessageModel::insertSubtree(const QModelIndex
&parent
, MessagePart::Ptr tree
)
107 std::vector
<MessagePart::Ptr
> parts
;
108 parts
.emplace_back(std::move(tree
));
109 insertSubtree(parent
, std::move(parts
));
112 void MessageModel::insertSubtree(const QModelIndex
&parent
, std::vector
<Cryptography::MessagePart::Ptr
> &&parts
)
114 Q_ASSERT(!parent
.isValid() || parent
.model() == this);
115 auto *part
= translatePtr(parent
);
118 #ifdef MIME_TREE_DEBUG
119 qDebug() << "Whole tree:\n" << *m_rootPart
;
120 qDebug() << "Inserting at:\n" << (void*)(part
);
123 beginInsertRows(parent
, 0, parts
.size());
125 Q_ASSERT(part
->m_children
.empty());
126 for (size_t i
= 0; i
< parts
.size(); ++i
) {
127 #ifdef MIME_TREE_DEBUG
128 qDebug() << "New item[" << i
<< "]:\n" << *(parts
[i
].get());
130 parts
[i
]->m_parent
= part
;
131 part
->m_children
[i
] = std::move(parts
[i
]);
134 bool needsDataChanged
= false;
135 if (LocalMessagePart
*localPart
= dynamic_cast<LocalMessagePart
*>(part
)) {
136 localPart
->m_localState
= MessagePart::FetchingState::DONE
;
137 needsDataChanged
= true;
142 if (needsDataChanged
) {
143 emit
dataChanged(parent
, parent
);
147 void MessageModel::replaceMeWithSubtree(const QModelIndex
&parent
, MessagePart
*partToReplace
, MessagePart::Ptr tree
)
149 Q_ASSERT(!parent
.isValid() || parent
.model() == this);
150 auto *part
= translatePtr(parent
);
153 #ifdef MIME_TREE_DEBUG
154 qDebug() << "Whole tree:\n" << *m_rootPart
;
155 qDebug() << "Replacing:\n" << (void*)(partToReplace
);
156 qDebug() << "New items:\n" << *(tree
.get());
159 Q_ASSERT(partToReplace
);
160 Q_ASSERT(tree
->row() == partToReplace
->row());
162 auto it
= part
->m_children
.find(partToReplace
->row());
163 Q_ASSERT(it
!= part
->m_children
.end());
164 Q_ASSERT(it
->second
->row() == partToReplace
->row());
165 Q_ASSERT(partToReplace
->row() == tree
->row());
167 emit
layoutAboutToBeChanged(QList
<QPersistentModelIndex
>() << parent
);
169 auto oldIndexes
= persistentIndexList();
170 auto newIndexes
= oldIndexes
;
171 for (int i
= 0; i
< oldIndexes
.size(); ++i
) {
172 const auto &index
= oldIndexes
[i
];
173 if (index
.parent() == parent
&& index
.column() == 0 && index
.row() == tree
->row()) {
174 newIndexes
[i
] = createIndex(tree
->row(), 0, tree
.get());
177 changePersistentIndexList(oldIndexes
, newIndexes
);
179 tree
->m_parent
= part
;
180 MessagePart::Ptr partGoingAway
= std::move(it
->second
);
181 it
->second
= std::move(tree
);
182 emit
layoutChanged(QList
<QPersistentModelIndex
>() << parent
);
184 emit
dataChanged(parent
, parent
);
186 #ifdef MIME_TREE_DEBUG
187 qDebug() << "After replacement:\n" << *m_rootPart
;
191 /** @short Get the underlying MessagePart * for the passed index */
192 MessagePart
*MessageModel::translatePtr(const QModelIndex
&part
) const
195 return m_rootPart
.get();
196 return static_cast<MessagePart
*>(part
.internalPointer());
199 int MessageModel::rowCount(const QModelIndex
&parent
) const
201 return translatePtr(parent
)->rowCount(const_cast<MessageModel
*>(this));
204 int MessageModel::columnCount(const QModelIndex
&parent
) const
206 return translatePtr(parent
)->columnCount(const_cast<MessageModel
*>(this));
209 void MessageModel::registerPartHandler(std::shared_ptr
<PartReplacer
> module
)
211 m_partHandlers
.push_back(module
);
214 #ifdef MIME_TREE_DEBUG
215 void MessageModel::debugDump()
217 qDebug() << "MIME tree:\n" << *m_rootPart
;