ui/MailFilterProxyModel.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "MailFilterProxyModel.h" | ||
| 2 | |||
| 3 | #include "MailListModel.h" | ||
| 4 | #include "data/Models.h" | ||
| 5 | |||
| 6 | 975 | MailFilterProxyModel::MailFilterProxyModel(QObject *parent) | |
| 7 | 975 | : QSortFilterProxyModel(parent) { | |
| 8 | // T-79.B2/M19: keep a thread visible when only a descendant matches the | ||
| 9 | // filter (e.g. unread reply under a read root). Flat models have no | ||
| 10 | // children, so their filtering is unaffected. | ||
| 11 |
1/1✓ Branch 6 → 7 taken 975 times.
|
975 | setRecursiveFilteringEnabled(true); |
| 12 | 975 | connect(this, &QAbstractProxyModel::sourceModelChanged, this, | |
| 13 |
1/1✓ Branch 7 → 8 taken 975 times.
|
975 | &MailFilterProxyModel::forgetShownUnread); |
| 14 | 975 | } | |
| 15 | |||
| 16 | 102202 | bool MailFilterProxyModel::lessThan(const QModelIndex &sourceLeft, | |
| 17 | const QModelIndex &sourceRight) const { | ||
| 18 | 102202 | const auto *mailModel = qobject_cast<const MailListModel *>(sourceModel()); | |
| 19 |
2/3✓ Branch 5 → 6 taken 102202 times.
✓ Branch 7 → 8 taken 102202 times.
✗ Branch 7 → 15 not taken.
|
102202 | if (mailModel && !sourceLeft.parent().isValid() && |
| 20 |
5/9✓ Branch 4 → 5 taken 102202 times.
✗ Branch 4 → 15 not taken.
✓ Branch 8 → 9 taken 102202 times.
✓ Branch 10 → 11 taken 102202 times.
✗ Branch 10 → 15 not taken.
✓ Branch 13 → 14 taken 102202 times.
✗ Branch 13 → 15 not taken.
✓ Branch 16 → 17 taken 102202 times.
✗ Branch 16 → 33 not taken.
|
306606 | !sourceRight.parent().isValid() && |
| 21 | 102202 | sourceLeft.column() == sourceRight.column()) { | |
| 22 | 102202 | const MailHeader *left = mailModel->headerAt(sourceLeft.row()); | |
| 23 | 102202 | const MailHeader *right = mailModel->headerAt(sourceRight.row()); | |
| 24 |
2/4✓ Branch 21 → 22 taken 102202 times.
✗ Branch 21 → 33 not taken.
✓ Branch 22 → 23 taken 102202 times.
✗ Branch 22 → 33 not taken.
|
102202 | if (left && right) { |
| 25 |
1/4✓ Branch 24 → 25 taken 102202 times.
✗ Branch 24 → 27 not taken.
✗ Branch 24 → 28 not taken.
✗ Branch 24 → 31 not taken.
|
102202 | switch (sourceLeft.column()) { |
| 26 | 102202 | case MailListModel::Date: | |
| 27 | 102202 | return left->date < right->date; | |
| 28 | ✗ | case MailListModel::Size: | |
| 29 | ✗ | return left->size < right->size; | |
| 30 | ✗ | case MailListModel::Star: | |
| 31 | ✗ | return left->isFlagged() < right->isFlagged(); | |
| 32 | ✗ | default: | |
| 33 | ✗ | break; | |
| 34 | } | ||
| 35 | } | ||
| 36 | } | ||
| 37 | ✗ | return QSortFilterProxyModel::lessThan(sourceLeft, sourceRight); | |
| 38 | } | ||
| 39 | |||
| 40 | 78 | void MailFilterProxyModel::invalidateMailFilter() { | |
| 41 | 78 | forgetShownUnread(); | |
| 42 |
5/6✓ Branch 4 → 5 taken 58 times.
✓ Branch 4 → 8 taken 20 times.
✓ Branch 6 → 7 taken 58 times.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 58 times.
✓ Branch 9 → 12 taken 20 times.
|
78 | if (m_sourceFilterDriver && m_sourceFilterDriver()) { |
| 43 | 58 | emit mailFilterChanged(); | |
| 44 | 58 | return; | |
| 45 | } | ||
| 46 | 20 | emit mailFilterAboutToChange(); | |
| 47 | #if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) | ||
| 48 | beginFilterChange(); | ||
| 49 | endFilterChange(QSortFilterProxyModel::Direction::Rows); | ||
| 50 | #else | ||
| 51 | 20 | invalidateFilter(); | |
| 52 | #endif | ||
| 53 | 20 | emit mailFilterChanged(); | |
| 54 | } | ||
| 55 | |||
| 56 | ✗ | void MailFilterProxyModel::setFilterText(const QString &text) { | |
| 57 | ✗ | if (m_filterText == text) return; | |
| 58 | ✗ | m_filterText = text; | |
| 59 | ✗ | invalidateMailFilter(); | |
| 60 | } | ||
| 61 | |||
| 62 | 5 | void MailFilterProxyModel::setShowUnreadOnly(bool on) { | |
| 63 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 5 times.
|
5 | if (m_showUnread == on) return; |
| 64 | 5 | m_showUnread = on; | |
| 65 | 5 | invalidateMailFilter(); | |
| 66 | } | ||
| 67 | |||
| 68 | ✗ | void MailFilterProxyModel::setShowStarredOnly(bool on) { | |
| 69 | ✗ | if (m_showStarred == on) return; | |
| 70 | ✗ | m_showStarred = on; | |
| 71 | ✗ | invalidateMailFilter(); | |
| 72 | } | ||
| 73 | |||
| 74 | ✗ | void MailFilterProxyModel::setShowWithAttachments(bool on) { | |
| 75 | ✗ | if (m_showAttachments == on) return; | |
| 76 | ✗ | m_showAttachments = on; | |
| 77 | ✗ | invalidateMailFilter(); | |
| 78 | } | ||
| 79 | |||
| 80 | 1669 | void MailFilterProxyModel::setFilters(const QString &text, bool unreadOnly, | |
| 81 | bool starredOnly, bool withAttachments) { | ||
| 82 |
2/2✓ Branch 4 → 5 taken 1615 times.
✓ Branch 4 → 8 taken 10 times.
|
3294 | if (m_filterText == text && m_showUnread == unreadOnly && |
| 83 |
8/8✓ Branch 3 → 4 taken 1625 times.
✓ Branch 3 → 8 taken 44 times.
✓ Branch 5 → 6 taken 1603 times.
✓ Branch 5 → 8 taken 12 times.
✓ Branch 6 → 7 taken 1596 times.
✓ Branch 6 → 8 taken 7 times.
✓ Branch 9 → 10 taken 1596 times.
✓ Branch 9 → 11 taken 73 times.
|
3294 | m_showStarred == starredOnly && m_showAttachments == withAttachments) |
| 84 | 1596 | return; | |
| 85 | 73 | m_filterText = text; | |
| 86 | 73 | m_showUnread = unreadOnly; | |
| 87 | 73 | m_showStarred = starredOnly; | |
| 88 | 73 | m_showAttachments = withAttachments; | |
| 89 | 73 | invalidateMailFilter(); | |
| 90 | } | ||
| 91 | |||
| 92 | 73657 | bool MailFilterProxyModel::filterAcceptsRow( | |
| 93 | int sourceRow, const QModelIndex &sourceParent) const { | ||
| 94 | // MailListModel is flat. Its retained MailHeader already holds the values | ||
| 95 | // needed by the common chip filters; avoid creating indexes and QVariants | ||
| 96 | // for every row of each filter pass. | ||
| 97 |
2/2✓ Branch 2 → 3 taken 73657 times.
✓ Branch 3 → 4 taken 73657 times.
|
73657 | const auto *mailModel = qobject_cast<const MailListModel *>(sourceModel()); |
| 98 |
1/2✓ Branch 6 → 7 taken 73654 times.
✗ Branch 6 → 9 not taken.
|
73654 | const MailHeader *header = mailModel && !sourceParent.isValid() |
| 99 |
3/3✓ Branch 4 → 5 taken 73654 times.
✓ Branch 4 → 9 taken 3 times.
✓ Branch 7 → 8 taken 73654 times.
|
147311 | ? mailModel->headerAt(sourceRow) |
| 100 | 73657 | : nullptr; | |
| 101 | 73657 | QModelIndex idx; | |
| 102 |
2/2✓ Branch 10 → 11 taken 3 times.
✓ Branch 10 → 13 taken 73654 times.
|
73657 | if (!header) |
| 103 |
2/2✓ Branch 11 → 12 taken 3 times.
✓ Branch 12 → 13 taken 3 times.
|
3 | idx = sourceModel()->index(sourceRow, 0, sourceParent); |
| 104 | |||
| 105 | // Unread filter: check Seen flag | ||
| 106 |
2/2✓ Branch 13 → 14 taken 49 times.
✓ Branch 13 → 37 taken 73608 times.
|
73657 | if (m_showUnread) { |
| 107 |
2/2✓ Branch 14 → 15 taken 46 times.
✓ Branch 14 → 16 taken 3 times.
|
49 | quint32 flags = header ? header->flags |
| 108 |
4/6✓ Branch 16 → 17 taken 3 times.
✓ Branch 17 → 18 taken 3 times.
✓ Branch 19 → 20 taken 3 times.
✓ Branch 19 → 21 taken 46 times.
✗ Branch 90 → 91 not taken.
✗ Branch 90 → 92 not taken.
|
49 | : idx.data(MailListModel::FlagsRole).toUInt(); |
| 109 | 49 | const bool seen = flags & MailFlag::Seen; | |
| 110 | // Read mails stay while this unread view lasts if it already showed | ||
| 111 | // them; the view is scoped to one folder, so another folder starts over. | ||
| 112 |
4/4✓ Branch 21 → 22 taken 46 times.
✓ Branch 21 → 25 taken 3 times.
✓ Branch 22 → 23 taken 6 times.
✓ Branch 22 → 25 taken 40 times.
|
49 | if (header && header->folderId != m_shownUnreadFolder) { |
| 113 | 6 | m_shownUnread.clear(); | |
| 114 | 6 | m_shownUnreadFolder = header->folderId; | |
| 115 | } | ||
| 116 |
8/8✓ Branch 25 → 26 taken 29 times.
✓ Branch 25 → 30 taken 20 times.
✓ Branch 26 → 27 taken 28 times.
✓ Branch 26 → 29 taken 1 time.
✓ Branch 28 → 29 taken 26 times.
✓ Branch 28 → 30 taken 2 times.
✓ Branch 31 → 32 taken 27 times.
✓ Branch 31 → 33 taken 22 times.
|
49 | if (seen && (!header || !m_shownUnread.contains(header->uid))) |
| 117 | 27 | return false; // mail is read → hide | |
| 118 |
5/5✓ Branch 33 → 34 taken 20 times.
✓ Branch 33 → 37 taken 2 times.
✓ Branch 34 → 35 taken 18 times.
✓ Branch 34 → 37 taken 2 times.
✓ Branch 35 → 36 taken 18 times.
|
22 | if (!seen && header) m_shownUnread.insert(header->uid); |
| 119 | } | ||
| 120 | |||
| 121 | // Starred filter: check Flagged flag | ||
| 122 |
2/2✓ Branch 37 → 38 taken 1 time.
✓ Branch 37 → 47 taken 73629 times.
|
73630 | if (m_showStarred) { |
| 123 |
1/2✓ Branch 38 → 39 taken 1 time.
✗ Branch 38 → 40 not taken.
|
1 | quint32 flags = header ? header->flags |
| 124 |
1/6✗ Branch 40 → 41 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 43 → 44 not taken.
✓ Branch 43 → 45 taken 1 time.
✗ Branch 95 → 96 not taken.
✗ Branch 95 → 97 not taken.
|
1 | : idx.data(MailListModel::FlagsRole).toUInt(); |
| 125 |
1/2✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 1 time.
|
1 | if (!(flags & MailFlag::Flagged)) |
| 126 | ✗ | return false; // mail is not starred → hide | |
| 127 | } | ||
| 128 | |||
| 129 | // Attachments filter | ||
| 130 |
2/2✓ Branch 47 → 48 taken 1 time.
✓ Branch 47 → 57 taken 73629 times.
|
73630 | if (m_showAttachments) { |
| 131 |
1/2✓ Branch 48 → 49 taken 1 time.
✗ Branch 48 → 50 not taken.
|
1 | bool hasAtt = header ? header->hasAttachments |
| 132 |
1/6✗ Branch 50 → 51 not taken.
✗ Branch 51 → 52 not taken.
✗ Branch 53 → 54 not taken.
✓ Branch 53 → 55 taken 1 time.
✗ Branch 99 → 100 not taken.
✗ Branch 99 → 101 not taken.
|
1 | : idx.data(MailListModel::HasAttachmentsRole).toBool(); |
| 133 |
1/2✗ Branch 55 → 56 not taken.
✓ Branch 55 → 57 taken 1 time.
|
1 | if (!hasAtt) |
| 134 | ✗ | return false; | |
| 135 | } | ||
| 136 | |||
| 137 | // Text filter: match against Subject and From columns | ||
| 138 |
2/2✓ Branch 58 → 59 taken 327 times.
✓ Branch 58 → 87 taken 73303 times.
|
73630 | if (!m_filterText.isEmpty()) { |
| 139 | auto subjectIdx = | ||
| 140 |
2/2✓ Branch 59 → 60 taken 327 times.
✓ Branch 60 → 61 taken 327 times.
|
327 | sourceModel()->index(sourceRow, MailListModel::Subject, sourceParent); |
| 141 | auto fromIdx = | ||
| 142 |
2/2✓ Branch 61 → 62 taken 327 times.
✓ Branch 62 → 63 taken 327 times.
|
327 | sourceModel()->index(sourceRow, MailListModel::From, sourceParent); |
| 143 | |||
| 144 |
2/2✓ Branch 63 → 64 taken 327 times.
✓ Branch 64 → 65 taken 327 times.
|
327 | QString subject = subjectIdx.data(Qt::DisplayRole).toString(); |
| 145 |
2/2✓ Branch 66 → 67 taken 327 times.
✓ Branch 67 → 68 taken 327 times.
|
327 | QString from = fromIdx.data(Qt::DisplayRole).toString(); |
| 146 | |||
| 147 |
5/5✓ Branch 69 → 70 taken 327 times.
✓ Branch 70 → 71 taken 257 times.
✓ Branch 70 → 74 taken 70 times.
✓ Branch 75 → 76 taken 237 times.
✓ Branch 75 → 77 taken 90 times.
|
584 | if (!subject.contains(m_filterText, Qt::CaseInsensitive) && |
| 148 |
3/3✓ Branch 71 → 72 taken 257 times.
✓ Branch 72 → 73 taken 237 times.
✓ Branch 72 → 74 taken 20 times.
|
257 | !from.contains(m_filterText, Qt::CaseInsensitive)) { |
| 149 | 237 | return false; | |
| 150 | } | ||
| 151 | 564 | } | |
| 152 | |||
| 153 | 73393 | return true; | |
| 154 | } | ||
| 155 |