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.4% 38 / 0 / 39
Functions: 97.4% 37 / 0 / 38
Branches: -% 0 / 0 / 0

presentation/QuickPimBackend.h
Line Branch Exec Source
1 #pragma once
2
3 #include "QuickCalendarModel.h"
4 #include "QuickCalendarSync.h"
5 #include "QuickDavPush.h"
6 #include "QuickNextUp.h"
7 #include "QuickEventMenu.h"
8 #include "QuickContactLookup.h"
9 #include "QuickContactGraph.h"
10 #include "QuickContactMap.h"
11 #include "QuickContactMailHistory.h"
12 #include "QuickContactMenu.h"
13 #include "QuickTaskMenu.h"
14 #include "QuickContactActions.h"
15 #include "QuickContactModel.h"
16 #include "QuickContactNavigation.h"
17 #include "QuickTaskModel.h"
18 #include "QuickTaskActions.h"
19 #include "data/MailRequest.h"
20 #include <QObject>
21 #include "data/CalendarModels.h"
22 #include <QVariant>
23 #include <functional>
24
25 class CalendarSyncCoordinator;
26 class MailSessionCore;
27 struct CalendarEvent;
28 class QuickPreferences;
29 class WorkspaceState;
30
31 // Calendar, task and contact surface of the Quick frontend (Sprint 91
32 // S91.1.1, extracted from QuickMailBackend). QML reaches it as
33 // `backend.pim`. It owns the three PIM projections and writes through the
34 // session's CalendarSyncCoordinator / ContactSyncCoordinator.
35 //
36 // Owner: QuickMailBackend (value member). GUI thread only. connectSignals()
37 // is called by the owner at the position of the former wirePim() block so
38 // the connection order of the backend constructor is unchanged. The
39 // injected callbacks answer from the owning backend (mail identity
40 // admission, active account name, status line).
41 class QuickPimBackend final : public QObject {
42 365 Q_OBJECT
43 // Real month-grid projection of the shared calendar database (D2/D5
44 // groundwork); navigation state lives in the model.
45 Q_PROPERTY(QAbstractItemModel *calendar READ calendar CONSTANT)
46 Q_PROPERTY(QVariantList calendarChoices READ calendarChoices NOTIFY calendarChoicesChanged)
47 Q_PROPERTY(QStringList calendarColorPalette READ calendarColorPalette CONSTANT)
48 // Read-only task projection of the shared calendar store (D6 groundwork).
49 Q_PROPERTY(QuickTaskMenu *taskMenu READ taskMenu CONSTANT)
50 Q_PROPERTY(QuickContactMenu *contactMenu READ contactMenu CONSTANT)
51 // Sprint 97 S97.5.3: recent mails of the shown contact.
52 Q_PROPERTY(QuickContactMailHistory *contactMails READ contactMails CONSTANT)
53 // Sprint 97 S97.5.1: people behind the addresses of the reader.
54 Q_PROPERTY(QuickContactLookup *contactLookup READ contactLookup CONSTANT)
55 // Sprint 103 S103.4: the contacts' world map.
56 Q_PROPERTY(QuickContactMap *contactMap READ contactMap CONSTANT)
57 Q_PROPERTY(QuickContactGraph *contactGraph READ contactGraph CONSTANT)
58 // F103-40: the small graph on the contact card (its own centre, no suggestions).
59 Q_PROPERTY(QuickContactGraph *contactMiniGraph READ contactMiniGraph CONSTANT)
60 Q_PROPERTY(QuickTaskActions *taskActions READ taskActions CONSTANT)
61 Q_PROPERTY(QAbstractItemModel *tasks READ tasks CONSTANT)
62 Q_PROPERTY(int taskLinkRevision READ taskLinkRevision NOTIFY taskLinksChanged)
63 // Paged contact projection of the shared contacts database (D7 groundwork).
64 Q_PROPERTY(QAbstractItemModel *contacts READ contacts CONSTANT)
65 // Sprint 97: contact writes by card key (save, delete with undo, move …).
66 Q_PROPERTY(QuickContactActions *contactActions READ contactActions CONSTANT)
67 // Sprint 97 S97.3.1: counts, books, groups and sync line of the sidebar.
68 Q_PROPERTY(QuickContactNavigation *contactNavigation READ contactNavigation CONSTANT)
69 // Q09: true while a CardDAV contact sync run is in flight.
70 Q_PROPERTY(bool contactSyncRunning READ contactSyncRunning NOTIFY contactSyncStateChanged)
71 // Sprint 93 S93.1.8: text of the calendar change Ctrl+Z / the toast's
72 // "Undo" would revert ("" = nothing to undo).
73 Q_PROPERTY(QString calendarUndoText READ calendarUndoText NOTIFY calendarUndoChanged)
74 // Sprint 93 S93.6.3: per-account sync state, "Sync now".
75 Q_PROPERTY(QuickCalendarSync *sync READ sync CONSTANT)
76 // Sprint 96: DAV-Push status, service form and actions.
77 Q_PROPERTY(QuickDavPush *push READ push CONSTANT)
78 // Sprint 93 S93.3.10: today's next appointment for the mail status bar.
79 Q_PROPERTY(QuickNextUp *nextUp READ nextUp CONSTANT)
80 // F93-08: native appointment menu.
81 Q_PROPERTY(QuickEventMenu *eventMenu READ eventMenu CONSTANT)
82 // F93-12: the agenda beside the mail list — its own agenda projection
83 // (from today) and the remembered visibility.
84 // Created on first show (no extra load at startup).
85 Q_PROPERTY(QAbstractItemModel *agendaPanel READ agendaPanel NOTIFY viewStateChanged)
86 Q_PROPERTY(bool agendaPanelVisible READ agendaPanelVisible WRITE setAgendaPanelVisible NOTIFY viewStateChanged)
87 // F94-50: width of the mail view's agenda in logical pixels (240–640).
88 Q_PROPERTY(int agendaPanelWidth READ agendaPanelWidth WRITE setAgendaPanelWidth NOTIFY viewStateChanged)
89 // F95-04: height of the task part below the agenda (unscaled px, 0 = 40 % of the panel).
90 Q_PROPERTY(int agendaTasksHeight READ agendaTasksHeight WRITE setAgendaTasksHeight NOTIFY viewStateChanged)
91 // F94-59: which tasks the mail agenda lists ("today", "week", "planned",
92 // "mine", "list:<key>", "tag:<name>"), remembered.
93 Q_PROPERTY(QString agendaTaskView READ agendaTaskView WRITE setAgendaTaskView NOTIFY viewStateChanged)
94 // F94-67: the section is optional; filter tokens (task search syntax) and
95 // order of the mail agenda's tasks; all remembered.
96 Q_PROPERTY(bool agendaTasksVisible READ agendaTasksVisible WRITE setAgendaTasksVisible NOTIFY viewStateChanged)
97 Q_PROPERTY(QString agendaTaskFilter READ agendaTaskFilter WRITE setAgendaTaskFilter NOTIFY viewStateChanged)
98 Q_PROPERTY(QString agendaTaskSort READ agendaTaskSort WRITE setAgendaTaskSort NOTIFY viewStateChanged)
99 // Sprint 93 S93.3.9: remembered calendar state besides the model's view
100 // mode, work week and hidden calendars — the time grid's hour zoom and
101 // the last calendar a new appointment was saved into ("accountId\npath").
102 Q_PROPERTY(int calendarHourZoom READ calendarHourZoom WRITE setCalendarHourZoom NOTIFY viewStateChanged)
103 Q_PROPERTY(QString lastCalendar READ lastCalendar WRITE setLastCalendar NOTIFY viewStateChanged)
104 // F93-20 / S93.3.7: working hours (shading, where a day opens) and the
105 // first day of the week (0 = the locale's).
106 Q_PROPERTY(int calendarWorkdayStart READ calendarWorkdayStart WRITE setCalendarWorkdayStart NOTIFY viewStateChanged)
107 Q_PROPERTY(int calendarWorkdayEnd READ calendarWorkdayEnd WRITE setCalendarWorkdayEnd NOTIFY viewStateChanged)
108 Q_PROPERTY(int calendarFirstDayOfWeek READ calendarFirstDayOfWeek WRITE setCalendarFirstDayOfWeek NOTIFY viewStateChanged)
109 // Sprint 108 D-22: working days (Qt::DayOfWeek values) for *Suggest times*.
110 Q_PROPERTY(QVariantList calendarWorkdays READ calendarWorkdays WRITE setCalendarWorkdays NOTIFY viewStateChanged)
111 // S93.5.1: reminders on/off and the default reminder for new events
112 // (minutes before the start, -1 = none); QSettings calendar/….
113 Q_PROPERTY(bool remindersEnabled READ remindersEnabled WRITE setRemindersEnabled NOTIFY reminderSettingsChanged)
114 Q_PROPERTY(int defaultReminder READ defaultReminder WRITE setDefaultReminder NOTIFY reminderSettingsChanged)
115 public:
116 struct Deps {
117 std::function<bool(const MailId &)> acceptsIdentity;
118 std::function<QString()> accountName;
119 std::function<void(const QString &)> setStatus;
120 };
121 QuickPimBackend(MailSessionCore &session, WorkspaceState &workspace,
122 QuickPreferences &preferences, Deps deps, QObject *parent = nullptr);
123 void connectSignals();
124
125 4307 QAbstractItemModel *calendar() { return &m_calendar; }
126 3650 QAbstractItemModel *tasks() { return &m_tasks; }
127 2745 QAbstractItemModel *contacts() { return &m_contacts; }
128 13420 QuickCalendarSync *sync() const { return m_sync; }
129 5132 QuickDavPush *push() const { return m_push; }
130 818 QuickNextUp *nextUp() { return &m_nextUp; }
131 2547 QuickEventMenu *eventMenu() { return &m_eventMenu; }
132 1073 QAbstractItemModel *agendaPanel() { return m_agendaPanel; }
133 1991 bool agendaPanelVisible() const { return m_agendaPanelVisible; }
134 void setAgendaPanelVisible(bool visible);
135 2335 int agendaPanelWidth() const { return m_agendaPanelWidth; }
136 1072 int agendaTasksHeight() const { return m_agendaTasksHeight; }
137 3018 QString agendaTaskView() const { return m_agendaTaskView; }
138 void setAgendaTaskView(const QString &view);
139 2152 bool agendaTasksVisible() const { return m_agendaTasksVisible; }
140 void setAgendaTasksVisible(bool visible);
141 3344 QString agendaTaskFilter() const { return m_agendaTaskFilter; }
142 void setAgendaTaskFilter(const QString &filter);
143 1200 QString agendaTaskSort() const { return m_agendaTaskSort; }
144 void setAgendaTaskSort(const QString &sort);
145 void setAgendaPanelWidth(int width);
146 void setAgendaTasksHeight(int height);
147 2298 QuickCalendarModel &calendarModel() { return m_calendar; }
148 3536 QuickTaskMenu *taskMenu() { return &m_taskMenu; }
149 83 QuickContactMenu *contactMenu() { return &m_contactMenu; }
150 79 QuickContactMailHistory *contactMails() { return &m_contactMails; }
151 3082 QuickContactLookup *contactLookup() { return &m_contactLookup; }
152 1052 QuickContactMap *contactMap() { return &m_contactMap; }
153 60 QuickContactGraph *contactGraph() { return &m_contactGraph; }
154 84 QuickContactGraph *contactMiniGraph() { return &m_contactMiniGraph; }
155 1811 QuickTaskActions *taskActions() { return &m_taskActions; }
156 2 QuickTaskModel &taskModel() { return m_tasks; }
157 1570 QuickContactModel &contactModel() { return m_contacts; }
158 8602 QuickContactActions *contactActions() { return &m_contactActions; }
159 1997 QuickContactNavigation *contactNavigation() { return &m_contactNavigation; }
160
161 // D6 task write-back: full record for the row (etag/href ride along),
162 // console-syntax creation ("Title /calendar @date !priority"), completion
163 // toggle, editor save and removal. All paths go through the
164 // CalendarSyncCoordinator (local-first + best-effort DAV push).
165 Q_INVOKABLE QVariantMap taskAt(int row) const;
166 Q_INVOKABLE QVariantMap taskRecord(const QString &uid, const QString &accountId, const QString &calendarPath) const;
167 Q_INVOKABLE QVariantMap createTaskFromInput(const QString &input);
168 bool toggleTaskAt(int row);
169 // S93.5.7: the calendar's task chips toggle by identity.
170 Q_INVOKABLE bool toggleTask(const QString &uid, const QString &accountId, const QString &calendarPath);
171 Q_INVOKABLE void secureMarkdownPreview(QObject *wrapper);
172 Q_INVOKABLE QVariantMap saveTask(const QVariantMap &fields);
173 // Stable task-to-mail association uses the RFC Message-ID, then resolves
174 // it inside the active account at open time so moves between folders keep
175 // working and another account cannot satisfy the link.
176 Q_INVOKABLE QVariantMap currentMailReference() const;
177 // S94.5.5: tasks linked to the displayed mail; QML re-reads it when
178 // taskLinkRevision changes (any calendar store change).
179 Q_INVOKABLE QVariantList tasksForCurrentMail() const;
180 3659 int taskLinkRevision() const { return m_taskLinkRevision; }
181 QSet<QString> openTaskMessageIds() const;
182 // S94.5.8: open tasks for today (agenda panel); re-read on taskLinkRevision.
183 ✗ Q_INVOKABLE QVariantList tasksDueToday() const { return m_taskActions.dueToday(); }
184 // F94-59: the open tasks below the mail view's agenda, for agendaTaskView.
185 1200 Q_INVOKABLE QVariantList agendaTasks() const {
186 1200 return m_taskActions.openTasksFor(m_agendaTaskView, m_agendaTaskFilter, m_agendaTaskSort);
187 }
188 Q_INVOKABLE QVariantMap taskMailReference(const QString &messageId) const;
189 Q_INVOKABLE bool openTaskMail(const QString &messageId);
190 bool removeTaskAt(int row);
191 Q_INVOKABLE bool removeTask(const QString &uid, const QString &accountId, const QString &calendarPath);
192 // D5 event write-back: editor save (uid empty = create on the selected
193 // calendar) and removal. Same coordinator contract as the task paths.
194 Q_INVOKABLE QVariantMap eventAt(const QString &uid, const QString &accountId,
195 const QString &calendarPath) const;
196 // Q11: the exception row for a moved occurrence (editor prefill).
197 Q_INVOKABLE QVariantMap eventOccurrenceAt(const QString &uid,
198 const QString &accountId,
199 const QString &calendarPath,
200 const QString &recurrenceId) const;
201 // Sprint 103 S103.6.1 (D-14): `people` [{uid, uri, name}] in `fields`
202 // replaces the people named in the event (CONTACT;ALTREP, never ATTENDEE);
203 // absent keeps them.
204 Q_INVOKABLE QVariantMap saveEvent(const QVariantMap &fields);
205 // The people an event names and the attendees other clients wrote
206 // (read-only): {people: [{uid, uri, name}], attendees: [{name, address, organizer}]}.
207 Q_INVOKABLE QVariantMap eventPeople(const QString &uid, const QString &accountId, const QString &calendarPath) const;
208 // Sprint 93 S93.1.5: structured view of an RRULE for the editor —
209 // frequency, interval, weekdays, monthly mode, end, `supported` (the
210 // structured editor can represent it) and the localized `text`.
211 Q_INVOKABLE QVariantMap describeRecurrence(const QString &rrule, const QString &startIso) const;
212 Q_INVOKABLE bool removeEvent(const QString &uid, const QString &accountId,
213 const QString &calendarPath);
214 // Q11 series exception: deletes a single occurrence of a recurring
215 // master by appending an EXDATE (UTC ISO timestamp of the occurrence).
216 // Only series masters qualify; the exclusion survives DAV round trips.
217 Q_INVOKABLE QVariantMap removeEventOccurrence(const QString &uid,
218 const QString &accountId,
219 const QString &calendarPath,
220 const QString &occurrenceStart);
221 // S93.1.8 scoped deletion of the occurrence map the views use
222 // ({uid, accountId, calendarPath, startIso, recurrenceIso}); scope is
223 // "this" (only this appointment), "following" (this and all following) or
224 // "all" (the series / a single event). Returns {ok, error, undoText}.
225 Q_INVOKABLE QVariantMap removeEventScoped(const QVariantMap &occurrence, const QString &scope);
226 // S93.4.1 details popover: everything the popover shows for an
227 // occurrence map (calendar, time and duration, foreign time zone,
228 // recurrence text, safe linkified notes, meeting link, sync/conflict
229 // state). Empty when the event no longer exists.
230 Q_INVOKABLE QVariantMap eventDetails(const QVariantMap &occurrence) const;
231 // Sprint 102: "Show all" for a series the calendar shows only in part.
232 Q_INVOKABLE void showAllOccurrences(const QVariantMap &occurrence);
233 // Popover actions: a copy of this appointment (single, new UID), a move
234 // to another writable calendar (same UID, the series moves along), the
235 // conflict choice ("mine"/"server"/"both"), "Retry now", an inline title
236 // edit (S93.4.9) and "Copy as text".
237 Q_INVOKABLE QVariantMap duplicateEvent(const QVariantMap &occurrence);
238 Q_INVOKABLE QVariantMap moveEventToCalendar(const QVariantMap &occurrence,
239 const QString &accountId, const QString &calendarPath);
240 Q_INVOKABLE bool resolveEventConflict(const QVariantMap &occurrence, const QString &choice);
241 Q_INVOKABLE void retryCalendarSync();
242 Q_INVOKABLE QVariantMap renameEvent(const QVariantMap &occurrence, const QString &summary);
243 Q_INVOKABLE bool copyEventAsText(const QVariantMap &occurrence) const;
244 // Reverts the last calendar change (save, move, delete) of this session.
245 Q_INVOKABLE bool undoCalendarChange();
246 QString calendarUndoText() const;
247 // Write targets for event creation: {path, displayName, accountId}.
248 Q_INVOKABLE QVariantList davCalendars() const;
249 QVariantList calendarChoices() const;
250 QStringList calendarColorPalette() const;
251 Q_INVOKABLE bool setCalendarColor(const QString &accountId, const QString &path, const QString &color);
252 // S93.4.4: move an occurrence by deltaMinutes and lengthen it by
253 // resizeMinutes (all-day: multiples of 1440); scope "this" or "series"
254 // for recurring appointments. Returns saveEvent's result.
255 Q_INVOKABLE QVariantMap moveOccurrence(const QVariantMap &occurrence, int deltaMinutes, int resizeMinutes,
256 const QString &scope);
257 Q_INVOKABLE void toggleCalendarVisibility(const QString &accountId, const QString &path);
258 287 int calendarHourZoom() const { return m_hourZoom; }
259 void setCalendarHourZoom(int zoom);
260 435 QString lastCalendar() const { return m_lastCalendar; }
261 227 int calendarWorkdayStart() const { return m_workdayStart; }
262 void setCalendarWorkdayStart(int hour);
263 223 int calendarWorkdayEnd() const { return m_workdayEnd; }
264 void setCalendarWorkdayEnd(int hour);
265 39 int calendarFirstDayOfWeek() const { return m_firstDayOfWeek; }
266 880 QVariantList calendarWorkdays() const { return m_workdays; }
267 void setCalendarWorkdays(const QVariantList &days);
268 bool remindersEnabled() const;
269 void setRemindersEnabled(bool enabled);
270 int defaultReminder() const;
271 void setDefaultReminder(int minutes);
272 void setCalendarFirstDayOfWeek(int day);
273 void setLastCalendar(const QString &key);
274 // The persisted view state (WorkspacePersistence::calendarState keys).
275 QVariantMap viewState() const;
276 void restoreViewState(const QVariantMap &state);
277 // Q09: manual CardDAV contact sync (same run as the interval timer;
278 // repeated presses join the current run).
279 Q_INVOKABLE void triggerContactSync();
280 bool contactSyncRunning() const;
281
282 signals:
283 void calendarChoicesChanged();
284 // Q09: a CardDAV contact sync run started or finished.
285 void contactSyncStateChanged();
286 void calendarUndoChanged();
287 // Any remembered calendar state changed (view, work week, hidden
288 // calendars, zoom, last calendar); the host persists viewState().
289 void viewStateChanged();
290 void reminderSettingsChanged();
291 // A calendar store change may have added, completed or removed mail-linked tasks.
292 void taskLinksChanged();
293
294 private:
295 int m_taskLinkRevision = 0;
296 // saveEvent() steps; each returns the user-facing error or an empty string.
297 QString eventRecurrenceRule(const QVariantMap &fields, QString &storedRule) const;
298 QString eventForSave(CalendarSyncCoordinator *sync, const QVariantMap &fields,
299 CalendarEvent &event, bool &wasNew) const;
300 // S93.1.8 undo: the rows of every resource a change touched, as they
301 // were before it (empty rows = the resource did not exist).
302 struct ResourceSnapshot {
303 QString uid, accountId, calendarPath;
304 QList<CalendarEvent> rows;
305 };
306 struct CalendarUndo {
307 QString text;
308 QList<ResourceSnapshot> resources;
309 };
310 ResourceSnapshot snapshot(const QString &uid, const QString &accountId,
311 const QString &calendarPath) const;
312 void pushUndo(const QString &text, const QList<ResourceSnapshot> &resources);
313 QString splitSeriesForSave(CalendarSyncCoordinator *sync, const QVariantMap &fields,
314 CalendarEvent &event, bool &wasNew, QList<ResourceSnapshot> &undo,
315 QString *seriesRule) const;
316 QList<CalendarUndo> m_calendarUndo;
317 MailSessionCore &m_session;
318 WorkspaceState &m_workspace;
319 QuickPreferences &m_preferences;
320 Deps m_deps;
321 QuickCalendarModel m_calendar;
322 QuickTaskModel m_tasks;
323 QuickTaskActions m_taskActions;
324 QuickContactModel m_contacts;
325 QuickContactActions m_contactActions;
326 QuickContactNavigation m_contactNavigation;
327 QuickCalendarModel *m_agendaPanel = nullptr;
328 bool m_agendaPanelVisible = false;
329 int m_agendaPanelWidth = 320;
330 int m_agendaTasksHeight = 0;
331 QString m_agendaTaskView = QStringLiteral("today");
332 QString m_agendaTaskFilter;
333 QString m_agendaTaskSort = QStringLiteral("due");
334 bool m_agendaTasksVisible = true;
335 QuickNextUp m_nextUp;
336 QuickEventMenu m_eventMenu{this};
337 QuickTaskMenu m_taskMenu{this};
338 QuickContactMenu m_contactMenu{this};
339 QuickContactMailHistory m_contactMails;
340 QuickContactLookup m_contactLookup;
341 QuickContactMap m_contactMap;
342 QuickContactGraph m_contactGraph;
343 QuickContactGraph m_contactMiniGraph;
344 QuickCalendarSync *m_sync = nullptr;
345 QuickDavPush *m_push = nullptr;
346 int m_hourZoom = 48;
347 QString m_lastCalendar;
348 int m_workdayStart = 8;
349 int m_workdayEnd = 18;
350 int m_firstDayOfWeek = 0;
351 QVariantList m_workdays{1, 2, 3, 4, 5};
352 };
353