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: 94.4% 352 / 0 / 373
Functions: 94.9% 37 / 0 / 39
Branches: 86.5% 461 / 0 / 533

presentation/QuickCalendarModel.cpp
Line Branch Exec Source
1 #include "QuickCalendarModel.h"
2 #include <algorithm>
3 #include "data/CalendarModels.h"
4 #include "data/CalendarStore.h"
5 #include "data/RecurrenceExpansion.h"
6 #include "CalendarSearch.h"
7 #include "CalendarBirthdayLayer.h"
8 #include "CalendarTaskLayer.h"
9 #include <QLocale>
10 #include <QMetaObject>
11 #include <QRegularExpression>
12
13 namespace {
14
15 892 bool validMode(const QString &mode) {
16
4/4
✓ Branch 7 → 8 taken 827 times.
✓ Branch 7 → 17 taken 35 times.
✓ Branch 10 → 11 taken 37 times.
✓ Branch 10 → 17 taken 790 times.
2581 return mode == QLatin1String("day") || mode == QLatin1String("week") ||
17
6/6
✓ Branch 4 → 5 taken 862 times.
✓ Branch 4 → 17 taken 30 times.
✓ Branch 13 → 14 taken 22 times.
✓ Branch 13 → 17 taken 15 times.
✓ Branch 16 → 17 taken 21 times.
✓ Branch 16 → 18 taken 1 time.
2603 mode == QLatin1String("month") || mode == QLatin1String("year") ||
18 914 mode == QLatin1String("agenda");
19 }
20
21 // The locale's long date without weekday and year ("d. MMMM", "MMMM d").
22 49 QString dayMonthFormat() {
23
2/2
✓ Branch 2 → 3 taken 49 times.
✓ Branch 3 → 4 taken 49 times.
49 QString format = QLocale().dateFormat(QLocale::LongFormat);
24
2/2
✓ Branch 9 → 10 taken 49 times.
✓ Branch 10 → 11 taken 49 times.
49 format.remove(QRegularExpression(QStringLiteral("d{4}[,.]?\\s*")));
25
2/2
✓ Branch 18 → 19 taken 49 times.
✓ Branch 19 → 20 taken 49 times.
49 format.remove(QRegularExpression(QStringLiteral("[,\\s]*y+[.\\s]*")));
26
1/1
✓ Branch 23 → 24 taken 49 times.
49 format = format.trimmed();
27
2/3
✓ Branch 30 → 31 taken 49 times.
✗ Branch 31 → 27 not taken.
✓ Branch 31 → 32 taken 49 times.
49 while (format.endsWith(QLatin1Char(',')))
28 ✗ format.chop(1);
29
2/4
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 37 taken 49 times.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 49 times.
98 return format.isEmpty() ? QStringLiteral("d MMMM") : format;
30 49 }
31
32 // "7.–11. September 2026" / "September 7 – 11, 2026" (P-03 period title).
33 49 QString rangeLabel(const QDate &first, const QDate &last) {
34
1/1
✓ Branch 2 → 3 taken 49 times.
49 const QLocale locale;
35
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 49 times.
49 if (first == last)
36 ✗ return locale.toString(first, QLocale::LongFormat);
37
1/1
✓ Branch 7 → 8 taken 49 times.
49 const QString dayMonth = dayMonthFormat();
38
1/1
✓ Branch 9 → 10 taken 49 times.
49 const bool monthFirst = dayMonth.indexOf(QLatin1String("MMMM")) < dayMonth.indexOf(QLatin1Char('d'));
39
7/7
✓ Branch 14 → 15 taken 49 times.
✓ Branch 15 → 16 taken 12 times.
✓ Branch 15 → 19 taken 37 times.
✓ Branch 22 → 23 taken 37 times.
✓ Branch 22 → 24 taken 12 times.
✓ Branch 24 → 25 taken 12 times.
✓ Branch 24 → 26 taken 37 times.
98 const QString dayOnly = dayMonth.contains(QLatin1String("d.")) ? QStringLiteral("d.") : QStringLiteral("d");
40
2/2
✓ Branch 26 → 27 taken 49 times.
✓ Branch 27 → 28 taken 49 times.
49 const QString year = QString::number(last.year());
41
9/10
✓ Branch 28 → 29 taken 49 times.
✓ Branch 29 → 30 taken 49 times.
✓ Branch 30 → 31 taken 49 times.
✗ Branch 30 → 35 not taken.
✓ Branch 31 → 32 taken 49 times.
✓ Branch 32 → 33 taken 49 times.
✓ Branch 33 → 34 taken 48 times.
✓ Branch 33 → 35 taken 1 time.
✓ Branch 36 → 37 taken 48 times.
✓ Branch 36 → 86 taken 1 time.
49 if (first.year() == last.year() && first.month() == last.month()) {
42
1/2
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 66 taken 48 times.
48 if (monthFirst)
43 ✗ return locale.toString(first, dayMonth) + QStringLiteral(" – ") + locale.toString(last, QStringLiteral("d")) +
44 ✗ QStringLiteral(", ") + year;
45
4/4
✓ Branch 68 → 69 taken 48 times.
✓ Branch 72 → 73 taken 48 times.
✓ Branch 73 → 74 taken 48 times.
✓ Branch 74 → 75 taken 48 times.
144 return locale.toString(first, dayOnly) + QStringLiteral("–") + locale.toString(last, dayMonth) +
46
2/2
✓ Branch 75 → 76 taken 48 times.
✓ Branch 76 → 77 taken 48 times.
144 QLatin1Char(' ') + year;
47 }
48
1/1
✓ Branch 95 → 96 taken 1 time.
2 const QString firstText = locale.toString(first, dayMonth) +
49
5/12
✓ Branch 86 → 87 taken 1 time.
✓ Branch 87 → 88 taken 1 time.
✗ Branch 88 → 89 not taken.
✓ Branch 88 → 94 taken 1 time.
✗ Branch 89 → 90 not taken.
✗ Branch 90 → 91 not taken.
✗ Branch 93 → 95 not taken.
✓ Branch 96 → 97 taken 1 time.
✗ Branch 99 → 100 not taken.
✓ Branch 99 → 101 taken 1 time.
✗ Branch 213 → 214 not taken.
✗ Branch 213 → 215 not taken.
3 (first.year() != last.year() ? QLatin1Char(' ') + QString::number(first.year()) : QString());
50
1/2
✗ Branch 101 → 102 not taken.
✓ Branch 101 → 123 taken 1 time.
1 if (monthFirst)
51 ✗ return firstText + QStringLiteral(" – ") + locale.toString(last, dayMonth) + QStringLiteral(", ") + year;
52
5/5
✓ Branch 125 → 126 taken 1 time.
✓ Branch 129 → 130 taken 1 time.
✓ Branch 130 → 131 taken 1 time.
✓ Branch 131 → 132 taken 1 time.
✓ Branch 132 → 133 taken 1 time.
2 return firstText + QStringLiteral(" – ") + locale.toString(last, dayMonth) + QLatin1Char(' ') + year;
53 49 }
54
55 } // namespace
56
57 3403 QVector<CalendarOccurrence> calendarOccurrencesFor(const CalendarStore &store, const QDate &start,
58 const QDate &end, const QStringList &hiddenCalendars,
59 const QSet<QString> &unlimitedSeries) {
60 3403 QHash<QString, CalendarInfoLookup> calendars;
61
5/5
✓ Branch 2 → 3 taken 3403 times.
✓ Branch 3 → 4 taken 3403 times.
✓ Branch 4 → 5 taken 3403 times.
✓ Branch 14 → 6 taken 4385 times.
✓ Branch 14 → 15 taken 3403 times.
7788 for (const CalendarInfo &calendar : store.allCalendars())
62
1/1
✓ Branch 9 → 10 taken 4385 times.
4385 calendars.insert(calendarSelectionKey(calendar.accountId, calendar.path),
63 3403 {calendar.displayName, calendar.readOnly});
64 // One day of margin: all-day dates and zone offsets around the edges.
65
3/3
✓ Branch 19 → 20 taken 3403 times.
✓ Branch 20 → 21 taken 3403 times.
✓ Branch 21 → 22 taken 3403 times.
6806 const auto events = store.eventsForDateRange(QDateTime(start.addDays(-1), QTime(0, 0)),
66
4/4
✓ Branch 16 → 17 taken 3403 times.
✓ Branch 17 → 18 taken 3403 times.
✓ Branch 18 → 19 taken 3403 times.
✓ Branch 22 → 23 taken 3403 times.
10209 QDateTime(end.addDays(1), QTime(23, 59, 59)));
67 3403 QVector<CalendarOccurrence> occurrences;
68 3403 for (const CalendarEvent &event :
69
5/5
✓ Branch 26 → 27 taken 3403 times.
✓ Branch 28 → 29 taken 3403 times.
✓ Branch 29 → 30 taken 3403 times.
✓ Branch 52 → 31 taken 25288 times.
✓ Branch 52 → 53 taken 3403 times.
32094 expandEventsForDisplay(events, start, end, false, {kDisplayOccurrencesPerSeries, unlimitedSeries})) {
70
3/3
✓ Branch 32 → 33 taken 25288 times.
✓ Branch 35 → 36 taken 17 times.
✓ Branch 35 → 37 taken 25271 times.
25288 if (hiddenCalendars.contains(calendarSelectionKey(event.accountId, event.calendarPath)))
71 17 continue;
72
1/1
✓ Branch 37 → 38 taken 25271 times.
25271 const CalendarOccurrence occurrence = CalendarLayout::fromEvent(event, calendars);
73
3/6
✓ Branch 40 → 41 taken 25271 times.
✗ Branch 40 → 45 not taken.
✓ Branch 43 → 44 taken 25271 times.
✗ Branch 43 → 45 not taken.
✓ Branch 46 → 47 taken 25271 times.
✗ Branch 46 → 48 not taken.
25271 if (occurrence.lastDay >= start && occurrence.firstDay <= end)
74
1/1
✓ Branch 47 → 48 taken 25271 times.
25271 occurrences.append(occurrence);
75 28674 }
76 3403 return occurrences;
77 11191 }
78
79 909 QString QuickCalendarModel::navigatorTitle() const {
80
3/3
✓ Branch 6 → 7 taken 909 times.
✓ Branch 7 → 8 taken 909 times.
✓ Branch 8 → 9 taken 909 times.
1818 return QLocale().standaloneMonthName(m_navigatorMonth.month(), QLocale::LongFormat) +
81
4/4
✓ Branch 2 → 3 taken 909 times.
✓ Branch 3 → 4 taken 909 times.
✓ Branch 9 → 10 taken 909 times.
✓ Branch 10 → 11 taken 909 times.
2727 QLatin1Char(' ') + QString::number(m_navigatorMonth.year());
82 }
83
84 ✗ void QuickCalendarModel::shiftNavigator(int months) {
85 ✗ const QDate target = m_navigatorMonth.addMonths(months);
86 ✗ if (!target.isValid()) return;
87 ✗ m_navigatorMonth = target;
88 ✗ notifyPeriodChanged();
89 }
90
91 808 QuickCalendarModel::QuickCalendarModel(QString databasePath, QObject *parent)
92 808 : QAbstractListModel(parent), m_databasePath(std::move(databasePath)),
93
15/15
✓ Branch 7 → 8 taken 808 times.
✓ Branch 13 → 14 taken 808 times.
✓ Branch 14 → 15 taken 808 times.
✓ Branch 20 → 21 taken 808 times.
✓ Branch 26 → 27 taken 808 times.
✓ Branch 27 → 28 taken 808 times.
✓ Branch 34 → 35 taken 808 times.
✓ Branch 35 → 36 taken 808 times.
✓ Branch 39 → 40 taken 808 times.
✓ Branch 40 → 41 taken 808 times.
✓ Branch 41 → 42 taken 808 times.
✓ Branch 42 → 43 taken 808 times.
✓ Branch 43 → 44 taken 808 times.
✓ Branch 54 → 55 taken 808 times.
✓ Branch 55 → 56 taken 808 times.
4848 m_firstDayOfWeek(int(QLocale().firstDayOfWeek())) {
94
1/1
✓ Branch 57 → 58 taken 808 times.
808 m_pool.setMaxThreadCount(1);
95
1/1
✓ Branch 58 → 59 taken 808 times.
808 m_midnight.setSingleShot(true);
96
1/1
✓ Branch 59 → 60 taken 808 times.
808 connect(&m_midnight, &QTimer::timeout, this, [this] {
97 ✗ emit monthChanged(); // todayIso
98 ✗ reload();
99 ✗ armMidnight();
100 ✗ });
101
1/1
✓ Branch 61 → 62 taken 808 times.
808 armMidnight();
102
1/1
✓ Branch 62 → 63 taken 808 times.
808 showCurrentMonth();
103 808 }
104
105 808 void QuickCalendarModel::armMidnight() {
106
1/1
✓ Branch 2 → 3 taken 808 times.
808 const QDateTime now = QDateTime::currentDateTime();
107
4/4
✓ Branch 3 → 4 taken 808 times.
✓ Branch 4 → 5 taken 808 times.
✓ Branch 5 → 6 taken 808 times.
✓ Branch 6 → 7 taken 808 times.
808 const QDateTime next(now.date().addDays(1), QTime(0, 0, 1));
108
3/3
✓ Branch 7 → 8 taken 808 times.
✓ Branch 8 → 9 taken 808 times.
✓ Branch 9 → 10 taken 808 times.
808 m_midnight.start(int(std::clamp<qint64>(now.msecsTo(next), 1000, 25LL * 3600 * 1000)));
109 808 }
110
111 814 QuickCalendarModel::~QuickCalendarModel() {
112 // F4: an explicit join makes the worker lifetime deterministic against
113 // future captures; the worker body only touches its own locals.
114 808 m_pool.waitForDone();
115 814 }
116
117 1349 QHash<int, QByteArray> QuickCalendarModel::roleNames() const {
118 ✗ return {{DayNumber, "dayNumber"}, {InMonth, "inMonth"}, {IsToday, "isToday"},
119 ✗ {DateIso, "dateIso"}, {Events, "dayEvents"}, {MonthDays, "monthDays"},
120
2/4
✓ Branch 13 → 14 taken 12141 times.
✓ Branch 13 → 15 taken 1349 times.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 20 not taken.
13490 {WeekNumber, "weekNumber"}, {IsWeekend, "isWeekend"}, {WeekdayName, "weekdayName"}};
121 1349 }
122
123 66823 int QuickCalendarModel::rowCount(const QModelIndex &parent) const {
124
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 66822 times.
66823 return parent.isValid() ? 0 : m_days.size();
125 }
126
127 48233 QVariant QuickCalendarModel::data(const QModelIndex &index, int role) const {
128
5/6
✓ Branch 3 → 4 taken 48231 times.
✓ Branch 3 → 7 taken 2 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 48231 times.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 11 taken 48231 times.
48233 if (index.row() < 0 || index.row() >= m_days.size()) return {};
129 48231 const DayCell &cell = m_days[index.row()];
130
1/1
✓ Branch 13 → 14 taken 48231 times.
48231 const QDate today = QDate::currentDate();
131
10/10
✓ Branch 14 → 15 taken 7023 times.
✓ Branch 14 → 17 taken 6638 times.
✓ Branch 14 → 18 taken 7646 times.
✓ Branch 14 → 34 taken 8633 times.
✓ Branch 14 → 38 taken 143 times.
✓ Branch 14 → 39 taken 1 time.
✓ Branch 14 → 41 taken 7023 times.
✓ Branch 14 → 43 taken 387 times.
✓ Branch 14 → 50 taken 10736 times.
✓ Branch 14 → 66 taken 1 time.
48231 switch (role) {
132
1/1
✓ Branch 15 → 16 taken 7023 times.
7023 case DayNumber: return cell.date.day();
133 6638 case InMonth: return cell.inMonth;
134 15292 case IsToday: return m_viewMode == QLatin1String("year")
135
7/8
✓ Branch 21 → 22 taken 139 times.
✓ Branch 22 → 23 taken 139 times.
✓ Branch 23 → 24 taken 139 times.
✗ Branch 23 → 28 not taken.
✓ Branch 24 → 25 taken 139 times.
✓ Branch 25 → 26 taken 139 times.
✓ Branch 26 → 27 taken 10 times.
✓ Branch 26 → 28 taken 129 times.
139 ? cell.date.year() == today.year() && cell.date.month() == today.month()
136
2/2
✓ Branch 20 → 21 taken 139 times.
✓ Branch 20 → 30 taken 7507 times.
7785 : cell.date == today;
137
1/1
✓ Branch 34 → 35 taken 8633 times.
8633 case DateIso: return cell.date.toString(Qt::ISODate);
138 143 case MonthDays: return cell.monthDays;
139
1/1
✓ Branch 39 → 40 taken 1 time.
1 case WeekNumber: return cell.date.weekNumber();
140
1/1
✓ Branch 41 → 42 taken 7023 times.
7023 case IsWeekend: return cell.date.dayOfWeek() >= 6;
141
3/3
✓ Branch 43 → 44 taken 387 times.
✓ Branch 44 → 45 taken 387 times.
✓ Branch 45 → 46 taken 387 times.
387 case WeekdayName: return QLocale().dayName(cell.date.dayOfWeek(), QLocale::ShortFormat);
142 10736 case Events: {
143 10736 QVariantList list;
144
1/1
✓ Branch 51 → 52 taken 10736 times.
10736 list.reserve(cell.events.size());
145
2/2
✓ Branch 62 → 54 taken 18698 times.
✓ Branch 62 → 63 taken 10736 times.
29434 for (const auto &occurrence : cell.events)
146
2/2
✓ Branch 55 → 56 taken 18698 times.
✓ Branch 57 → 58 taken 18698 times.
18698 list.append(CalendarLayout::toVariant(occurrence));
147 10736 return list;
148 10736 }
149 1 default: return {};
150 }
151 }
152
153 148 QString QuickCalendarModel::monthLabel() const {
154
3/3
✓ Branch 5 → 6 taken 148 times.
✓ Branch 6 → 7 taken 148 times.
✓ Branch 7 → 8 taken 148 times.
296 return QLocale().standaloneMonthName(m_month, QLocale::LongFormat) + QLatin1Char(' ') +
155
2/2
✓ Branch 2 → 3 taken 148 times.
✓ Branch 8 → 9 taken 148 times.
444 QString::number(m_year);
156 }
157
158 1886 QDate QuickCalendarModel::gridStartFor(int year, int month) const {
159 // Six-week grid starting on the configured first day: always 42 cells.
160
2/2
✓ Branch 2 → 3 taken 1886 times.
✓ Branch 3 → 4 taken 1886 times.
1886 return CalendarLayout::weekStart(QDate(year, month, 1), m_firstDayOfWeek);
161 }
162
163 1 int QuickCalendarModel::visibleDays() const {
164
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1 time.
1 if (m_viewMode == QLatin1String("day")) return 1;
165
2/4
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 13 not taken.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 11 not taken.
1 if (m_viewMode == QLatin1String("week")) return m_workWeek ? 5 : 7;
166 ✗ return 7;
167 }
168
169 266 QString QuickCalendarModel::periodLabel() const {
170
4/4
✓ Branch 3 → 4 taken 18 times.
✓ Branch 3 → 9 taken 248 times.
✓ Branch 4 → 5 taken 18 times.
✓ Branch 6 → 7 taken 18 times.
284 if (!m_searchQuery.isEmpty()) return tr("Search: \u201C%1\u201D").arg(m_searchQuery);
171
2/2
✓ Branch 11 → 12 taken 13 times.
✓ Branch 11 → 13 taken 235 times.
248 if (m_viewMode == QLatin1String("year")) return QString::number(m_year);
172
4/4
✓ Branch 15 → 16 taken 26 times.
✓ Branch 15 → 21 taken 209 times.
✓ Branch 16 → 17 taken 26 times.
✓ Branch 17 → 18 taken 26 times.
235 if (m_viewMode == QLatin1String("day")) return QLocale().toString(m_anchorDate, QLocale::LongFormat);
173
2/2
✓ Branch 23 → 24 taken 49 times.
✓ Branch 23 → 25 taken 160 times.
209 if (m_viewMode == QLatin1String("week")) return rangeLabel(m_gridStart, m_gridEnd);
174
2/2
✓ Branch 27 → 28 taken 13 times.
✓ Branch 27 → 38 taken 147 times.
160 if (m_viewMode == QLatin1String("agenda"))
175
4/4
✓ Branch 28 → 29 taken 13 times.
✓ Branch 30 → 31 taken 13 times.
✓ Branch 31 → 32 taken 13 times.
✓ Branch 32 → 33 taken 13 times.
26 return tr("From %1").arg(QLocale().toString(m_anchorDate, QLocale::LongFormat));
176 147 return monthLabel();
177 }
178
179 266 QString QuickCalendarModel::weekLabel() const {
180
2/2
✓ Branch 3 → 4 taken 17 times.
✓ Branch 3 → 5 taken 249 times.
266 if (!m_searchQuery.isEmpty()) return {};
181
6/6
✓ Branch 7 → 8 taken 199 times.
✓ Branch 7 → 12 taken 50 times.
✓ Branch 10 → 11 taken 173 times.
✓ Branch 10 → 12 taken 26 times.
✓ Branch 13 → 14 taken 173 times.
✓ Branch 13 → 15 taken 76 times.
249 if (m_viewMode != QLatin1String("week") && m_viewMode != QLatin1String("day"))
182 173 return {};
183 // ISO weeks start on Monday: name the week by the Monday inside the range.
184
2/2
✓ Branch 15 → 16 taken 76 times.
✓ Branch 16 → 17 taken 76 times.
76 const QDate monday = m_gridStart.addDays((8 - m_gridStart.dayOfWeek()) % 7);
185
5/5
✓ Branch 17 → 18 taken 76 times.
✓ Branch 21 → 22 taken 26 times.
✓ Branch 21 → 23 taken 50 times.
✓ Branch 24 → 25 taken 76 times.
✓ Branch 25 → 26 taken 76 times.
152 return tr("Week %1").arg((m_viewMode == QLatin1String("day") ? m_anchorDate : monday).weekNumber());
186 }
187
188 898 QStringList QuickCalendarModel::weekdayNames(bool shortNames) const {
189 898 QStringList names;
190
2/2
✓ Branch 12 → 3 taken 6286 times.
✓ Branch 12 → 13 taken 898 times.
7184 for (int i = 0; i < 7; ++i)
191
4/5
✓ Branch 3 → 4 taken 6286 times.
✓ Branch 4 → 5 taken 6286 times.
✗ Branch 4 → 6 not taken.
✓ Branch 7 → 8 taken 6286 times.
✓ Branch 8 → 9 taken 6286 times.
6286 names.append(QLocale().dayName((m_firstDayOfWeek - 1 + i) % 7 + 1,
192 shortNames ? QLocale::ShortFormat : QLocale::LongFormat));
193 898 return names;
194 ✗ }
195
196 1386 int QuickCalendarModel::weekNumber(const QString &dateIso) const {
197
2/2
✓ Branch 2 → 3 taken 1386 times.
✓ Branch 3 → 4 taken 1386 times.
1386 return QDate::fromString(dateIso, Qt::ISODate).weekNumber();
198 }
199
200 814 void QuickCalendarModel::showCurrentMonth() {
201
1/1
✓ Branch 2 → 3 taken 814 times.
814 leaveSearch();
202
1/1
✓ Branch 3 → 4 taken 814 times.
814 const QDate today = QDate::currentDate();
203 814 m_anchorDate = today;
204
1/1
✓ Branch 4 → 5 taken 814 times.
814 m_year = today.year();
205
1/1
✓ Branch 5 → 6 taken 814 times.
814 m_month = today.month();
206 814 m_agendaDays = 30;
207
1/1
✓ Branch 6 → 7 taken 814 times.
814 notifyPeriodChanged();
208
1/1
✓ Branch 7 → 8 taken 814 times.
814 emit todayShown();
209 814 }
210
211 9 void QuickCalendarModel::shiftMonths(int delta) {
212
1/1
✓ Branch 2 → 3 taken 9 times.
9 const QDate target = m_anchorDate.addMonths(delta);
213
2/3
✓ Branch 3 → 4 taken 9 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 9 times.
9 if (!target.isValid()) return;
214 9 m_anchorDate = target;
215
1/1
✓ Branch 6 → 7 taken 9 times.
9 m_year = target.year();
216
1/1
✓ Branch 7 → 8 taken 9 times.
9 m_month = target.month();
217
1/1
✓ Branch 8 → 9 taken 9 times.
9 notifyPeriodChanged();
218 }
219
220 // Choosing a view or a date ends a search (the agenda of results).
221 1705 void QuickCalendarModel::leaveSearch() {
222
1/2
✓ Branch 3 → 4 taken 1705 times.
✗ Branch 3 → 5 not taken.
1705 if (m_searchQuery.isEmpty()) return;
223 ✗ m_searchQuery.clear();
224 ✗ m_modeBeforeSearch.clear();
225 ✗ emit searchQueryChanged();
226 }
227
228 839 void QuickCalendarModel::setViewMode(const QString &mode) {
229
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 838 times.
839 if (!validMode(mode)) return;
230 838 const bool searching = !m_searchQuery.isEmpty();
231 838 leaveSearch();
232
5/6
✓ Branch 8 → 9 taken 776 times.
✓ Branch 8 → 11 taken 62 times.
✓ Branch 9 → 10 taken 776 times.
✗ Branch 9 → 11 not taken.
✓ Branch 12 → 13 taken 776 times.
✓ Branch 12 → 14 taken 62 times.
838 if (mode == m_viewMode && !searching) return;
233 62 m_viewMode = mode;
234 62 m_agendaDays = 30;
235 62 notifyPeriodChanged();
236 }
237
238 5 void QuickCalendarModel::setFirstDayOfWeek(int day) {
239
4/6
✓ Branch 2 → 3 taken 5 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 5 not taken.
✓ Branch 4 → 5 taken 3 times.
✓ Branch 4 → 6 taken 2 times.
5 if (day < 1 || day > 7 || day == m_firstDayOfWeek) return;
240 2 m_firstDayOfWeek = day;
241 2 notifyPeriodChanged();
242 }
243
244 781 void QuickCalendarModel::setWorkWeek(bool workWeek) {
245
2/2
✓ Branch 2 → 3 taken 765 times.
✓ Branch 2 → 4 taken 16 times.
781 if (workWeek == m_workWeek) return;
246 16 m_workWeek = workWeek;
247 16 notifyPeriodChanged();
248 }
249
250 54 void QuickCalendarModel::showDate(const QString &dateIso, const QString &mode) {
251
1/1
✓ Branch 2 → 3 taken 54 times.
54 const auto date = QDate::fromString(dateIso, Qt::ISODate);
252
6/7
✓ Branch 3 → 4 taken 54 times.
✓ Branch 4 → 5 taken 53 times.
✓ Branch 4 → 7 taken 1 time.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 53 times.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 53 times.
54 if (!date.isValid() || !validMode(mode)) return;
253
1/1
✓ Branch 11 → 12 taken 53 times.
53 leaveSearch();
254 53 m_anchorDate = date;
255
2/2
✓ Branch 12 → 13 taken 53 times.
✓ Branch 13 → 14 taken 53 times.
53 m_year = date.year(); m_month = date.month(); m_viewMode = mode;
256 53 m_agendaDays = 30;
257
1/1
✓ Branch 15 → 16 taken 53 times.
53 notifyPeriodChanged();
258 }
259
260 40 void QuickCalendarModel::loadMoreAgenda() {
261
7/8
✓ Branch 4 → 5 taken 37 times.
✓ Branch 4 → 8 taken 3 times.
✓ Branch 5 → 6 taken 37 times.
✗ Branch 5 → 8 not taken.
✓ Branch 7 → 8 taken 3 times.
✓ Branch 7 → 9 taken 34 times.
✓ Branch 10 → 11 taken 6 times.
✓ Branch 10 → 12 taken 34 times.
40 if (m_viewMode != QLatin1String("agenda") || m_agendaDays >= 366 || !m_searchQuery.isEmpty()) return;
262 34 m_agendaDays += 30;
263 34 reload();
264 }
265
266 5 void QuickCalendarModel::shiftPeriod(int delta) {
267
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 5 times.
5 if (!m_searchQuery.isEmpty()) return; // a search result has no period
268
1/3
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 5 times.
✗ Branch 8 → 9 not taken.
5 if (m_viewMode == QLatin1String("month")) { shiftMonths(delta); return; }
269
2/2
✓ Branch 12 → 13 taken 4 times.
✓ Branch 12 → 14 taken 1 time.
6 const int days = m_viewMode == QLatin1String("week") ? 7
270
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 1 time.
1 : m_viewMode == QLatin1String("agenda") ? 30 : 1;
271
3/3
✓ Branch 22 → 23 taken 1 time.
✓ Branch 22 → 24 taken 4 times.
✓ Branch 23 → 25 taken 1 time.
5 const auto target = m_viewMode == QLatin1String("year") ? m_anchorDate.addYears(delta)
272
1/1
✓ Branch 24 → 25 taken 4 times.
4 : m_anchorDate.addDays(qint64(delta) * days);
273
2/3
✓ Branch 25 → 26 taken 5 times.
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 28 taken 5 times.
5 if (!target.isValid()) return;
274 5 m_anchorDate = target;
275
1/1
✓ Branch 28 → 29 taken 5 times.
5 m_year = target.year();
276
1/1
✓ Branch 29 → 30 taken 5 times.
5 m_month = target.month();
277
1/1
✓ Branch 30 → 31 taken 5 times.
5 notifyPeriodChanged();
278 }
279
280 2283 void QuickCalendarModel::computeRange() {
281 // The navigator follows the anchor unless it was browsed away from it.
282
6/6
✓ Branch 3 → 4 taken 1475 times.
✓ Branch 3 → 6 taken 808 times.
✓ Branch 5 → 6 taken 38 times.
✓ Branch 5 → 7 taken 1437 times.
✓ Branch 8 → 9 taken 846 times.
✓ Branch 8 → 13 taken 1437 times.
2283 if (!m_navigatorMonth.isValid() || m_navigatorAnchor != m_anchorDate) {
283
3/3
✓ Branch 9 → 10 taken 846 times.
✓ Branch 10 → 11 taken 846 times.
✓ Branch 11 → 12 taken 846 times.
846 m_navigatorMonth = QDate(m_anchorDate.year(), m_anchorDate.month(), 1);
284 846 m_navigatorAnchor = m_anchorDate;
285 }
286
2/2
✓ Branch 15 → 16 taken 86 times.
✓ Branch 15 → 17 taken 2197 times.
2283 if (m_viewMode == QLatin1String("day")) {
287 86 m_gridStart = m_gridEnd = m_anchorDate;
288
2/2
✓ Branch 19 → 20 taken 143 times.
✓ Branch 19 → 28 taken 2054 times.
2197 } else if (m_viewMode == QLatin1String("week")) {
289 // The work week is Monday–Friday whatever the first day of the week is.
290
2/2
✓ Branch 20 → 21 taken 21 times.
✓ Branch 20 → 22 taken 122 times.
143 m_gridStart = CalendarLayout::weekStart(m_anchorDate, m_workWeek ? 1 : m_firstDayOfWeek);
291
2/2
✓ Branch 24 → 25 taken 21 times.
✓ Branch 24 → 26 taken 122 times.
143 m_gridEnd = m_gridStart.addDays(m_workWeek ? 4 : 6);
292
2/2
✓ Branch 30 → 31 taken 38 times.
✓ Branch 30 → 34 taken 2016 times.
2054 } else if (m_viewMode == QLatin1String("year")) {
293
1/1
✓ Branch 31 → 32 taken 38 times.
38 m_gridStart = QDate(m_year, 1, 1);
294
1/1
✓ Branch 32 → 33 taken 38 times.
38 m_gridEnd = QDate(m_year, 12, 31);
295
2/2
✓ Branch 36 → 37 taken 130 times.
✓ Branch 36 → 38 taken 1886 times.
2016 } else if (m_viewMode == QLatin1String("agenda")) {
296 130 m_gridStart = m_anchorDate;
297 130 m_gridEnd = m_anchorDate.addDays(m_agendaDays - 1);
298 } else {
299 1886 m_gridStart = gridStartFor(m_year, m_month);
300 1886 m_gridEnd = m_gridStart.addDays(41);
301 }
302 2283 }
303
304 // S93.5.5: the agenda cells of a search — days with matches, in order.
305 13 QVector<QuickCalendarModel::DayCell> QuickCalendarModel::searchCells(const LoadRequest &request) {
306
1/1
✓ Branch 2 → 3 taken 13 times.
13 CalendarStore store;
307
2/3
✓ Branch 3 → 4 taken 13 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 13 times.
13 if (!store.open(request.databasePath)) return {};
308 13 QVector<DayCell> cells;
309 13 QList<CalendarOccurrence> found = CalendarSearch::matches(store, request.searchWords, request.hiddenCalendars,
310
2/2
✓ Branch 6 → 7 taken 13 times.
✓ Branch 7 → 8 taken 13 times.
13 QDate::currentDate(), request.unlimitedSeries);
311
2/2
✓ Branch 8 → 9 taken 13 times.
✓ Branch 9 → 10 taken 13 times.
13 CalendarLayout::attachPeople(found, store.namedPeopleByEvent()); // S103.6.1
312
2/2
✓ Branch 30 → 14 taken 7 times.
✓ Branch 30 → 31 taken 13 times.
20 for (const CalendarOccurrence &occurrence : std::as_const(found)) {
313
7/7
✓ Branch 16 → 17 taken 3 times.
✓ Branch 16 → 20 taken 4 times.
✓ Branch 17 → 18 taken 3 times.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 21 taken 2 times.
✓ Branch 22 → 23 taken 5 times.
✓ Branch 22 → 26 taken 2 times.
7 if (cells.isEmpty() || cells.last().date != occurrence.firstDay) {
314 5 DayCell cell;
315 5 cell.date = occurrence.firstDay;
316 5 cell.inMonth = true;
317
1/1
✓ Branch 23 → 24 taken 5 times.
5 cells.append(cell);
318 5 }
319
2/2
✓ Branch 26 → 27 taken 7 times.
✓ Branch 27 → 28 taken 7 times.
7 cells.last().events.append(occurrence);
320 }
321 13 return cells;
322 13 }
323
324 1124 QuickCalendarModel::LoadResult QuickCalendarModel::load(const LoadRequest &request) {
325 1124 LoadResult result;
326 1124 result.mode = request.mode;
327 // The worker's own store connection (WAL: the GUI thread has one too).
328
1/1
✓ Branch 3 → 4 taken 1124 times.
1124 CalendarStore store;
329
1/1
✓ Branch 4 → 5 taken 1124 times.
1124 const bool opened = store.open(request.databasePath);
330 // Appointments (each series bounded, counted from `first`), tasks, birthdays.
331 1313 const auto occurrencesBetween = [&](const QDate &first, const QDate &last) {
332 1313 QVector<CalendarOccurrence> occurrences;
333
1/2
✓ Branch 2 → 3 taken 1313 times.
✗ Branch 2 → 12 not taken.
1313 if (opened) {
334
1/1
✓ Branch 3 → 4 taken 1313 times.
1313 occurrences = calendarOccurrencesFor(store, first, last, request.hiddenCalendars, request.unlimitedSeries);
335
2/2
✓ Branch 6 → 7 taken 6 times.
✓ Branch 6 → 12 taken 1307 times.
1313 if (request.showTasks) // S93.5.7
336
3/3
✓ Branch 7 → 8 taken 6 times.
✓ Branch 8 → 9 taken 6 times.
✓ Branch 9 → 10 taken 6 times.
6 occurrences += CalendarTaskLayer::occurrences(store, first, last, QDate::currentDate(), request.hiddenCalendars);
337 }
338
2/2
✓ Branch 12 → 13 taken 1313 times.
✓ Branch 13 → 14 taken 1313 times.
1313 occurrences += CalendarBirthdayLayer::occurrences(request.birthdays, first, last); // S97.5.10
339
1/1
✓ Branch 17 → 18 taken 1313 times.
2626 return QList<CalendarOccurrence>(occurrences.cbegin(), occurrences.cend());
340 1313 };
341 // S106-881: view and navigator month expand separately — one expansion
342 // over both let a frequent series spend its bound in the navigator's first
343 // days, and a later day or week showed none of it (nor "Show all").
344
1/1
✓ Branch 5 → 6 taken 1124 times.
1124 const QDate navigatorFirst = CalendarLayout::weekStart(request.navigatorMonth, request.firstDayOfWeek);
345
1/1
✓ Branch 6 → 7 taken 1124 times.
1124 const QDate navigatorLast = navigatorFirst.addDays(41);
346
1/1
✓ Branch 7 → 8 taken 1124 times.
1124 const QList<CalendarOccurrence> all = occurrencesBetween(request.start, request.end);
347
1/2
✓ Branch 11 → 12 taken 935 times.
✗ Branch 11 → 13 not taken.
2059 const auto navigator = navigatorFirst == request.start && navigatorLast == request.end
348
3/3
✓ Branch 9 → 10 taken 935 times.
✓ Branch 9 → 13 taken 189 times.
✓ Branch 13 → 14 taken 189 times.
2059 ? all : occurrencesBetween(navigatorFirst, navigatorLast);
349
2/2
✓ Branch 15 → 16 taken 1124 times.
✓ Branch 16 → 17 taken 1124 times.
2248 result.navigatorDays = CalendarLayout::monthDayMaps(navigatorFirst, request.navigatorMonth.month(),
350
1/1
✓ Branch 14 → 15 taken 1124 times.
3372 CalendarLayout::rangeSummary(navigator, navigatorFirst, navigatorLast));
351
2/2
✓ Branch 21 → 22 taken 13 times.
✓ Branch 21 → 26 taken 1111 times.
1124 if (!request.searchWords.isEmpty()) {
352
1/1
✓ Branch 22 → 23 taken 13 times.
13 result.cells = searchCells(request);
353 13 return result;
354 }
355 1111 QList<CalendarOccurrence> list;
356
2/2
✓ Branch 41 → 28 taken 6390 times.
✓ Branch 41 → 42 taken 1111 times.
7501 for (const CalendarOccurrence &occurrence : all)
357
3/6
✓ Branch 31 → 32 taken 6390 times.
✗ Branch 31 → 36 not taken.
✓ Branch 34 → 35 taken 6390 times.
✗ Branch 34 → 36 not taken.
✓ Branch 37 → 38 taken 6390 times.
✗ Branch 37 → 39 not taken.
6390 if (occurrence.lastDay >= request.start && occurrence.firstDay <= request.end)
358
1/1
✓ Branch 38 → 39 taken 6390 times.
6390 list.append(occurrence);
359
5/6
✓ Branch 42 → 43 taken 1111 times.
✗ Branch 42 → 47 not taken.
✓ Branch 45 → 46 taken 44 times.
✓ Branch 45 → 47 taken 1067 times.
✓ Branch 48 → 49 taken 44 times.
✓ Branch 48 → 53 taken 1067 times.
1111 if (opened && request.mode == QLatin1String("agenda"))
360
2/2
✓ Branch 49 → 50 taken 44 times.
✓ Branch 50 → 51 taken 44 times.
44 CalendarLayout::attachPeople(list, store.namedPeopleByEvent()); // S103.6.1: the agenda's avatars
361
2/2
✓ Branch 55 → 56 taken 17 times.
✓ Branch 55 → 88 taken 1094 times.
1111 if (request.mode == QLatin1String("year")) {
362
1/1
✓ Branch 56 → 57 taken 17 times.
17 const auto summaries = CalendarLayout::yearSummary(list, request.gridYear);
363
2/2
✓ Branch 85 → 58 taken 204 times.
✓ Branch 85 → 86 taken 17 times.
221 for (int month = 1; month <= 12; ++month) {
364 204 DayCell cell;
365
1/1
✓ Branch 58 → 59 taken 204 times.
204 cell.date = QDate(request.gridYear, month, 1);
366 204 cell.inMonth = true;
367
2/2
✓ Branch 59 → 60 taken 204 times.
✓ Branch 60 → 61 taken 204 times.
204 const QDate last(request.gridYear, month, cell.date.daysInMonth());
368 // A multi-day occurrence appears once in each covered month.
369
4/4
✓ Branch 61 → 62 taken 204 times.
✓ Branch 62 → 63 taken 204 times.
✓ Branch 77 → 64 taken 5340 times.
✓ Branch 77 → 78 taken 204 times.
5544 for (const CalendarOccurrence &occurrence : list)
370
6/6
✓ Branch 67 → 68 taken 1987 times.
✓ Branch 67 → 72 taken 3353 times.
✓ Branch 70 → 71 taken 446 times.
✓ Branch 70 → 72 taken 1541 times.
✓ Branch 73 → 74 taken 446 times.
✓ Branch 73 → 75 taken 4894 times.
5340 if (occurrence.lastDay >= cell.date && occurrence.firstDay <= last)
371
1/1
✓ Branch 74 → 75 taken 446 times.
446 cell.events.append(occurrence);
372
2/2
✓ Branch 78 → 79 taken 204 times.
✓ Branch 79 → 80 taken 204 times.
408 cell.monthDays = CalendarLayout::monthDayMaps(CalendarLayout::weekStart(cell.date, request.firstDayOfWeek),
373 204 month, summaries);
374
1/1
✓ Branch 82 → 83 taken 204 times.
204 result.cells.append(cell);
375 204 }
376 17 return result;
377 17 }
378
1/1
✓ Branch 88 → 89 taken 1094 times.
1094 const int days = int(request.start.daysTo(request.end)) + 1;
379
1/1
✓ Branch 89 → 90 taken 1094 times.
1094 const auto buckets = CalendarLayout::bucketByDay(list, request.start, days);
380
2/2
✓ Branch 124 → 91 taken 42495 times.
✓ Branch 124 → 125 taken 1094 times.
43589 for (int i = 0; i < days; ++i) {
381 42495 DayCell cell;
382
1/1
✓ Branch 91 → 92 taken 42495 times.
42495 cell.date = request.start.addDays(i);
383
2/2
✓ Branch 94 → 95 taken 39270 times.
✓ Branch 94 → 99 taken 3225 times.
81765 cell.inMonth = request.mode != QLatin1String("month") ||
384
5/6
✓ Branch 95 → 96 taken 39270 times.
✓ Branch 96 → 97 taken 28980 times.
✓ Branch 96 → 100 taken 10290 times.
✓ Branch 97 → 98 taken 28980 times.
✓ Branch 98 → 99 taken 28980 times.
✗ Branch 98 → 100 not taken.
39270 (cell.date.month() == request.gridMonth && cell.date.year() == request.gridYear);
385 42495 cell.events = buckets.at(i);
386
1/1
✓ Branch 103 → 104 taken 42495 times.
42495 CalendarLayout::assignLanes(cell.events);
387 // The agenda lists only days with appointments (and always today).
388
4/4
✓ Branch 106 → 107 taken 2700 times.
✓ Branch 106 → 113 taken 39795 times.
✓ Branch 108 → 109 taken 2472 times.
✓ Branch 108 → 113 taken 228 times.
44967 if (request.mode == QLatin1String("agenda") && cell.events.isEmpty() &&
389
5/5
✓ Branch 109 → 110 taken 2472 times.
✓ Branch 111 → 112 taken 2456 times.
✓ Branch 111 → 113 taken 16 times.
✓ Branch 114 → 115 taken 2456 times.
✓ Branch 114 → 116 taken 40039 times.
44967 cell.date != QDate::currentDate())
390 2456 continue;
391
1/1
✓ Branch 116 → 117 taken 40039 times.
40039 result.cells.append(cell);
392 42495 }
393
2/2
✓ Branch 127 → 128 taken 44 times.
✓ Branch 127 → 129 taken 1050 times.
1094 if (request.mode == QLatin1String("agenda"))
394 44 return result;
395
2/2
✓ Branch 131 → 132 taken 935 times.
✓ Branch 131 → 133 taken 115 times.
1050 const int rowDays = request.mode == QLatin1String("month") ? 7 : days;
396
2/2
✓ Branch 155 → 135 taken 5725 times.
✓ Branch 155 → 156 taken 1050 times.
6775 for (int row = 0; row * rowDays < days; ++row) {
397 5725 QVariantList spans;
398
6/6
✓ Branch 135 → 136 taken 5725 times.
✓ Branch 136 → 137 taken 5725 times.
✓ Branch 137 → 138 taken 5725 times.
✓ Branch 138 → 139 taken 5725 times.
✓ Branch 148 → 140 taken 120 times.
✓ Branch 148 → 149 taken 5725 times.
5845 for (const CalendarSpan &span : CalendarLayout::spanRow(list, request.start.addDays(row * rowDays), rowDays))
399
2/2
✓ Branch 141 → 142 taken 120 times.
✓ Branch 143 → 144 taken 120 times.
5845 spans.append(CalendarLayout::toVariant(span));
400
1/1
✓ Branch 151 → 152 taken 5725 times.
5725 result.weekSpans.append(QVariant(spans));
401 5725 }
402 1050 return result;
403 1124 }
404
405 // The range is part of what monthChanged() announces (periodLabel,
406 // rangeStart/End): compute it before notifying.
407 989 void QuickCalendarModel::notifyPeriodChanged() {
408 989 computeRange();
409 989 emit monthChanged();
410 989 reload();
411 989 }
412
413 1294 void QuickCalendarModel::reload() {
414
1/1
✓ Branch 2 → 3 taken 1294 times.
1294 computeRange();
415 1294 ++m_generation;
416
5/6
✓ Branch 4 → 5 taken 1294 times.
✗ Branch 4 → 6 not taken.
✓ Branch 5 → 6 taken 170 times.
✓ Branch 5 → 7 taken 1124 times.
✓ Branch 8 → 9 taken 170 times.
✓ Branch 8 → 10 taken 1124 times.
1294 if (m_databasePath.isEmpty() || m_loading) return;
417 1124 const quint64 generation = m_generation;
418 // Captured per load: the worker must not read mutable members.
419 3372 LoadRequest request{m_databasePath, m_viewMode, m_gridStart, m_gridEnd, m_year, m_month,
420 1124 m_firstDayOfWeek, m_workWeek, m_hiddenCalendars, m_navigatorMonth,
421 2248 CalendarSearch::words(m_searchQuery), m_showTasks,
422
3/9
✓ Branch 13 → 14 taken 1124 times.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 16 taken 1123 times.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 31 not taken.
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
1124 m_showBirthdays ? m_contactsDatabasePath : QString(), m_unlimitedSeries};
423 1124 m_loading = true;
424
1/1
✓ Branch 18 → 19 taken 1124 times.
1124 emit loadingChanged();
425
1/1
✓ Branch 20 → 21 taken 1124 times.
1124 m_pool.start([this, generation, request] {
426
1/1
✓ Branch 2 → 3 taken 1124 times.
1124 LoadResult result = load(request);
427
1/1
✓ Branch 5 → 6 taken 1124 times.
1124 QMetaObject::invokeMethod(this, [this, generation, result = std::move(result)]() mutable {
428
2/2
✓ Branch 2 → 3 taken 64 times.
✓ Branch 2 → 5 taken 958 times.
1022 if (generation != m_generation) {
429 64 m_loading = false;
430 64 reload();
431 64 return;
432 }
433
2/2
✓ Branch 6 → 7 taken 126 times.
✓ Branch 6 → 13 taken 832 times.
958 if (result.mode != m_dataMode) {
434 // Hand over between views: the old one empties, the new one binds
435 // to an empty model and builds once from the reset below.
436 126 beginResetModel();
437 126 m_days.clear();
438 126 m_weekSpans.clear();
439 126 endResetModel();
440 126 m_dataMode = result.mode;
441 126 emit dataModeChanged();
442 }
443 // CAL-PERIOD-REBUILD: a step in the same view (same cell count) rebinds the delegates in place.
444
4/4
✓ Branch 14 → 15 taken 122 times.
✓ Branch 14 → 19 taken 836 times.
✓ Branch 17 → 18 taken 114 times.
✓ Branch 17 → 19 taken 8 times.
958 const bool inPlace = !m_days.isEmpty() && result.cells.size() == m_days.size();
445
2/2
✓ Branch 20 → 21 taken 844 times.
✓ Branch 20 → 22 taken 114 times.
958 if (!inPlace) beginResetModel();
446 958 m_days = std::move(result.cells);
447 958 m_weekSpans = std::move(result.weekSpans);
448 958 const bool navigatorChanged = m_navigatorDays != result.navigatorDays;
449
2/2
✓ Branch 27 → 28 taken 794 times.
✓ Branch 27 → 30 taken 164 times.
958 if (navigatorChanged) m_navigatorDays = std::move(result.navigatorDays);
450
5/5
✓ Branch 30 → 31 taken 114 times.
✓ Branch 30 → 40 taken 844 times.
✓ Branch 34 → 35 taken 114 times.
✓ Branch 36 → 37 taken 114 times.
✓ Branch 37 → 38 taken 114 times.
958 if (inPlace) emit dataChanged(index(0), index(int(m_days.size()) - 1));
451 844 else endResetModel();
452 958 m_loading = false;
453 958 emit layoutChanged();
454
2/2
✓ Branch 42 → 43 taken 794 times.
✓ Branch 42 → 44 taken 164 times.
958 if (navigatorChanged) emit navigatorDaysChanged();
455 958 emit loadingChanged();
456 }, Qt::QueuedConnection);
457 1124 });
458 1124 }
459
460 40 void QuickCalendarModel::setSearchQuery(const QString &query) {
461
2/2
✓ Branch 2 → 3 taken 40 times.
✓ Branch 3 → 4 taken 40 times.
40 const QString trimmed = query.left(256).trimmed();
462
2/2
✓ Branch 6 → 7 taken 12 times.
✓ Branch 6 → 8 taken 28 times.
40 if (trimmed == m_searchQuery) return;
463
5/6
✓ Branch 9 → 10 taken 11 times.
✓ Branch 9 → 13 taken 17 times.
✓ Branch 11 → 12 taken 11 times.
✗ Branch 11 → 13 not taken.
✓ Branch 14 → 15 taken 11 times.
✓ Branch 14 → 16 taken 17 times.
28 if (m_searchQuery.isEmpty() && !trimmed.isEmpty()) m_modeBeforeSearch = m_viewMode;
464 28 m_searchQuery = trimmed;
465
1/1
✓ Branch 17 → 18 taken 28 times.
28 emit searchQueryChanged();
466
2/2
✓ Branch 19 → 20 taken 17 times.
✓ Branch 19 → 27 taken 11 times.
28 if (!m_searchQuery.isEmpty()) {
467 17 m_viewMode = QStringLiteral("agenda");
468
1/2
✓ Branch 28 → 29 taken 11 times.
✗ Branch 28 → 31 not taken.
11 } else if (!m_modeBeforeSearch.isEmpty()) {
469 11 m_viewMode = m_modeBeforeSearch;
470 11 m_modeBeforeSearch.clear();
471 }
472
1/1
✓ Branch 31 → 32 taken 28 times.
28 notifyPeriodChanged();
473 40 }
474
475 799 void QuickCalendarModel::setHiddenCalendars(const QStringList &keys) {
476
2/2
✓ Branch 3 → 4 taken 789 times.
✓ Branch 3 → 5 taken 10 times.
799 if (keys == m_hiddenCalendars) return;
477 10 m_hiddenCalendars = keys;
478 10 emit hiddenCalendarsChanged();
479 10 reload();
480 }
481