MailJDTourDownloadDocsQualityTestsCoverage

Which source lines and branches the tests execute. Lines 91.5 %, branches 75.0 % (minimum 85 % and 72 %). main @ 399ffe3d · 21 October 2026 · pipeline 7238.

GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 95.8% 205 / 0 / 214
Functions: 96.4% 27 / 0 / 28
Branches: 81.0% 303 / 0 / 374

presentation/MailPresentationModel.cpp
Line Branch Exec Source
1 #include "MailPresentationModel.h"
2 #include <QLocale>
3 #include "WorkspaceState.h"
4 #include "ui/LabelDelegate.h"
5 #include "service/ImapResponseParser.h"
6
7 972 MailPresentationModel::MailPresentationModel(MailListModel *source, QString accountId, QObject *parent)
8 972 : MailFilterProxyModel(parent), m_headers(source), m_accountId(std::move(accountId)) {
9
1/1
✓ Branch 13 → 14 taken 972 times.
972 setSourceModel(source);
10 // Source roles describe widget columns; Quick properties span the entire row.
11 972 connect(source, &QAbstractItemModel::dataChanged, this,
12
1/1
✓ Branch 14 → 15 taken 972 times.
972 [this](const QModelIndex &first, const QModelIndex &last, const QList<int> &sourceRoles) {
13 740 QList<int> quickRoles;
14
2/2
✓ Branch 3 → 4 taken 591 times.
✓ Branch 3 → 5 taken 149 times.
740 if (sourceRoles.contains(MailListModel::FlagsRole))
15
1/1
✓ Branch 4 → 26 taken 591 times.
591 quickRoles = {Unread, Starred, Answered};
16
2/2
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 9 taken 148 times.
149 else if (sourceRoles.contains(MailListModel::HasAttachmentsRole))
17
1/1
✓ Branch 7 → 8 taken 1 time.
1 quickRoles = {Attachment};
18
2/6
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 14 taken 148 times.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 14 not taken.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 18 taken 148 times.
148 else if (first.column() == MailListModel::Suggestion &&
19 ✗ last.column() == MailListModel::Suggestion)
20 ✗ quickRoles = {Suggestion};
21
5/6
✓ Branch 19 → 20 taken 90 times.
✓ Branch 19 → 23 taken 58 times.
✓ Branch 21 → 22 taken 90 times.
✗ Branch 21 → 23 not taken.
✓ Branch 24 → 25 taken 90 times.
✓ Branch 24 → 26 taken 58 times.
238 else if (first.column() == MailListModel::Subject &&
22 90 last.column() == MailListModel::Subject)
23
1/1
✓ Branch 25 → 26 taken 90 times.
90 quickRoles = {Subject, Folder};
24
2/2
✓ Branch 41 → 27 taken 13316 times.
✓ Branch 41 → 42 taken 740 times.
14056 for (int row = first.row(); row <= last.row(); ++row) {
25
2/2
✓ Branch 28 → 29 taken 13316 times.
✓ Branch 29 → 30 taken 13316 times.
13316 const auto proxy = mapFromSource(m_headers->index(row, 0));
26
4/5
✓ Branch 31 → 32 taken 13316 times.
✗ Branch 31 → 39 not taken.
✓ Branch 34 → 35 taken 13316 times.
✓ Branch 36 → 37 taken 13316 times.
✓ Branch 37 → 38 taken 13316 times.
13316 if (proxy.isValid()) emit dataChanged(proxy, index(proxy.row(), columnCount() - 1), quickRoles);
27 }
28 740 });
29
1/1
✓ Branch 16 → 17 taken 972 times.
972 connect(source, &QObject::destroyed, this, [this] { m_headers = nullptr; });
30 972 }
31 2486 QHash<int, QByteArray> MailPresentationModel::roleNames() const {
32 ✗ return {{Identity, "mailIdentity"}, {Subject, "subject"}, {Sender, "sender"},
33 ✗ {Date, "dateText"}, {Unread, "unread"}, {Starred, "starred"},
34 ✗ {Labels, "labels"}, {Attachment, "hasAttachment"}, {Selected, "mailSelected"}, {Folder, "folderBadge"}, {Suggestion, "folderSuggestion"},
35 ✗ {Depth, "depth"}, {ThreadCount, "threadCount"}, {HasChildren, "threadHasChildren"}, {Expanded, "threadExpanded"},
36 ✗ {LabelChips, "labelChips"}, {OpenTask, "hasOpenTask"}, {RuleMatch, "ruleMatched"},
37 ✗ {Recipient, "recipient"}, {SizeText, "sizeText"}, {Period, "period"},
38
2/4
✓ Branch 27 → 28 taken 57178 times.
✓ Branch 27 → 29 taken 2486 times.
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
59664 {MatchedInText, "matchedInText"}, {Answered, "answered"}};
39 2486 }
40 793 void MailPresentationModel::setAccountId(const QString &accountId) {
41
2/2
✓ Branch 3 → 4 taken 15 times.
✓ Branch 3 → 5 taken 778 times.
793 if (m_accountId == accountId) return;
42 778 m_accountId = accountId;
43
9/9
✓ Branch 7 → 8 taken 778 times.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 21 taken 777 times.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
778 if (rowCount() > 0) emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), {Identity});
44 }
45 931474 QVariant MailPresentationModel::data(const QModelIndex &index, int role) const {
46
3/6
✓ Branch 2 → 3 taken 931474 times.
✗ Branch 2 → 5 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 931474 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 931474 times.
931474 if (!m_headers || !index.isValid()) return {};
47
2/2
✓ Branch 9 → 10 taken 931474 times.
✓ Branch 11 → 12 taken 931474 times.
931474 const auto *header = m_headers->headerAt(mapToSource(index).row());
48
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 931474 times.
931474 if (!header) return {};
49
24/24
✓ Branch 14 → 15 taken 47083 times.
✓ Branch 14 → 21 taken 53527 times.
✓ Branch 14 → 22 taken 40589 times.
✓ Branch 14 → 26 taken 46155 times.
✓ Branch 14 → 27 taken 39630 times.
✓ Branch 14 → 31 taken 30766 times.
✓ Branch 14 → 38 taken 39631 times.
✓ Branch 14 → 44 taken 39844 times.
✓ Branch 14 → 46 taken 39785 times.
✓ Branch 14 → 48 taken 39783 times.
✓ Branch 14 → 50 taken 30674 times.
✓ Branch 14 → 51 taken 39632 times.
✓ Branch 14 → 52 taken 41386 times.
✓ Branch 14 → 62 taken 45840 times.
✓ Branch 14 → 74 taken 39630 times.
✓ Branch 14 → 75 taken 39630 times.
✓ Branch 14 → 76 taken 39630 times.
✓ Branch 14 → 77 taken 39630 times.
✓ Branch 14 → 78 taken 39643 times.
✓ Branch 14 → 84 taken 40018 times.
✓ Branch 14 → 90 taken 39630 times.
✓ Branch 14 → 91 taken 39630 times.
✓ Branch 14 → 101 taken 39630 times.
✓ Branch 14 → 105 taken 78 times.
931474 switch (role) {
50 47083 case Identity: return WorkspaceState::encode({m_accountId, header->folderId, header->uid});
51 53527 case Subject: return header->subject;
52
2/2
✓ Branch 22 → 23 taken 40589 times.
✓ Branch 23 → 24 taken 40589 times.
40589 case Folder: return m_headers->data(mapToSource(index), MailListModel::FolderBadgeRole);
53 46155 case Sender: return header->from;
54
1/1
✓ Branch 27 → 28 taken 39630 times.
39630 case Date: return MailListModel::formatDate(header->date);
55
3/3
✓ Branch 32 → 33 taken 88 times.
✓ Branch 32 → 34 taken 30678 times.
✓ Branch 33 → 35 taken 88 times.
30766 case Period: return m_period ? m_period(header->date) : QString();
56
2/2
✓ Branch 39 → 40 taken 12073 times.
✓ Branch 39 → 42 taken 27558 times.
39631 case MatchedInText: return m_matchedInText ? m_matchedInText(*header) : false;
57 39844 case Unread: return !header->isSeen();
58 39785 case Starred: return header->isFlagged();
59 39783 case Answered: return header->isAnswered();
60 30674 case Labels: return header->labels;
61 39632 case Attachment: return header->hasAttachments;
62 41386 case Selected: {
63
5/5
✓ Branch 53 → 54 taken 34818 times.
✓ Branch 53 → 57 taken 6568 times.
✓ Branch 54 → 55 taken 34818 times.
✓ Branch 55 → 56 taken 3128 times.
✓ Branch 55 → 57 taken 31690 times.
41386 const bool selected = m_selected && m_selected(header->folderId, header->uid);
64
2/2
✓ Branch 58 → 59 taken 41386 times.
✓ Branch 59 → 60 taken 41386 times.
41386 m_selectedCache.insert(qMakePair(header->folderId, header->uid), selected);
65 41386 return selected;
66 }
67 45840 case Suggestion: {
68
4/6
✓ Branch 63 → 64 taken 27200 times.
✓ Branch 63 → 66 taken 18640 times.
✓ Branch 67 → 68 taken 27200 times.
✓ Branch 67 → 69 taken 18640 times.
✗ Branch 120 → 121 not taken.
✗ Branch 120 → 122 not taken.
73040 const QString suggestion = m_suggestion ? m_suggestion({m_accountId, header->folderId, header->uid}) : QString{};
69
2/2
✓ Branch 69 → 70 taken 45840 times.
✓ Branch 70 → 71 taken 45840 times.
45840 m_suggestionCache.insert(qMakePair(header->folderId, header->uid), suggestion);
70 45840 return suggestion;
71 45840 }
72 // The flat list has no thread structure. Constant neutral roles let one
73 // QML delegate serve both this projection and QuickThreadListModel.
74 39630 case Depth: return 0;
75 39630 case ThreadCount: return 0;
76 39630 case HasChildren: return false;
77 39630 case Expanded: return false;
78
2/2
✓ Branch 79 → 80 taken 21003 times.
✓ Branch 79 → 82 taken 18640 times.
39643 case OpenTask: return m_taskLink ? m_taskLink(header->messageId) : false;
79
2/2
✓ Branch 85 → 86 taken 21378 times.
✓ Branch 85 → 88 taken 18640 times.
40018 case RuleMatch: return m_ruleMatch ? m_ruleMatch(*header) : false;
80 39630 case Recipient: return header->to;
81
6/8
✓ Branch 91 → 92 taken 1998 times.
✓ Branch 91 → 95 taken 37632 times.
✓ Branch 92 → 93 taken 1998 times.
✓ Branch 94 → 96 taken 1998 times.
✓ Branch 98 → 99 taken 1998 times.
✓ Branch 98 → 100 taken 37632 times.
✗ Branch 133 → 134 not taken.
✗ Branch 133 → 135 not taken.
39630 case SizeText: return header->size > 0 ? QLocale().formattedDataSize(header->size, 0) : QString();
82
1/1
✓ Branch 101 → 102 taken 39630 times.
39630 case LabelChips: return labelChipsFor(header->labels);
83 78 default: return MailFilterProxyModel::data(index, role);
84 }
85 74283 }
86 42643 QVariantList MailPresentationModel::labelChipsFor(const QStringList &labels) {
87 42643 QVariantList chips;
88
2/2
✓ Branch 30 → 4 taken 2954 times.
✓ Branch 30 → 31 taken 42643 times.
45597 for (const auto &label : labels) {
89
3/3
✓ Branch 5 → 6 taken 2954 times.
✓ Branch 6 → 7 taken 9 times.
✓ Branch 6 → 8 taken 2945 times.
2954 if (ImapResponseParser::isInternalKeyword(label)) continue;
90
1/1
✓ Branch 18 → 19 taken 2945 times.
2945 chips.append(QVariantMap{{"name", LabelDelegate::displayName(label)},
91
1/1
✓ Branch 11 → 12 taken 2945 times.
5890 {"color", LabelDelegate::colorForLabel(label).name()},
92
3/5
✓ Branch 14 → 15 taken 2945 times.
✓ Branch 22 → 23 taken 8835 times.
✓ Branch 22 → 24 taken 2945 times.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 40 not taken.
17670 {"textColor", QColor(Qt::white).name()}});
93 }
94 42643 return chips;
95 8835 }
96
97 6526 QVariantMap MailPresentationModel::mailAt(int row) const {
98
6/7
✓ Branch 2 → 3 taken 6526 times.
✗ Branch 2 → 6 not taken.
✓ Branch 4 → 5 taken 6526 times.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 6525 times.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 6525 times.
6526 if (row < 0 || row >= rowCount()) return {};
99
2/2
✓ Branch 11 → 12 taken 6525 times.
✓ Branch 12 → 13 taken 6525 times.
6525 return {{"identity", data(index(row, 0), Identity)},
100
2/2
✓ Branch 15 → 16 taken 6525 times.
✓ Branch 16 → 17 taken 6525 times.
13050 {"subject", data(index(row, 0), Subject)},
101
4/6
✓ Branch 19 → 20 taken 6525 times.
✓ Branch 20 → 21 taken 6525 times.
✓ Branch 24 → 25 taken 19575 times.
✓ Branch 24 → 26 taken 6525 times.
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 35 not taken.
39150 {"sender", data(index(row, 0), Sender)}};
102 26100 }
103 20451 int MailPresentationModel::rowForIdentity(const QVariantMap &identity) const {
104
1/1
✓ Branch 2 → 3 taken 20451 times.
20451 const auto id = WorkspaceState::decode(identity);
105
5/6
✓ Branch 3 → 4 taken 20451 times.
✗ Branch 3 → 6 not taken.
✓ Branch 5 → 6 taken 2398 times.
✓ Branch 5 → 7 taken 18053 times.
✓ Branch 8 → 9 taken 2398 times.
✓ Branch 8 → 10 taken 18053 times.
20451 if (!m_headers || id.accountId != m_accountId) return -1;
106
1/1
✓ Branch 10 → 11 taken 18053 times.
18053 const int sourceRow = m_headers->rowForUid(id.uid, id.folderId);
107
4/4
✓ Branch 11 → 12 taken 16439 times.
✓ Branch 11 → 16 taken 1614 times.
✓ Branch 13 → 14 taken 16439 times.
✓ Branch 14 → 15 taken 16439 times.
18053 return sourceRow < 0 ? -1 : mapFromSource(m_headers->index(sourceRow, 0)).row();
108 20451 }
109 766 void MailPresentationModel::filter(const QString &text, bool unreadOnly, bool starredOnly, bool withAttachments) {
110 766 setFilters(text, unreadOnly, starredOnly, withAttachments);
111 766 }
112 903 void MailPresentationModel::clearFilters() {
113
1/1
✓ Branch 3 → 4 taken 903 times.
903 setFilters({}, false, false, false);
114 903 }
115 110 void MailPresentationModel::sortByColumn(const QString &columnId, bool ascending) {
116 110 int column = -1;
117
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 110 times.
110 if (columnId == QLatin1String("star")) column = MailListModel::Star;
118
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 110 times.
110 else if (columnId == QLatin1String("subject")) column = MailListModel::Subject;
119
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 110 times.
110 else if (columnId == QLatin1String("from")) column = MailListModel::From;
120
1/2
✓ Branch 16 → 17 taken 110 times.
✗ Branch 16 → 18 not taken.
110 else if (columnId == QLatin1String("date")) column = MailListModel::Date;
121 ✗ else if (columnId == QLatin1String("size")) column = MailListModel::Size;
122
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 110 times.
110 if (column < 0) return;
123
1/2
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 110 times.
110 sort(column, ascending ? Qt::AscendingOrder : Qt::DescendingOrder);
124 }
125 11453 MailSelectionKey MailPresentationModel::keyAt(int row) const {
126
7/9
✓ Branch 2 → 3 taken 11453 times.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 10541 times.
✓ Branch 3 → 7 taken 912 times.
✓ Branch 5 → 6 taken 10541 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 10541 times.
✓ Branch 9 → 10 taken 912 times.
✓ Branch 9 → 12 taken 10541 times.
12365 if (!m_headers || row < 0 || row >= rowCount()) return {};
127
3/3
✓ Branch 13 → 14 taken 10541 times.
✓ Branch 14 → 15 taken 10541 times.
✓ Branch 16 → 17 taken 10541 times.
10541 const auto *header = m_headers->headerAt(mapToSource(index(row, 0)).row());
128
1/2
✓ Branch 17 → 18 taken 10541 times.
✗ Branch 17 → 19 not taken.
10541 return header ? MailSelectionKey{header->folderId, header->uid, header->date} : MailSelectionKey{};
129 912 }
130 namespace {
131 // P90.12: coalesce rows whose cached role value actually changed into the
132 // minimal set of contiguous ranges.
133 template <typename Value, typename Compute>
134 4215 QVector<QPair<int, int>> roleDiffRanges(int rows,
135 const std::function<const MailHeader *(int)> &headerAtRow,
136 QHash<QPair<qint64, qint64>, Value> &cache,
137 const Compute &compute) {
138 4215 QVector<int> changed;
139
2/2
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 2 → 3 taken 4079 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 2 → 3 taken 136 times.
4215 changed.reserve(8);
140
6/6
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 22 → 23 taken 555 times.
✓ Branch 22 → 25 taken 347703 times.
✓ Branch 27 → 4 taken 348258 times.
✓ Branch 27 → 28 taken 4079 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 22 → 4 taken 18051 times.
✓ Branch 22 → 23 taken 136 times.
718782 for (int row = 0; row < rows; ++row) {
141
2/2
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 4 → 5 taken 348258 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 4 → 5 taken 18051 times.
366309 const auto *header = headerAtRow(row);
142
2/4
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 348258 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 18051 times.
731462 if (!header) continue;
143
2/2
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 7 → 8 taken 348258 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 7 → 8 taken 18051 times.
366309 const auto key = qMakePair(header->folderId, header->uid);
144
2/2
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 8 → 9 taken 348258 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 8 → 9 taken 18051 times.
366309 const Value value = compute(header);
145 366309 const auto cached = cache.constFind(key);
146 // No entry: no view has read this row's value (data() records every
147 // read), so a delegate created later reads the current value itself.
148
4/4
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 12 → 13 taken 315244 times.
✓ Branch 12 → 14 taken 33014 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 12 → 13 taken 14361 times.
✓ Branch 12 → 14 taken 3690 times.
366309 if (cached == cache.constEnd()) continue;
149
4/4
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 16 → 17 taken 32459 times.
✓ Branch 16 → 18 taken 555 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 15 → 16 taken 3089 times.
✓ Branch 15 → 17 taken 601 times.
36704 if (cached.value() == value) continue;
150
2/2
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 18 → 19 taken 555 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 17 → 18 taken 601 times.
1156 cache.insert(key, value);
151
2/2
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 19 → 20 taken 555 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 18 → 19 taken 601 times.
1156 changed.append(row);
152 }
153 4215 QVector<QPair<int, int>> ranges;
154
4/4
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 45 → 29 taken 118 times.
✓ Branch 45 → 46 taken 4079 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 40 → 24 taken 114 times.
✓ Branch 40 → 41 taken 136 times.
4447 for (int at = 0; at < changed.size();) {
155 232 int end = at;
156
11/12
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 32 → 33 taken 437 times.
✓ Branch 32 → 37 taken 118 times.
✓ Branch 35 → 36 taken 437 times.
✗ Branch 35 → 37 not taken.
✓ Branch 38 → 30 taken 437 times.
✓ Branch 38 → 39 taken 118 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 27 → 28 taken 507 times.
✓ Branch 27 → 32 taken 94 times.
✓ Branch 30 → 31 taken 487 times.
✓ Branch 30 → 32 taken 20 times.
✓ Branch 33 → 25 taken 487 times.
✓ Branch 33 → 34 taken 114 times.
1156 while (end + 1 < changed.size() && changed.at(end + 1) == changed.at(end) + 1) ++end;
157
2/2
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<QString, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, QString>&, MailPresentationModel::suggestionsChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 42 → 43 taken 118 times.
QList<std::pair<int, int> > (anonymous namespace)::roleDiffRanges<bool, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1}>(int, std::function<MailHeader const* (int)> const&, QHash<std::pair<long long, long long>, bool>&, MailPresentationModel::selectionChanged()::{lambda(MailHeader const*)#1} const&):
✓ Branch 37 → 38 taken 114 times.
232 ranges.append({changed.at(at), changed.at(end)});
158 232 at = end + 1;
159 }
160 4215 return ranges;
161 4215 }
162 }
163
164 137 void MailPresentationModel::selectionChanged() {
165 // P90.12/P90.17: only rows whose membership flipped re-render (normally
166 // the old and the new selection row), never the entire flat model.
167
7/9
✓ Branch 2 → 3 taken 137 times.
✗ Branch 2 → 8 not taken.
✓ Branch 4 → 5 taken 137 times.
✓ Branch 5 → 6 taken 136 times.
✓ Branch 5 → 8 taken 1 time.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 136 times.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 31 taken 136 times.
137 if (!m_headers || rowCount() <= 0 || !m_selected) {
168 1 const bool had = !m_selectedCache.isEmpty();
169 1 m_selectedCache.clear();
170
4/12
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 18 not taken.
✓ Branch 15 → 16 taken 1 time.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 1 time.
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 30 taken 1 time.
✗ Branch 20 → 21 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 27 → 28 not taken.
1 if (had && rowCount() > 0) emit dataChanged(index(0, 0), index(rowCount() - 1, 0), {Selected});
171 1 return;
172 }
173 136 for (const auto &range : roleDiffRanges(rowCount(), [this](int row) {
174
3/3
✓ Branch 3 → 4 taken 18051 times.
✓ Branch 4 → 5 taken 18051 times.
✓ Branch 6 → 7 taken 18051 times.
18051 return m_headers->headerAt(mapToSource(index(row, 0)).row());
175 136 }, m_selectedCache, [this](const MailHeader *header) {
176 18051 return m_selected(header->folderId, header->uid);
177
6/6
✓ Branch 33 → 34 taken 136 times.
✓ Branch 34 → 35 taken 136 times.
✓ Branch 36 → 37 taken 136 times.
✓ Branch 37 → 38 taken 136 times.
✓ Branch 49 → 39 taken 114 times.
✓ Branch 49 → 50 taken 136 times.
386 }))
178
4/4
✓ Branch 40 → 41 taken 114 times.
✓ Branch 42 → 43 taken 114 times.
✓ Branch 44 → 45 taken 114 times.
✓ Branch 45 → 46 taken 114 times.
250 emit dataChanged(index(range.first, 0), index(range.second, 0), {Selected});
179 }
180 2824 void MailPresentationModel::singleSelectionChanged(MailSelectionKey previous,
181 MailSelectionKey current) {
182
3/7
✓ Branch 3 → 4 taken 2824 times.
✗ Branch 3 → 5 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2824 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 2824 times.
✗ Branch 8 → 9 not taken.
2824 if (!m_selected || !m_headers) { selectionChanged(); return; }
183 3880 const auto update = [this](const MailSelectionKey &key) {
184
3/4
✓ Branch 2 → 3 taken 1443 times.
✓ Branch 2 → 4 taken 2437 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1443 times.
4093 if (key.folderId < 0 || key.uid < 0) return;
185
1/1
✓ Branch 5 → 6 taken 1443 times.
1443 const auto identity = qMakePair(key.folderId, key.uid);
186
1/1
✓ Branch 6 → 7 taken 1443 times.
1443 const int sourceRow = m_headers->rowForUid(key.uid, key.folderId);
187
2/2
✓ Branch 7 → 8 taken 92 times.
✓ Branch 7 → 9 taken 1351 times.
1443 const QModelIndex visible = sourceRow < 0 ? QModelIndex{}
188
2/2
✓ Branch 10 → 11 taken 1351 times.
✓ Branch 11 → 12 taken 1351 times.
1443 : mapFromSource(m_headers->index(sourceRow, 0));
189
3/3
✓ Branch 13 → 14 taken 92 times.
✓ Branch 13 → 16 taken 1351 times.
✓ Branch 14 → 15 taken 92 times.
1443 if (!visible.isValid()) { m_selectedCache.remove(identity); return; }
190
1/1
✓ Branch 16 → 17 taken 1351 times.
1351 const bool selected = m_selected(key.folderId, key.uid);
191 1351 const auto cached = m_selectedCache.constFind(identity);
192
6/6
✓ Branch 20 → 21 taken 1333 times.
✓ Branch 20 → 24 taken 18 times.
✓ Branch 22 → 23 taken 121 times.
✓ Branch 22 → 24 taken 1212 times.
✓ Branch 25 → 26 taken 121 times.
✓ Branch 25 → 27 taken 1230 times.
1351 if (cached != m_selectedCache.cend() && cached.value() == selected) return;
193
1/1
✓ Branch 27 → 28 taken 1230 times.
1230 m_selectedCache.insert(identity, selected);
194
2/2
✓ Branch 28 → 29 taken 1230 times.
✓ Branch 29 → 30 taken 1230 times.
1230 emit dataChanged(visible, visible, {Selected});
195 2824 };
196
1/1
✓ Branch 10 → 11 taken 2824 times.
2824 update(previous);
197
4/4
✓ Branch 11 → 12 taken 2030 times.
✓ Branch 11 → 13 taken 794 times.
✓ Branch 12 → 13 taken 262 times.
✓ Branch 12 → 14 taken 1768 times.
2824 if (previous.folderId != current.folderId || previous.uid != current.uid)
198
1/1
✓ Branch 13 → 14 taken 1056 times.
1056 update(current);
199 }
200 8571 void MailPresentationModel::suggestionsChanged() {
201
7/9
✓ Branch 2 → 3 taken 8571 times.
✗ Branch 2 → 8 not taken.
✓ Branch 4 → 5 taken 8571 times.
✓ Branch 5 → 6 taken 4079 times.
✓ Branch 5 → 8 taken 4492 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 4079 times.
✓ Branch 10 → 11 taken 4492 times.
✓ Branch 10 → 31 taken 4079 times.
8571 if (!m_headers || rowCount() <= 0 || !m_suggestion) {
202 4492 const bool had = !m_suggestionCache.isEmpty();
203 4492 m_suggestionCache.clear();
204
5/12
✓ Branch 13 → 14 taken 43 times.
✓ Branch 13 → 18 taken 4449 times.
✓ Branch 15 → 16 taken 43 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 43 times.
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 30 taken 4492 times.
✗ Branch 20 → 21 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 27 → 28 not taken.
4492 if (had && rowCount() > 0) emit dataChanged(index(0, 0), index(rowCount() - 1, 0), {Suggestion});
205 4492 return;
206 }
207 4079 for (const auto &range : roleDiffRanges(rowCount(), [this](int row) {
208
3/3
✓ Branch 3 → 4 taken 348258 times.
✓ Branch 4 → 5 taken 348258 times.
✓ Branch 6 → 7 taken 348258 times.
348258 return m_headers->headerAt(mapToSource(index(row, 0)).row());
209 4079 }, m_suggestionCache, [this](const MailHeader *header) {
210
1/3
✓ Branch 3 → 4 taken 348258 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
696516 return m_suggestion(MailId{m_accountId, header->folderId, header->uid});
211
6/6
✓ Branch 33 → 34 taken 4079 times.
✓ Branch 34 → 35 taken 4079 times.
✓ Branch 36 → 37 taken 4079 times.
✓ Branch 37 → 38 taken 4079 times.
✓ Branch 49 → 39 taken 118 times.
✓ Branch 49 → 50 taken 4079 times.
8276 }))
212
4/4
✓ Branch 40 → 41 taken 118 times.
✓ Branch 42 → 43 taken 118 times.
✓ Branch 44 → 45 taken 118 times.
✓ Branch 45 → 46 taken 118 times.
4197 emit dataChanged(index(range.first, 0), index(range.second, 0), {Suggestion});
213 }
214
215 3 void MailPresentationModel::setPeriodProvider(std::function<QString(const QDateTime &)> provider) {
216 3 m_period = std::move(provider);
217
7/8
✓ Branch 5 → 6 taken 3 times.
✓ Branch 6 → 7 taken 3 times.
✗ Branch 6 → 17 not taken.
✓ Branch 7 → 8 taken 3 times.
✓ Branch 10 → 11 taken 3 times.
✓ Branch 11 → 12 taken 3 times.
✓ Branch 13 → 14 taken 3 times.
✓ Branch 14 → 15 taken 3 times.
3 if (rowCount() > 0) emit dataChanged(index(0, 0), index(rowCount() - 1, 0), {Period});
218 3 }
219
220 89 void MailPresentationModel::setMatchProvider(std::function<bool(const MailHeader &)> provider) {
221 89 m_matchedInText = std::move(provider);
222 89 matchesChanged();
223 89 }
224
225 89 void MailPresentationModel::matchesChanged() {
226
2/8
✓ Branch 3 → 4 taken 89 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 15 taken 89 times.
✗ Branch 5 → 6 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 12 → 13 not taken.
89 if (rowCount() > 0) emit dataChanged(index(0, 0), index(rowCount() - 1, 0), {MatchedInText});
227 89 }
228
229 35 void MailPresentationModel::ruleMatchesChanged() {
230
7/8
✓ Branch 3 → 4 taken 35 times.
✓ Branch 4 → 5 taken 35 times.
✗ Branch 4 → 15 not taken.
✓ Branch 5 → 6 taken 35 times.
✓ Branch 8 → 9 taken 35 times.
✓ Branch 9 → 10 taken 35 times.
✓ Branch 11 → 12 taken 35 times.
✓ Branch 12 → 13 taken 35 times.
35 if (rowCount() > 0) emit dataChanged(index(0, 0), index(rowCount() - 1, 0), {RuleMatch});
231 35 }
232
233 29 void MailPresentationModel::taskLinksChanged() {
234
8/8
✓ Branch 3 → 4 taken 29 times.
✓ Branch 4 → 5 taken 5 times.
✓ Branch 4 → 15 taken 24 times.
✓ Branch 5 → 6 taken 5 times.
✓ Branch 8 → 9 taken 5 times.
✓ Branch 9 → 10 taken 5 times.
✓ Branch 11 → 12 taken 5 times.
✓ Branch 12 → 13 taken 5 times.
29 if (rowCount() > 0) emit dataChanged(index(0, 0), index(rowCount() - 1, 0), {OpenTask});
235 29 }
236