1 /*
2   This file is part of the kcalcore library.
3 
4   SPDX-FileCopyrightText: 1998 Preston Brown <pbrown@kde.org>
5   SPDX-FileCopyrightText: 2001 Cornelius Schumacher <schumacher@kde.org>
6   SPDX-FileCopyrightText: 2003 David Jarvie <djarvie@kde.org>
7 
8   SPDX-License-Identifier: LGPL-2.0-or-later
9 */
10 /**
11   @file
12   This file is part of the API for handling calendar data and
13   defines the Alarm class.
14 
15   @brief
16   Represents an alarm notification.
17 
18   @author Cornelius Schumacher \<schumacher@kde.org\>
19 */
20 #include "alarm.h"
21 #include "incidence.h"
22 #include "utils_p.h"
23 
24 #include <QTime>
25 #include <QTimeZone>
26 
27 using namespace KCalendarCore;
28 
29 /**
30   Private class that helps to provide binary compatibility between releases.
31   @internal
32 */
33 //@cond PRIVATE
34 class Q_DECL_HIDDEN KCalendarCore::Alarm::Private
35 {
36 public:
Private()37     Private()
38         : mParent(nullptr)
39         , mType(Alarm::Invalid)
40         , mAlarmSnoozeTime(5)
41         , mAlarmRepeatCount(0)
42         , mEndOffset(false)
43         , mHasTime(false)
44         , mAlarmEnabled(false)
45         , mHasLocationRadius(false)
46         , mLocationRadius(0)
47     {
48     }
49 
50     Incidence *mParent = nullptr; // the incidence which this alarm belongs to
51 
52     Type mType; // type of alarm
53     QString mDescription; // text to display/email body/procedure arguments
54     QString mFile; // program to run/optional audio file to play
55     QString mMailSubject; // subject of email
56     QStringList mMailAttachFiles; // filenames to attach to email
57     Person::List mMailAddresses; // who to mail for reminder
58 
59     QDateTime mAlarmTime; // time at which to trigger the alarm
60     Duration mAlarmSnoozeTime; // how long after alarm to snooze before
61     // triggering again
62     int mAlarmRepeatCount; // number of times for alarm to repeat
63     // after the initial time
64 
65     Duration mOffset; // time relative to incidence DTSTART
66     // to trigger the alarm
67     bool mEndOffset; // if true, mOffset relates to DTEND, not DTSTART
68     bool mHasTime; // use mAlarmTime, not mOffset
69     bool mAlarmEnabled;
70 
71     bool mHasLocationRadius;
72     int mLocationRadius; // location radius for the alarm
73 };
74 //@endcond
75 
Alarm(Incidence * parent)76 Alarm::Alarm(Incidence *parent)
77     : d(new KCalendarCore::Alarm::Private)
78 {
79     d->mParent = parent;
80 }
81 
Alarm(const Alarm & other)82 Alarm::Alarm(const Alarm &other)
83     : CustomProperties(other)
84     , d(new KCalendarCore::Alarm::Private(*other.d))
85 {
86 }
87 
~Alarm()88 Alarm::~Alarm()
89 {
90     delete d;
91 }
92 
operator =(const Alarm & a)93 Alarm &Alarm::operator=(const Alarm &a)
94 {
95     if (&a != this) {
96         d->mParent = a.d->mParent;
97         d->mType = a.d->mType;
98         d->mDescription = a.d->mDescription;
99         d->mFile = a.d->mFile;
100         d->mMailAttachFiles = a.d->mMailAttachFiles;
101         d->mMailAddresses = a.d->mMailAddresses;
102         d->mMailSubject = a.d->mMailSubject;
103         d->mAlarmSnoozeTime = a.d->mAlarmSnoozeTime;
104         d->mAlarmRepeatCount = a.d->mAlarmRepeatCount;
105         d->mAlarmTime = a.d->mAlarmTime;
106         d->mOffset = a.d->mOffset;
107         d->mEndOffset = a.d->mEndOffset;
108         d->mHasTime = a.d->mHasTime;
109         d->mAlarmEnabled = a.d->mAlarmEnabled;
110     }
111 
112     return *this;
113 }
114 
compareMailAddresses(const Person::List & list1,const Person::List & list2)115 static bool compareMailAddresses(const Person::List &list1, const Person::List &list2)
116 {
117     if (list1.count() == list2.count()) {
118         for (int i = 0; i < list1.count(); ++i) {
119             if (list1.at(i) != list2.at(i)) {
120                 return false;
121             }
122         }
123         return true;
124     }
125 
126     return false;
127 }
128 
operator ==(const Alarm & rhs) const129 bool Alarm::operator==(const Alarm &rhs) const
130 {
131     if (d->mType != rhs.d->mType //
132         || d->mAlarmSnoozeTime != rhs.d->mAlarmSnoozeTime //
133         || d->mAlarmRepeatCount != rhs.d->mAlarmRepeatCount //
134         || d->mAlarmEnabled != rhs.d->mAlarmEnabled //
135         || d->mHasTime != rhs.d->mHasTime //
136         || d->mHasLocationRadius != rhs.d->mHasLocationRadius //
137         || d->mLocationRadius != rhs.d->mLocationRadius) {
138         return false;
139     }
140 
141     if (d->mHasTime) {
142         if (d->mAlarmTime != rhs.d->mAlarmTime) {
143             return false;
144         }
145     } else {
146         if (d->mOffset != rhs.d->mOffset || d->mEndOffset != rhs.d->mEndOffset) {
147             return false;
148         }
149     }
150 
151     switch (d->mType) {
152     case Display:
153         return d->mDescription == rhs.d->mDescription;
154 
155     case Email:
156         return d->mDescription == rhs.d->mDescription //
157             && d->mMailAttachFiles == rhs.d->mMailAttachFiles //
158             && compareMailAddresses(d->mMailAddresses, rhs.d->mMailAddresses) //
159             && d->mMailSubject == rhs.d->mMailSubject;
160 
161     case Procedure:
162         return d->mFile == rhs.d->mFile && d->mDescription == rhs.d->mDescription;
163 
164     case Audio:
165         return d->mFile == rhs.d->mFile;
166 
167     case Invalid:
168         break;
169     }
170     return false;
171 }
172 
operator !=(const Alarm & a) const173 bool Alarm::operator!=(const Alarm &a) const
174 {
175     return !operator==(a);
176 }
177 
setType(Alarm::Type type)178 void Alarm::setType(Alarm::Type type)
179 {
180     if (type == d->mType) {
181         return;
182     }
183 
184     if (d->mParent) {
185         d->mParent->update();
186     }
187     switch (type) {
188     case Display:
189         d->mDescription.clear();
190         break;
191     case Procedure:
192         d->mFile.clear();
193         d->mDescription.clear();
194         break;
195     case Audio:
196         d->mFile.clear();
197         break;
198     case Email:
199         d->mMailSubject.clear();
200         d->mDescription.clear();
201         d->mMailAddresses.clear();
202         d->mMailAttachFiles.clear();
203         break;
204     case Invalid:
205         break;
206     default:
207         if (d->mParent) {
208             d->mParent->updated(); // not really
209         }
210         return;
211     }
212     d->mType = type;
213     if (d->mParent) {
214         d->mParent->updated();
215     }
216 }
217 
type() const218 Alarm::Type Alarm::type() const
219 {
220     return d->mType;
221 }
222 
setAudioAlarm(const QString & audioFile)223 void Alarm::setAudioAlarm(const QString &audioFile)
224 {
225     if (d->mParent) {
226         d->mParent->update();
227     }
228     d->mType = Audio;
229     d->mFile = audioFile;
230     if (d->mParent) {
231         d->mParent->updated();
232     }
233 }
234 
setAudioFile(const QString & audioFile)235 void Alarm::setAudioFile(const QString &audioFile)
236 {
237     if (d->mType == Audio) {
238         if (d->mParent) {
239             d->mParent->update();
240         }
241         d->mFile = audioFile;
242         if (d->mParent) {
243             d->mParent->updated();
244         }
245     }
246 }
247 
audioFile() const248 QString Alarm::audioFile() const
249 {
250     return (d->mType == Audio) ? d->mFile : QString();
251 }
252 
setProcedureAlarm(const QString & programFile,const QString & arguments)253 void Alarm::setProcedureAlarm(const QString &programFile, const QString &arguments)
254 {
255     if (d->mParent) {
256         d->mParent->update();
257     }
258     d->mType = Procedure;
259     d->mFile = programFile;
260     d->mDescription = arguments;
261     if (d->mParent) {
262         d->mParent->updated();
263     }
264 }
265 
setProgramFile(const QString & programFile)266 void Alarm::setProgramFile(const QString &programFile)
267 {
268     if (d->mType == Procedure) {
269         if (d->mParent) {
270             d->mParent->update();
271         }
272         d->mFile = programFile;
273         if (d->mParent) {
274             d->mParent->updated();
275         }
276     }
277 }
278 
programFile() const279 QString Alarm::programFile() const
280 {
281     return (d->mType == Procedure) ? d->mFile : QString();
282 }
283 
setProgramArguments(const QString & arguments)284 void Alarm::setProgramArguments(const QString &arguments)
285 {
286     if (d->mType == Procedure) {
287         if (d->mParent) {
288             d->mParent->update();
289         }
290         d->mDescription = arguments;
291         if (d->mParent) {
292             d->mParent->updated();
293         }
294     }
295 }
296 
programArguments() const297 QString Alarm::programArguments() const
298 {
299     return (d->mType == Procedure) ? d->mDescription : QString();
300 }
301 
setEmailAlarm(const QString & subject,const QString & text,const Person::List & addressees,const QStringList & attachments)302 void Alarm::setEmailAlarm(const QString &subject, const QString &text, const Person::List &addressees, const QStringList &attachments)
303 {
304     if (d->mParent) {
305         d->mParent->update();
306     }
307     d->mType = Email;
308     d->mMailSubject = subject;
309     d->mDescription = text;
310     d->mMailAddresses = addressees;
311     d->mMailAttachFiles = attachments;
312     if (d->mParent) {
313         d->mParent->updated();
314     }
315 }
316 
setMailAddress(const Person & mailAddress)317 void Alarm::setMailAddress(const Person &mailAddress)
318 {
319     if (d->mType == Email) {
320         if (d->mParent) {
321             d->mParent->update();
322         }
323         d->mMailAddresses.clear();
324         d->mMailAddresses.append(mailAddress);
325         if (d->mParent) {
326             d->mParent->updated();
327         }
328     }
329 }
330 
setMailAddresses(const Person::List & mailAddresses)331 void Alarm::setMailAddresses(const Person::List &mailAddresses)
332 {
333     if (d->mType == Email) {
334         if (d->mParent) {
335             d->mParent->update();
336         }
337         d->mMailAddresses += mailAddresses;
338         if (d->mParent) {
339             d->mParent->updated();
340         }
341     }
342 }
343 
addMailAddress(const Person & mailAddress)344 void Alarm::addMailAddress(const Person &mailAddress)
345 {
346     if (d->mType == Email) {
347         if (d->mParent) {
348             d->mParent->update();
349         }
350         d->mMailAddresses.append(mailAddress);
351         if (d->mParent) {
352             d->mParent->updated();
353         }
354     }
355 }
356 
mailAddresses() const357 Person::List Alarm::mailAddresses() const
358 {
359     return (d->mType == Email) ? d->mMailAddresses : Person::List();
360 }
361 
setMailSubject(const QString & mailAlarmSubject)362 void Alarm::setMailSubject(const QString &mailAlarmSubject)
363 {
364     if (d->mType == Email) {
365         if (d->mParent) {
366             d->mParent->update();
367         }
368         d->mMailSubject = mailAlarmSubject;
369         if (d->mParent) {
370             d->mParent->updated();
371         }
372     }
373 }
374 
mailSubject() const375 QString Alarm::mailSubject() const
376 {
377     return (d->mType == Email) ? d->mMailSubject : QString();
378 }
379 
setMailAttachment(const QString & mailAttachFile)380 void Alarm::setMailAttachment(const QString &mailAttachFile)
381 {
382     if (d->mType == Email) {
383         if (d->mParent) {
384             d->mParent->update();
385         }
386         d->mMailAttachFiles.clear();
387         d->mMailAttachFiles += mailAttachFile;
388         if (d->mParent) {
389             d->mParent->updated();
390         }
391     }
392 }
393 
setMailAttachments(const QStringList & mailAttachFiles)394 void Alarm::setMailAttachments(const QStringList &mailAttachFiles)
395 {
396     if (d->mType == Email) {
397         if (d->mParent) {
398             d->mParent->update();
399         }
400         d->mMailAttachFiles = mailAttachFiles;
401         if (d->mParent) {
402             d->mParent->updated();
403         }
404     }
405 }
406 
addMailAttachment(const QString & mailAttachFile)407 void Alarm::addMailAttachment(const QString &mailAttachFile)
408 {
409     if (d->mType == Email) {
410         if (d->mParent) {
411             d->mParent->update();
412         }
413         d->mMailAttachFiles += mailAttachFile;
414         if (d->mParent) {
415             d->mParent->updated();
416         }
417     }
418 }
419 
mailAttachments() const420 QStringList Alarm::mailAttachments() const
421 {
422     return (d->mType == Email) ? d->mMailAttachFiles : QStringList();
423 }
424 
setMailText(const QString & text)425 void Alarm::setMailText(const QString &text)
426 {
427     if (d->mType == Email) {
428         if (d->mParent) {
429             d->mParent->update();
430         }
431         d->mDescription = text;
432         if (d->mParent) {
433             d->mParent->updated();
434         }
435     }
436 }
437 
mailText() const438 QString Alarm::mailText() const
439 {
440     return (d->mType == Email) ? d->mDescription : QString();
441 }
442 
setDisplayAlarm(const QString & text)443 void Alarm::setDisplayAlarm(const QString &text)
444 {
445     if (d->mParent) {
446         d->mParent->update();
447     }
448     d->mType = Display;
449     if (!text.isNull()) {
450         d->mDescription = text;
451     }
452     if (d->mParent) {
453         d->mParent->updated();
454     }
455 }
456 
setText(const QString & text)457 void Alarm::setText(const QString &text)
458 {
459     if (d->mType == Display) {
460         if (d->mParent) {
461             d->mParent->update();
462         }
463         d->mDescription = text;
464         if (d->mParent) {
465             d->mParent->updated();
466         }
467     }
468 }
469 
text() const470 QString Alarm::text() const
471 {
472     return (d->mType == Display) ? d->mDescription : QString();
473 }
474 
setTime(const QDateTime & alarmTime)475 void Alarm::setTime(const QDateTime &alarmTime)
476 {
477     if (d->mParent) {
478         d->mParent->update();
479     }
480     d->mAlarmTime = alarmTime;
481     d->mHasTime = true;
482 
483     if (d->mParent) {
484         d->mParent->updated();
485     }
486 }
487 
time() const488 QDateTime Alarm::time() const
489 {
490     if (hasTime()) {
491         return d->mAlarmTime;
492     } else if (d->mParent) {
493         if (d->mEndOffset) {
494             QDateTime dt = d->mParent->dateTime(Incidence::RoleAlarmEndOffset);
495             return d->mOffset.end(dt);
496         } else {
497             QDateTime dt = d->mParent->dateTime(Incidence::RoleAlarmStartOffset);
498             return d->mOffset.end(dt);
499         }
500     } else {
501         return QDateTime();
502     }
503 }
504 
nextTime(const QDateTime & preTime,bool ignoreRepetitions) const505 QDateTime Alarm::nextTime(const QDateTime &preTime, bool ignoreRepetitions) const
506 {
507     if (d->mParent && d->mParent->recurs()) {
508         QDateTime dtEnd = d->mParent->dateTime(Incidence::RoleAlarmEndOffset);
509 
510         QDateTime dtStart = d->mParent->dtStart();
511         // Find the incidence's earliest alarm
512         // Alarm time is defined by an offset from the event start or end time.
513         QDateTime alarmStart = d->mOffset.end(d->mEndOffset ? dtEnd : dtStart);
514         // Find the offset from the event start time, which is also used as the
515         // offset from the recurrence time.
516         Duration alarmOffset(dtStart, alarmStart);
517         /*
518         qCDebug(KCALCORE_LOG) << "dtStart       " << dtStart;
519         qCDebug(KCALCORE_LOG) << "dtEnd         " << dtEnd;
520         qCDebug(KCALCORE_LOG) << "alarmStart    " << alarmStart;
521         qCDebug(KCALCORE_LOG) << "alarmOffset   " << alarmOffset.value();
522         qCDebug(KCALCORE_LOG) << "preTime       " << preTime;
523         */
524         if (alarmStart > preTime) {
525             // No need to go further.
526             return alarmStart;
527         }
528         if (d->mAlarmRepeatCount && !ignoreRepetitions) {
529             // The alarm has repetitions, so check whether repetitions of previous
530             // recurrences happen after given time.
531             QDateTime prevRecurrence = d->mParent->recurrence()->getPreviousDateTime(preTime);
532             if (prevRecurrence.isValid()) {
533                 QDateTime prevLastRepeat = alarmOffset.end(duration().end(prevRecurrence));
534                 // qCDebug(KCALCORE_LOG) << "prevRecurrence" << prevRecurrence;
535                 // qCDebug(KCALCORE_LOG) << "prevLastRepeat" << prevLastRepeat;
536                 if (prevLastRepeat > preTime) {
537                     // Yes they did, return alarm offset to previous recurrence.
538                     QDateTime prevAlarm = alarmOffset.end(prevRecurrence);
539                     // qCDebug(KCALCORE_LOG) << "prevAlarm     " << prevAlarm;
540                     return prevAlarm;
541                 }
542             }
543         }
544         // Check the next recurrence now.
545         QDateTime nextRecurrence = d->mParent->recurrence()->getNextDateTime(preTime);
546         if (nextRecurrence.isValid()) {
547             QDateTime nextAlarm = alarmOffset.end(nextRecurrence);
548             /*
549             qCDebug(KCALCORE_LOG) << "nextRecurrence" << nextRecurrence;
550             qCDebug(KCALCORE_LOG) << "nextAlarm     " << nextAlarm;
551             */
552             if (nextAlarm > preTime) {
553                 // It's first alarm takes place after given time.
554                 return nextAlarm;
555             }
556         }
557     } else {
558         // Not recurring.
559         QDateTime alarmTime = time();
560         if (alarmTime > preTime) {
561             return alarmTime;
562         }
563     }
564     return QDateTime();
565 }
566 
hasTime() const567 bool Alarm::hasTime() const
568 {
569     return d->mHasTime;
570 }
571 
shiftTimes(const QTimeZone & oldZone,const QTimeZone & newZone)572 void Alarm::shiftTimes(const QTimeZone &oldZone, const QTimeZone &newZone)
573 {
574     if (d->mParent) {
575         d->mParent->update();
576     }
577     d->mAlarmTime = d->mAlarmTime.toTimeZone(oldZone);
578     d->mAlarmTime.setTimeZone(newZone);
579     if (d->mParent) {
580         d->mParent->updated();
581     }
582 }
583 
setSnoozeTime(const Duration & alarmSnoozeTime)584 void Alarm::setSnoozeTime(const Duration &alarmSnoozeTime)
585 {
586     if (alarmSnoozeTime.value() > 0) {
587         if (d->mParent) {
588             d->mParent->update();
589         }
590         d->mAlarmSnoozeTime = alarmSnoozeTime;
591         if (d->mParent) {
592             d->mParent->updated();
593         }
594     }
595 }
596 
snoozeTime() const597 Duration Alarm::snoozeTime() const
598 {
599     return d->mAlarmSnoozeTime;
600 }
601 
setRepeatCount(int alarmRepeatCount)602 void Alarm::setRepeatCount(int alarmRepeatCount)
603 {
604     if (d->mParent) {
605         d->mParent->update();
606     }
607     d->mAlarmRepeatCount = alarmRepeatCount;
608     if (d->mParent) {
609         d->mParent->updated();
610     }
611 }
612 
repeatCount() const613 int Alarm::repeatCount() const
614 {
615     return d->mAlarmRepeatCount;
616 }
617 
duration() const618 Duration Alarm::duration() const
619 {
620     return Duration(d->mAlarmSnoozeTime.value() * d->mAlarmRepeatCount, d->mAlarmSnoozeTime.type());
621 }
622 
nextRepetition(const QDateTime & preTime) const623 QDateTime Alarm::nextRepetition(const QDateTime &preTime) const
624 {
625     QDateTime at = nextTime(preTime);
626     if (at > preTime) {
627         return at;
628     }
629     if (!d->mAlarmRepeatCount) {
630         // there isn't an occurrence after the specified time
631         return QDateTime();
632     }
633     qint64 repetition;
634     int interval = d->mAlarmSnoozeTime.value();
635     bool daily = d->mAlarmSnoozeTime.isDaily();
636     if (daily) {
637         qint64 daysTo = at.daysTo(preTime);
638         if (preTime.time() <= at.time()) {
639             --daysTo;
640         }
641         repetition = daysTo / interval + 1;
642     } else {
643         repetition = at.secsTo(preTime) / interval + 1;
644     }
645     if (repetition > d->mAlarmRepeatCount) {
646         // all repetitions have finished before the specified time
647         return QDateTime();
648     }
649     return daily ? at.addDays(int(repetition * interval)) : at.addSecs(repetition * interval);
650 }
651 
previousRepetition(const QDateTime & afterTime) const652 QDateTime Alarm::previousRepetition(const QDateTime &afterTime) const
653 {
654     QDateTime at = time();
655     if (at >= afterTime) {
656         // alarm's first/only time is at/after the specified time
657         return QDateTime();
658     }
659     if (!d->mAlarmRepeatCount) {
660         return at;
661     }
662     qint64 repetition;
663     int interval = d->mAlarmSnoozeTime.value();
664     bool daily = d->mAlarmSnoozeTime.isDaily();
665     if (daily) {
666         qint64 daysTo = at.daysTo(afterTime);
667         if (afterTime.time() <= at.time()) {
668             --daysTo;
669         }
670         repetition = daysTo / interval;
671     } else {
672         repetition = (at.secsTo(afterTime) - 1) / interval;
673     }
674     if (repetition > d->mAlarmRepeatCount) {
675         repetition = d->mAlarmRepeatCount;
676     }
677     return daily ? at.addDays(int(repetition * interval)) : at.addSecs(repetition * interval);
678 }
679 
endTime() const680 QDateTime Alarm::endTime() const
681 {
682     if (!d->mAlarmRepeatCount) {
683         return time();
684     }
685     if (d->mAlarmSnoozeTime.isDaily()) {
686         return time().addDays(d->mAlarmRepeatCount * d->mAlarmSnoozeTime.asDays());
687     } else {
688         return time().addSecs(d->mAlarmRepeatCount * d->mAlarmSnoozeTime.asSeconds());
689     }
690 }
691 
toggleAlarm()692 void Alarm::toggleAlarm()
693 {
694     if (d->mParent) {
695         d->mParent->update();
696     }
697     d->mAlarmEnabled = !d->mAlarmEnabled;
698     if (d->mParent) {
699         d->mParent->updated();
700     }
701 }
702 
setEnabled(bool enable)703 void Alarm::setEnabled(bool enable)
704 {
705     if (d->mParent) {
706         d->mParent->update();
707     }
708     d->mAlarmEnabled = enable;
709     if (d->mParent) {
710         d->mParent->updated();
711     }
712 }
713 
enabled() const714 bool Alarm::enabled() const
715 {
716     return d->mAlarmEnabled;
717 }
718 
setStartOffset(const Duration & offset)719 void Alarm::setStartOffset(const Duration &offset)
720 {
721     if (d->mParent) {
722         d->mParent->update();
723     }
724     d->mOffset = offset;
725     d->mEndOffset = false;
726     d->mHasTime = false;
727     if (d->mParent) {
728         d->mParent->updated();
729     }
730 }
731 
startOffset() const732 Duration Alarm::startOffset() const
733 {
734     return (d->mHasTime || d->mEndOffset) ? Duration(0) : d->mOffset;
735 }
736 
hasStartOffset() const737 bool Alarm::hasStartOffset() const
738 {
739     return !d->mHasTime && !d->mEndOffset;
740 }
741 
hasEndOffset() const742 bool Alarm::hasEndOffset() const
743 {
744     return !d->mHasTime && d->mEndOffset;
745 }
746 
setEndOffset(const Duration & offset)747 void Alarm::setEndOffset(const Duration &offset)
748 {
749     if (d->mParent) {
750         d->mParent->update();
751     }
752     d->mOffset = offset;
753     d->mEndOffset = true;
754     d->mHasTime = false;
755     if (d->mParent) {
756         d->mParent->updated();
757     }
758 }
759 
endOffset() const760 Duration Alarm::endOffset() const
761 {
762     return (d->mHasTime || !d->mEndOffset) ? Duration(0) : d->mOffset;
763 }
764 
setParent(Incidence * parent)765 void Alarm::setParent(Incidence *parent)
766 {
767     d->mParent = parent;
768 }
769 
parentUid() const770 QString Alarm::parentUid() const
771 {
772     return d->mParent ? d->mParent->uid() : QString();
773 }
774 
customPropertyUpdated()775 void Alarm::customPropertyUpdated()
776 {
777     if (d->mParent) {
778         d->mParent->update();
779         d->mParent->updated();
780     }
781 }
782 
setHasLocationRadius(bool hasLocationRadius)783 void Alarm::setHasLocationRadius(bool hasLocationRadius)
784 {
785     if (d->mParent) {
786         d->mParent->update();
787     }
788     d->mHasLocationRadius = hasLocationRadius;
789     if (hasLocationRadius) {
790         setNonKDECustomProperty("X-LOCATION-RADIUS", QString::number(d->mLocationRadius));
791     } else {
792         removeNonKDECustomProperty("X-LOCATION-RADIUS");
793     }
794     if (d->mParent) {
795         d->mParent->updated();
796     }
797 }
798 
hasLocationRadius() const799 bool Alarm::hasLocationRadius() const
800 {
801     return d->mHasLocationRadius;
802 }
803 
setLocationRadius(int locationRadius)804 void Alarm::setLocationRadius(int locationRadius)
805 {
806     if (d->mParent) {
807         d->mParent->update();
808     }
809     d->mLocationRadius = locationRadius;
810     if (d->mParent) {
811         d->mParent->updated();
812     }
813 }
814 
locationRadius() const815 int Alarm::locationRadius() const
816 {
817     return d->mLocationRadius;
818 }
819 
operator <<(QDataStream & out,const KCalendarCore::Alarm::Ptr & a)820 QDataStream &KCalendarCore::operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &a)
821 {
822     if (a) {
823         out << ((quint32)a->d->mType) << a->d->mAlarmSnoozeTime << a->d->mAlarmRepeatCount << a->d->mEndOffset << a->d->mHasTime << a->d->mAlarmEnabled
824             << a->d->mHasLocationRadius << a->d->mLocationRadius << a->d->mOffset;
825 
826         serializeQDateTimeAsKDateTime(out, a->d->mAlarmTime);
827 
828         out << a->d->mFile << a->d->mMailSubject << a->d->mDescription << a->d->mMailAttachFiles << a->d->mMailAddresses;
829     }
830     return out;
831 }
832 
operator >>(QDataStream & in,const KCalendarCore::Alarm::Ptr & a)833 QDataStream &KCalendarCore::operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &a)
834 {
835     if (a) {
836         quint32 type;
837         in >> type;
838         a->d->mType = static_cast<Alarm::Type>(type);
839         in >> a->d->mAlarmSnoozeTime >> a->d->mAlarmRepeatCount >> a->d->mEndOffset >> a->d->mHasTime >> a->d->mAlarmEnabled >> a->d->mHasLocationRadius
840             >> a->d->mLocationRadius >> a->d->mOffset;
841         deserializeKDateTimeAsQDateTime(in, a->d->mAlarmTime);
842         in >> a->d->mFile >> a->d->mMailSubject >> a->d->mDescription >> a->d->mMailAttachFiles >> a->d->mMailAddresses;
843     }
844     return in;
845 }
846 
virtual_hook(int id,void * data)847 void Alarm::virtual_hook(int id, void *data)
848 {
849     Q_UNUSED(id);
850     Q_UNUSED(data);
851     Q_ASSERT(false);
852 }
853