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 "PrettyMailboxModel.h" 0023 #include "ItemRoles.h" 0024 0025 #include <QFont> 0026 #include "UiUtils/Formatting.h" 0027 #include "UiUtils/IconLoader.h" 0028 0029 namespace Imap 0030 { 0031 0032 namespace Mailbox 0033 { 0034 0035 PrettyMailboxModel::PrettyMailboxModel(QObject *parent, QAbstractItemModel *mailboxModel): 0036 QSortFilterProxyModel(parent), m_showOnlySubscribed(false) 0037 { 0038 setDynamicSortFilter(true); 0039 setSourceModel(mailboxModel); 0040 } 0041 0042 QVariant PrettyMailboxModel::data(const QModelIndex &index, int role) const 0043 { 0044 if (!index.isValid()) 0045 return QVariant(); 0046 0047 if (index.column() != 0) 0048 return QVariant(); 0049 0050 if (index.row() < 0 || index.row() >= rowCount(index.parent()) || index.model() != this) 0051 return QVariant(); 0052 0053 switch (role) { 0054 case Qt::DisplayRole: 0055 { 0056 QModelIndex translated = mapToSource(index); 0057 qlonglong unreadCount = translated.data(RoleUnreadMessageCount).toLongLong(); 0058 qlonglong recentCount = translated.data(RoleRecentMessageCount).toLongLong(); 0059 // The "problem" is that the \Recent and (lack of) \Seen flags are orthogonal states. 0060 // 0061 // There is no rule saying that a recent message is still unseen (trivial example: an already-read message being copied), 0062 // or that an unread message is recent. 0063 // 0064 // That's not really so much of a problem after the mailbox has been synced because we have all flags for each and every 0065 // message, and can therefore easily compute the difference. The problem, however, is that there is no such feature 0066 // in the SELECT command (and before you ask, SEARCH requires a selected mailbox, and "selected" is very close to 0067 // "synchronized" in Trojita). Trojita tries to satisfy all requests for "message numbers" at once, via the STATUS command 0068 // for unselected mailboxes, or through the already-known and cached information in the message flags for the recently 0069 // synchronized ones. In theory, it is possible to implement a workaround involving EXAMINE and (E)SEARCH, but even that 0070 // has its drawbacks (like the necessary serialization of requests and the requirement for a ton of new code). 0071 // 0072 // So in short, this is why there's no "(1 + 5)" result with six unread an one recent message. 0073 // 0074 // We also deliberately put an emphasis on the "unread count", even to an extent where there's no special information 0075 // for mailboxes with some recent, but no unread messages. 0076 if (recentCount && unreadCount) { 0077 return tr("%1 (%2/%3)") 0078 .arg(QSortFilterProxyModel::data(index, RoleShortMailboxName).toString(), 0079 QString::number(recentCount), QString::number(unreadCount)); 0080 } else if (unreadCount) { 0081 return tr("%1 (%2)") 0082 .arg(QSortFilterProxyModel::data(index, RoleShortMailboxName).toString(), 0083 QString::number(unreadCount)); 0084 } else { 0085 return QSortFilterProxyModel::data(index, RoleShortMailboxName); 0086 } 0087 } 0088 case Qt::FontRole: 0089 { 0090 QModelIndex translated = mapToSource(index); 0091 if (translated.data(RoleMailboxNumbersFetched).toBool() && 0092 translated.data(RoleUnreadMessageCount).toULongLong() > 0) { 0093 QFont font; 0094 font.setBold(true); 0095 return font; 0096 } else { 0097 return QVariant(); 0098 } 0099 } 0100 case Qt::DecorationRole: 0101 { 0102 QModelIndex translated = mapToSource(index); 0103 if (translated.data(RoleMailboxItemsAreLoading).toBool()) 0104 return UiUtils::loadIcon(QStringLiteral("folder-grey")); 0105 else if (translated.data(RoleMailboxIsINBOX).toBool()) 0106 return UiUtils::loadIcon(QStringLiteral("mail-folder-inbox")); 0107 else if (translated.data(RoleRecentMessageCount).toInt() > 0) 0108 return UiUtils::loadIcon(QStringLiteral("folder-bookmark")); 0109 else if (translated.data(RoleMailboxIsSelectable).toBool()) 0110 return UiUtils::loadIcon(QStringLiteral("folder")); 0111 else 0112 return UiUtils::loadIcon(QStringLiteral("folder-open")); 0113 } 0114 case Qt::ToolTipRole: 0115 { 0116 QModelIndex translated = mapToSource(index); 0117 return QStringLiteral("<p>%1</p>\n<p>%2<br/>%3<br/>%4</p>").arg( 0118 UiUtils::Formatting::htmlEscaped(translated.data(RoleShortMailboxName).toString()), 0119 tr("%n messages", 0, translated.data(RoleTotalMessageCount).toInt()), 0120 tr("%n unread", 0, translated.data(RoleUnreadMessageCount).toInt()), 0121 tr("%n recent", 0, translated.data(RoleRecentMessageCount).toInt())); 0122 } 0123 default: 0124 return QSortFilterProxyModel::data(index, role); 0125 } 0126 } 0127 0128 bool PrettyMailboxModel::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const 0129 { 0130 Q_UNUSED(source_parent); 0131 return source_column == 0; 0132 } 0133 0134 bool PrettyMailboxModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const 0135 { 0136 if (!m_showOnlySubscribed) 0137 return true; 0138 0139 QModelIndex index = sourceModel()->index(source_row, 0, source_parent); 0140 Q_ASSERT(index.isValid()); 0141 0142 // FIXME: walk the tree resursively from here instead of just checking for children 0143 return index.data(RoleMailboxIsSubscribed).toBool() || sourceModel()->hasChildren(index); 0144 } 0145 0146 bool PrettyMailboxModel::hasChildren(const QModelIndex &parent) const 0147 { 0148 return sourceModel()->hasChildren(mapToSource(parent)); 0149 } 0150 0151 void PrettyMailboxModel::setShowOnlySubscribed(bool filterUnsubscribed) 0152 { 0153 m_showOnlySubscribed = filterUnsubscribed; 0154 invalidateFilter(); 0155 } 0156 0157 } 0158 0159 }