Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : #include <QList>
4 : : #include <QString>
5 : : #include <memory>
6 : : #include <vector>
7 : :
8 : : #include "data/Models.h"
9 : :
10 : : // A node in the mail thread tree.
11 : : // Children are owned via unique_ptr; root nodes are owned by the caller.
12 : : struct ThreadNode {
13 : : const MailHeader *header = nullptr; // Points into the original header list
14 : : ThreadNode *parent = nullptr;
15 : : std::vector<std::unique_ptr<ThreadNode>> children;
16 : : int depth = 0;
17 : :
18 : 247 : ~ThreadNode() = default;
19 : :
20 : : // Newest date in this subtree (for sorting root nodes).
21 : 423 : QDateTime newestDate() const {
22 [ + + ]: 423 : QDateTime newest = header ? header->date : QDateTime();
23 [ + + ]: 447 : for (const auto &child : children) {
24 [ + - ]: 24 : QDateTime childDate = child->newestDate();
25 [ + - + + : 24 : if (childDate.isValid() && (!newest.isValid() || childDate > newest))
+ - + + +
- + + +
+ ]
26 : 22 : newest = childDate;
27 : 24 : }
28 : 423 : return newest;
29 : 0 : }
30 : :
31 : : // Total count of descendants (not including self).
32 : 99 : int descendantCount() const {
33 : 99 : int count = 0;
34 [ + + ]: 165 : for (const auto &child : children) {
35 [ + - ]: 66 : count += 1 + child->descendantCount();
36 : : }
37 : 99 : return count;
38 : : }
39 : :
40 : : // T-547: Check if any descendant has unseen mail.
41 : 13 : bool hasUnseenDescendant() const {
42 [ + + ]: 16 : for (const auto &child : children) {
43 [ + - + + : 9 : if (child->header && !child->header->isSeen())
+ + ]
44 : 6 : return true;
45 [ + - + + ]: 5 : if (child->hasUnseenDescendant())
46 : 2 : return true;
47 : : }
48 : 7 : return false;
49 : : }
50 : :
51 : : // T-547: Count unseen descendants (not including self).
52 : 102 : int unseenDescendantCount() const {
53 : 102 : int count = 0;
54 [ + + ]: 169 : for (const auto &child : children) {
55 [ + + + + : 67 : if (child->header && !child->header->isSeen())
+ + ]
56 : 61 : ++count;
57 [ + - ]: 67 : count += child->unseenDescendantCount();
58 : : }
59 : 102 : return count;
60 : : }
61 : : };
62 : :
63 : : // Builds a thread tree from a flat list of MailHeaders.
64 : : // Uses a simplified JWZ algorithm: In-Reply-To based + subject fallback.
65 : : class ThreadBuilder {
66 : : public:
67 : : // Build thread tree from flat header list.
68 : : // The returned unique_ptrs own the root-level ThreadNodes (and their children).
69 : : // IMPORTANT: The MailHeader pointers in ThreadNode point into 'headers',
70 : : // so 'headers' must remain valid for the lifetime of the tree.
71 : : static std::vector<std::unique_ptr<ThreadNode>> buildThreads(const QList<MailHeader> &headers);
72 : :
73 : : private:
74 : : // Strip Re:/Fwd:/etc. prefixes for subject-based threading.
75 : : static QString normalizeSubject(const QString &subject);
76 : : };
|