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: 100.0% 12 / 0 / 12
Functions: 100.0% 12 / 0 / 12
Branches: 100.0% 1 / 0 / 1

presentation/WorkspaceState.h
Line Branch Exec Source
1 #pragma once
2
3 #include "data/MailRequest.h"
4 #include <QAbstractListModel>
5 #include <QPointer>
6 #include <QVariantMap>
7 #include <QJsonObject>
8 #include <QMap>
9 #include <QStringList>
10 #include <functional>
11 #include <QPointF>
12
13 // View-independent state. Layout changes never issue domain requests.
14 class WorkspaceState final : public QAbstractListModel {
15 1797 Q_OBJECT
16 Q_PROPERTY(QString layout READ layout WRITE setLayout NOTIFY layoutChanged)
17 Q_PROPERTY(bool readerFocused READ readerFocused WRITE setReaderFocused NOTIFY readerFocusedChanged)
18 Q_PROPERTY(QString area READ area WRITE setArea NOTIFY areaChanged)
19 Q_PROPERTY(int activeTab READ activeTab NOTIFY activeTabChanged)
20 Q_PROPERTY(QString activeTabKind READ activeTabKind NOTIFY activeTabChanged)
21 Q_PROPERTY(QVariantMap selection READ selection NOTIFY selectionChanged)
22 Q_PROPERTY(QString generation READ generation NOTIFY selectionChanged)
23 Q_PROPERTY(QString readingMode READ readingMode NOTIFY readingModeChanged)
24 public:
25 struct HtmlReadingState {
26 quint32 uidValidity = 0;
27 QByteArray digest;
28 QPointF scroll;
29 bool allowExternal = false; // Session-only user consent; never serialized.
30 };
31 enum Role { TabIdRole = Qt::UserRole + 1, TitleRole, IdentityRole, ModeRole, ClosableRole,
32 KindRole, DormantRole, TooltipRole };
33 // Sprint 101 S101.1.1: a tab is the folder view ("main", tab 0), one mail
34 // ("mail") or one search ("search"). A search tab carries its canonical
35 // query and account; its `mailId` is the previewed result.
36 static constexpr int MaximumTabs = 128;
37 static constexpr int MaximumQueryCharacters = 4096;
38 // Canonical default for fresh tabs and untouched main-list reading:
39 // the persisted "view/defaultMode" preference, one of text/light/html.
40 static QString configuredReadingMode();
41 explicit WorkspaceState(QObject *parent = nullptr);
42 void setConfiguredReadingMode(const QString &mode);
43 int rowCount(const QModelIndex &parent = {}) const override;
44 QVariant data(const QModelIndex &index, int role) const override;
45 QHash<int, QByteArray> roleNames() const override;
46 2066 QString layout() const { return m_layout; }
47 void setLayout(const QString &layout);
48 4122 bool readerFocused() const { return m_readerFocused; }
49 void setReaderFocused(bool focused);
50 576262 QString area() const { return m_area; }
51 void setArea(const QString &area);
52 477387 int activeTab() const { return m_activeTab; }
53 QVariantMap selection() const;
54 3556 QString generation() const { return QString::number(m_generation); }
55 64863 const MailId &mailId() const { return m_selection; }
56 bool accepts(const MailId &id, quint64 generation) const;
57 void select(const MailId &id);
58 bool replaceActiveMail(const MailId &id, const QString &title);
59 Q_INVOKABLE bool selectIdentity(const QVariantMap &identity);
60 Q_INVOKABLE int openMail(const QVariantMap &identity, const QString &title);
61 Q_INVOKABLE bool closeTab(int index);
62 void invalidateFolder(const QString &accountId, qint64 folderId);
63 Q_INVOKABLE bool activateTab(int index);
64 Q_INVOKABLE void cycleTabs(int offset);
65 Q_INVOKABLE bool setReadingMode(const QString &mode);
66 static QVariantMap encode(const MailId &id);
67 static MailId decode(const QVariantMap &map);
68 QJsonObject saveSession() const;
69 bool restoreSession(const QJsonObject &session, QString *error = nullptr,
70 const std::function<bool(const MailId &)> &acceptIdentity = {});
71 10700 QString readingMode() const { return m_tabs.at(m_activeTab).mode; }
72 729 QString activeTabId() const { return m_tabs.at(m_activeTab).id; }
73 HtmlReadingState bindHtmlDocument(const QString &tabId, const MailId &, quint32 epoch, const QByteArray &digest);
74 bool rememberHtmlScroll(const QString &tabId, const MailId &, quint32 epoch, const QByteArray &digest, const QPointF &);
75 bool allowHtmlExternal(const QString &tabId, const MailId &, quint32 epoch, const QByteArray &digest);
76 void clearHtmlConsent();
77 void retainMailIdentities(const std::function<bool(const MailId &)> &acceptIdentity);
78 // ── Sprint 101: tab kinds and search tabs ─────────────────────────────
79 Q_INVOKABLE QString tabKind(int index) const;
80 31597 QString activeTabKind() const { return m_tabs.at(m_activeTab).kind; }
81 24860 bool activeIsSearch() const { return activeTabKind() == QLatin1String("search"); }
82 int rowForTabId(const QString &tabId) const;
83 // D-2: a new search reuses the most recently used search tab unless
84 // `newTab`; a tab with the same canonical query and account is
85 // activated instead. Returns the row (-1 at the tab limit).
86 int openSearch(const QString &query, const QString &accountId, const QString &title, bool newTab);
87 bool setSearchQuery(const QString &tabId, const QString &query, const QString &title, const QString &tooltip);
88 QString searchQuery(const QString &tabId) const;
89 QString searchAccount(const QString &tabId) const;
90 QStringList searchTabIds() const;
91 // D-16: the result the list was scrolled to, restored by identity.
92 bool setSearchAnchor(const QString &tabId, const MailId &anchor);
93 MailId searchAnchor(const QString &tabId) const;
94 // D-15: search tabs of another account stay open but dormant.
95 void setActiveAccount(const QString &accountId);
96 bool tabDormant(int index) const;
97 // D-18: Esc in a search tab returns to the tab used before it (closing
98 // the search tab, F100-49).
99 Q_INVOKABLE bool activatePreviousTab();
100 // ── Sprint 108 S108.9.1: compose tabs (a new mail as a document tab) ─
101 // One tab per ComposeSession; a second open of the same session
102 // activates its tab. Returns the row (-1 at the tab limit).
103 Q_INVOKABLE int openCompose(const QString &sessionId, const QString &title, bool activate = true);
104 Q_INVOKABLE bool setComposeTitle(const QString &sessionId, const QString &title);
105 Q_INVOKABLE bool closeCompose(const QString &sessionId);
106 Q_INVOKABLE QString composeSessionAt(int index) const;
107 Q_INVOKABLE int rowForComposeSession(const QString &sessionId) const;
108 Q_INVOKABLE QStringList composeSessionIds() const;
109 // S108.7.7: the Outbox as one document tab (opened from the folder list).
110 Q_INVOKABLE int openOutbox(const QString &title);
111
1/1
✓ Branch 3 → 4 taken 876 times.
1752 QStringList expandedFolders(const QString &account) const { return m_expandedFolders.value(account); }
112 bool setFolderExpanded(const QString &account, const QString &path, bool expanded);
113 void retainFolderBranches(const QString &account, const QStringList &paths);
114 signals:
115 void layoutChanged();
116 void readerFocusedChanged();
117 void areaChanged();
118 void activeTabChanged();
119 void selectionChanged();
120 void readingModeChanged();
121 void folderExpansionChanged();
122 void readerStateChanged();
123 // A tab left the model (closed, invalidated or dropped by an account switch).
124 void tabRemoved(const QString &tabId, const QString &kind);
125 private:
126 struct Tab {
127 QString id, title;
128 MailId mailId;
129 QString mode = QStringLiteral("text");
130 HtmlReadingState html;
131 QString kind = QStringLiteral("mail");
132 // Search tabs only (S101.1.1).
133 QString query, accountId, tooltip;
134 // Compose tabs only (S108.9.1): the ComposeSession the tab shows.
135 QString sessionId;
136 MailId anchor;
137 quint64 used = 0; // activation clock: the most recently used search tab is reused
138 };
139 void emitRemoved(const QList<Tab> &before);
140 bool restoreSearchPayload(const QJsonObject &entry, Tab &tab) const;
141 static bool validComposeSessionId(const QString &sessionId);
142 Tab *findTab(const QString &tabId, const MailId &);
143 QString m_configuredMode;
144 QList<Tab> m_tabs;
145 QString m_layout = QStringLiteral("classic");
146 // Set when the main tab's reading mode was chosen explicitly this
147 // session; until then the main tab follows the configured default.
148 bool m_mainModeTouched = false;
149 QString m_area = QStringLiteral("mail");
150 bool m_readerFocused = false;
151 int m_activeTab = 0;
152 MailId m_selection;
153 quint64 m_generation = 0;
154 QMap<QString, QStringList> m_expandedFolders;
155 quint64 m_useClock = 0;
156 QString m_previousTabId;
157 QString m_activeAccount;
158 };
159