KCalendarCore

incidence.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: 2003-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 Incidence class.
13 
14  @brief
15  Provides the class common to non-FreeBusy (Events, To-dos, Journals)
16  calendar components known as incidences.
17 
18  @author Cornelius Schumacher <[email protected]>
19  @author Reinhold Kainhofer <[email protected]>
20 */
21 
22 #include "incidence.h"
23 #include "calformat.h"
24 #include "utils_p.h"
25 
26 #include <QStringList>
27 #include <QTextDocument> // for .toHtmlEscaped() and Qt::mightBeRichText()
28 #include <QTime>
29 #include <QTimeZone>
30 
31 using namespace KCalendarCore;
32 
33 /**
34  Private class that helps to provide binary compatibility between releases.
35  @internal
36 */
37 //@cond PRIVATE
38 class Q_DECL_HIDDEN KCalendarCore::Incidence::Private
39 {
40 public:
41  Private()
42  : mGeoLatitude(INVALID_LATLON)
43  , mGeoLongitude(INVALID_LATLON)
44  , mRecurrence(nullptr)
45  , mRevision(0)
46  , mPriority(0)
47  , mStatus(StatusNone)
48  , mSecrecy(SecrecyPublic)
49  , mDescriptionIsRich(false)
50  , mSummaryIsRich(false)
51  , mLocationIsRich(false)
52  , mHasGeo(false)
53  , mThisAndFuture(false)
54  , mLocalOnly(false)
55  {
56  }
57 
58  Private(const Private &p)
59  : mCreated(p.mCreated)
60  , mDescription(p.mDescription)
61  , mSummary(p.mSummary)
62  , mLocation(p.mLocation)
63  , mCategories(p.mCategories)
64  , mResources(p.mResources)
65  , mStatusString(p.mStatusString)
66  , mSchedulingID(p.mSchedulingID)
67  , mRelatedToUid(p.mRelatedToUid)
68  , mRecurrenceId(p.mRecurrenceId)
69  , mConferences(p.mConferences)
70  , mGeoLatitude(p.mGeoLatitude)
71  , mGeoLongitude(p.mGeoLongitude)
72  , mRecurrence(nullptr)
73  , mRevision(p.mRevision)
74  , mPriority(p.mPriority)
75  , mStatus(p.mStatus)
76  , mSecrecy(p.mSecrecy)
77  , mColor(p.mColor)
78  , mDescriptionIsRich(p.mDescriptionIsRich)
79  , mSummaryIsRich(p.mSummaryIsRich)
80  , mLocationIsRich(p.mLocationIsRich)
81  , mHasGeo(p.mHasGeo)
82  , mThisAndFuture(p.mThisAndFuture)
83  , mLocalOnly(false)
84  {
85  }
86 
87  void clear()
88  {
89  mAlarms.clear();
90  mAttachments.clear();
91  delete mRecurrence;
92  mRecurrence = nullptr;
93  }
94 
95  void init(Incidence *dest, const Incidence &src)
96  {
97  mRevision = src.d->mRevision;
98  mCreated = src.d->mCreated;
99  mDescription = src.d->mDescription;
100  mSummary = src.d->mSummary;
101  mCategories = src.d->mCategories;
102  mRelatedToUid = src.d->mRelatedToUid;
103  mResources = src.d->mResources;
104  mStatusString = src.d->mStatusString;
105  mStatus = src.d->mStatus;
106  mSecrecy = src.d->mSecrecy;
107  mPriority = src.d->mPriority;
108  mLocation = src.d->mLocation;
109  mGeoLatitude = src.d->mGeoLatitude;
110  mGeoLongitude = src.d->mGeoLongitude;
111  mHasGeo = src.d->mHasGeo;
112  mRecurrenceId = src.d->mRecurrenceId;
113  mConferences = src.d->mConferences;
114  mThisAndFuture = src.d->mThisAndFuture;
115  mLocalOnly = src.d->mLocalOnly;
116 
117  // Alarms and Attachments are stored in ListBase<...>, which is a QValueList<...*>.
118  // We need to really duplicate the objects stored therein, otherwise deleting
119  // i will also delete all attachments from this object (setAutoDelete...)
120  mAlarms.reserve(src.d->mAlarms.count());
121  for (const Alarm::Ptr &alarm : qAsConst(src.d->mAlarms)) {
122  Alarm::Ptr b(new Alarm(*alarm.data()));
123  b->setParent(dest);
124  mAlarms.append(b);
125  }
126 
127  mAttachments = src.d->mAttachments;
128  if (src.d->mRecurrence) {
129  mRecurrence = new Recurrence(*(src.d->mRecurrence));
130  mRecurrence->addObserver(dest);
131  } else {
132  mRecurrence = nullptr;
133  }
134  }
135 
136  QDateTime mCreated; // creation datetime
137  QString mDescription; // description string
138  QString mSummary; // summary string
139  QString mLocation; // location string
140  QStringList mCategories; // category list
141  Attachment::List mAttachments; // attachments list
142  Alarm::List mAlarms; // alarms list
143  QStringList mResources; // resources list (not calendar resources)
144  QString mStatusString; // status string, for custom status
145  QString mSchedulingID; // ID for scheduling mails
146  QMap<RelType, QString> mRelatedToUid; // incidence uid this is related to, for each relType
147  QDateTime mRecurrenceId; // recurrenceId
148  Conference::List mConferences; // conference list
149 
150  float mGeoLatitude; // Specifies latitude in decimal degrees
151  float mGeoLongitude; // Specifies longitude in decimal degrees
152  mutable Recurrence *mRecurrence; // recurrence
153  int mRevision; // revision number
154  int mPriority; // priority: 1 = highest, 2 = less, etc.
155  Status mStatus; // status
156  Secrecy mSecrecy; // secrecy
157  QString mColor; // background color
158  bool mDescriptionIsRich = false; // description string is richtext.
159  bool mSummaryIsRich = false; // summary string is richtext.
160  bool mLocationIsRich = false; // location string is richtext.
161  bool mHasGeo = false; // if incidence has geo data
162  bool mThisAndFuture = false;
163  bool mLocalOnly = false; // allow changes that won't go to the server
164 };
165 //@endcond
166 
168  : IncidenceBase()
169  , d(new KCalendarCore::Incidence::Private)
170 {
171  recreate();
173 }
174 
176  : IncidenceBase(i)
177  , Recurrence::RecurrenceObserver()
178  , d(new KCalendarCore::Incidence::Private(*i.d))
179 {
180  d->init(this, i);
182 }
183 
185 {
186  // Alarm has a raw incidence pointer, so we must set it to 0
187  // so Alarm doesn't use it after Incidence is destroyed
188  for (const Alarm::Ptr &alarm : qAsConst(d->mAlarms)) {
189  alarm->setParent(nullptr);
190  }
191  delete d->mRecurrence;
192  delete d;
193 }
194 
195 //@cond PRIVATE
196 // A string comparison that considers that null and empty are the same
197 static bool stringCompare(const QString &s1, const QString &s2)
198 {
199  return (s1.isEmpty() && s2.isEmpty()) || (s1 == s2);
200 }
201 
202 //@endcond
204 {
205  if (&other != this) {
206  d->clear();
207  // TODO: should relations be cleared out, as in destructor???
208  IncidenceBase::assign(other);
209  const Incidence *i = static_cast<const Incidence *>(&other);
210  d->init(this, *i);
211  }
212 
213  return *this;
214 }
215 
216 bool Incidence::equals(const IncidenceBase &incidence) const
217 {
218  if (!IncidenceBase::equals(incidence)) {
219  return false;
220  }
221 
222  // If they weren't the same type IncidenceBase::equals would had returned false already
223  const Incidence *i2 = static_cast<const Incidence *>(&incidence);
224 
225  const auto alarmList = alarms();
226  const auto otherAlarmsList = i2->alarms();
227  if (alarmList.count() != otherAlarmsList.count()) {
228  return false;
229  }
230 
231  Alarm::List::ConstIterator a1 = alarmList.constBegin();
232  Alarm::List::ConstIterator a1end = alarmList.constEnd();
233  Alarm::List::ConstIterator a2 = otherAlarmsList.constBegin();
234  Alarm::List::ConstIterator a2end = otherAlarmsList.constEnd();
235  for (; a1 != a1end && a2 != a2end; ++a1, ++a2) {
236  if (**a1 == **a2) {
237  continue;
238  } else {
239  return false;
240  }
241  }
242 
243  const auto attachmentList = attachments();
244  const auto otherAttachmentList = i2->attachments();
245  if (attachmentList.count() != otherAttachmentList.count()) {
246  return false;
247  }
248 
249  Attachment::List::ConstIterator att1 = attachmentList.constBegin();
250  const Attachment::List::ConstIterator att1end = attachmentList.constEnd();
251  Attachment::List::ConstIterator att2 = otherAttachmentList.constBegin();
252  const Attachment::List::ConstIterator att2end = otherAttachmentList.constEnd();
253  for (; att1 != att1end && att2 != att2end; ++att1, ++att2) {
254  if (*att1 == *att2) {
255  continue;
256  } else {
257  return false;
258  }
259  }
260 
261  bool recurrenceEqual = (d->mRecurrence == nullptr && i2->d->mRecurrence == nullptr);
262  if (!recurrenceEqual) {
263  recurrence(); // create if doesn't exist
264  i2->recurrence(); // create if doesn't exist
265  recurrenceEqual = d->mRecurrence != nullptr && i2->d->mRecurrence != nullptr && *d->mRecurrence == *i2->d->mRecurrence;
266  }
267 
268  if (d->mHasGeo == i2->d->mHasGeo) {
269  if (d->mHasGeo && (!qFuzzyCompare(d->mGeoLatitude, i2->d->mGeoLatitude) || !qFuzzyCompare(d->mGeoLongitude, i2->d->mGeoLongitude))) {
270  return false;
271  }
272  } else {
273  return false;
274  }
275  // clang-format off
276  return
277  recurrenceEqual
278  && created() == i2->created()
279  && stringCompare(description(), i2->description())
280  && stringCompare(summary(), i2->summary())
281  && categories() == i2->categories()
282  && stringCompare(relatedTo(), i2->relatedTo())
283  && resources() == i2->resources()
284  && d->mStatus == i2->d->mStatus
285  && (d->mStatus == StatusNone || stringCompare(d->mStatusString, i2->d->mStatusString))
286  && secrecy() == i2->secrecy()
287  && priority() == i2->priority()
288  && stringCompare(location(), i2->location())
289  && stringCompare(color(), i2->color())
290  && stringCompare(schedulingID(), i2->schedulingID())
291  && recurrenceId() == i2->recurrenceId()
292  && conferences() == i2->conferences()
293  && thisAndFuture() == i2->thisAndFuture();
294  // clang-format on
295 }
296 
298 {
299  if (hasRecurrenceId()) {
300  return uid() + recurrenceId().toString(Qt::ISODate);
301  }
302  return uid();
303 }
304 
306 {
307  const QDateTime nowUTC = QDateTime::currentDateTimeUtc();
308  setCreated(nowUTC);
309 
311  setRevision(0);
312  setLastModified(nowUTC); // NOLINT false clang-analyzer-optin.cplusplus.VirtualCall
313 }
314 
316 {
317  if (!d->mLocalOnly) {
319  }
320 }
321 
322 void Incidence::setReadOnly(bool readOnly)
323 {
324  IncidenceBase::setReadOnly(readOnly);
325  if (d->mRecurrence) {
326  d->mRecurrence->setRecurReadOnly(readOnly);
327  }
328 }
329 
331 {
332  if (mReadOnly) {
333  return;
334  }
335  d->mLocalOnly = localOnly;
336 }
337 
339 {
340  return d->mLocalOnly;
341 }
342 
344 {
345  if (mReadOnly) {
346  return;
347  }
348  if (d->mRecurrence) {
349  d->mRecurrence->setAllDay(allDay);
350  }
351  IncidenceBase::setAllDay(allDay);
352 }
353 
355 {
356  if (mReadOnly || d->mLocalOnly) {
357  return;
358  }
359 
360  d->mCreated = created.toUTC();
361  const auto ct = d->mCreated.time();
362  // Remove milliseconds
363  d->mCreated.setTime(QTime(ct.hour(), ct.minute(), ct.second()));
365 
366  // FIXME: Shouldn't we call updated for the creation date, too?
367  // updated();
368 }
369 
371 {
372  return d->mCreated;
373 }
374 
376 {
377  if (mReadOnly || d->mLocalOnly) {
378  return;
379  }
380 
381  update();
382 
383  d->mRevision = rev;
385  updated();
386 }
387 
389 {
390  return d->mRevision;
391 }
392 
394 {
396  if (d->mRecurrence && dirtyFields().contains(FieldDtStart)) {
397  d->mRecurrence->setStartDateTime(dt, allDay());
398  }
399 }
400 
401 void Incidence::shiftTimes(const QTimeZone &oldZone, const QTimeZone &newZone)
402 {
403  IncidenceBase::shiftTimes(oldZone, newZone);
404  if (d->mRecurrence) {
405  d->mRecurrence->shiftTimes(oldZone, newZone);
406  }
407  for (int i = 0, end = d->mAlarms.count(); i < end; ++i) {
408  d->mAlarms[i]->shiftTimes(oldZone, newZone);
409  }
410 }
411 
413 {
414  if (mReadOnly) {
415  return;
416  }
417  update();
418  d->mDescription = description;
419  d->mDescriptionIsRich = isRich;
421  updated();
422 }
423 
425 {
426  setDescription(description, Qt::mightBeRichText(description));
427 }
428 
430 {
431  return d->mDescription;
432 }
433 
435 {
436  if (descriptionIsRich()) {
437  return d->mDescription;
438  } else {
439  return d->mDescription.toHtmlEscaped().replace(QLatin1Char('\n'), QStringLiteral("<br/>"));
440  }
441 }
442 
444 {
445  return d->mDescriptionIsRich;
446 }
447 
448 void Incidence::setSummary(const QString &summary, bool isRich)
449 {
450  if (mReadOnly) {
451  return;
452  }
453  if (d->mSummary != summary || d->mSummaryIsRich != isRich) {
454  update();
455  d->mSummary = summary;
456  d->mSummaryIsRich = isRich;
458  updated();
459  }
460 }
461 
463 {
464  setSummary(summary, Qt::mightBeRichText(summary));
465 }
466 
468 {
469  return d->mSummary;
470 }
471 
473 {
474  if (summaryIsRich()) {
475  return d->mSummary;
476  } else {
477  return d->mSummary.toHtmlEscaped().replace(QLatin1Char('\n'), QStringLiteral("<br/>"));
478  }
479 }
480 
482 {
483  return d->mSummaryIsRich;
484 }
485 
487 {
488  if (mReadOnly) {
489  return;
490  }
491 
492  update();
493  d->mCategories = categories;
494  updated();
495 }
496 
498 {
499  if (mReadOnly) {
500  return;
501  }
502  update();
504 
505  d->mCategories.clear();
506 
507  if (catStr.isEmpty()) {
508  updated();
509  return;
510  }
511 
512  d->mCategories = catStr.split(QLatin1Char(','));
513 
515  for (it = d->mCategories.begin(); it != d->mCategories.end(); ++it) {
516  *it = (*it).trimmed();
517  }
518 
519  updated();
520 }
521 
523 {
524  return d->mCategories;
525 }
526 
528 {
529  return d->mCategories.join(QLatin1Char(','));
530 }
531 
532 void Incidence::setRelatedTo(const QString &relatedToUid, RelType relType)
533 {
534  // TODO: RFC says that an incidence can have more than one related-to field
535  // even for the same relType.
536 
537  if (d->mRelatedToUid[relType] != relatedToUid) {
538  update();
539  d->mRelatedToUid[relType] = relatedToUid;
541  updated();
542  }
543 }
544 
546 {
547  return d->mRelatedToUid.value(relType);
548 }
549 
550 void Incidence::setColor(const QString &colorName)
551 {
552  if (mReadOnly) {
553  return;
554  }
555  if (!stringCompare(d->mColor, colorName)) {
556  update();
557  d->mColor = colorName;
559  updated();
560  }
561 }
562 
564 {
565  return d->mColor;
566 }
567 
568 // %%%%%%%%%%%% Recurrence-related methods %%%%%%%%%%%%%%%%%%%%
569 
571 {
572  if (!d->mRecurrence) {
573  d->mRecurrence = new Recurrence();
574  d->mRecurrence->setStartDateTime(dateTime(RoleRecurrenceStart), allDay());
575  d->mRecurrence->setAllDay(allDay());
576  d->mRecurrence->setRecurReadOnly(mReadOnly);
577  d->mRecurrence->addObserver(const_cast<KCalendarCore::Incidence *>(this));
578  }
579 
580  return d->mRecurrence;
581 }
582 
584 {
585  delete d->mRecurrence;
586  d->mRecurrence = nullptr;
587 }
588 
590 {
591  if (d->mRecurrence) {
592  return d->mRecurrence->recurrenceType();
593  } else {
594  return Recurrence::rNone;
595  }
596 }
597 
598 bool Incidence::recurs() const
599 {
600  if (d->mRecurrence) {
601  return d->mRecurrence->recurs();
602  } else {
603  return false;
604  }
605 }
606 
607 bool Incidence::recursOn(const QDate &date, const QTimeZone &timeZone) const
608 {
609  return d->mRecurrence && d->mRecurrence->recursOn(date, timeZone);
610 }
611 
612 bool Incidence::recursAt(const QDateTime &qdt) const
613 {
614  return d->mRecurrence && d->mRecurrence->recursAt(qdt);
615 }
616 
618 {
619  QDateTime start = dtStart();
620  QDateTime end = dateTime(RoleEndRecurrenceBase);
621 
622  QList<QDateTime> result;
623 
624  // TODO_Recurrence: Also work if only due date is given...
625  if (!start.isValid() && !end.isValid()) {
626  return result;
627  }
628 
629  // if the incidence doesn't recur,
630  QDateTime kdate(date, {}, timeZone);
631  if (!recurs()) {
632  if (!(start > kdate || end < kdate)) {
633  result << start;
634  }
635  return result;
636  }
637 
638  qint64 days = start.daysTo(end);
639  // Account for possible recurrences going over midnight, while the original event doesn't
640  QDate tmpday(date.addDays(-days - 1));
641  QDateTime tmp;
642  while (tmpday <= date) {
643  if (recurrence()->recursOn(tmpday, timeZone)) {
644  const QList<QTime> times = recurrence()->recurTimesOn(tmpday, timeZone);
645  for (const QTime &time : times) {
646  tmp = QDateTime(tmpday, time, start.timeZone());
647  if (endDateForStart(tmp) >= kdate) {
648  result << tmp;
649  }
650  }
651  }
652  tmpday = tmpday.addDays(1);
653  }
654  return result;
655 }
656 
658 {
659  QDateTime start = dtStart();
660  QDateTime end = dateTime(RoleEndRecurrenceBase);
661 
662  QList<QDateTime> result;
663 
664  // TODO_Recurrence: Also work if only due date is given...
665  if (!start.isValid() && !end.isValid()) {
666  return result;
667  }
668 
669  // if the incidence doesn't recur,
670  if (!recurs()) {
671  if (!(start > datetime || end < datetime)) {
672  result << start;
673  }
674  return result;
675  }
676 
677  qint64 days = start.daysTo(end);
678  // Account for possible recurrences going over midnight, while the original event doesn't
679  QDate tmpday(datetime.date().addDays(-days - 1));
680  QDateTime tmp;
681  while (tmpday <= datetime.date()) {
682  if (recurrence()->recursOn(tmpday, datetime.timeZone())) {
683  // Get the times during the day (in start date's time zone) when recurrences happen
684  const QList<QTime> times = recurrence()->recurTimesOn(tmpday, start.timeZone());
685  for (const QTime &time : times) {
686  tmp = QDateTime(tmpday, time, start.timeZone());
687  if (!(tmp > datetime || endDateForStart(tmp) < datetime)) {
688  result << tmp;
689  }
690  }
691  }
692  tmpday = tmpday.addDays(1);
693  }
694  return result;
695 }
696 
698 {
699  QDateTime start = dtStart();
700  QDateTime end = dateTime(RoleEndRecurrenceBase);
701  if (!end.isValid()) {
702  return start;
703  }
704  if (!start.isValid()) {
705  return end;
706  }
707 
708  return startDt.addSecs(start.secsTo(end));
709 }
710 
711 void Incidence::addAttachment(const Attachment &attachment)
712 {
713  if (mReadOnly || attachment.isEmpty()) {
714  return;
715  }
716 
717  update();
718  d->mAttachments.append(attachment);
720  updated();
721 }
722 
724 {
725  Attachment::List result;
726  Attachment::List::Iterator it = d->mAttachments.begin();
727  while (it != d->mAttachments.end()) {
728  if ((*it).mimeType() != mime) {
729  result += *it;
730  }
731  ++it;
732  }
733  d->mAttachments = result;
735 }
736 
738 {
739  return d->mAttachments;
740 }
741 
743 {
745  for (const Attachment &attachment : qAsConst(d->mAttachments)) {
746  if (attachment.mimeType() == mime) {
747  attachments.append(attachment);
748  }
749  }
750  return attachments;
751 }
752 
754 {
756  d->mAttachments.clear();
757 }
758 
760 {
761  if (mReadOnly) {
762  return;
763  }
764 
765  update();
766  d->mResources = resources;
768  updated();
769 }
770 
772 {
773  return d->mResources;
774 }
775 
777 {
778  if (mReadOnly) {
779  return;
780  }
781 
782  update();
783  d->mPriority = priority;
785  updated();
786 }
787 
788 int Incidence::priority() const
789 {
790  return d->mPriority;
791 }
792 
794 {
795  if (mReadOnly || status == StatusX) {
796  return;
797  }
798 
799  update();
800  d->mStatus = status;
801  d->mStatusString.clear();
803  updated();
804 }
805 
807 {
808  if (mReadOnly) {
809  return;
810  }
811 
812  update();
813  d->mStatus = status.isEmpty() ? StatusNone : StatusX;
814  d->mStatusString = status;
816  updated();
817 }
818 
820 {
821  return d->mStatus;
822 }
823 
825 {
826  if (d->mStatus == StatusX) {
827  return d->mStatusString;
828  } else {
829  return QString();
830  }
831 }
832 
834 {
835  if (mReadOnly) {
836  return;
837  }
838 
839  update();
840  d->mSecrecy = secrecy;
842  updated();
843 }
844 
846 {
847  return d->mSecrecy;
848 }
849 
851 {
852  return d->mAlarms;
853 }
854 
856 {
857  Alarm::Ptr alarm(new Alarm(this));
858  d->mAlarms.append(alarm);
859  return alarm;
860 }
861 
862 void Incidence::addAlarm(const Alarm::Ptr &alarm)
863 {
864  update();
865  d->mAlarms.append(alarm);
867  updated();
868 }
869 
871 {
872  const int index = d->mAlarms.indexOf(alarm);
873  if (index > -1) {
874  update();
875  d->mAlarms.remove(index);
877  updated();
878  }
879 }
880 
882 {
883  update();
884  d->mAlarms.clear();
886  updated();
887 }
888 
890 {
891  for (const Alarm::Ptr &alarm : qAsConst(d->mAlarms)) {
892  if (alarm->enabled()) {
893  return true;
894  }
895  }
896  return false;
897 }
898 
900 {
901  return d->mConferences;
902 }
903 
904 void Incidence::addConference(const Conference &conference)
905 {
906  update();
907  d->mConferences.push_back(conference);
909  updated();
910 }
911 
913 {
914  update();
915  d->mConferences = conferences;
917  updated();
918 }
919 
921 {
922  update();
923  d->mConferences.clear();
925  updated();
926 }
927 
928 void Incidence::setLocation(const QString &location, bool isRich)
929 {
930  if (mReadOnly) {
931  return;
932  }
933 
934  if (d->mLocation != location || d->mLocationIsRich != isRich) {
935  update();
936  d->mLocation = location;
937  d->mLocationIsRich = isRich;
939  updated();
940  }
941 }
942 
944 {
945  setLocation(location, Qt::mightBeRichText(location));
946 }
947 
949 {
950  return d->mLocation;
951 }
952 
954 {
955  if (locationIsRich()) {
956  return d->mLocation;
957  } else {
958  return d->mLocation.toHtmlEscaped().replace(QLatin1Char('\n'), QStringLiteral("<br/>"));
959  }
960 }
961 
963 {
964  return d->mLocationIsRich;
965 }
966 
968 {
969  if (!uid.isEmpty()) {
970  setUid(uid);
971  }
972  if (sid != d->mSchedulingID) {
973  d->mSchedulingID = sid;
975  }
976 }
977 
979 {
980  if (d->mSchedulingID.isNull()) {
981  // Nothing set, so use the normal uid
982  return uid();
983  }
984  return d->mSchedulingID;
985 }
986 
987 bool Incidence::hasGeo() const
988 {
989  return d->mHasGeo;
990 }
991 
993 {
994  if (mReadOnly) {
995  return;
996  }
997 
998  if (hasGeo == d->mHasGeo) {
999  return;
1000  }
1001 
1002  update();
1003  d->mHasGeo = hasGeo;
1006  updated();
1007 }
1008 
1009 float Incidence::geoLatitude() const
1010 {
1011  return d->mGeoLatitude;
1012 }
1013 
1014 void Incidence::setGeoLatitude(float geolatitude)
1015 {
1016  if (mReadOnly) {
1017  return;
1018  }
1019 
1020  update();
1021  d->mGeoLatitude = geolatitude;
1023  updated();
1024 }
1025 
1026 float Incidence::geoLongitude() const
1027 {
1028  return d->mGeoLongitude;
1029 }
1030 
1031 void Incidence::setGeoLongitude(float geolongitude)
1032 {
1033  if (!mReadOnly) {
1034  update();
1035  d->mGeoLongitude = geolongitude;
1037  updated();
1038  }
1039 }
1040 
1042 {
1043  return (allDay() && d->mRecurrenceId.date().isValid()) || d->mRecurrenceId.isValid();
1044 }
1045 
1047 {
1048  return d->mRecurrenceId;
1049 }
1050 
1052 {
1053  d->mThisAndFuture = thisAndFuture;
1054 }
1055 
1057 {
1058  return d->mThisAndFuture;
1059 }
1060 
1062 {
1063  if (!mReadOnly) {
1064  update();
1065  d->mRecurrenceId = recurrenceId;
1067  updated();
1068  }
1069 }
1070 
1071 /** Observer interface for the recurrence class. If the recurrence is changed,
1072  this method will be called for the incidence the recurrence object
1073  belongs to. */
1075 {
1076  if (recurrence == d->mRecurrence) {
1077  update();
1079  updated();
1080  }
1081 }
1082 
1083 //@cond PRIVATE
1084 #define ALT_DESC_FIELD "X-ALT-DESC"
1085 #define ALT_DESC_PARAMETERS QStringLiteral("FMTTYPE=text/html")
1086 //@endcond
1087 
1089 {
1090  const QString value = nonKDECustomProperty(ALT_DESC_FIELD);
1091  const QString parameter = nonKDECustomPropertyParameters(ALT_DESC_FIELD);
1092 
1093  return parameter == ALT_DESC_PARAMETERS && !value.isEmpty();
1094 }
1095 
1096 void Incidence::setAltDescription(const QString &altdescription)
1097 {
1098  if (altdescription.isEmpty()) {
1099  removeNonKDECustomProperty(ALT_DESC_FIELD);
1100  } else {
1101  setNonKDECustomProperty(ALT_DESC_FIELD, altdescription, ALT_DESC_PARAMETERS);
1102  }
1103 }
1104 
1106 {
1107  if (!hasAltDescription()) {
1108  return QString();
1109  } else {
1110  return nonKDECustomProperty(ALT_DESC_FIELD);
1111  }
1112 }
1113 
1114 /** static */
1116 {
1117  return QStringList() << QStringLiteral("text/calendar") << KCalendarCore::Event::eventMimeType() << KCalendarCore::Todo::todoMimeType()
1119 }
1120 
1122 {
1123  serializeQDateTimeAsKDateTime(out, d->mCreated);
1124  out << d->mRevision << d->mDescription << d->mDescriptionIsRich << d->mSummary << d->mSummaryIsRich << d->mLocation << d->mLocationIsRich << d->mCategories
1125  << d->mResources << d->mStatusString << d->mPriority << d->mSchedulingID << d->mGeoLatitude << d->mGeoLongitude << d->mHasGeo;
1126  serializeQDateTimeAsKDateTime(out, d->mRecurrenceId);
1127  out << d->mThisAndFuture << d->mLocalOnly << d->mStatus << d->mSecrecy << (d->mRecurrence ? true : false) << d->mAttachments.count() << d->mAlarms.count()
1128  << d->mConferences.count() << d->mRelatedToUid;
1129 
1130  if (d->mRecurrence) {
1131  out << d->mRecurrence;
1132  }
1133 
1134  for (const Attachment &attachment : qAsConst(d->mAttachments)) {
1135  out << attachment;
1136  }
1137 
1138  for (const Alarm::Ptr &alarm : qAsConst(d->mAlarms)) {
1139  out << alarm;
1140  }
1141 
1142  for (const Conference &conf : qAsConst(d->mConferences)) {
1143  out << conf;
1144  }
1145 }
1146 
1148 {
1149  quint32 status, secrecy;
1150  bool hasRecurrence;
1151  int attachmentCount, alarmCount, conferencesCount;
1152  QMap<int, QString> relatedToUid;
1153  deserializeKDateTimeAsQDateTime(in, d->mCreated);
1154  in >> d->mRevision >> d->mDescription >> d->mDescriptionIsRich >> d->mSummary >> d->mSummaryIsRich >> d->mLocation >> d->mLocationIsRich >> d->mCategories
1155  >> d->mResources >> d->mStatusString >> d->mPriority >> d->mSchedulingID >> d->mGeoLatitude >> d->mGeoLongitude >> d->mHasGeo;
1156  deserializeKDateTimeAsQDateTime(in, d->mRecurrenceId);
1157  in >> d->mThisAndFuture >> d->mLocalOnly >> status >> secrecy >> hasRecurrence >> attachmentCount >> alarmCount >> conferencesCount >> relatedToUid;
1158 
1159  if (hasRecurrence) {
1160  d->mRecurrence = new Recurrence();
1161  d->mRecurrence->addObserver(const_cast<KCalendarCore::Incidence *>(this));
1162  in >> d->mRecurrence;
1163  }
1164 
1165  d->mAttachments.clear();
1166  d->mAlarms.clear();
1167  d->mConferences.clear();
1168 
1169  d->mAttachments.reserve(attachmentCount);
1170  for (int i = 0; i < attachmentCount; ++i) {
1171  Attachment attachment;
1172  in >> attachment;
1173  d->mAttachments.append(attachment);
1174  }
1175 
1176  d->mAlarms.reserve(alarmCount);
1177  for (int i = 0; i < alarmCount; ++i) {
1178  Alarm::Ptr alarm = Alarm::Ptr(new Alarm(this));
1179  in >> alarm;
1180  d->mAlarms.append(alarm);
1181  }
1182 
1183  d->mConferences.reserve(conferencesCount);
1184  for (int i = 0; i < conferencesCount; ++i) {
1185  Conference conf;
1186  in >> conf;
1187  d->mConferences.push_back(conf);
1188  }
1189 
1190  d->mStatus = static_cast<Incidence::Status>(status);
1191  d->mSecrecy = static_cast<Incidence::Secrecy>(secrecy);
1192 
1193  d->mRelatedToUid.clear();
1194 
1195  auto it = relatedToUid.cbegin(), end = relatedToUid.cend();
1196  for (; it != end; ++it) {
1197  d->mRelatedToUid.insert(static_cast<Incidence::RelType>(it.key()), it.value());
1198  }
1199 }
1200 
1201 namespace
1202 {
1203 template<typename T>
1204 QVariantList toVariantList(int size, typename QVector<T>::ConstIterator begin, typename QVector<T>::ConstIterator end)
1205 {
1206  QVariantList l;
1207  l.reserve(size);
1208  std::transform(begin, end, std::back_inserter(l), [](const T &val) {
1209  return QVariant::fromValue(val);
1210  });
1211  return l;
1212 }
1213 
1214 } // namespace
1215 
1216 QVariantList Incidence::attachmentsVariant() const
1217 {
1218  return toVariantList<Attachment>(d->mAttachments.size(), d->mAttachments.cbegin(), d->mAttachments.cend());
1219 }
1220 
1221 QVariantList Incidence::conferencesVariant() const
1222 {
1223  return toVariantList<Conference>(d->mConferences.size(), d->mConferences.cbegin(), d->mConferences.cend());
1224 }
QStringList resources() const
Returns the incidence resources as a list of strings.
Definition: incidence.cpp:771
Represents an alarm notification.
Definition: alarm.h:50
float geoLongitude() const
Returns the incidence geoLongitude.
Secrecy secrecy() const
Returns the incidence Secrecy.
static QStringList mimeTypes()
Returns the list of possible mime types in an Incidence object: "text/calendar" "application/x-vnd.akonadi.calendar.event" "application/x-vnd.akonadi.calendar.todo" "application/x-vnd.akonadi.calendar.journal".
Definition: incidence.cpp:1115
Secrecy
The different types of incidence access classifications.
Definition: incidence.h:94
QString toString(Qt::DateFormat format) const const
void setRecurrenceId(const QDateTime &recurrenceId)
Set the incidences recurrenceId.
Definition: incidence.cpp:1061
void setNonKDECustomProperty(const QByteArray &name, const QString &value, const QString &parameters=QString())
Create or modify a non-KDE or non-standard custom calendar property.
bool hasRecurrenceId() const
Returns true if the incidence has recurrenceId, otherwise return false.
Definition: incidence.cpp:1041
typedef Iterator
QString categoriesStr() const
Returns the incidence categories as a comma separated string.
Definition: incidence.cpp:527
Field representing the CREATED component.
Alarm::List alarms() const
Returns a list of all incidence alarms.
Definition: incidence.cpp:850
void setColor(const QString &colorName)
Set the incidence color, as added in RFC7986.
Definition: incidence.cpp:550
void addConference(const Conference &conference)
Adds a conference to the incidence.
Definition: incidence.cpp:904
QDateTime toUTC() const const
virtual IncidenceBase & assign(const IncidenceBase &other)
Provides polymorfic assignment.
virtual void setLastModified(const QDateTime &lm)
Sets the time the incidence was last modified to lm.
void update()
Call this to notify the observers after the IncidenceBase object will be changed. ...
void serialize(QDataStream &out) const override
Sub-type specific serialization.
Definition: incidence.cpp:1121
void append(const T &value)
virtual QList< QDateTime > startDateTimesForDateTime(const QDateTime &datetime) const
Calculates the start date/time for all recurrences that happen at the given time. ...
Definition: incidence.cpp:657
Incidence()
Constructs an empty incidence.
Definition: incidence.cpp:167
virtual bool recursOn(const QDate &date, const QTimeZone &timeZone) const
Returns true if the date specified is one on which the event will recur.
Definition: incidence.cpp:607
QString richSummary() const
Returns the incidence summary in rich text format.
Definition: incidence.cpp:472
bool hasEnabledAlarms() const
Returns true if any of the incidence alarms are enabled; false otherwise.
Definition: incidence.cpp:889
RelType
The different types of RELTYPE values specified by the RFC.
Definition: incidence.h:105
qint64 daysTo(const QDateTime &other) const const
Status status() const
Returns the incidence Status.
void setSummary(const QString &summary, bool isRich)
Sets the incidence summary.
Definition: incidence.cpp:448
bool recursOn(const QDate &date, const QTimeZone &timeZone) const
Returns true if the date specified is one on which the event will recur.
Definition: recurrence.cpp:315
static QString createUniqueId()
Creates a unique id string.
Definition: calformat.cpp:105
bool recurs() const
Returns whether the event recurs at all.
Definition: incidence.cpp:598
QString richDescription() const
Returns the incidence description in rich text format.
Definition: incidence.cpp:434
bool locationIsRich() const
Returns true if incidence location contains RichText; false otherwise.
Definition: incidence.cpp:962
void setStatus(Status status)
Sets the incidence status to a standard Status value.
Definition: incidence.cpp:793
void addAttachment(const Attachment &attachment)
Adds an attachment to the incidence.
Definition: incidence.cpp:711
Field representing the EXDATE, EXRULE, RDATE, and RRULE components.
void removeAlarm(const Alarm::Ptr &alarm)
Removes the specified alarm from the incidence.
Definition: incidence.cpp:870
QString relatedTo(RelType relType=RelTypeParent) const
Returns a UID string for the incidence that is related to this one.
Definition: incidence.cpp:545
static QLatin1String eventMimeType()
Returns the Akonadi specific sub MIME type of a KCalendarCore::Event.
Definition: event.cpp:296
static QLatin1String journalMimeType()
Returns the Akonadi specific sub MIME type of a KCalendarCore::Journal.
Definition: journal.cpp:103
QTime time() const const
Field representing the PRIORITY component.
virtual bool equals(const IncidenceBase &incidenceBase) const
Provides polymorfic comparison for equality.
Field representing the STATUS component.
typedef ConstIterator
Field representing the RECURRENCE-ID component.
TimeList recurTimesOn(const QDate &date, const QTimeZone &timeZone) const
Returns a list of the times on the specified date at which the recurrence will occur.
Definition: recurrence.cpp:977
void recreate()
Recreate incidence.
Definition: incidence.cpp:305
QString nonKDECustomProperty(const QByteArray &name) const
Return the value of a non-KDE or non-standard custom calendar property.
bool mightBeRichText(const QString &text)
~Incidence() override
Destroys an incidence.
Definition: incidence.cpp:184
void clearAlarms()
Removes all alarms.
Definition: incidence.cpp:881
void setCreated(const QDateTime &dt)
Sets the incidence creation date/time.
Definition: incidence.cpp:354
This file is part of the API for handling calendar data and defines the CalFormat abstract base class...
Role for determining the start of the recurrence.
Represents information related to a conference information of an Calendar Incidence, typically a meeting or task (to-do).
Definition: conference.h:31
void setRevision(int rev)
Sets the number of revisions this incidence has seen.
Definition: incidence.cpp:375
void setSecrecy(Secrecy secrecy)
Sets the incidence Secrecy.
Definition: incidence.cpp:833
An abstract class that provides a common base for all calendar incidence classes. ...
Definition: incidencebase.h:97
Conference::List conferences() const
Returns list of all incidence conferencing methods.
virtual void setReadOnly(bool readOnly)
Sets readonly status.
virtual QList< QDateTime > startDateTimesForDate(const QDate &date, const QTimeZone &timeZone) const
Calculates the start date/time for all recurrences that happen at some time on the given date (might ...
Definition: incidence.cpp:617
QStringList categories() const
Returns the incidence categories as a list of strings.
Field representing the X-KDE-LIBKCAL-ID component.
void setAllDay(bool allDay) override
Definition: incidence.cpp:343
bool hasGeo() const
Returns true if the incidence has geo data, otherwise return false.
void clearRecurrence()
Removes all recurrence and exception rules and dates.
Definition: incidence.cpp:583
void setAltDescription(const QString &altdescription)
Sets the incidence&#39;s alternative (=text/html) description.
Definition: incidence.cpp:1096
void removeNonKDECustomProperty(const QByteArray &name)
Delete a non-KDE or non-standard custom calendar property.
void setThisAndFuture(bool thisAndFuture)
Set to true if the exception also applies to all future occurrences.
Definition: incidence.cpp:1051
virtual void setDtStart(const QDateTime &dtStart)
Sets the incidence&#39;s starting date/time with a QDateTime.
Field representing the CATEGORIES component.
void setGeoLatitude(float geolatitude)
Set the incidences geoLatitude.
Definition: incidence.cpp:1014
Alarm::Ptr newAlarm()
Create a new incidence alarm.
Definition: incidence.cpp:855
void clearAttachments()
Removes all attachments and frees the memory used by them.
Definition: incidence.cpp:753
bool isEmpty() const const
QString customStatus() const
Returns the non-standard status value.
Definition: incidence.cpp:824
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...
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
void shiftTimes(const QTimeZone &oldZone, const QTimeZone &newZone) override
Shift the times of the incidence so that they appear at the same clock time as before but in a new ti...
Definition: incidence.cpp:401
bool recursAt(const QDateTime &dt) const
Returns true if the date/time specified is one at which the event will recur.
Definition: incidence.cpp:612
void setCustomStatus(const QString &status)
Sets the incidence Status to a non-standard status value.
Definition: incidence.cpp:806
QString location() const
Returns the incidence location.
typedef Iterator
void setConferences(const Conference::List &conferences)
Replaces all conferences in the incidence with given conferences.
Definition: incidence.cpp:912
Represents information related to an attachment for a Calendar Incidence.
Definition: attachment.h:46
void setUid(const QString &uid)
Sets the unique id for the incidence to uid.
virtual QDateTime dateTime(DateTimeRole role) const =0
Returns a date/time corresponding to the specified DateTimeRole.
void setLocalOnly(bool localonly)
Set localOnly state of incidence.
Definition: incidence.cpp:330
QString richLocation() const
Returns the incidence location in rich text format.
Definition: incidence.cpp:953
void setDtStart(const QDateTime &dt) override
Sets the incidence starting date/time.
Definition: incidence.cpp:393
Field representing the RESOURCES component.
QSet< IncidenceBase::Field > dirtyFields() const
Returns a QSet with all Fields that were changed since the incidence was created or resetDirtyFields(...
bool localOnly() const
Get the localOnly status.
Definition: incidence.cpp:338
QString schedulingID() const
Returns the incidence scheduling ID.
Definition: incidence.cpp:978
Field representing the longitude part of the GEO component.
float geoLatitude() const
Returns the incidence geoLatidude.
void setLocation(const QString &location, bool isRich)
Sets the incidence location.
Definition: incidence.cpp:928
static QLatin1String todoMimeType()
Returns the Akonadi specific sub MIME type of a KCalendarCore::Todo.
Definition: todo.cpp:510
void setGeoLongitude(float geolongitude)
Set the incidencesgeoLongitude.
Definition: incidence.cpp:1031
QString toHtmlEscaped() const const
bool descriptionIsRich() const
Returns true if incidence description contains RichText; false otherwise.
Definition: incidence.cpp:443
void updated()
Call this to notify the observers after the IncidenceBase object has changed.
void recurrenceUpdated(Recurrence *recurrence) override
Observer interface for the recurrence class.
Definition: incidence.cpp:1074
QVariant fromValue(const T &value)
QCA_EXPORT void init()
bool isValid() const const
void setCategories(const QStringList &categories)
Sets the incidence category list.
Definition: incidence.cpp:486
Field representing the DTSTART component.
QString & replace(int position, int n, QChar after)
void setSchedulingID(const QString &sid, const QString &uid=QString())
Set the incidence scheduling ID.
Definition: incidence.cpp:967
Recurrence * recurrence() const
Returns the recurrence rule associated with this incidence.
Definition: incidence.cpp:570
Field representing the LOCATION component.
int priority() const
Returns the incidence priority.
void setDescription(const QString &description, bool isRich)
Sets the incidence description.
Definition: incidence.cpp:412
This class represents a recurrence rule for a calendar incidence.
Definition: recurrence.h:75
QDate date() const const
void setFieldDirty(IncidenceBase::Field field)
Marks Field field as dirty.
QString color() const
Returns the color, if any is defined, for this incidence.
Definition: incidence.cpp:563
Field representing the COLOR component.
void setRelatedTo(const QString &uid, RelType relType=RelTypeParent)
Relates another incidence to this one, by UID.
Definition: incidence.cpp:532
Attachment::List attachments() const
Returns a list of all incidence attachments.
Field representing the ATTACH component.
qint64 secsTo(const QDateTime &other) const const
This file is part of the API for handling calendar data and defines the Incidence class...
QString instanceIdentifier() const
Returns a unique identifier for a specific instance of an incidence.
Definition: incidence.cpp:297
Field representing the RELATED-TO component.
void deserialize(QDataStream &in) override
Sub-type specific deserialization.
Definition: incidence.cpp:1147
QDateTime recurrenceId() const override
Returns the incidence recurrenceId.
Definition: incidence.cpp:1046
bool allDay() const
Returns true or false depending on whether the incidence is all-day.
void setResources(const QStringList &resources)
Sets a list of incidence resources.
Definition: incidence.cpp:759
Field representing the DESCRIPTION component.
bool hasAltDescription() const
Returns true if the alternative (=text/html) description is available.
Definition: incidence.cpp:1088
Field representing the latitude part of the GEO component.
void addAlarm(const Alarm::Ptr &alarm)
Adds an alarm to the incidence.
Definition: incidence.cpp:862
Field representing the VALARM component.
QDateTime created() const
Returns the incidence creation date/time.
void clearConferences()
Removes all conferences from the incidence.
Definition: incidence.cpp:920
Field representing the CLASS component.
void setReadOnly(bool readonly) override
Set readonly state of incidence.
Definition: incidence.cpp:322
virtual QDateTime endDateForStart(const QDateTime &startDt) const
Returns the end date/time of the incidence occurrence if it starts at specified date/time.
Definition: incidence.cpp:697
void resetDirtyFields()
Resets dirty fields.
QDate addDays(qint64 ndays) const const
virtual void setAllDay(bool allDay)
Sets whether the incidence is all-day, i.e.
QString description() const
Returns the incidence description.
virtual QDateTime dtStart() const
Returns an incidence&#39;s starting date/time as a QDateTime.
Field representing the SEQUENCE component.
Status
The different types of overall incidence status or confirmation.
Definition: incidence.h:77
bool thisAndFuture() const
Returns true if the exception also applies to all future occurrences.
Definition: incidence.cpp:1056
QDateTime addSecs(qint64 s) const const
Provides the abstract base class common to non-FreeBusy (Events, To-dos, Journals) calendar component...
Definition: incidence.h:56
bool summaryIsRich() const
Returns true if incidence summary contains RichText; false otherwise.
Definition: incidence.cpp:481
ushort recurrenceType() const
Returns the event&#39;s recurrence status.
Definition: incidence.cpp:589
QString altDescription() const
Returns the incidence alternative (=text/html) description.
Definition: incidence.cpp:1105
IncidenceBase & assign(const IncidenceBase &other) override
Provides polymorfic assignment.
Definition: incidence.cpp:203
Field representing the CONFERENCE component.
a non-standard status string
Definition: incidence.h:87
int revision() const
Returns the number of revisions this incidence has seen.
Definition: incidence.cpp:388
void deleteAttachments(const QString &mime)
Removes all attachments of the specified MIME type from the incidence.
Definition: incidence.cpp:723
QDateTime currentDateTimeUtc()
QString nonKDECustomPropertyParameters(const QByteArray &name) const
Return the parameters of a non-KDE or non-standard custom calendar property.
Field representing the SUMMARY component.
void setHasGeo(bool hasGeo)
Sets if the incidence has geo data.
Definition: incidence.cpp:992
QSharedPointer< Alarm > Ptr
A shared pointer to an Alarm object.
Definition: alarm.h:67
bool equals(const IncidenceBase &incidence) const override
Compares this with Incidence incidence for equality.
Definition: incidence.cpp:216
void setLastModified(const QDateTime &lm) override
Definition: incidence.cpp:315
Namespace for all KCalendarCore types.
Definition: alarm.h:36
QString uid() const
Returns the unique id (uid) for the incidence.
QTimeZone timeZone() const const
void setPriority(int priority)
Sets the incidences priority.
Definition: incidence.cpp:776
QString summary() const
Returns the incidence summary.
bool mReadOnly
Identifies a read-only incidence.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Fri Apr 16 2021 22:50:49 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.