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 }