File indexing completed on 2024-06-16 05:01:24
0001 /* Copyright (C) 2014 - 2015 Stephan Platz <trojita@paalsteek.de> 0002 Copyright (C) 2006 - 2016 Jan Kundrát <jkt@kde.org> 0003 0004 This file is part of the Trojita Qt IMAP e-mail client, 0005 http://trojita.flaska.net/ 0006 0007 This program is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU General Public License as 0009 published by the Free Software Foundation; either version 2 of 0010 the License or (at your option) version 3 or any later version 0011 accepted by the membership of KDE e.V. (or its successor approved 0012 by the membership of KDE e.V.), which shall act as a proxy 0013 defined in Section 14 of version 3 of the license. 0014 0015 This program is distributed in the hope that it will be useful, 0016 but WITHOUT ANY WARRANTY; without even the implied warranty of 0017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0018 GNU General Public License for more details. 0019 0020 You should have received a copy of the GNU General Public License 0021 along with this program. If not, see <http://www.gnu.org/licenses/>. 0022 */ 0023 0024 #include "Cryptography/MessageModel.h" 0025 #include "Cryptography/MessagePart.h" 0026 #include "Cryptography/PartReplacer.h" 0027 #include "Common/MetaTypes.h" 0028 #include "Imap/Model/ItemRoles.h" 0029 #include "Imap/Model/MailboxTree.h" 0030 0031 namespace Cryptography { 0032 0033 MessageModel::MessageModel(QObject *parent, const QModelIndex &message) 0034 : QAbstractItemModel(parent) 0035 , m_message(message) 0036 , m_rootPart(std::move(new TopLevelMessage(m_message, this))) 0037 { 0038 Q_ASSERT(m_message.isValid()); 0039 connect(m_message.model(), &QAbstractItemModel::dataChanged, this, &MessageModel::mapDataChanged); 0040 } 0041 0042 void MessageModel::mapDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 0043 { 0044 if (!m_message.isValid()) { 0045 return; 0046 } 0047 0048 Q_ASSERT(m_message.model()); 0049 Q_ASSERT(topLeft.parent() == bottomRight.parent()); 0050 0051 QModelIndex root = index(0,0); 0052 if (!root.isValid()) 0053 return; 0054 0055 auto topLeftIt = m_map.constFind(topLeft); 0056 auto bottomRightIt = m_map.constFind(bottomRight); 0057 if (topLeftIt != m_map.constEnd() && bottomRightIt != m_map.constEnd()) { 0058 emit dataChanged( 0059 createIndex(topLeft.row(), topLeft.column(), *topLeftIt), 0060 createIndex(bottomRight.row(), bottomRight.column(), *bottomRightIt) 0061 ); 0062 } 0063 } 0064 0065 QModelIndex MessageModel::index(int row, int column, const QModelIndex &parent) const 0066 { 0067 Q_ASSERT(!parent.isValid() || parent.model() == this); 0068 auto parentPart = translatePtr(parent); 0069 Q_ASSERT(parentPart); 0070 auto childPtr = parentPart->child(const_cast<MessageModel *>(this), row, column); 0071 if (!childPtr) { 0072 return QModelIndex(); 0073 } else { 0074 return createIndex(row, column, childPtr); 0075 } 0076 } 0077 0078 QModelIndex MessageModel::parent(const QModelIndex &child) const 0079 { 0080 if (!child.isValid()) 0081 return QModelIndex(); 0082 Q_ASSERT(child.model() == this); 0083 auto childPart = translatePtr(child); 0084 Q_ASSERT(childPart); 0085 auto parentPart = childPart->parent(); 0086 return (parentPart && parentPart != m_rootPart.get()) ? createIndex(parentPart->row(), 0, parentPart) : QModelIndex(); 0087 } 0088 0089 QVariant MessageModel::data(const QModelIndex &index, int role) const 0090 { 0091 if (role == Imap::Mailbox::RoleIsNetworkOffline) 0092 return m_message.data(Imap::Mailbox::RoleIsNetworkOffline); 0093 0094 if (!index.isValid()) { 0095 return QVariant(); 0096 } 0097 0098 Q_ASSERT(index.model() == this); 0099 0100 return translatePtr(index)->data(role); 0101 } 0102 0103 QModelIndex MessageModel::message() const 0104 { 0105 return m_message; 0106 } 0107 0108 void MessageModel::insertSubtree(const QModelIndex &parent, MessagePart::Ptr tree) 0109 { 0110 std::vector<MessagePart::Ptr> parts; 0111 parts.emplace_back(std::move(tree)); 0112 insertSubtree(parent, std::move(parts)); 0113 } 0114 0115 void MessageModel::insertSubtree(const QModelIndex &parent, std::vector<Cryptography::MessagePart::Ptr> &&parts) 0116 { 0117 Q_ASSERT(!parent.isValid() || parent.model() == this); 0118 auto *part = translatePtr(parent); 0119 Q_ASSERT(part); 0120 0121 #ifdef MIME_TREE_DEBUG 0122 qDebug() << "Whole tree:\n" << *m_rootPart; 0123 qDebug() << "Inserting at:\n" << (void*)(part); 0124 #endif 0125 0126 beginInsertRows(parent, 0, parts.size()); 0127 0128 Q_ASSERT(part->m_children.empty()); 0129 for (size_t i = 0; i < parts.size(); ++i) { 0130 #ifdef MIME_TREE_DEBUG 0131 qDebug() << "New item[" << i << "]:\n" << *(parts[i].get()); 0132 #endif 0133 parts[i]->m_parent = part; 0134 part->m_children[i] = std::move(parts[i]); 0135 } 0136 0137 bool needsDataChanged = false; 0138 if (LocalMessagePart *localPart = dynamic_cast<LocalMessagePart*>(part)) { 0139 localPart->m_localState = MessagePart::FetchingState::DONE; 0140 needsDataChanged = true; 0141 } 0142 0143 endInsertRows(); 0144 0145 if (needsDataChanged) { 0146 emit dataChanged(parent, parent); 0147 } 0148 } 0149 0150 void MessageModel::replaceMeWithSubtree(const QModelIndex &parent, MessagePart *partToReplace, MessagePart::Ptr tree) 0151 { 0152 Q_ASSERT(!parent.isValid() || parent.model() == this); 0153 auto *part = translatePtr(parent); 0154 Q_ASSERT(part); 0155 0156 #ifdef MIME_TREE_DEBUG 0157 qDebug() << "Whole tree:\n" << *m_rootPart; 0158 qDebug() << "Replacing:\n" << (void*)(partToReplace); 0159 qDebug() << "New items:\n" << *(tree.get()); 0160 #endif 0161 0162 Q_ASSERT(partToReplace); 0163 Q_ASSERT(tree->row() == partToReplace->row()); 0164 0165 auto it = part->m_children.find(partToReplace->row()); 0166 Q_ASSERT(it != part->m_children.end()); 0167 Q_ASSERT(it->second->row() == partToReplace->row()); 0168 Q_ASSERT(partToReplace->row() == tree->row()); 0169 0170 emit layoutAboutToBeChanged(QList<QPersistentModelIndex>() << parent); 0171 0172 auto oldIndexes = persistentIndexList(); 0173 auto newIndexes = oldIndexes; 0174 for (int i = 0; i < oldIndexes.size(); ++i) { 0175 const auto &index = oldIndexes[i]; 0176 if (index.parent() == parent && index.column() == 0 && index.row() == tree->row()) { 0177 newIndexes[i] = createIndex(tree->row(), 0, tree.get()); 0178 } 0179 } 0180 changePersistentIndexList(oldIndexes, newIndexes); 0181 0182 tree->m_parent = part; 0183 MessagePart::Ptr partGoingAway = std::move(it->second); 0184 it->second = std::move(tree); 0185 emit layoutChanged(QList<QPersistentModelIndex>() << parent); 0186 0187 emit dataChanged(parent, parent); 0188 0189 #ifdef MIME_TREE_DEBUG 0190 qDebug() << "After replacement:\n" << *m_rootPart; 0191 #endif 0192 } 0193 0194 /** @short Get the underlying MessagePart * for the passed index */ 0195 MessagePart *MessageModel::translatePtr(const QModelIndex &part) const 0196 { 0197 if (!part.isValid()) 0198 return m_rootPart.get(); 0199 return static_cast<MessagePart *>(part.internalPointer()); 0200 } 0201 0202 int MessageModel::rowCount(const QModelIndex &parent) const 0203 { 0204 return translatePtr(parent)->rowCount(const_cast<MessageModel *>(this)); 0205 } 0206 0207 int MessageModel::columnCount(const QModelIndex &parent) const 0208 { 0209 return translatePtr(parent)->columnCount(const_cast<MessageModel *>(this)); 0210 } 0211 0212 void MessageModel::registerPartHandler(std::shared_ptr<PartReplacer> module) 0213 { 0214 m_partHandlers.push_back(module); 0215 } 0216 0217 #ifdef MIME_TREE_DEBUG 0218 void MessageModel::debugDump() 0219 { 0220 qDebug() << "MIME tree:\n" << *m_rootPart; 0221 } 0222 #endif 0223 0224 }