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

KDE's Doxygen guidelines are available online.