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

KDE's Doxygen guidelines are available online.