KCalendarCore

freebusy.cpp
Go to the documentation of this file.
1/*
2 This file is part of the kcalcore library.
3
4 SPDX-FileCopyrightText: 2001 Cornelius Schumacher <schumacher@kde.org>
5 SPDX-FileCopyrightText: 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9/**
10 @file
11 This file is part of the API for handling calendar data and
12 defines the FreeBusy class.
13
14 @brief
15 Provides information about the free/busy time of a calendar user.
16
17 @author Cornelius Schumacher <schumacher@kde.org>
18 @author Reinhold Kainhofer <reinhold@kainhofer.com>
19*/
20#include "freebusy.h"
21#include "utils_p.h"
22#include "visitor.h"
23
24#include "icalformat.h"
25
26#include "incidencebase_p.h"
27#include "kcalendarcore_debug.h"
28#include <QTime>
29
30using namespace KCalendarCore;
31
32//@cond PRIVATE
33class KCalendarCore::FreeBusyPrivate : public IncidenceBasePrivate
34{
35public:
36 FreeBusyPrivate() = default;
37 FreeBusyPrivate(const FreeBusyPrivate &other) = default;
38
39 FreeBusyPrivate(const FreeBusyPeriod::List &busyPeriods)
40 : IncidenceBasePrivate()
41 , mBusyPeriods(busyPeriods)
42 {
43 }
44
45 void init(const FreeBusyPrivate &other);
46 void init(const Event::List &events, const QDateTime &start, const QDateTime &end);
47
48 QDateTime mDtEnd; // end datetime
49 FreeBusyPeriod::List mBusyPeriods; // list of periods
50
51 // This is used for creating a freebusy object for the current user
52 bool addLocalPeriod(const QDateTime &eventStart, const QDateTime &eventEnd);
53
54 void sortBusyPeriods()
55 {
56 std::sort(mBusyPeriods.begin(), mBusyPeriods.end());
57 }
58};
59
60void FreeBusyPrivate::init(const FreeBusyPrivate &other)
61{
62 mDtEnd = other.mDtEnd;
63 mBusyPeriods = other.mBusyPeriods;
64}
65//@endcond
66
68 : IncidenceBase(new FreeBusyPrivate())
69{
70}
71
73 : IncidenceBase(other, new FreeBusyPrivate(*other.d_func()))
74{
75}
76
78 : FreeBusy()
79{
80 setDtStart(start); // NOLINT false clang-analyzer-optin.cplusplus.VirtualCall
81 setDtEnd(end); // NOLINT false clang-analyzer-optin.cplusplus.VirtualCall
82}
83
84FreeBusy::FreeBusy(const Event::List &events, const QDateTime &start, const QDateTime &end)
85 : FreeBusy()
86{
87 setDtStart(start); // NOLINT false clang-analyzer-optin.cplusplus.VirtualCall
88 setDtEnd(end); // NOLINT false clang-analyzer-optin.cplusplus.VirtualCall
89
91 d->init(events, start, end);
92}
93
94//@cond PRIVATE
95void FreeBusyPrivate::init(const Event::List &eventList, const QDateTime &start, const QDateTime &end)
96{
97 const qint64 duration = start.daysTo(end);
98 QDate day;
99 QDateTime tmpStart;
100 QDateTime tmpEnd;
101
102 // Loops through every event in the calendar
103 for (auto event : eventList) {
104 // If this event is transparent it shouldn't be in the freebusy list.
105 if (event->transparency() == Event::Transparent) {
106 continue;
107 }
108
109 // The code below can not handle all-day events. Fixing this resulted
110 // in a lot of duplicated code. Instead, make a copy of the event and
111 // set the period to the full day(s). This trick works for recurring,
112 // multiday, and single day all-day events.
113 Event::Ptr allDayEvent;
114 if (event->allDay()) {
115 // addDay event. Do the hack
116 qCDebug(KCALCORE_LOG) << "All-day event";
117 allDayEvent = Event::Ptr(new Event(*event));
118
119 // Set the start and end times to be on midnight
120 QDateTime st = allDayEvent->dtStart();
121 st.setTime(QTime(0, 0));
122 QDateTime nd = allDayEvent->dtEnd();
123 nd.setTime(QTime(23, 59, 59, 999));
124 allDayEvent->setAllDay(false);
125 allDayEvent->setDtStart(st);
126 allDayEvent->setDtEnd(nd);
127
128 qCDebug(KCALCORE_LOG) << "Use:" << st.toString() << "to" << nd.toString();
129 // Finally, use this event for the setting below
130 event = allDayEvent;
131 }
132
133 // This whole for loop is for recurring events, it loops through
134 // each of the days of the freebusy request
135
136 for (qint64 i = 0; i <= duration; ++i) {
137 day = start.addDays(i).date();
138 tmpStart.setDate(day);
139 tmpEnd.setDate(day);
140
141 if (event->recurs()) {
142 if (event->isMultiDay()) {
143 // FIXME: This doesn't work for sub-daily recurrences or recurrences with
144 // a different time than the original event.
145 const qint64 extraDays = event->dtStart().daysTo(event->dtEnd());
146 for (qint64 x = 0; x <= extraDays; ++x) {
147 if (event->recursOn(day.addDays(-x), start.timeZone())) {
148 tmpStart.setDate(day.addDays(-x));
149 tmpStart.setTime(event->dtStart().time());
150 tmpEnd = event->duration().end(tmpStart);
151
152 addLocalPeriod(tmpStart, tmpEnd);
153 break;
154 }
155 }
156 } else {
157 if (event->recursOn(day, start.timeZone())) {
158 tmpStart.setTime(event->dtStart().time());
159 tmpEnd.setTime(event->dtEnd().time());
160
161 addLocalPeriod(tmpStart, tmpEnd);
162 }
163 }
164 }
165 }
166
167 // Non-recurring events
168 addLocalPeriod(event->dtStart(), event->dtEnd());
169 }
170
171 sortBusyPeriods();
172}
173//@endcond
174
176 : IncidenceBase(new FreeBusyPrivate())
177{
179}
180
182 : IncidenceBase(new FreeBusyPrivate(busyPeriods))
183{
184}
185
186FreeBusy::~FreeBusy() = default;
187
192
194{
195 return QByteArrayLiteral("FreeBusy");
196}
197
202
204{
205 Q_D(FreeBusy);
206 update();
207 d->mDtEnd = end;
209 updated();
210}
211
213{
214 Q_D(const FreeBusy);
215 return d->mDtEnd;
216}
217
219{
220 Period::List res;
221
222 Q_D(const FreeBusy);
223 res.reserve(d->mBusyPeriods.count());
224 for (const FreeBusyPeriod &p : std::as_const(d->mBusyPeriods)) {
225 res << p;
226 }
227
228 return res;
229}
230
232{
233 Q_D(const FreeBusy);
234 return d->mBusyPeriods;
235}
236
238{
239 Q_D(FreeBusy);
240 d->sortBusyPeriods();
241}
242
244{
245 Q_D(FreeBusy);
246 d->mBusyPeriods.reserve(d->mBusyPeriods.count() + list.count());
247 for (const Period &p : std::as_const(list)) {
248 d->mBusyPeriods << FreeBusyPeriod(p);
249 }
250 sortList();
251}
252
254{
255 Q_D(FreeBusy);
256 d->mBusyPeriods += list;
257 sortList();
258}
259
261{
262 Q_D(FreeBusy);
263 d->mBusyPeriods.append(FreeBusyPeriod(start, end));
264 sortList();
265}
266
267void FreeBusy::addPeriod(const QDateTime &start, const Duration &duration)
268{
269 Q_D(FreeBusy);
270 d->mBusyPeriods.append(FreeBusyPeriod(start, duration));
271 sortList();
272}
273
274void FreeBusy::merge(const FreeBusy::Ptr &freeBusy)
275{
276 if (freeBusy->dtStart() < dtStart()) {
277 setDtStart(freeBusy->dtStart());
278 }
279
280 if (freeBusy->dtEnd() > dtEnd()) {
281 setDtEnd(freeBusy->dtEnd());
282 }
283
284 Q_D(FreeBusy);
285 const Period::List periods = freeBusy->busyPeriods();
286 d->mBusyPeriods.reserve(d->mBusyPeriods.count() + periods.count());
287 for (const auto &p : periods) {
288 d->mBusyPeriods.append(FreeBusyPeriod(p.start(), p.end()));
289 }
290 sortList();
291}
292
293void FreeBusy::shiftTimes(const QTimeZone &oldZone, const QTimeZone &newZone)
294{
295 Q_D(FreeBusy);
296 if (oldZone.isValid() && newZone.isValid() && oldZone != newZone) {
297 IncidenceBase::shiftTimes(oldZone, newZone);
298 update();
299 d->mDtEnd = d->mDtEnd.toTimeZone(oldZone);
300 d->mDtEnd.setTimeZone(newZone);
301 for (FreeBusyPeriod p : std::as_const(d->mBusyPeriods)) {
302 p.shiftTimes(oldZone, newZone);
303 }
305 updated();
306 }
307}
308
310{
311 Q_D(FreeBusy);
312 if (&other != this) {
314 const FreeBusy *f = static_cast<const FreeBusy *>(&other);
315 d->init(*(f->d_func()));
316 }
317 return *this;
318}
319
320bool FreeBusy::equals(const IncidenceBase &freeBusy) const
321{
322 if (!IncidenceBase::equals(freeBusy)) {
323 return false;
324 } else {
325 Q_D(const FreeBusy);
326 // If they weren't the same type IncidenceBase::equals would had returned false already
327 const FreeBusy *fb = static_cast<const FreeBusy *>(&freeBusy);
328 return identical(dtEnd(), fb->dtEnd()) && d->mBusyPeriods == fb->d_func()->mBusyPeriods;
329 }
330}
331
332bool FreeBusy::accept(Visitor &v, const IncidenceBase::Ptr &incidence)
333{
334 return v.visit(incidence.staticCast<FreeBusy>());
335}
336
338{
339 Q_UNUSED(role);
340 // No roles affecting freeBusy yet
341 return QDateTime();
342}
343
345{
346 Q_UNUSED(dateTime);
347 Q_UNUSED(role);
348}
349
350void FreeBusy::virtual_hook(VirtualHook id, void *data)
351{
352 Q_UNUSED(id);
353 Q_UNUSED(data);
354 Q_ASSERT(false);
355}
356
357//@cond PRIVATE
358bool FreeBusyPrivate::addLocalPeriod(const QDateTime &eventStart, const QDateTime &eventEnd)
359{
360 QDateTime tmpStart;
361 QDateTime tmpEnd;
362
363 // Check to see if the start *or* end of the event is
364 // between the start and end of the freebusy dates.
365 QDateTime start = mDtStart;
366 if (!(((start.secsTo(eventStart) >= 0) && (eventStart.secsTo(mDtEnd) >= 0)) || ((start.secsTo(eventEnd) >= 0) && (eventEnd.secsTo(mDtEnd) >= 0)))) {
367 return false;
368 }
369
370 if (eventStart.secsTo(start) >= 0) {
371 tmpStart = start;
372 } else {
373 tmpStart = eventStart;
374 }
375
376 if (eventEnd.secsTo(mDtEnd) <= 0) {
377 tmpEnd = mDtEnd;
378 } else {
379 tmpEnd = eventEnd;
380 }
381
382 FreeBusyPeriod p(tmpStart, tmpEnd);
383 mBusyPeriods.append(p);
384
385 return true;
386}
387//@endcond
388
393
395{
396 return QLatin1String("application/x-vnd.akonadi.calendar.freebusy");
397}
398
400{
402 QString data = format.createScheduleMessage(freebusy, iTIPPublish);
403 return stream << data;
404}
405
407{
408 QString freeBusyVCal;
409 stream >> freeBusyVCal;
410
412 freebusy = format.parseFreeBusy(freeBusyVCal);
413
414 if (!freebusy) {
415 qCDebug(KCALCORE_LOG) << "Error parsing free/busy";
416 qCDebug(KCALCORE_LOG) << freeBusyVCal;
417 }
418
419 return stream;
420}
Represents a span of time measured in seconds or days.
Definition duration.h:44
This class provides an Event in the sense of RFC2445.
Definition event.h:33
@ Transparent
Event does not appear in free/busy time.
Definition event.h:43
QSharedPointer< Event > Ptr
A shared pointer to an Event object.
Definition event.h:50
The period can be defined by either a start time and an end time or by a start time and a duration.
Provides information about the free/busy time of a calendar.
Definition freebusy.h:43
void addPeriod(const QDateTime &start, const QDateTime &end)
Adds a period to the freebusy list and sorts the list.
Definition freebusy.cpp:260
void setDateTime(const QDateTime &dateTime, DateTimeRole role) override
Definition freebusy.cpp:344
Period::List busyPeriods() const
Returns the list of all periods within the free/busy.
Definition freebusy.cpp:218
void sortList()
Sorts the list of free/busy periods into ascending order.
Definition freebusy.cpp:237
QLatin1String mimeType() const override
Definition freebusy.cpp:389
~FreeBusy() override
Destroys a free/busy.
void setDtEnd(const QDateTime &end)
Sets the end datetime for the free/busy.
Definition freebusy.cpp:203
IncidenceType type() const override
Definition freebusy.cpp:188
QByteArray typeStr() const override
Definition freebusy.cpp:193
static QLatin1String freeBusyMimeType()
Returns the Akonadi specific sub MIME type of a KCalendarCore::FreeBusy.
Definition freebusy.cpp:394
FreeBusyPeriod::List fullBusyPeriods() const
Returns the list of all periods within the free/busy.
Definition freebusy.cpp:231
void addPeriods(const Period::List &list)
Adds a list of periods to the freebusy object and then sorts that list.
Definition freebusy.cpp:243
virtual QDateTime dtEnd() const
Returns the end datetime for the free/busy.
Definition freebusy.cpp:212
FreeBusy()
Constructs an free/busy without any periods.
Definition freebusy.cpp:67
void shiftTimes(const QTimeZone &oldZone, const QTimeZone &newZone) override
Definition freebusy.cpp:293
void merge(const FreeBusy::Ptr &freebusy)
Merges another free/busy into this free/busy.
Definition freebusy.cpp:274
QDateTime dateTime(DateTimeRole role) const override
Definition freebusy.cpp:337
IncidenceBase & assign(const IncidenceBase &other) override
Definition freebusy.cpp:309
void setDtStart(const QDateTime &start) override
Sets the start date/time for the free/busy.
Definition freebusy.cpp:198
void virtual_hook(VirtualHook id, void *data) override
Definition freebusy.cpp:350
bool equals(const IncidenceBase &freebusy) const override
Compare this with freebusy for equality.
Definition freebusy.cpp:320
iCalendar format implementation.
Definition icalformat.h:45
FreeBusy::Ptr parseFreeBusy(const QString &string)
Converts a QString into a FreeBusy object.
QString createScheduleMessage(const IncidenceBase::Ptr &incidence, iTIPMethod method)
Creates a scheduling message string for an Incidence.
An abstract class that provides a common base for all calendar incidence classes.
void updated()
Call this to notify the observers after the IncidenceBase object has changed.
virtual void setDtStart(const QDateTime &dtStart)
Sets the incidence's starting date/time with a QDateTime.
virtual void shiftTimes(const QTimeZone &oldZone, const QTimeZone &newZone)
Shift the times of the incidence so that they appear at the same clock time as before but in a new ti...
IncidenceType
The different types of incidences, per RFC2445.
@ TypeFreeBusy
Type is a free/busy.
Duration duration() const
Returns the length of the incidence duration.
void update()
Call this to notify the observers after the IncidenceBase object will be changed.
@ FieldDtEnd
Field representing the DTEND component.
virtual IncidenceBase & assign(const IncidenceBase &other)
Provides polymorfic assignment.
void setFieldDirty(IncidenceBase::Field field)
Marks Field field as dirty.
DateTimeRole
The different types of incidence date/times roles.
virtual bool equals(const IncidenceBase &incidenceBase) const
Provides polymorfic comparison for equality.
The period can be defined by either a start time and an end time or by a start time and a duration.
Definition period.h:38
This class provides the interface for a visitor of calendar components.
Definition visitor.h:31
virtual bool visit(const Event::Ptr &event)
Reimplement this function in your concrete subclass of IncidenceBase::Visitor to perform actions on a...
Definition visitor.cpp:25
This file is part of the API for handling calendar data and defines the FreeBusy class.
Q_SCRIPTABLE Q_NOREPLY void start()
This file is part of the API for handling calendar data and defines the ICalFormat class.
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
Namespace for all KCalendarCore types.
Definition alarm.h:37
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
Alarm deserializer.
Definition alarm.cpp:833
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
Alarm serializer.
Definition alarm.cpp:820
KCALENDARCORE_EXPORT bool identical(const QDateTime &dt1, const QDateTime &dt2)
Compare two QDateTimes for extended equality.
@ iTIPPublish
Event, to-do, journal or freebusy posting.
QCA_EXPORT void init()
QDate addDays(qint64 ndays) const const
qint64 secsTo(const QDateTime &other) const const
void setDate(QDate date)
void setTime(QTime time)
QString toString(QStringView format, QCalendar cal) const const
iterator begin()
qsizetype count() const const
iterator end()
void reserve(qsizetype size)
QSharedPointer< X > staticCast() const const
bool isValid() const const
Q_D(Todo)
Private class that helps to provide binary compatibility between releases.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:47 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.