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: 97.1% 101 / 0 / 104
Functions: 100.0% 13 / 0 / 13
Branches: 79.0% 94 / 0 / 119

presentation/AltHoldDetector.cpp
Line Branch Exec Source
1 #include "AltHoldDetector.h"
2
3 namespace {
4 15012 bool isAltKey(int key) { return key == Qt::Key_Alt; }
5 // Some platforms report AltGr as Ctrl+Alt; Meta is never part of a hold.
6 52 bool foreignModifiers(Qt::KeyboardModifiers modifiers) {
7 52 return modifiers & (Qt::ControlModifier | Qt::MetaModifier | Qt::GroupSwitchModifier);
8 }
9 21 bool isLetterOrDigit(QChar letter) {
10 21 const QChar upper = letter.toUpper();
11
4/8
✓ Branch 7 → 8 taken 20 times.
✓ Branch 7 → 13 taken 1 time.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 23 taken 20 times.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 24 taken 1 time.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 24 not taken.
21 return (upper >= QLatin1Char('A') && upper <= QLatin1Char('Z')) || (upper >= QLatin1Char('0') && upper <= QLatin1Char('9'));
12 }
13 } // namespace
14
15 1139 AltHoldDetector::Result AltHoldDetector::hide() {
16
3/4
✓ Branch 3 → 4 taken 1056 times.
✓ Branch 3 → 5 taken 83 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1056 times.
1139 const bool wasShown = shown() || m_toggled;
17 1139 const bool wasHolding = m_state == State::Holding;
18 1139 m_state = State::Idle;
19 1139 m_deadline = -1;
20 1139 m_explained = false;
21 1139 m_toggled = false;
22
2/2
✓ Branch 7 → 8 taken 83 times.
✓ Branch 7 → 9 taken 1056 times.
1139 if (wasShown) return {Action::Hide, {}, false};
23
2/2
✓ Branch 9 → 10 taken 3 times.
✓ Branch 9 → 11 taken 1053 times.
1056 if (wasHolding) return {Action::HoldCancelled, {}, false};
24 1053 return {};
25 }
26
27 28 AltHoldDetector::Result AltHoldDetector::enterKeys(qint64 now) {
28 28 m_state = State::Keys;
29
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 27 times.
28 if (m_settings.explain == ExplainMode::AtOnce) {
30 1 m_state = State::Explained;
31 1 m_explained = true;
32 1 m_deadline = -1;
33 1 return {Action::ShowExplained, {}, false};
34 }
35
2/2
✓ Branch 4 → 5 taken 26 times.
✓ Branch 4 → 6 taken 1 time.
27 m_deadline = m_settings.explain == ExplainMode::AfterHold ? now + m_settings.explainAfterMs : -1;
36 27 return {Action::Show, {}, false};
37 }
38
39 7765 AltHoldDetector::Result AltHoldDetector::keyPress(int key, Qt::KeyboardModifiers modifiers, bool autoRepeat, qint64 now,
40 QChar letter, bool tipLetter) {
41
2/2
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 6 taken 7763 times.
7765 if (key == Qt::Key_AltGr) {
42 // AltGr is a character key here: it never shows anything and ends a hold.
43
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1 time.
2 if (m_state == State::Holding) { m_state = State::Suppressed; m_deadline = -1; return {Action::HoldCancelled, {}, false}; }
44 1 return {};
45 }
46
2/2
✓ Branch 7 → 8 taken 53 times.
✓ Branch 7 → 23 taken 7710 times.
7763 if (isAltKey(key)) {
47
2/2
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 52 times.
53 if (autoRepeat) return {};
48 52 m_altDown = true;
49
2/2
✓ Branch 11 → 12 taken 2 times.
✓ Branch 11 → 17 taken 50 times.
52 if (foreignModifiers(modifiers)) {
50 // Ctrl+Alt (AltGr on some platforms): never a hold.
51
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 2 times.
2 if (m_state == State::Holding) { m_state = State::Suppressed; m_deadline = -1; return {Action::HoldCancelled, {}, false}; }
52
1/2
✓ Branch 14 → 15 taken 2 times.
✗ Branch 14 → 16 not taken.
2 if (m_state == State::Idle) m_state = State::Suppressed;
53 2 return {};
54 }
55
4/4
✓ Branch 17 → 18 taken 40 times.
✓ Branch 17 → 19 taken 10 times.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 20 taken 39 times.
50 if (m_state != State::Idle || !m_settings.holdEnabled) return {};
56
2/2
✓ Branch 20 → 21 taken 1 time.
✓ Branch 20 → 22 taken 38 times.
39 if (m_settings.delayMs <= 0) return enterKeys(now);
57 38 m_state = State::Holding;
58 38 m_deadline = now + m_settings.delayMs;
59 38 return {Action::HoldStarted, {}, false};
60 }
61
4/6
✓ Branch 23 → 24 taken 12 times.
✓ Branch 23 → 27 taken 7698 times.
✓ Branch 24 → 25 taken 12 times.
✗ Branch 24 → 26 not taken.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 12 times.
7710 if (autoRepeat && (m_state == State::Holding || m_state == State::Suppressed)) return {};
62
4/5
✓ Branch 27 → 28 taken 7680 times.
✓ Branch 27 → 29 taken 1 time.
✓ Branch 27 → 30 taken 6 times.
✓ Branch 27 → 31 taken 23 times.
✗ Branch 27 → 61 not taken.
7710 switch (m_state) {
63 7680 case State::Idle:
64 7680 return {};
65 1 case State::Suppressed:
66 1 return {};
67 6 case State::Holding:
68 // Alt+Up, Alt+Tab …: the overlay never appears inside an Alt combination.
69 6 m_state = State::Suppressed;
70 6 m_deadline = -1;
71 6 return {Action::HoldCancelled, {}, false};
72 23 case State::Keys:
73 case State::Explained:
74 case State::Acting: {
75
3/4
✓ Branch 31 → 32 taken 2 times.
✓ Branch 31 → 34 taken 21 times.
✓ Branch 32 → 33 taken 2 times.
✗ Branch 32 → 34 not taken.
23 if (key == Qt::Key_Escape && m_toggled) return hide();
76
3/4
✓ Branch 36 → 37 taken 2 times.
✓ Branch 36 → 38 taken 19 times.
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 2 times.
21 const bool altHeld = (modifiers & Qt::AltModifier) || m_altDown;
77
3/4
✓ Branch 41 → 42 taken 20 times.
✓ Branch 41 → 47 taken 1 time.
✓ Branch 45 → 46 taken 20 times.
✗ Branch 45 → 47 not taken.
21 const bool letterKey = isLetterOrDigit(letter) && !(modifiers & (Qt::ControlModifier | Qt::MetaModifier));
78 // A second tip letter before the first action settled chains too.
79
7/8
✓ Branch 48 → 49 taken 20 times.
✓ Branch 48 → 54 taken 1 time.
✓ Branch 49 → 50 taken 17 times.
✓ Branch 49 → 54 taken 3 times.
✓ Branch 50 → 51 taken 1 time.
✓ Branch 50 → 52 taken 16 times.
✓ Branch 51 → 52 taken 1 time.
✗ Branch 51 → 54 not taken.
21 if (letterKey && tipLetter && (altHeld || m_toggled)) {
80 17 m_state = State::Acting;
81 17 m_deadline = -1;
82 17 return {Action::Activate, letter.toUpper(), true};
83 }
84
1/2
✗ Branch 54 → 55 not taken.
✓ Branch 54 → 56 taken 4 times.
4 if (autoRepeat) return {};
85 // Any other key closes the overlay and keeps its own meaning.
86 4 Result result = hide();
87
2/2
✓ Branch 57 → 58 taken 3 times.
✓ Branch 57 → 59 taken 1 time.
4 if (m_altDown) m_state = State::Suppressed;
88 4 return result;
89 }
90 }
91 ✗ return {};
92 }
93
94 7249 AltHoldDetector::Result AltHoldDetector::keyRelease(int key, Qt::KeyboardModifiers, bool autoRepeat, qint64) {
95
5/6
✓ Branch 3 → 4 taken 22 times.
✓ Branch 3 → 5 taken 7227 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 22 times.
✓ Branch 7 → 8 taken 7227 times.
✓ Branch 7 → 9 taken 22 times.
7249 if (!isAltKey(key) || autoRepeat) return {};
96 22 m_altDown = false;
97
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 22 times.
22 if (m_toggled) return {};
98
2/2
✓ Branch 11 → 12 taken 7 times.
✓ Branch 11 → 13 taken 15 times.
22 if (m_state == State::Suppressed) { m_state = State::Idle; return {}; }
99 15 return hide();
100 }
101
102 491 AltHoldDetector::Result AltHoldDetector::pointerPress() {
103
2/2
✓ Branch 2 → 3 taken 489 times.
✓ Branch 2 → 4 taken 2 times.
491 if (m_state == State::Idle) return {};
104 2 Result result = hide();
105
1/2
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 7 not taken.
2 if (m_altDown) m_state = State::Suppressed; // Alt+drag stays a drag
106 2 return result;
107 }
108
109 33 AltHoldDetector::Result AltHoldDetector::windowDeactivated() {
110 33 m_altDown = false; // a release outside the window never arrives
111 33 return hide();
112 }
113
114 1082 AltHoldDetector::Result AltHoldDetector::cancel() {
115 1082 Result result = hide();
116
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1082 times.
1082 if (m_altDown) m_state = State::Suppressed;
117 1082 return result;
118 }
119
120 48 AltHoldDetector::Result AltHoldDetector::tick(qint64 now) {
121
4/4
✓ Branch 2 → 3 taken 37 times.
✓ Branch 2 → 4 taken 11 times.
✓ Branch 3 → 4 taken 7 times.
✓ Branch 3 → 5 taken 30 times.
48 if (m_deadline < 0 || now < m_deadline) return {};
122
2/2
✓ Branch 5 → 6 taken 27 times.
✓ Branch 5 → 7 taken 3 times.
30 if (m_state == State::Holding) return enterKeys(now);
123
2/4
✓ Branch 7 → 8 taken 3 times.
✗ Branch 7 → 10 not taken.
✓ Branch 8 → 9 taken 3 times.
✗ Branch 8 → 10 not taken.
3 if (m_state == State::Keys && m_settings.explain == ExplainMode::AfterHold) {
124 3 m_state = State::Explained;
125 3 m_explained = true;
126 3 m_deadline = -1;
127 3 return {Action::Explain, {}, false};
128 }
129 ✗ m_deadline = -1;
130 ✗ return {};
131 }
132
133 69 AltHoldDetector::Result AltHoldDetector::toggle() {
134
5/6
✓ Branch 3 → 4 taken 68 times.
✓ Branch 3 → 5 taken 1 time.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 68 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 68 times.
69 if (shown() || m_toggled) return hide();
135 68 m_toggled = true;
136 68 m_explained = m_settings.explain != ExplainMode::Never;
137
1/2
✓ Branch 9 → 10 taken 68 times.
✗ Branch 9 → 11 not taken.
68 m_state = m_explained ? State::Explained : State::Keys;
138 68 m_deadline = -1;
139
1/2
✓ Branch 12 → 13 taken 68 times.
✗ Branch 12 → 14 not taken.
68 return {m_explained ? Action::ShowExplained : Action::Show, {}, false};
140 }
141
142 6 AltHoldDetector::Result AltHoldDetector::actionDone() {
143
2/2
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 4 taken 4 times.
6 if (m_state != State::Acting) return {};
144
3/4
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 7 taken 3 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 1 time.
4 if (!m_altDown && !m_toggled) return hide();
145 // D-21: still held — the overlay shows the new state at once.
146
2/2
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 3 times.
4 m_state = m_explained ? State::Explained : State::Keys;
147 4 return {Action::Recompute, {}, false};
148 }
149