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