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

KDE's Doxygen guidelines are available online.