File indexing completed on 2024-11-24 04:53:13
0001 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net> 0002 0003 This file is part of the Trojita Qt IMAP e-mail client, 0004 http://trojita.flaska.net/ 0005 0006 This program is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU General Public License as 0008 published by the Free Software Foundation; either version 2 of 0009 the License or (at your option) version 3 or any later version 0010 accepted by the membership of KDE e.V. (or its successor approved 0011 by the membership of KDE e.V.), which shall act as a proxy 0012 defined in Section 14 of version 3 of the license. 0013 0014 This program is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 GNU General Public License for more details. 0018 0019 You should have received a copy of the GNU General Public License 0020 along with this program. If not, see <http://www.gnu.org/licenses/>. 0021 */ 0022 #include "PrettyMsgListModel.h" 0023 #include "ItemRoles.h" 0024 #include "MsgListModel.h" 0025 #include "ThreadingMsgListModel.h" 0026 #include "UiUtils/Formatting.h" 0027 #include "UiUtils/IconLoader.h" 0028 0029 0030 namespace Imap 0031 { 0032 0033 namespace Mailbox 0034 { 0035 0036 PrettyMsgListModel::PrettyMsgListModel(QObject *parent): 0037 QSortFilterProxyModel(parent), m_hideRead(false) 0038 { 0039 setDynamicSortFilter(true); 0040 } 0041 0042 QVariant PrettyMsgListModel::data(const QModelIndex &index, int role) const 0043 { 0044 if (! index.isValid() || index.model() != this) 0045 return QVariant(); 0046 0047 if (index.column() < 0 || index.column() >= columnCount(index.parent())) 0048 return QVariant(); 0049 0050 if (index.row() < 0 || index.row() >= rowCount(index.parent())) 0051 return QVariant(); 0052 0053 QModelIndex translated = mapToSource(index); 0054 0055 switch (role) { 0056 0057 case Qt::DisplayRole: 0058 case Qt::ToolTipRole: 0059 switch (index.column()) { 0060 case MsgListModel::TO: 0061 case MsgListModel::FROM: 0062 case MsgListModel::CC: 0063 case MsgListModel::BCC: 0064 { 0065 int backendRole = 0; 0066 switch (index.column()) { 0067 case MsgListModel::FROM: 0068 backendRole = RoleMessageFrom; 0069 break; 0070 case MsgListModel::TO: 0071 backendRole = RoleMessageTo; 0072 break; 0073 case MsgListModel::CC: 0074 backendRole = RoleMessageCc; 0075 break; 0076 case MsgListModel::BCC: 0077 backendRole = RoleMessageBcc; 0078 break; 0079 } 0080 QVariantList items = translated.data(backendRole).toList(); 0081 if (role == Qt::DisplayRole) { 0082 return Imap::Message::MailAddress::prettyList(items, Imap::Message::MailAddress::FORMAT_JUST_NAME); 0083 } else { 0084 return UiUtils::Formatting::htmlEscaped(Imap::Message::MailAddress::prettyList(items, Imap::Message::MailAddress::FORMAT_READABLE)); 0085 } 0086 } 0087 case MsgListModel::DATE: 0088 case MsgListModel::RECEIVED_DATE: 0089 { 0090 QDateTime res = translated.data(RoleMessageDate).toDateTime(); 0091 if (role == Qt::ToolTipRole) { 0092 // tooltips shall always show the full and complete data 0093 return QLocale().toString(res.toLocalTime(), QLocale::LongFormat); 0094 } 0095 return UiUtils::Formatting::prettyDate(res.toLocalTime()); 0096 } 0097 case MsgListModel::SIZE: 0098 { 0099 QVariant size = translated.data(RoleMessageSize); 0100 if (!size.isValid()) { 0101 return QVariant(); 0102 } 0103 return UiUtils::Formatting::prettySize(size.toULongLong()); 0104 } 0105 case MsgListModel::SUBJECT: 0106 { 0107 if (!translated.data(RoleIsFetched).toBool()) 0108 return tr("Loading..."); 0109 QString subject = translated.data(RoleMessageSubject).toString(); 0110 if (role == Qt::ToolTipRole) { 0111 subject = UiUtils::Formatting::htmlEscaped(subject); 0112 } 0113 return subject.isEmpty() ? tr("(no subject)") : subject; 0114 } 0115 } 0116 break; 0117 0118 0119 case Qt::TextAlignmentRole: 0120 switch (index.column()) { 0121 case MsgListModel::DATE: 0122 case MsgListModel::RECEIVED_DATE: 0123 case MsgListModel::SIZE: 0124 return int(Qt::AlignRight | Qt::AlignVCenter); 0125 default: 0126 return int(Qt::AlignLeft | Qt::AlignVCenter); 0127 } // we return int because QVariant cannot hold QFlag: https://bugreports.qt.io/browse/QTBUG-54210 0128 0129 case Qt::DecorationRole: 0130 // We will need the data, but asking for Flags or IsMarkedXYZ doesn't cause a fetch 0131 translated.data(RoleMessageSubject); 0132 0133 switch (index.column()) { 0134 case MsgListModel::SUBJECT: 0135 { 0136 if (! translated.data(RoleIsFetched).toBool()) 0137 return QVariant(); 0138 0139 bool isForwarded = translated.data(RoleMessageIsMarkedForwarded).toBool(); 0140 bool isReplied = translated.data(RoleMessageIsMarkedReplied).toBool(); 0141 0142 if (isForwarded && isReplied) 0143 return UiUtils::loadIcon(QStringLiteral("mail-forwarded-replied")); 0144 else if (isReplied) 0145 return UiUtils::loadIcon(QStringLiteral("mail-replied")); 0146 else if (isForwarded) 0147 return UiUtils::loadIcon(QStringLiteral("mail-forwarded")); 0148 else if (translated.data(RoleMessageIsMarkedRecent).toBool()) 0149 return UiUtils::loadIcon(QStringLiteral("mail-mark-unread-new")); 0150 else if (!translated.data(RoleMessageIsMarkedRead).toBool()) 0151 return UiUtils::loadIcon(QStringLiteral("mail-mark-unread")); 0152 else 0153 return UiUtils::loadIcon(QStringLiteral("mail-mark-read")); 0154 } 0155 case MsgListModel::SEEN: 0156 if (! translated.data(RoleIsFetched).toBool()) 0157 return QVariant(); 0158 break; 0159 case MsgListModel::FLAGGED: 0160 if (! translated.data(RoleIsFetched).toBool()) 0161 return QVariant(); 0162 if (translated.data(RoleMessageIsMarkedFlagged).toBool()) 0163 return UiUtils::loadIcon(QStringLiteral("mail-flagged")); 0164 else 0165 return UiUtils::loadIcon(QStringLiteral("mail-unflagged")); 0166 case MsgListModel::ATTACHMENT: 0167 if (translated.data(RoleMessageHasAttachments).toBool()) 0168 return UiUtils::loadIcon(QStringLiteral("mail-attachment")); 0169 else 0170 return QVariant(); 0171 default: 0172 return QVariant(); 0173 } 0174 0175 } 0176 0177 return QSortFilterProxyModel::data(index, role); 0178 } 0179 0180 void PrettyMsgListModel::setHideRead(bool value) 0181 { 0182 m_hideRead = value; 0183 invalidateFilter(); 0184 } 0185 0186 bool PrettyMsgListModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const 0187 { 0188 if (!m_hideRead) 0189 return true; 0190 0191 QModelIndex source_index = sourceModel()->index(source_row, 0, source_parent); 0192 0193 for (QModelIndex test = source_index; test.isValid(); test = test.parent()) 0194 if (test.data(RoleThreadRootWithUnreadMessages).toBool() || test.data(RoleMessageWasUnread).toBool()) 0195 return true; 0196 0197 return false; 0198 } 0199 0200 0201 void PrettyMsgListModel::sort(int column, Qt::SortOrder order) 0202 { 0203 ThreadingMsgListModel *threadingModel = qobject_cast<ThreadingMsgListModel*>(sourceModel()); 0204 Q_ASSERT(threadingModel); 0205 0206 ThreadingMsgListModel::SortCriterium criterium = ThreadingMsgListModel::SORT_NONE; 0207 switch (column) { 0208 case MsgListModel::SEEN: 0209 case MsgListModel::FLAGGED: 0210 case MsgListModel::ATTACHMENT: 0211 case MsgListModel::COLUMN_COUNT: 0212 case MsgListModel::BCC: 0213 case -1: 0214 criterium = ThreadingMsgListModel::SORT_NONE; 0215 break; 0216 case MsgListModel::SUBJECT: 0217 criterium = ThreadingMsgListModel::SORT_SUBJECT; 0218 break; 0219 case MsgListModel::FROM: 0220 criterium = ThreadingMsgListModel::SORT_FROM; 0221 break; 0222 case MsgListModel::TO: 0223 criterium = ThreadingMsgListModel::SORT_TO; 0224 break; 0225 case MsgListModel::CC: 0226 criterium = ThreadingMsgListModel::SORT_CC; 0227 break; 0228 case MsgListModel::DATE: 0229 criterium = ThreadingMsgListModel::SORT_DATE; 0230 break; 0231 case MsgListModel::RECEIVED_DATE: 0232 criterium = ThreadingMsgListModel::SORT_ARRIVAL; 0233 break; 0234 case MsgListModel::SIZE: 0235 criterium = ThreadingMsgListModel::SORT_SIZE; 0236 break; 0237 } 0238 0239 bool willSort = threadingModel->setUserSearchingSortingPreference(threadingModel->currentSearchCondition(), criterium, order); 0240 0241 // Now let the view know about whether we accept such a sorting criteria. 0242 // This is needed because the QHeaderView doesn't offer a way to say "hey, you cannot sort in columns XYZ, only on ABC". 0243 if (criterium != ThreadingMsgListModel::SORT_NONE && willSort) 0244 emit sortingPreferenceChanged(column, order); 0245 else 0246 emit sortingPreferenceChanged(-1, order); 0247 } 0248 0249 } 0250 0251 }