• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.10 API Reference
  • KDE Home
  • Contact Us
 

KAlarm Library

  • kalarmcal
kaevent.cpp
1/*
2 * kaevent.cpp - represents calendar events
3 * This file is part of kalarmcal library, which provides access to KAlarm
4 * calendar data.
5 * Copyright © 2001-2016 by David Jarvie <djarvie@kde.org>
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or (at
10 * your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
21 */
22
23#include "kaevent.h"
24
25#include "alarmtext.h"
26#include "identities.h"
27#include "version.h"
28
29#ifndef KALARMCAL_USE_KRESOURCES
30#include <kcalcore/memorycalendar.h>
31#else
32#include <kcal/calendarlocal.h>
33#endif
34#include <kholidays/holidays.h>
35using namespace KHolidays;
36
37#include <ksystemtimezone.h>
38#include <klocalizedstring.h>
39#ifdef KALARMCAL_USE_KRESOURCES
40#include <ksharedconfig.h>
41#include <kglobal.h>
42#include <kconfiggroup.h>
43#endif
44#include <kglobal.h>
45#include <kdebug.h>
46
47#ifndef KALARMCAL_USE_KRESOURCES
48using namespace KCalCore;
49#else
50using namespace KCal;
51#endif
52using namespace KHolidays;
53
54namespace KAlarmCal
55{
56
57//=============================================================================
58
59#ifndef KALARMCAL_USE_KRESOURCES
60typedef KCalCore::Person EmailAddress;
61class EmailAddressList : public KCalCore::Person::List
62#else
63typedef KCal::Person EmailAddress;
64class EmailAddressList : public QList<KCal::Person>
65#endif
66{
67 public:
68#ifndef KALARMCAL_USE_KRESOURCES
69 EmailAddressList() : KCalCore::Person::List() { }
70 EmailAddressList(const KCalCore::Person::List& list) { operator=(list); }
71 EmailAddressList& operator=(const KCalCore::Person::List&);
72#else
73 EmailAddressList() : QList<KCal::Person>() { }
74 EmailAddressList(const QList<KCal::Person>& list) { operator=(list); }
75 EmailAddressList& operator=(const QList<KCal::Person>&);
76#endif
77 operator QStringList() const;
78 QString join(const QString& separator) const;
79 QStringList pureAddresses() const;
80 QString pureAddresses(const QString& separator) const;
81 private:
82 QString address(int index) const;
83};
84
85//=============================================================================
86
87class KAAlarm::Private
88{
89 public:
90 Private();
91
92 Action mActionType; // alarm action type
93 Type mType; // alarm type
94 DateTime mNextMainDateTime; // next time to display the alarm, excluding repetitions
95 Repetition mRepetition; // sub-repetition count and interval
96 int mNextRepeat; // repetition count of next due sub-repetition
97 bool mRepeatAtLogin; // whether to repeat the alarm at every login
98 bool mRecurs; // there is a recurrence rule for the alarm
99 bool mDeferred; // whether the alarm is an extra deferred/deferred-reminder alarm
100 bool mTimedDeferral; // if mDeferred = true: true if the deferral is timed, false if date-only
101};
102
103//=============================================================================
104
105class KAEventPrivate : public QSharedData
106{
107 public:
108 // Read-only internal flags additional to KAEvent::Flags enum values.
109 // NOTE: If any values are added to those in KAEvent::Flags, ensure
110 // that these values don't overlap them.
111 enum
112 {
113 REMINDER = 0x100000,
114 DEFERRAL = 0x200000,
115 TIMED_FLAG = 0x400000,
116 DATE_DEFERRAL = DEFERRAL,
117 TIME_DEFERRAL = DEFERRAL | TIMED_FLAG,
118 DISPLAYING_ = 0x800000,
119 READ_ONLY_FLAGS = 0xF00000
120 };
121 enum ReminderType // current active state of reminder
122 {
123 NO_REMINDER, // reminder is not due
124 ACTIVE_REMINDER, // reminder is due
125 HIDDEN_REMINDER // reminder-after is disabled due to main alarm being deferred past it
126 };
127 enum DeferType
128 {
129 NO_DEFERRAL = 0, // there is no deferred alarm
130 NORMAL_DEFERRAL, // the main alarm, a recurrence or a repeat is deferred
131 REMINDER_DEFERRAL // a reminder alarm is deferred
132 };
133 // Alarm types.
134 // This uses the same scheme as KAAlarm::Type, with some extra values.
135 // Note that the actual enum values need not be the same as in KAAlarm::Type.
136 enum AlarmType
137 {
138 INVALID_ALARM = 0, // Not an alarm
139 MAIN_ALARM = 1, // THE real alarm. Must be the first in the enumeration.
140 REMINDER_ALARM = 0x02, // Reminder in advance of/after the main alarm
141 DEFERRED_ALARM = 0x04, // Deferred alarm
142 DEFERRED_REMINDER_ALARM = REMINDER_ALARM | DEFERRED_ALARM, // Deferred reminder alarm
143 // The following values must be greater than the preceding ones, to
144 // ensure that in ordered processing they are processed afterwards.
145 AT_LOGIN_ALARM = 0x10, // Additional repeat-at-login trigger
146 DISPLAYING_ALARM = 0x20, // Copy of the alarm currently being displayed
147 // The following are extra internal KAEvent values
148 AUDIO_ALARM = 0x30, // sound to play when displaying the alarm
149 PRE_ACTION_ALARM = 0x40, // command to execute before displaying the alarm
150 POST_ACTION_ALARM = 0x50 // command to execute after the alarm window is closed
151 };
152
153 struct AlarmData
154 {
155#ifndef KALARMCAL_USE_KRESOURCES
156 Alarm::Ptr alarm;
157#else
158 const Alarm* alarm;
159#endif
160 QString cleanText; // text or audio file name
161 QFont font;
162 QColor bgColour, fgColour;
163 float soundVolume;
164 float fadeVolume;
165 int fadeSeconds;
166 int repeatSoundPause;
167 int nextRepeat;
168 uint emailFromId;
169 KAEventPrivate::AlarmType type;
170 KAAlarm::Action action;
171 int displayingFlags;
172 KAEvent::ExtraActionOptions extraActionOptions;
173 bool speak;
174 bool defaultFont;
175 bool isEmailText;
176 bool commandScript;
177 bool timedDeferral;
178 bool hiddenReminder;
179 };
180 typedef QMap<AlarmType, AlarmData> AlarmMap;
181
182 KAEventPrivate();
183 KAEventPrivate(const KDateTime&, const QString& message, const QColor& bg, const QColor& fg,
184 const QFont& f, KAEvent::SubAction, int lateCancel, KAEvent::Flags flags,
185 bool changesPending = false);
186#ifndef KALARMCAL_USE_KRESOURCES
187 explicit KAEventPrivate(const KCalCore::Event::Ptr&);
188#else
189 explicit KAEventPrivate(const KCal::Event*);
190#endif
191 KAEventPrivate(const KAEventPrivate&);
192 ~KAEventPrivate() { delete mRecurrence; }
193 KAEventPrivate& operator=(const KAEventPrivate& e) { if (&e != this) copy(e); return *this; }
194#ifndef KALARMCAL_USE_KRESOURCES
195 void set(const KCalCore::Event::Ptr&);
196#else
197 void set(const KCal::Event*);
198#endif
199 void set(const KDateTime&, const QString& message, const QColor& bg, const QColor& fg,
200 const QFont&, KAEvent::SubAction, int lateCancel, KAEvent::Flags flags,
201 bool changesPending = false);
202 void setAudioFile(const QString& filename, float volume, float fadeVolume, int fadeSeconds, int repeatPause, bool allowEmptyFile);
203 KAEvent::OccurType setNextOccurrence(const KDateTime& preDateTime);
204 void setFirstRecurrence();
205 void setCategory(CalEvent::Type);
206 void setRepeatAtLogin(bool);
207 void setRepeatAtLoginTrue(bool clearReminder);
208 void setReminder(int minutes, bool onceOnly);
209 void activateReminderAfter(const DateTime& mainAlarmTime);
210 void defer(const DateTime&, bool reminder, bool adjustRecurrence = false);
211 void cancelDefer();
212#ifndef KALARMCAL_USE_KRESOURCES
213 bool setDisplaying(const KAEventPrivate&, KAAlarm::Type, Akonadi::Collection::Id, const KDateTime& dt, bool showEdit, bool showDefer);
214 void reinstateFromDisplaying(const KCalCore::Event::Ptr&, Akonadi::Collection::Id&, bool& showEdit, bool& showDefer);
215#else
216 bool setDisplaying(const KAEventPrivate&, KAAlarm::Type, const QString& resourceID, const KDateTime& dt, bool showEdit, bool showDefer);
217 void reinstateFromDisplaying(const KCal::Event*, QString& resourceID, bool& showEdit, bool& showDefer);
218 void setCommandError(const QString& configString);
219 void setCommandError(KAEvent::CmdErrType, bool writeConfig) const;
220#endif
221 void startChanges() { ++mChangeCount; }
222 void endChanges();
223 void removeExpiredAlarm(KAAlarm::Type);
224 KAAlarm alarm(KAAlarm::Type) const;
225 KAAlarm firstAlarm() const;
226 KAAlarm nextAlarm(KAAlarm::Type) const;
227#ifndef KALARMCAL_USE_KRESOURCES
228 bool updateKCalEvent(const KCalCore::Event::Ptr&, KAEvent::UidAction, bool setCustomProperties = true) const;
229#else
230 bool updateKCalEvent(KCal::Event*, KAEvent::UidAction) const;
231#endif
232 DateTime mainDateTime(bool withRepeats = false) const
233 { return (withRepeats && mNextRepeat && mRepetition)
234 ? mRepetition.duration(mNextRepeat).end(mNextMainDateTime.kDateTime()) : mNextMainDateTime; }
235 DateTime mainEndRepeatTime() const
236 { return mRepetition ? mRepetition.duration().end(mNextMainDateTime.kDateTime()) : mNextMainDateTime; }
237 DateTime deferralLimit(KAEvent::DeferLimitType* = 0) const;
238 KAEvent::Flags flags() const;
239 bool isWorkingTime(const KDateTime&) const;
240 bool setRepetition(const Repetition&);
241 bool occursAfter(const KDateTime& preDateTime, bool includeRepetitions) const;
242 KAEvent::OccurType nextOccurrence(const KDateTime& preDateTime, DateTime& result, KAEvent::OccurOption = KAEvent::IGNORE_REPETITION) const;
243 KAEvent::OccurType previousOccurrence(const KDateTime& afterDateTime, DateTime& result, bool includeRepetitions = false) const;
244 void setRecurrence(const KARecurrence&);
245#ifndef KALARMCAL_USE_KRESOURCES
246 bool setRecur(KCalCore::RecurrenceRule::PeriodType, int freq, int count, const QDate& end, KARecurrence::Feb29Type = KARecurrence::Feb29_None);
247 bool setRecur(KCalCore::RecurrenceRule::PeriodType, int freq, int count, const KDateTime& end, KARecurrence::Feb29Type = KARecurrence::Feb29_None);
248#else
249 bool setRecur(KCal::RecurrenceRule::PeriodType, int freq, int count, const QDate& end, KARecurrence::Feb29Type = KARecurrence::Feb29_None);
250 bool setRecur(KCal::RecurrenceRule::PeriodType, int freq, int count, const KDateTime& end, KARecurrence::Feb29Type = KARecurrence::Feb29_None);
251#endif
252 KARecurrence::Type checkRecur() const;
253 void clearRecur();
254 void calcTriggerTimes() const;
255#ifdef KDE_NO_DEBUG_OUTPUT
256 void dumpDebug() const { }
257#else
258 void dumpDebug() const;
259#endif
260#ifndef KALARMCAL_USE_KRESOURCES
261 static bool convertRepetition(const KCalCore::Event::Ptr&);
262 static bool convertStartOfDay(const KCalCore::Event::Ptr&);
263 static DateTime readDateTime(const KCalCore::Event::Ptr&, bool dateOnly, DateTime& start);
264 static void readAlarms(const KCalCore::Event::Ptr&, AlarmMap*, bool cmdDisplay = false);
265 static void readAlarm(const KCalCore::Alarm::Ptr&, AlarmData&, bool audioMain, bool cmdDisplay = false);
266#else
267 static bool convertRepetition(KCal::Event*);
268 static bool convertStartOfDay(KCal::Event*);
269 static DateTime readDateTime(const KCal::Event*, bool dateOnly, DateTime& start);
270 static void readAlarms(const KCal::Event*, AlarmMap*, bool cmdDisplay = false);
271 static void readAlarm(const KCal::Alarm*, AlarmData&, bool audioMain, bool cmdDisplay = false);
272#endif
273
274 private:
275 void copy(const KAEventPrivate&);
276 bool mayOccurDailyDuringWork(const KDateTime&) const;
277 int nextWorkRepetition(const KDateTime& pre) const;
278 void calcNextWorkingTime(const DateTime& nextTrigger) const;
279 DateTime nextWorkingTime() const;
280 KAEvent::OccurType nextRecurrence(const KDateTime& preDateTime, DateTime& result) const;
281#ifndef KALARMCAL_USE_KRESOURCES
282 void setAudioAlarm(const KCalCore::Alarm::Ptr&) const;
283 KCalCore::Alarm::Ptr initKCalAlarm(const KCalCore::Event::Ptr&, const DateTime&, const QStringList& types, AlarmType = INVALID_ALARM) const;
284 KCalCore::Alarm::Ptr initKCalAlarm(const KCalCore::Event::Ptr&, int startOffsetSecs, const QStringList& types, AlarmType = INVALID_ALARM) const;
285#else
286 void setAudioAlarm(KCal::Alarm*) const;
287 KCal::Alarm* initKCalAlarm(KCal::Event*, const DateTime&, const QStringList& types, AlarmType = INVALID_ALARM) const;
288 KCal::Alarm* initKCalAlarm(KCal::Event*, int startOffsetSecs, const QStringList& types, AlarmType = INVALID_ALARM) const;
289#endif
290 inline void set_deferral(DeferType);
291 inline void activate_reminder(bool activate);
292
293 public:
294#ifdef KALARMCAL_USE_KRESOURCES
295 static QString mCmdErrConfigGroup; // config file group for command error recording
296#endif
297 static QFont mDefaultFont; // default alarm message font
298 static const KHolidays::HolidayRegion* mHolidays; // holiday region to use
299 static QBitArray mWorkDays; // working days of the week
300 static QTime mWorkDayStart; // start time of the working day
301 static QTime mWorkDayEnd; // end time of the working day
302 static int mWorkTimeIndex; // incremented every time working days/times are changed
303#ifdef KALARMCAL_USE_KRESOURCES
304 AlarmResource* mResource; // resource which owns the event (for convenience - not used by this class)
305#endif
306 mutable DateTime mAllTrigger; // next trigger time, including reminders, ignoring working hours
307 mutable DateTime mMainTrigger; // next trigger time, ignoring reminders and working hours
308 mutable DateTime mAllWorkTrigger; // next trigger time, taking account of reminders and working hours
309 mutable DateTime mMainWorkTrigger; // next trigger time, ignoring reminders but taking account of working hours
310 mutable KAEvent::CmdErrType mCommandError; // command execution error last time the alarm triggered
311
312 QString mEventID; // UID: KCal::Event unique ID
313 QString mTemplateName; // alarm template's name, or null if normal event
314#ifndef KALARMCAL_USE_KRESOURCES
315 QMap<QByteArray, QString> mCustomProperties; // KCal::Event's non-KAlarm custom properties
316 Akonadi::Item::Id mItemId; // Akonadi::Item ID for this event
317 mutable Akonadi::Collection::Id mCollectionId; // ID of collection containing the event, or for a displaying event,
318 // saved collection ID (not the collection the event is in)
319#else
320 QString mOriginalResourceId;// saved resource ID (not the resource the event is in)
321#endif
322 QString mText; // message text, file URL, command, email body [or audio file for KAAlarm]
323 QString mAudioFile; // ATTACH: audio file to play
324 QString mPreAction; // command to execute before alarm is displayed
325 QString mPostAction; // command to execute after alarm window is closed
326 DateTime mStartDateTime; // DTSTART and DTEND: start and end time for event
327 KDateTime mCreatedDateTime; // CREATED: date event was created, or saved in archive calendar
328 DateTime mNextMainDateTime; // next time to display the alarm, excluding repetitions
329 KDateTime mAtLoginDateTime; // repeat-at-login end time
330 DateTime mDeferralTime; // extra time to trigger alarm (if alarm or reminder deferred)
331 DateTime mDisplayingTime; // date/time shown in the alarm currently being displayed
332 int mDisplayingFlags; // type of alarm which is currently being displayed (for display alarm)
333 int mReminderMinutes; // how long in advance reminder is to be, or 0 if none (<0 for reminder AFTER the alarm)
334 DateTime mReminderAfterTime; // if mReminderActive true, time to trigger reminder AFTER the main alarm, or invalid if not pending
335 ReminderType mReminderActive; // whether a reminder is due (before next, or after last, main alarm/recurrence)
336 int mDeferDefaultMinutes; // default number of minutes for deferral dialog, or 0 to select time control
337 bool mDeferDefaultDateOnly;// select date-only by default in deferral dialog
338 int mRevision; // SEQUENCE: revision number of the original alarm, or 0
339 KARecurrence* mRecurrence; // RECUR: recurrence specification, or 0 if none
340 Repetition mRepetition; // sub-repetition count and interval
341 int mNextRepeat; // repetition count of next due sub-repetition
342 int mAlarmCount; // number of alarms: count of !mMainExpired, mRepeatAtLogin, mDeferral, mReminderActive, mDisplaying
343 DeferType mDeferral; // whether the alarm is an extra deferred/deferred-reminder alarm
344 unsigned long mKMailSerialNumber; // if email text, message's KMail serial number
345 int mTemplateAfterTime; // time not specified: use n minutes after default time, or -1 (applies to templates only)
346 QColor mBgColour; // background colour of alarm message
347 QColor mFgColour; // foreground colour of alarm message, or invalid for default
348 QFont mFont; // font of alarm message (ignored if mUseDefaultFont true)
349 uint mEmailFromIdentity; // standard email identity uoid for 'From' field, or empty
350 EmailAddressList mEmailAddresses; // ATTENDEE: addresses to send email to
351 QString mEmailSubject; // SUMMARY: subject line of email
352 QStringList mEmailAttachments; // ATTACH: email attachment file names
353 mutable int mChangeCount; // >0 = inhibit calling calcTriggerTimes()
354 mutable bool mTriggerChanged; // true if need to recalculate trigger times
355 QString mLogFile; // alarm output is to be logged to this URL
356 float mSoundVolume; // volume for sound file (range 0 - 1), or < 0 for unspecified
357 float mFadeVolume; // initial volume for sound file (range 0 - 1), or < 0 for no fade
358 int mFadeSeconds; // fade time (seconds) for sound file, or 0 if none
359 int mRepeatSoundPause; // seconds to pause between sound file repetitions, or -1 if no repetition
360 int mLateCancel; // how many minutes late will cancel the alarm, or 0 for no cancellation
361 mutable const KHolidays::HolidayRegion*
362 mExcludeHolidays; // non-null to not trigger alarms on holidays (= mHolidays when trigger calculated)
363 mutable int mWorkTimeOnly; // non-zero to trigger alarm only during working hours (= mWorkTimeIndex when trigger calculated)
364 KAEvent::SubAction mActionSubType; // sub-action type for the event's main alarm
365 CalEvent::Type mCategory; // event category (active, archived, template, ...)
366 KAEvent::ExtraActionOptions mExtraActionOptions;// options for pre- or post-alarm actions
367#ifndef KALARMCAL_USE_KRESOURCES
368 KACalendar::Compat mCompatibility; // event's storage format compatibility
369 bool mReadOnly; // event is read-only in its original calendar file
370#endif
371 bool mConfirmAck; // alarm acknowledgement requires confirmation by user
372 bool mUseDefaultFont; // use default message font, not mFont
373 bool mCommandScript; // the command text is a script, not a shell command line
374 bool mCommandXterm; // command alarm is to be executed in a terminal window
375 bool mCommandDisplay; // command output is to be displayed in an alarm window
376 bool mEmailBcc; // blind copy the email to the user
377 bool mBeep; // whether to beep when the alarm is displayed
378 bool mSpeak; // whether to speak the message when the alarm is displayed
379 bool mCopyToKOrganizer; // KOrganizer should hold a copy of the event
380 bool mReminderOnceOnly; // the reminder is output only for the first recurrence
381 bool mAutoClose; // whether to close the alarm window after the late-cancel period
382 bool mMainExpired; // main alarm has expired (in which case a deferral alarm will exist)
383 bool mRepeatAtLogin; // whether to repeat the alarm at every login
384 bool mArchiveRepeatAtLogin; // if now archived, original event was repeat-at-login
385 bool mArchive; // event has triggered in the past, so archive it when closed
386 bool mDisplaying; // whether the alarm is currently being displayed (i.e. in displaying calendar)
387 bool mDisplayingDefer; // show Defer button (applies to displaying calendar only)
388 bool mDisplayingEdit; // show Edit button (applies to displaying calendar only)
389 bool mEnabled; // false if event is disabled
390
391 public:
392 static const QByteArray FLAGS_PROPERTY;
393 static const QString DATE_ONLY_FLAG;
394 static const QString EMAIL_BCC_FLAG;
395 static const QString CONFIRM_ACK_FLAG;
396 static const QString KORGANIZER_FLAG;
397 static const QString EXCLUDE_HOLIDAYS_FLAG;
398 static const QString WORK_TIME_ONLY_FLAG;
399 static const QString REMINDER_ONCE_FLAG;
400 static const QString DEFER_FLAG;
401 static const QString LATE_CANCEL_FLAG;
402 static const QString AUTO_CLOSE_FLAG;
403 static const QString TEMPL_AFTER_TIME_FLAG;
404 static const QString KMAIL_SERNUM_FLAG;
405 static const QString ARCHIVE_FLAG;
406 static const QByteArray NEXT_RECUR_PROPERTY;
407 static const QByteArray REPEAT_PROPERTY;
408 static const QByteArray LOG_PROPERTY;
409 static const QString xtermURL;
410 static const QString displayURL;
411 static const QByteArray TYPE_PROPERTY;
412 static const QString FILE_TYPE;
413 static const QString AT_LOGIN_TYPE;
414 static const QString REMINDER_TYPE;
415 static const QString REMINDER_ONCE_TYPE;
416 static const QString TIME_DEFERRAL_TYPE;
417 static const QString DATE_DEFERRAL_TYPE;
418 static const QString DISPLAYING_TYPE;
419 static const QString PRE_ACTION_TYPE;
420 static const QString POST_ACTION_TYPE;
421 static const QString SOUND_REPEAT_TYPE;
422 static const QByteArray NEXT_REPEAT_PROPERTY;
423 static const QString HIDDEN_REMINDER_FLAG;
424 static const QByteArray FONT_COLOUR_PROPERTY;
425 static const QByteArray VOLUME_PROPERTY;
426 static const QString EMAIL_ID_FLAG;
427 static const QString SPEAK_FLAG;
428 static const QString EXEC_ON_DEFERRAL_FLAG;
429 static const QString CANCEL_ON_ERROR_FLAG;
430 static const QString DONT_SHOW_ERROR_FLAG;
431 static const QString DISABLED_STATUS;
432 static const QString DISP_DEFER;
433 static const QString DISP_EDIT;
434 static const QString CMD_ERROR_VALUE;
435 static const QString CMD_ERROR_PRE_VALUE;
436 static const QString CMD_ERROR_POST_VALUE;
437 static const QString SC;
438};
439
440//=============================================================================
441
442// KAlarm version which first used the current calendar/event format.
443// If this changes, KAEvent::convertKCalEvents() must be changed correspondingly.
444// The string version is the KAlarm version string used in the calendar file.
445QByteArray KAEvent::currentCalendarVersionString() { return QByteArray("2.7.0"); }
446int KAEvent::currentCalendarVersion() { return Version(2,7,0); }
447
448// Custom calendar properties.
449// Note that all custom property names are prefixed with X-KDE-KALARM- in the calendar file.
450
451// Event properties
452const QByteArray KAEventPrivate::FLAGS_PROPERTY("FLAGS"); // X-KDE-KALARM-FLAGS property
453const QString KAEventPrivate::DATE_ONLY_FLAG = QLatin1String("DATE");
454const QString KAEventPrivate::EMAIL_BCC_FLAG = QLatin1String("BCC");
455const QString KAEventPrivate::CONFIRM_ACK_FLAG = QLatin1String("ACKCONF");
456const QString KAEventPrivate::KORGANIZER_FLAG = QLatin1String("KORG");
457const QString KAEventPrivate::EXCLUDE_HOLIDAYS_FLAG = QLatin1String("EXHOLIDAYS");
458const QString KAEventPrivate::WORK_TIME_ONLY_FLAG = QLatin1String("WORKTIME");
459const QString KAEventPrivate::REMINDER_ONCE_FLAG = QLatin1String("ONCE");
460const QString KAEventPrivate::DEFER_FLAG = QLatin1String("DEFER"); // default defer interval for this alarm
461const QString KAEventPrivate::LATE_CANCEL_FLAG = QLatin1String("LATECANCEL");
462const QString KAEventPrivate::AUTO_CLOSE_FLAG = QLatin1String("LATECLOSE");
463const QString KAEventPrivate::TEMPL_AFTER_TIME_FLAG = QLatin1String("TMPLAFTTIME");
464const QString KAEventPrivate::KMAIL_SERNUM_FLAG = QLatin1String("KMAIL");
465const QString KAEventPrivate::ARCHIVE_FLAG = QLatin1String("ARCHIVE");
466
467const QByteArray KAEventPrivate::NEXT_RECUR_PROPERTY("NEXTRECUR"); // X-KDE-KALARM-NEXTRECUR property
468const QByteArray KAEventPrivate::REPEAT_PROPERTY("REPEAT"); // X-KDE-KALARM-REPEAT property
469const QByteArray KAEventPrivate::LOG_PROPERTY("LOG"); // X-KDE-KALARM-LOG property
470const QString KAEventPrivate::xtermURL = QLatin1String("xterm:");
471const QString KAEventPrivate::displayURL = QLatin1String("display:");
472
473// - General alarm properties
474const QByteArray KAEventPrivate::TYPE_PROPERTY("TYPE"); // X-KDE-KALARM-TYPE property
475const QString KAEventPrivate::FILE_TYPE = QLatin1String("FILE");
476const QString KAEventPrivate::AT_LOGIN_TYPE = QLatin1String("LOGIN");
477const QString KAEventPrivate::REMINDER_TYPE = QLatin1String("REMINDER");
478const QString KAEventPrivate::TIME_DEFERRAL_TYPE = QLatin1String("DEFERRAL");
479const QString KAEventPrivate::DATE_DEFERRAL_TYPE = QLatin1String("DATE_DEFERRAL");
480const QString KAEventPrivate::DISPLAYING_TYPE = QLatin1String("DISPLAYING"); // used only in displaying calendar
481const QString KAEventPrivate::PRE_ACTION_TYPE = QLatin1String("PRE");
482const QString KAEventPrivate::POST_ACTION_TYPE = QLatin1String("POST");
483const QString KAEventPrivate::SOUND_REPEAT_TYPE = QLatin1String("SOUNDREPEAT");
484const QByteArray KAEventPrivate::NEXT_REPEAT_PROPERTY("NEXTREPEAT"); // X-KDE-KALARM-NEXTREPEAT property
485const QString KAEventPrivate::HIDDEN_REMINDER_FLAG = QLatin1String("HIDE");
486// - Display alarm properties
487const QByteArray KAEventPrivate::FONT_COLOUR_PROPERTY("FONTCOLOR"); // X-KDE-KALARM-FONTCOLOR property
488// - Email alarm properties
489const QString KAEventPrivate::EMAIL_ID_FLAG = QLatin1String("EMAILID");
490// - Audio alarm properties
491const QByteArray KAEventPrivate::VOLUME_PROPERTY("VOLUME"); // X-KDE-KALARM-VOLUME property
492const QString KAEventPrivate::SPEAK_FLAG = QLatin1String("SPEAK");
493// - Command alarm properties
494const QString KAEventPrivate::EXEC_ON_DEFERRAL_FLAG = QLatin1String("EXECDEFER");
495const QString KAEventPrivate::CANCEL_ON_ERROR_FLAG = QLatin1String("ERRCANCEL");
496const QString KAEventPrivate::DONT_SHOW_ERROR_FLAG = QLatin1String("ERRNOSHOW");
497
498// Event status strings
499const QString KAEventPrivate::DISABLED_STATUS = QLatin1String("DISABLED");
500
501// Displaying event ID identifier
502const QString KAEventPrivate::DISP_DEFER = QLatin1String("DEFER");
503const QString KAEventPrivate::DISP_EDIT = QLatin1String("EDIT");
504
505// Command error strings
506#ifdef KALARMCAL_USE_KRESOURCES
507QString KAEventPrivate::mCmdErrConfigGroup = QLatin1String("CommandErrors");
508#endif
509const QString KAEventPrivate::CMD_ERROR_VALUE = QLatin1String("MAIN");
510const QString KAEventPrivate::CMD_ERROR_PRE_VALUE = QLatin1String("PRE");
511const QString KAEventPrivate::CMD_ERROR_POST_VALUE = QLatin1String("POST");
512
513const QString KAEventPrivate::SC = QLatin1String(";");
514
515QFont KAEventPrivate::mDefaultFont;
516const KHolidays::HolidayRegion* KAEventPrivate::mHolidays = 0;
517QBitArray KAEventPrivate::mWorkDays(7);
518QTime KAEventPrivate::mWorkDayStart(9, 0, 0);
519QTime KAEventPrivate::mWorkDayEnd(17, 0, 0);
520int KAEventPrivate::mWorkTimeIndex = 1;
521
522#ifndef KALARMCAL_USE_KRESOURCES
523static void setProcedureAlarm(const Alarm::Ptr&, const QString& commandLine);
524#else
525static void setProcedureAlarm(Alarm*, const QString& commandLine);
526#endif
527static QString reminderToString(int minutes);
528
529/*=============================================================================
530= Class KAEvent
531= Corresponds to a KCal::Event instance.
532=============================================================================*/
533
534inline void KAEventPrivate::set_deferral(DeferType type)
535{
536 if (type)
537 {
538 if (mDeferral == NO_DEFERRAL)
539 ++mAlarmCount;
540 }
541 else
542 {
543 if (mDeferral != NO_DEFERRAL)
544 --mAlarmCount;
545 }
546 mDeferral = type;
547}
548
549inline void KAEventPrivate::activate_reminder(bool activate)
550{
551 if (activate && mReminderActive != ACTIVE_REMINDER && mReminderMinutes)
552 {
553 if (mReminderActive == NO_REMINDER)
554 ++mAlarmCount;
555 mReminderActive = ACTIVE_REMINDER;
556 }
557 else if (!activate && mReminderActive != NO_REMINDER)
558 {
559 mReminderActive = NO_REMINDER;
560 mReminderAfterTime = DateTime();
561 --mAlarmCount;
562 }
563}
564
565K_GLOBAL_STATIC_WITH_ARGS(QSharedDataPointer<KAEventPrivate>,
566 emptyKAEventPrivate, (new KAEventPrivate))
567
568KAEvent::KAEvent()
569 : d(*emptyKAEventPrivate)
570{ }
571
572KAEventPrivate::KAEventPrivate()
573 :
574#ifdef KALARMCAL_USE_KRESOURCES
575 mResource(0),
576#endif
577 mCommandError(KAEvent::CMD_NO_ERROR),
578#ifndef KALARMCAL_USE_KRESOURCES
579 mItemId(-1),
580 mCollectionId(-1),
581#endif
582 mReminderMinutes(0),
583 mReminderActive(NO_REMINDER),
584 mRevision(0),
585 mRecurrence(0),
586 mNextRepeat(0),
587 mAlarmCount(0),
588 mDeferral(NO_DEFERRAL),
589 mChangeCount(0),
590 mTriggerChanged(false),
591 mLateCancel(0),
592 mExcludeHolidays(0),
593 mWorkTimeOnly(0),
594 mCategory(CalEvent::EMPTY),
595#ifndef KALARMCAL_USE_KRESOURCES
596 mCompatibility(KACalendar::Current),
597 mReadOnly(false),
598#endif
599 mConfirmAck(false),
600 mEmailBcc(false),
601 mBeep(false),
602 mAutoClose(false),
603 mRepeatAtLogin(false),
604 mDisplaying(false)
605{ }
606
607KAEvent::KAEvent(const KDateTime& dt, const QString& message, const QColor& bg, const QColor& fg, const QFont& f,
608 SubAction action, int lateCancel, Flags flags, bool changesPending)
609 : d(new KAEventPrivate(dt, message, bg, fg, f, action, lateCancel, flags, changesPending))
610{
611}
612
613KAEventPrivate::KAEventPrivate(const KDateTime& dt, const QString& message, const QColor& bg, const QColor& fg, const QFont& f,
614 KAEvent::SubAction action, int lateCancel, KAEvent::Flags flags, bool changesPending)
615 : mRevision(0),
616 mRecurrence(0)
617{
618 set(dt, message, bg, fg, f, action, lateCancel, flags, changesPending);
619}
620
621#ifndef KALARMCAL_USE_KRESOURCES
622KAEvent::KAEvent(const Event::Ptr& e)
623#else
624KAEvent::KAEvent(const Event* e)
625#endif
626 : d(new KAEventPrivate(e))
627{
628}
629
630#ifndef KALARMCAL_USE_KRESOURCES
631KAEventPrivate::KAEventPrivate(const Event::Ptr& e)
632#else
633KAEventPrivate::KAEventPrivate(const Event* e)
634#endif
635 : mRecurrence(0)
636{
637 set(e);
638}
639
640KAEventPrivate::KAEventPrivate(const KAEventPrivate& e)
641 : QSharedData(e),
642 mRecurrence(0)
643{
644 copy(e);
645}
646
647KAEvent::KAEvent(const KAEvent& other)
648 : d(other.d)
649{ }
650
651KAEvent::~KAEvent()
652{ }
653
654KAEvent& KAEvent::operator=(const KAEvent& other)
655{
656 if (&other != this)
657 d = other.d;
658 return *this;
659}
660
661/******************************************************************************
662* Copies the data from another instance.
663*/
664void KAEventPrivate::copy(const KAEventPrivate& event)
665{
666#ifdef KALARMCAL_USE_KRESOURCES
667 mResource = event.mResource;
668#endif
669 mAllTrigger = event.mAllTrigger;
670 mMainTrigger = event.mMainTrigger;
671 mAllWorkTrigger = event.mAllWorkTrigger;
672 mMainWorkTrigger = event.mMainWorkTrigger;
673 mCommandError = event.mCommandError;
674 mEventID = event.mEventID;
675 mTemplateName = event.mTemplateName;
676#ifndef KALARMCAL_USE_KRESOURCES
677 mCustomProperties = event.mCustomProperties;
678 mItemId = event.mItemId;
679 mCollectionId = event.mCollectionId;
680#else
681 mOriginalResourceId = event.mOriginalResourceId;
682#endif
683 mText = event.mText;
684 mAudioFile = event.mAudioFile;
685 mPreAction = event.mPreAction;
686 mPostAction = event.mPostAction;
687 mStartDateTime = event.mStartDateTime;
688 mCreatedDateTime = event.mCreatedDateTime;
689 mNextMainDateTime = event.mNextMainDateTime;
690 mAtLoginDateTime = event.mAtLoginDateTime;
691 mDeferralTime = event.mDeferralTime;
692 mDisplayingTime = event.mDisplayingTime;
693 mDisplayingFlags = event.mDisplayingFlags;
694 mReminderMinutes = event.mReminderMinutes;
695 mReminderAfterTime = event.mReminderAfterTime;
696 mReminderActive = event.mReminderActive;
697 mDeferDefaultMinutes = event.mDeferDefaultMinutes;
698 mDeferDefaultDateOnly = event.mDeferDefaultDateOnly;
699 mRevision = event.mRevision;
700 mRepetition = event.mRepetition;
701 mNextRepeat = event.mNextRepeat;
702 mAlarmCount = event.mAlarmCount;
703 mDeferral = event.mDeferral;
704 mKMailSerialNumber = event.mKMailSerialNumber;
705 mTemplateAfterTime = event.mTemplateAfterTime;
706 mBgColour = event.mBgColour;
707 mFgColour = event.mFgColour;
708 mFont = event.mFont;
709 mEmailFromIdentity = event.mEmailFromIdentity;
710 mEmailAddresses = event.mEmailAddresses;
711 mEmailSubject = event.mEmailSubject;
712 mEmailAttachments = event.mEmailAttachments;
713 mLogFile = event.mLogFile;
714 mSoundVolume = event.mSoundVolume;
715 mFadeVolume = event.mFadeVolume;
716 mFadeSeconds = event.mFadeSeconds;
717 mRepeatSoundPause = event.mRepeatSoundPause;
718 mLateCancel = event.mLateCancel;
719 mExcludeHolidays = event.mExcludeHolidays;
720 mWorkTimeOnly = event.mWorkTimeOnly;
721 mActionSubType = event.mActionSubType;
722 mCategory = event.mCategory;
723 mExtraActionOptions = event.mExtraActionOptions;
724#ifndef KALARMCAL_USE_KRESOURCES
725 mCompatibility = event.mCompatibility;
726 mReadOnly = event.mReadOnly;
727#endif
728 mConfirmAck = event.mConfirmAck;
729 mUseDefaultFont = event.mUseDefaultFont;
730 mCommandScript = event.mCommandScript;
731 mCommandXterm = event.mCommandXterm;
732 mCommandDisplay = event.mCommandDisplay;
733 mEmailBcc = event.mEmailBcc;
734 mBeep = event.mBeep;
735 mSpeak = event.mSpeak;
736 mCopyToKOrganizer = event.mCopyToKOrganizer;
737 mReminderOnceOnly = event.mReminderOnceOnly;
738 mAutoClose = event.mAutoClose;
739 mMainExpired = event.mMainExpired;
740 mRepeatAtLogin = event.mRepeatAtLogin;
741 mArchiveRepeatAtLogin = event.mArchiveRepeatAtLogin;
742 mArchive = event.mArchive;
743 mDisplaying = event.mDisplaying;
744 mDisplayingDefer = event.mDisplayingDefer;
745 mDisplayingEdit = event.mDisplayingEdit;
746 mEnabled = event.mEnabled;
747 mChangeCount = 0;
748 mTriggerChanged = event.mTriggerChanged;
749 delete mRecurrence;
750 if (event.mRecurrence)
751 mRecurrence = new KARecurrence(*event.mRecurrence);
752 else
753 mRecurrence = 0;
754}
755
756#ifndef KALARMCAL_USE_KRESOURCES
757void KAEvent::set(const Event::Ptr& e)
758#else
759void KAEvent::set(const Event* e)
760#endif
761{
762 d->set(e);
763}
764
765/******************************************************************************
766* Initialise the KAEventPrivate from a KCal::Event.
767*/
768#ifndef KALARMCAL_USE_KRESOURCES
769void KAEventPrivate::set(const Event::Ptr& event)
770#else
771void KAEventPrivate::set(const Event* event)
772#endif
773{
774 startChanges();
775 // Extract status from the event
776 mCommandError = KAEvent::CMD_NO_ERROR;
777#ifdef KALARMCAL_USE_KRESOURCES
778 mResource = 0;
779#endif
780 mEventID = event->uid();
781 mRevision = event->revision();
782 mTemplateName.clear();
783 mLogFile.clear();
784#ifndef KALARMCAL_USE_KRESOURCES
785 mItemId = -1;
786 mCollectionId = -1;
787#else
788 mOriginalResourceId.clear();
789#endif
790 mTemplateAfterTime = -1;
791 mBeep = false;
792 mSpeak = false;
793 mEmailBcc = false;
794 mCommandXterm = false;
795 mCommandDisplay = false;
796 mCopyToKOrganizer = false;
797 mConfirmAck = false;
798 mArchive = false;
799 mReminderOnceOnly = false;
800 mAutoClose = false;
801 mArchiveRepeatAtLogin = false;
802 mDisplayingDefer = false;
803 mDisplayingEdit = false;
804 mDeferDefaultDateOnly = false;
805 mReminderActive = NO_REMINDER;
806 mReminderMinutes = 0;
807 mDeferDefaultMinutes = 0;
808 mLateCancel = 0;
809 mKMailSerialNumber = 0;
810 mExcludeHolidays = 0;
811 mWorkTimeOnly = 0;
812 mChangeCount = 0;
813 mBgColour = QColor(255, 255, 255); // missing/invalid colour - return white background
814 mFgColour = QColor(0, 0, 0); // and black foreground
815#ifndef KALARMCAL_USE_KRESOURCES
816 mCompatibility = KACalendar::Current;
817 mReadOnly = event->isReadOnly();
818#endif
819 mUseDefaultFont = true;
820 mEnabled = true;
821 clearRecur();
822 QString param;
823 bool ok;
824 mCategory = CalEvent::status(event, &param);
825 if (mCategory == CalEvent::DISPLAYING)
826 {
827 // It's a displaying calendar event - set values specific to displaying alarms
828 const QStringList params = param.split(SC, QString::KeepEmptyParts);
829 int n = params.count();
830 if (n)
831 {
832#ifndef KALARMCAL_USE_KRESOURCES
833 const qlonglong id = params[0].toLongLong(&ok);
834 if (ok)
835 mCollectionId = id; // original collection ID which contained the event
836#else
837 mOriginalResourceId = params[0];
838#endif
839 for (int i = 1; i < n; ++i)
840 {
841 if (params[i] == DISP_DEFER)
842 mDisplayingDefer = true;
843 if (params[i] == DISP_EDIT)
844 mDisplayingEdit = true;
845 }
846 }
847 }
848#ifndef KALARMCAL_USE_KRESOURCES
849 // Store the non-KAlarm custom properties of the event
850 const QByteArray kalarmKey = "X-KDE-" + KACalendar::APPNAME + '-';
851 mCustomProperties = event->customProperties();
852 for (QMap<QByteArray, QString>::Iterator it = mCustomProperties.begin(); it != mCustomProperties.end(); )
853 {
854 if (it.key().startsWith(kalarmKey))
855 it = mCustomProperties.erase(it);
856 else
857 ++it;
858 }
859#endif
860
861 bool dateOnly = false;
862 QStringList flags = event->customProperty(KACalendar::APPNAME, FLAGS_PROPERTY).split(SC, QString::SkipEmptyParts);
863 flags << QString() << QString(); // to avoid having to check for end of list
864 for (int i = 0, end = flags.count() - 1; i < end; ++i)
865 {
866 QString flag = flags.at(i);
867 if (flag == DATE_ONLY_FLAG)
868 dateOnly = true;
869 else if (flag == CONFIRM_ACK_FLAG)
870 mConfirmAck = true;
871 else if (flag == EMAIL_BCC_FLAG)
872 mEmailBcc = true;
873 else if (flag == KORGANIZER_FLAG)
874 mCopyToKOrganizer = true;
875 else if (flag == EXCLUDE_HOLIDAYS_FLAG)
876 mExcludeHolidays = mHolidays;
877 else if (flag == WORK_TIME_ONLY_FLAG)
878 mWorkTimeOnly = 1;
879 else if (flag == KMAIL_SERNUM_FLAG)
880 {
881 const unsigned long n = flags.at(i + 1).toULong(&ok);
882 if (!ok)
883 continue;
884 mKMailSerialNumber = n;
885 ++i;
886 }
887 else if (flag == KAEventPrivate::ARCHIVE_FLAG)
888 mArchive = true;
889 else if (flag == KAEventPrivate::AT_LOGIN_TYPE)
890 mArchiveRepeatAtLogin = true;
891 else if (flag == KAEventPrivate::REMINDER_TYPE)
892 {
893 flag = flags.at(++i);
894 if (flag == KAEventPrivate::REMINDER_ONCE_FLAG)
895 {
896 mReminderOnceOnly = true;
897 ++i;
898 }
899 const int len = flag.length() - 1;
900 mReminderMinutes = -flag.left(len).toInt(); // -> 0 if conversion fails
901 switch (flag.at(len).toLatin1())
902 {
903 case 'M': break;
904 case 'H': mReminderMinutes *= 60; break;
905 case 'D': mReminderMinutes *= 1440; break;
906 default: mReminderMinutes = 0; break;
907 }
908 }
909 else if (flag == DEFER_FLAG)
910 {
911 QString mins = flags.at(i + 1);
912 if (mins.endsWith(QLatin1Char('D')))
913 {
914 mDeferDefaultDateOnly = true;
915 mins.truncate(mins.length() - 1);
916 }
917 const int n = static_cast<int>(mins.toUInt(&ok));
918 if (!ok)
919 continue;
920 mDeferDefaultMinutes = n;
921 ++i;
922 }
923 else if (flag == TEMPL_AFTER_TIME_FLAG)
924 {
925 const int n = static_cast<int>(flags.at(i + 1).toUInt(&ok));
926 if (!ok)
927 continue;
928 mTemplateAfterTime = n;
929 ++i;
930 }
931 else if (flag == LATE_CANCEL_FLAG)
932 {
933 mLateCancel = static_cast<int>(flags.at(i + 1).toUInt(&ok));
934 if (ok)
935 ++i;
936 if (!ok || !mLateCancel)
937 mLateCancel = 1; // invalid parameter defaults to 1 minute
938 }
939 else if (flag == AUTO_CLOSE_FLAG)
940 {
941 mLateCancel = static_cast<int>(flags.at(i + 1).toUInt(&ok));
942 if (ok)
943 ++i;
944 if (!ok || !mLateCancel)
945 mLateCancel = 1; // invalid parameter defaults to 1 minute
946 mAutoClose = true;
947 }
948 }
949
950 QString prop = event->customProperty(KACalendar::APPNAME, LOG_PROPERTY);
951 if (!prop.isEmpty())
952 {
953 if (prop == xtermURL)
954 mCommandXterm = true;
955 else if (prop == displayURL)
956 mCommandDisplay = true;
957 else
958 mLogFile = prop;
959 }
960 prop = event->customProperty(KACalendar::APPNAME, REPEAT_PROPERTY);
961 if (!prop.isEmpty())
962 {
963 // This property is used when the main alarm has expired
964 const QStringList list = prop.split(QLatin1Char(':'));
965 if (list.count() >= 2)
966 {
967 const int interval = static_cast<int>(list[0].toUInt());
968 const int count = static_cast<int>(list[1].toUInt());
969 if (interval && count)
970 {
971 if (interval % (24*60))
972 mRepetition.set(Duration(interval * 60, Duration::Seconds), count);
973 else
974 mRepetition.set(Duration(interval / (24*60), Duration::Days), count);
975 }
976 }
977 }
978 mNextMainDateTime = readDateTime(event, dateOnly, mStartDateTime);
979 mCreatedDateTime = event->created();
980 if (dateOnly && !mRepetition.isDaily())
981 mRepetition.set(Duration(mRepetition.intervalDays(), Duration::Days));
982 if (mCategory == CalEvent::TEMPLATE)
983 mTemplateName = event->summary();
984#ifndef KALARMCAL_USE_KRESOURCES
985 if (event->customStatus() == DISABLED_STATUS)
986#else
987 if (event->statusStr() == DISABLED_STATUS)
988#endif
989 mEnabled = false;
990
991 // Extract status from the event's alarms.
992 // First set up defaults.
993 mActionSubType = KAEvent::MESSAGE;
994 mMainExpired = true;
995 mRepeatAtLogin = false;
996 mDisplaying = false;
997 mCommandScript = false;
998 mExtraActionOptions = 0;
999 mDeferral = NO_DEFERRAL;
1000 mSoundVolume = -1;
1001 mFadeVolume = -1;
1002 mRepeatSoundPause = -1;
1003 mFadeSeconds = 0;
1004 mEmailFromIdentity = 0;
1005 mReminderAfterTime = DateTime();
1006 mText.clear();
1007 mAudioFile.clear();
1008 mPreAction.clear();
1009 mPostAction.clear();
1010 mEmailSubject.clear();
1011 mEmailAddresses.clear();
1012 mEmailAttachments.clear();
1013
1014 // Extract data from all the event's alarms and index the alarms by sequence number
1015 AlarmMap alarmMap;
1016 readAlarms(event, &alarmMap, mCommandDisplay);
1017
1018 // Incorporate the alarms' details into the overall event
1019 mAlarmCount = 0; // initialise as invalid
1020 DateTime alTime;
1021 bool set = false;
1022 bool isEmailText = false;
1023 bool setDeferralTime = false;
1024 Duration deferralOffset;
1025 for (AlarmMap::ConstIterator it = alarmMap.constBegin(); it != alarmMap.constEnd(); ++it)
1026 {
1027 const AlarmData& data = it.value();
1028 const DateTime dateTime = data.alarm->hasStartOffset() ? data.alarm->startOffset().end(mNextMainDateTime.effectiveKDateTime()) : data.alarm->time();
1029 switch (data.type)
1030 {
1031 case MAIN_ALARM:
1032 mMainExpired = false;
1033 alTime = dateTime;
1034 alTime.setDateOnly(mStartDateTime.isDateOnly());
1035 if (data.alarm->repeatCount() && data.alarm->snoozeTime())
1036 {
1037 mRepetition.set(data.alarm->snoozeTime(), data.alarm->repeatCount()); // values may be adjusted in setRecurrence()
1038 mNextRepeat = data.nextRepeat;
1039 }
1040 if (data.action != KAAlarm::AUDIO)
1041 break;
1042 // Fall through to AUDIO_ALARM
1043 case AUDIO_ALARM:
1044 mAudioFile = data.cleanText;
1045 mSpeak = data.speak && mAudioFile.isEmpty();
1046 mBeep = !mSpeak && mAudioFile.isEmpty();
1047 mSoundVolume = (!mBeep && !mSpeak) ? data.soundVolume : -1;
1048 mFadeVolume = (mSoundVolume >= 0 && data.fadeSeconds > 0) ? data.fadeVolume : -1;
1049 mFadeSeconds = (mFadeVolume >= 0) ? data.fadeSeconds : 0;
1050 mRepeatSoundPause = (!mBeep && !mSpeak) ? data.repeatSoundPause : -1;
1051 break;
1052 case AT_LOGIN_ALARM:
1053 mRepeatAtLogin = true;
1054 mAtLoginDateTime = dateTime.kDateTime();
1055 alTime = mAtLoginDateTime;
1056 break;
1057 case REMINDER_ALARM:
1058 // N.B. there can be a start offset but no valid date/time (e.g. in template)
1059 if (data.alarm->startOffset().asSeconds() / 60)
1060 {
1061 mReminderActive = ACTIVE_REMINDER;
1062 if (mReminderMinutes < 0)
1063 {
1064 mReminderAfterTime = dateTime; // the reminder is AFTER the main alarm
1065 mReminderAfterTime.setDateOnly(dateOnly);
1066 if (data.hiddenReminder)
1067 mReminderActive = HIDDEN_REMINDER;
1068 }
1069 }
1070 break;
1071 case DEFERRED_REMINDER_ALARM:
1072 case DEFERRED_ALARM:
1073 mDeferral = (data.type == DEFERRED_REMINDER_ALARM) ? REMINDER_DEFERRAL : NORMAL_DEFERRAL;
1074 if (data.timedDeferral)
1075 {
1076 // Don't use start-of-day time for applying timed deferral alarm offset
1077 mDeferralTime = data.alarm->hasStartOffset() ? data.alarm->startOffset().end(mNextMainDateTime.calendarKDateTime()) : data.alarm->time();
1078 }
1079 else
1080 {
1081 mDeferralTime = dateTime;
1082 mDeferralTime.setDateOnly(true);
1083 }
1084 if (data.alarm->hasStartOffset())
1085 deferralOffset = data.alarm->startOffset();
1086 break;
1087 case DISPLAYING_ALARM:
1088 {
1089 mDisplaying = true;
1090 mDisplayingFlags = data.displayingFlags;
1091 const bool dateOnly = (mDisplayingFlags & DEFERRAL) ? !(mDisplayingFlags & TIMED_FLAG)
1092 : mStartDateTime.isDateOnly();
1093 mDisplayingTime = dateTime;
1094 mDisplayingTime.setDateOnly(dateOnly);
1095 alTime = mDisplayingTime;
1096 break;
1097 }
1098 case PRE_ACTION_ALARM:
1099 mPreAction = data.cleanText;
1100 mExtraActionOptions = data.extraActionOptions;
1101 break;
1102 case POST_ACTION_ALARM:
1103 mPostAction = data.cleanText;
1104 break;
1105 case INVALID_ALARM:
1106 default:
1107 break;
1108 }
1109
1110 bool noSetNextTime = false;
1111 switch (data.type)
1112 {
1113 case DEFERRED_REMINDER_ALARM:
1114 case DEFERRED_ALARM:
1115 if (!set)
1116 {
1117 // The recurrence has to be evaluated before we can
1118 // calculate the time of a deferral alarm.
1119 setDeferralTime = true;
1120 noSetNextTime = true;
1121 }
1122 // fall through to REMINDER_ALARM
1123 case REMINDER_ALARM:
1124 case AT_LOGIN_ALARM:
1125 case DISPLAYING_ALARM:
1126 if (!set && !noSetNextTime)
1127 mNextMainDateTime = alTime;
1128 // fall through to MAIN_ALARM
1129 case MAIN_ALARM:
1130 // Ensure that the basic fields are set up even if there is no main
1131 // alarm in the event (if it has expired and then been deferred)
1132 if (!set)
1133 {
1134 mActionSubType = static_cast<KAEvent::SubAction>(data.action);
1135 mText = (mActionSubType == KAEvent::COMMAND) ? data.cleanText.trimmed() : data.cleanText;
1136 switch (data.action)
1137 {
1138 case KAAlarm::COMMAND:
1139 mCommandScript = data.commandScript;
1140 if (!mCommandDisplay)
1141 break;
1142 // fall through to MESSAGE
1143 case KAAlarm::MESSAGE:
1144 mFont = data.font;
1145 mUseDefaultFont = data.defaultFont;
1146 if (data.isEmailText)
1147 isEmailText = true;
1148 // fall through to FILE
1149 case KAAlarm::FILE:
1150 mBgColour = data.bgColour;
1151 mFgColour = data.fgColour;
1152 break;
1153 case KAAlarm::EMAIL:
1154 mEmailFromIdentity = data.emailFromId;
1155 mEmailAddresses = data.alarm->mailAddresses();
1156 mEmailSubject = data.alarm->mailSubject();
1157 mEmailAttachments = data.alarm->mailAttachments();
1158 break;
1159 case KAAlarm::AUDIO:
1160 // Already mostly handled above
1161 mRepeatSoundPause = data.repeatSoundPause;
1162 break;
1163 default:
1164 break;
1165 }
1166 set = true;
1167 }
1168 if (data.action == KAAlarm::FILE && mActionSubType == KAEvent::MESSAGE)
1169 mActionSubType = KAEvent::FILE;
1170 ++mAlarmCount;
1171 break;
1172 case AUDIO_ALARM:
1173 case PRE_ACTION_ALARM:
1174 case POST_ACTION_ALARM:
1175 case INVALID_ALARM:
1176 default:
1177 break;
1178 }
1179 }
1180 if (!isEmailText)
1181 mKMailSerialNumber = 0;
1182
1183 Recurrence* recur = event->recurrence();
1184 if (recur && recur->recurs())
1185 {
1186 const int nextRepeat = mNextRepeat; // setRecurrence() clears mNextRepeat
1187 setRecurrence(*recur);
1188 if (nextRepeat <= mRepetition.count())
1189 mNextRepeat = nextRepeat;
1190 }
1191 else if (mRepetition)
1192 {
1193 // Convert a repetition with no recurrence into a recurrence
1194 if (mRepetition.isDaily())
1195 setRecur(RecurrenceRule::rDaily, mRepetition.intervalDays(), mRepetition.count() + 1, QDate());
1196 else
1197 setRecur(RecurrenceRule::rMinutely, mRepetition.intervalMinutes(), mRepetition.count() + 1, KDateTime());
1198 mRepetition.set(0, 0);
1199 mTriggerChanged = true;
1200 }
1201
1202 if (mRepeatAtLogin)
1203 {
1204 mArchiveRepeatAtLogin = false;
1205 if (mReminderMinutes > 0)
1206 {
1207 mReminderMinutes = 0; // pre-alarm reminder not allowed for at-login alarm
1208 mReminderActive = NO_REMINDER;
1209 }
1210 setRepeatAtLoginTrue(false); // clear other incompatible statuses
1211 }
1212
1213 if (mMainExpired && deferralOffset && checkRecur() != KARecurrence::NO_RECUR)
1214 {
1215 // Adjust the deferral time for an expired recurrence, since the
1216 // offset is relative to the first actual occurrence.
1217 DateTime dt = mRecurrence->getNextDateTime(mStartDateTime.addDays(-1).kDateTime());
1218 dt.setDateOnly(mStartDateTime.isDateOnly());
1219 if (mDeferralTime.isDateOnly())
1220 {
1221 mDeferralTime = deferralOffset.end(dt.kDateTime());
1222 mDeferralTime.setDateOnly(true);
1223 }
1224 else
1225 mDeferralTime = deferralOffset.end(dt.effectiveKDateTime());
1226 }
1227 if (mDeferral != NO_DEFERRAL)
1228 {
1229 if (setDeferralTime)
1230 mNextMainDateTime = mDeferralTime;
1231 }
1232 mTriggerChanged = true;
1233 endChanges();
1234}
1235
1236void KAEvent::set(const KDateTime& dt, const QString& message, const QColor& bg, const QColor& fg,
1237 const QFont& f, SubAction act, int lateCancel, Flags flags, bool changesPending)
1238{
1239 d->set(dt, message, bg, fg, f, act, lateCancel, flags, changesPending);
1240}
1241
1242/******************************************************************************
1243* Initialise the instance with the specified parameters.
1244*/
1245void KAEventPrivate::set(const KDateTime& dateTime, const QString& text, const QColor& bg, const QColor& fg,
1246 const QFont& font, KAEvent::SubAction action, int lateCancel, KAEvent::Flags flags,
1247 bool changesPending)
1248{
1249 clearRecur();
1250 mStartDateTime = dateTime;
1251 mStartDateTime.setDateOnly(flags & KAEvent::ANY_TIME);
1252 mNextMainDateTime = mStartDateTime;
1253 switch (action)
1254 {
1255 case KAEvent::MESSAGE:
1256 case KAEvent::FILE:
1257 case KAEvent::COMMAND:
1258 case KAEvent::EMAIL:
1259 case KAEvent::AUDIO:
1260 mActionSubType = static_cast<KAEvent::SubAction>(action);
1261 break;
1262 default:
1263 mActionSubType = KAEvent::MESSAGE;
1264 break;
1265 }
1266 mEventID.clear();
1267 mTemplateName.clear();
1268#ifndef KALARMCAL_USE_KRESOURCES
1269 mItemId = -1;
1270 mCollectionId = -1;
1271#else
1272 mResource = 0;
1273 mOriginalResourceId.clear();
1274#endif
1275 mPreAction.clear();
1276 mPostAction.clear();
1277 mText = (mActionSubType == KAEvent::COMMAND) ? text.trimmed()
1278 : (mActionSubType == KAEvent::AUDIO) ? QString() : text;
1279 mCategory = CalEvent::ACTIVE;
1280 mAudioFile = (mActionSubType == KAEvent::AUDIO) ? text : QString();
1281 mSoundVolume = -1;
1282 mFadeVolume = -1;
1283 mTemplateAfterTime = -1;
1284 mFadeSeconds = 0;
1285 mBgColour = bg;
1286 mFgColour = fg;
1287 mFont = font;
1288 mAlarmCount = 1;
1289 mLateCancel = lateCancel; // do this before setting flags
1290 mDeferral = NO_DEFERRAL; // do this before setting flags
1291
1292 mStartDateTime.setDateOnly(flags & KAEvent::ANY_TIME);
1293 set_deferral((flags & DEFERRAL) ? NORMAL_DEFERRAL : NO_DEFERRAL);
1294 mRepeatAtLogin = flags & KAEvent::REPEAT_AT_LOGIN;
1295 mConfirmAck = flags & KAEvent::CONFIRM_ACK;
1296 mUseDefaultFont = flags & KAEvent::DEFAULT_FONT;
1297 mCommandScript = flags & KAEvent::SCRIPT;
1298 mCommandXterm = flags & KAEvent::EXEC_IN_XTERM;
1299 mCommandDisplay = flags & KAEvent::DISPLAY_COMMAND;
1300 mCopyToKOrganizer = flags & KAEvent::COPY_KORGANIZER;
1301 mExcludeHolidays = (flags & KAEvent::EXCL_HOLIDAYS) ? mHolidays : 0;
1302 mWorkTimeOnly = flags & KAEvent::WORK_TIME_ONLY;
1303 mEmailBcc = flags & KAEvent::EMAIL_BCC;
1304 mEnabled = !(flags & KAEvent::DISABLED);
1305 mDisplaying = flags & DISPLAYING_;
1306 mReminderOnceOnly = flags & KAEvent::REMINDER_ONCE;
1307 mAutoClose = (flags & KAEvent::AUTO_CLOSE) && mLateCancel;
1308 mRepeatSoundPause = (flags & KAEvent::REPEAT_SOUND) ? 0 : -1;
1309 mSpeak = (flags & KAEvent::SPEAK) && action != KAEvent::AUDIO;
1310 mBeep = (flags & KAEvent::BEEP) && action != KAEvent::AUDIO && !mSpeak;
1311 if (mRepeatAtLogin) // do this after setting other flags
1312 {
1313 ++mAlarmCount;
1314 setRepeatAtLoginTrue(false);
1315 }
1316
1317 mKMailSerialNumber = 0;
1318 mReminderMinutes = 0;
1319 mDeferDefaultMinutes = 0;
1320 mDeferDefaultDateOnly = false;
1321 mArchiveRepeatAtLogin = false;
1322 mReminderActive = NO_REMINDER;
1323 mDisplaying = false;
1324 mMainExpired = false;
1325 mDisplayingDefer = false;
1326 mDisplayingEdit = false;
1327 mArchive = false;
1328 mReminderAfterTime = DateTime();
1329 mExtraActionOptions = 0;
1330#ifndef KALARMCAL_USE_KRESOURCES
1331 mCompatibility = KACalendar::Current;
1332 mReadOnly = false;
1333#endif
1334 mCommandError = KAEvent::CMD_NO_ERROR;
1335 mChangeCount = changesPending ? 1 : 0;
1336 mTriggerChanged = true;
1337}
1338
1339/******************************************************************************
1340* Update an existing KCal::Event with the KAEventPrivate data.
1341* If 'setCustomProperties' is true, all the KCal::Event's existing custom
1342* properties are cleared and replaced with the KAEvent's custom properties. If
1343* false, the KCal::Event's non-KAlarm custom properties are left untouched.
1344*/
1345#ifndef KALARMCAL_USE_KRESOURCES
1346bool KAEvent::updateKCalEvent(const KCalCore::Event::Ptr& e, UidAction u, bool setCustomProperties) const
1347{
1348 return d->updateKCalEvent(e, u, setCustomProperties);
1349}
1350
1351#else
1352bool KAEvent::updateKCalEvent(KCal::Event* e, UidAction u) const
1353{
1354 return d->updateKCalEvent(e, u);
1355}
1356#endif
1357
1358#ifndef KALARMCAL_USE_KRESOURCES
1359bool KAEventPrivate::updateKCalEvent(const Event::Ptr& ev, KAEvent::UidAction uidact, bool setCustomProperties) const
1360#else
1361bool KAEventPrivate::updateKCalEvent(Event* ev, KAEvent::UidAction uidact) const
1362#endif
1363{
1364 // If it's an archived event, the event start date/time will be adjusted to its original
1365 // value instead of its next occurrence, and the expired main alarm will be reinstated.
1366 const bool archived = (mCategory == CalEvent::ARCHIVED);
1367
1368 if (!ev
1369 || (uidact == KAEvent::UID_CHECK && !mEventID.isEmpty() && mEventID != ev->uid())
1370 || (!mAlarmCount && (!archived || !mMainExpired)))
1371 return false;
1372
1373 ev->startUpdates(); // prevent multiple update notifications
1374 checkRecur(); // ensure recurrence/repetition data is consistent
1375 const bool readOnly = ev->isReadOnly();
1376 if (uidact == KAEvent::UID_SET)
1377 ev->setUid(mEventID);
1378#ifndef KALARMCAL_USE_KRESOURCES
1379 ev->setReadOnly(mReadOnly);
1380#else
1381 ev->setReadOnly(false);
1382#endif
1383 ev->setTransparency(Event::Transparent);
1384
1385 // Set up event-specific data
1386
1387 // Set up custom properties.
1388#ifndef KALARMCAL_USE_KRESOURCES
1389 if (setCustomProperties)
1390 ev->setCustomProperties(mCustomProperties);
1391#endif
1392 ev->removeCustomProperty(KACalendar::APPNAME, FLAGS_PROPERTY);
1393 ev->removeCustomProperty(KACalendar::APPNAME, NEXT_RECUR_PROPERTY);
1394 ev->removeCustomProperty(KACalendar::APPNAME, REPEAT_PROPERTY);
1395 ev->removeCustomProperty(KACalendar::APPNAME, LOG_PROPERTY);
1396
1397 QString param;
1398 if (mCategory == CalEvent::DISPLAYING)
1399 {
1400#ifndef KALARMCAL_USE_KRESOURCES
1401 param = QString::number(mCollectionId); // original collection ID which contained the event
1402#else
1403 param = mOriginalResourceId;
1404#endif
1405 if (mDisplayingDefer)
1406 param += SC + DISP_DEFER;
1407 if (mDisplayingEdit)
1408 param += SC + DISP_EDIT;
1409 }
1410#ifndef KALARMCAL_USE_KRESOURCES
1411 CalEvent::setStatus(ev, mCategory, param);
1412#else
1413 CalEvent::setStatus(ev, mCategory, param);
1414#endif
1415 QStringList flags;
1416 if (mStartDateTime.isDateOnly())
1417 flags += DATE_ONLY_FLAG;
1418 if (mConfirmAck)
1419 flags += CONFIRM_ACK_FLAG;
1420 if (mEmailBcc)
1421 flags += EMAIL_BCC_FLAG;
1422 if (mCopyToKOrganizer)
1423 flags += KORGANIZER_FLAG;
1424 if (mExcludeHolidays)
1425 flags += EXCLUDE_HOLIDAYS_FLAG;
1426 if (mWorkTimeOnly)
1427 flags += WORK_TIME_ONLY_FLAG;
1428 if (mLateCancel)
1429 (flags += (mAutoClose ? AUTO_CLOSE_FLAG : LATE_CANCEL_FLAG)) += QString::number(mLateCancel);
1430 if (mReminderMinutes)
1431 {
1432 flags += REMINDER_TYPE;
1433 if (mReminderOnceOnly)
1434 flags += REMINDER_ONCE_FLAG;
1435 flags += reminderToString(-mReminderMinutes);
1436 }
1437 if (mDeferDefaultMinutes)
1438 {
1439 QString param = QString::number(mDeferDefaultMinutes);
1440 if (mDeferDefaultDateOnly)
1441 param += QLatin1Char('D');
1442 (flags += DEFER_FLAG) += param;
1443 }
1444 if (!mTemplateName.isEmpty() && mTemplateAfterTime >= 0)
1445 (flags += TEMPL_AFTER_TIME_FLAG) += QString::number(mTemplateAfterTime);
1446 if (mKMailSerialNumber)
1447 (flags += KMAIL_SERNUM_FLAG) += QString::number(mKMailSerialNumber);
1448 if (mArchive && !archived)
1449 {
1450 flags += ARCHIVE_FLAG;
1451 if (mArchiveRepeatAtLogin)
1452 flags += AT_LOGIN_TYPE;
1453 }
1454 if (!flags.isEmpty())
1455 ev->setCustomProperty(KACalendar::APPNAME, FLAGS_PROPERTY, flags.join(SC));
1456
1457 if (mCommandXterm)
1458 ev->setCustomProperty(KACalendar::APPNAME, LOG_PROPERTY, xtermURL);
1459 else if (mCommandDisplay)
1460 ev->setCustomProperty(KACalendar::APPNAME, LOG_PROPERTY, displayURL);
1461 else if (!mLogFile.isEmpty())
1462 ev->setCustomProperty(KACalendar::APPNAME, LOG_PROPERTY, mLogFile);
1463
1464 ev->setCustomStatus(mEnabled ? QString() : DISABLED_STATUS);
1465 ev->setRevision(mRevision);
1466 ev->clearAlarms();
1467
1468 /* Always set DTSTART as date/time, and use the category "DATE" to indicate
1469 * a date-only event, instead of calling setAllDay(). This is necessary to
1470 * allow a time zone to be specified for a date-only event. Also, KAlarm
1471 * allows the alarm to float within the 24-hour period defined by the
1472 * start-of-day time (which is user-dependent and therefore can't be
1473 * written into the calendar) rather than midnight to midnight, and there
1474 * is no RFC2445 conformant way to specify this.
1475 * RFC2445 states that alarm trigger times specified in absolute terms
1476 * (rather than relative to DTSTART or DTEND) can only be specified as a
1477 * UTC DATE-TIME value. So always use a time relative to DTSTART instead of
1478 * an absolute time.
1479 */
1480 ev->setDtStart(mStartDateTime.calendarKDateTime());
1481 ev->setAllDay(false);
1482 ev->setDtEnd(KDateTime());
1483
1484 const DateTime dtMain = archived ? mStartDateTime : mNextMainDateTime;
1485 int ancillaryType = 0; // 0 = invalid, 1 = time, 2 = offset
1486 DateTime ancillaryTime; // time for ancillary alarms (pre-action, extra audio, etc)
1487 int ancillaryOffset = 0; // start offset for ancillary alarms
1488 if (!mMainExpired || archived)
1489 {
1490 /* The alarm offset must always be zero for the main alarm. To determine
1491 * which recurrence is due, the property X-KDE-KALARM_NEXTRECUR is used.
1492 * If the alarm offset was non-zero, exception dates and rules would not
1493 * work since they apply to the event time, not the alarm time.
1494 */
1495 if (!archived && checkRecur() != KARecurrence::NO_RECUR)
1496 {
1497 QDateTime dt = mNextMainDateTime.kDateTime().toTimeSpec(mStartDateTime.timeSpec()).dateTime();
1498 ev->setCustomProperty(KACalendar::APPNAME, NEXT_RECUR_PROPERTY,
1499 dt.toString(mNextMainDateTime.isDateOnly() ? QLatin1String("yyyyMMdd") : QLatin1String("yyyyMMddThhmmss")));
1500 }
1501 // Add the main alarm
1502 initKCalAlarm(ev, 0, QStringList(), MAIN_ALARM);
1503 ancillaryOffset = 0;
1504 ancillaryType = dtMain.isValid() ? 2 : 0;
1505 }
1506 else if (mRepetition)
1507 {
1508 // Alarm repetition is normally held in the main alarm, but since
1509 // the main alarm has expired, store in a custom property.
1510 const QString param = QString::fromLatin1("%1:%2").arg(mRepetition.intervalMinutes()).arg(mRepetition.count());
1511 ev->setCustomProperty(KACalendar::APPNAME, REPEAT_PROPERTY, param);
1512 }
1513
1514 // Add subsidiary alarms
1515 if (mRepeatAtLogin || (mArchiveRepeatAtLogin && archived))
1516 {
1517 DateTime dtl;
1518 if (mArchiveRepeatAtLogin)
1519 dtl = mStartDateTime.calendarKDateTime().addDays(-1);
1520 else if (mAtLoginDateTime.isValid())
1521 dtl = mAtLoginDateTime;
1522 else if (mStartDateTime.isDateOnly())
1523 dtl = DateTime(KDateTime::currentLocalDate().addDays(-1), mStartDateTime.timeSpec());
1524 else
1525 dtl = KDateTime::currentUtcDateTime();
1526 initKCalAlarm(ev, dtl, QStringList(AT_LOGIN_TYPE));
1527 if (!ancillaryType && dtl.isValid())
1528 {
1529 ancillaryTime = dtl;
1530 ancillaryType = 1;
1531 }
1532 }
1533
1534 // Find the base date/time for calculating alarm offsets
1535 DateTime nextDateTime = mNextMainDateTime;
1536 if (mMainExpired)
1537 {
1538 if (checkRecur() == KARecurrence::NO_RECUR)
1539 nextDateTime = mStartDateTime;
1540 else if (!archived)
1541 {
1542 // It's a deferral of an expired recurrence.
1543 // Need to ensure that the alarm offset is to an occurrence
1544 // which isn't excluded by an exception - otherwise, it will
1545 // never be triggered. So choose the first recurrence which
1546 // isn't an exception.
1547 KDateTime dt = mRecurrence->getNextDateTime(mStartDateTime.addDays(-1).kDateTime());
1548 dt.setDateOnly(mStartDateTime.isDateOnly());
1549 nextDateTime = dt;
1550 }
1551 }
1552
1553 if (mReminderMinutes && (mReminderActive != NO_REMINDER || archived))
1554 {
1555 int startOffset;
1556 if (mReminderMinutes < 0 && mReminderActive != NO_REMINDER)
1557 {
1558 // A reminder AFTER the main alarm is active or disabled
1559 startOffset = nextDateTime.calendarKDateTime().secsTo(mReminderAfterTime.calendarKDateTime());
1560 }
1561 else
1562 {
1563 // A reminder BEFORE the main alarm is active
1564 startOffset = -mReminderMinutes * 60;
1565 }
1566 initKCalAlarm(ev, startOffset, QStringList(REMINDER_TYPE));
1567 // Don't set ancillary time if the reminder AFTER is hidden by a deferral
1568 if (!ancillaryType && (mReminderActive == ACTIVE_REMINDER || archived))
1569 {
1570 ancillaryOffset = startOffset;
1571 ancillaryType = 2;
1572 }
1573 }
1574 if (mDeferral != NO_DEFERRAL)
1575 {
1576 int startOffset;
1577 QStringList list;
1578 if (mDeferralTime.isDateOnly())
1579 {
1580 startOffset = nextDateTime.secsTo(mDeferralTime.calendarKDateTime());
1581 list += DATE_DEFERRAL_TYPE;
1582 }
1583 else
1584 {
1585 startOffset = nextDateTime.calendarKDateTime().secsTo(mDeferralTime.calendarKDateTime());
1586 list += TIME_DEFERRAL_TYPE;
1587 }
1588 if (mDeferral == REMINDER_DEFERRAL)
1589 list += REMINDER_TYPE;
1590 initKCalAlarm(ev, startOffset, list);
1591 if (!ancillaryType && mDeferralTime.isValid())
1592 {
1593 ancillaryOffset = startOffset;
1594 ancillaryType = 2;
1595 }
1596 }
1597 if (!mTemplateName.isEmpty())
1598 ev->setSummary(mTemplateName);
1599 else if (mDisplaying)
1600 {
1601 QStringList list(DISPLAYING_TYPE);
1602 if (mDisplayingFlags & KAEvent::REPEAT_AT_LOGIN)
1603 list += AT_LOGIN_TYPE;
1604 else if (mDisplayingFlags & DEFERRAL)
1605 {
1606 if (mDisplayingFlags & TIMED_FLAG)
1607 list += TIME_DEFERRAL_TYPE;
1608 else
1609 list += DATE_DEFERRAL_TYPE;
1610 }
1611 if (mDisplayingFlags & REMINDER)
1612 list += REMINDER_TYPE;
1613 initKCalAlarm(ev, mDisplayingTime, list);
1614 if (!ancillaryType && mDisplayingTime.isValid())
1615 {
1616 ancillaryTime = mDisplayingTime;
1617 ancillaryType = 1;
1618 }
1619 }
1620 if ((mBeep || mSpeak || !mAudioFile.isEmpty()) && mActionSubType != KAEvent::AUDIO)
1621 {
1622 // A sound is specified
1623 if (ancillaryType == 2)
1624 initKCalAlarm(ev, ancillaryOffset, QStringList(), AUDIO_ALARM);
1625 else
1626 initKCalAlarm(ev, ancillaryTime, QStringList(), AUDIO_ALARM);
1627 }
1628 if (!mPreAction.isEmpty())
1629 {
1630 // A pre-display action is specified
1631 if (ancillaryType == 2)
1632 initKCalAlarm(ev, ancillaryOffset, QStringList(PRE_ACTION_TYPE), PRE_ACTION_ALARM);
1633 else
1634 initKCalAlarm(ev, ancillaryTime, QStringList(PRE_ACTION_TYPE), PRE_ACTION_ALARM);
1635 }
1636 if (!mPostAction.isEmpty())
1637 {
1638 // A post-display action is specified
1639 if (ancillaryType == 2)
1640 initKCalAlarm(ev, ancillaryOffset, QStringList(POST_ACTION_TYPE), POST_ACTION_ALARM);
1641 else
1642 initKCalAlarm(ev, ancillaryTime, QStringList(POST_ACTION_TYPE), POST_ACTION_ALARM);
1643 }
1644
1645 if (mRecurrence)
1646 mRecurrence->writeRecurrence(*ev->recurrence());
1647 else
1648 ev->clearRecurrence();
1649 if (mCreatedDateTime.isValid())
1650 ev->setCreated(mCreatedDateTime);
1651 ev->setReadOnly(readOnly);
1652 ev->endUpdates(); // finally issue an update notification
1653 return true;
1654}
1655
1656/******************************************************************************
1657* Create a new alarm for a libkcal event, and initialise it according to the
1658* alarm action. If 'types' is non-null, it is appended to the X-KDE-KALARM-TYPE
1659* property value list.
1660* NOTE: The variant taking a DateTime calculates the offset from mStartDateTime,
1661* which is not suitable for an alarm in a recurring event.
1662*/
1663#ifndef KALARMCAL_USE_KRESOURCES
1664Alarm::Ptr KAEventPrivate::initKCalAlarm(const Event::Ptr& event, const DateTime& dt, const QStringList& types, AlarmType type) const
1665#else
1666Alarm* KAEventPrivate::initKCalAlarm(Event* event, const DateTime& dt, const QStringList& types, AlarmType type) const
1667#endif
1668{
1669 const int startOffset = dt.isDateOnly() ? mStartDateTime.secsTo(dt)
1670 : mStartDateTime.calendarKDateTime().secsTo(dt.calendarKDateTime());
1671 return initKCalAlarm(event, startOffset, types, type);
1672}
1673
1674#ifndef KALARMCAL_USE_KRESOURCES
1675Alarm::Ptr KAEventPrivate::initKCalAlarm(const Event::Ptr& event, int startOffsetSecs, const QStringList& types, AlarmType type) const
1676#else
1677Alarm* KAEventPrivate::initKCalAlarm(Event* event, int startOffsetSecs, const QStringList& types, AlarmType type) const
1678#endif
1679{
1680 QStringList alltypes;
1681 QStringList flags;
1682#ifndef KALARMCAL_USE_KRESOURCES
1683 Alarm::Ptr alarm = event->newAlarm();
1684#else
1685 Alarm* alarm = event->newAlarm();
1686#endif
1687 alarm->setEnabled(true);
1688 if (type != MAIN_ALARM)
1689 {
1690 // RFC2445 specifies that absolute alarm times must be stored as a UTC DATE-TIME value.
1691 // Set the alarm time as an offset to DTSTART for the reasons described in updateKCalEvent().
1692 alarm->setStartOffset(startOffsetSecs);
1693 }
1694
1695 switch (type)
1696 {
1697 case AUDIO_ALARM:
1698 setAudioAlarm(alarm);
1699 if (mSpeak)
1700 flags << KAEventPrivate::SPEAK_FLAG;
1701 if (mRepeatSoundPause >= 0)
1702 {
1703 // Alarm::setSnoozeTime() sets 5 seconds if duration parameter is zero,
1704 // so repeat count = -1 represents 0 pause, -2 represents non-zero pause.
1705 alarm->setRepeatCount(mRepeatSoundPause ? -2 : -1);
1706 alarm->setSnoozeTime(Duration(mRepeatSoundPause, Duration::Seconds));
1707 }
1708 break;
1709 case PRE_ACTION_ALARM:
1710 setProcedureAlarm(alarm, mPreAction);
1711 if (mExtraActionOptions & KAEvent::ExecPreActOnDeferral)
1712 flags << KAEventPrivate::EXEC_ON_DEFERRAL_FLAG;
1713 if (mExtraActionOptions & KAEvent::CancelOnPreActError)
1714 flags << KAEventPrivate::CANCEL_ON_ERROR_FLAG;
1715 if (mExtraActionOptions & KAEvent::DontShowPreActError)
1716 flags << KAEventPrivate::DONT_SHOW_ERROR_FLAG;
1717 break;
1718 case POST_ACTION_ALARM:
1719 setProcedureAlarm(alarm, mPostAction);
1720 break;
1721 case MAIN_ALARM:
1722 alarm->setSnoozeTime(mRepetition.interval());
1723 alarm->setRepeatCount(mRepetition.count());
1724 if (mRepetition)
1725 alarm->setCustomProperty(KACalendar::APPNAME, NEXT_REPEAT_PROPERTY,
1726 QString::number(mNextRepeat));
1727 // fall through to INVALID_ALARM
1728 case REMINDER_ALARM:
1729 case INVALID_ALARM:
1730 {
1731 if (types == QStringList(REMINDER_TYPE)
1732 && mReminderMinutes < 0 && mReminderActive == HIDDEN_REMINDER)
1733 {
1734 // It's a reminder AFTER the alarm which is currently disabled
1735 // due to the main alarm being deferred past it.
1736 flags << HIDDEN_REMINDER_FLAG;
1737 }
1738 bool display = false;
1739 switch (mActionSubType)
1740 {
1741 case KAEvent::FILE:
1742 alltypes += FILE_TYPE;
1743 // fall through to MESSAGE
1744 case KAEvent::MESSAGE:
1745 alarm->setDisplayAlarm(AlarmText::toCalendarText(mText));
1746 display = true;
1747 break;
1748 case KAEvent::COMMAND:
1749 if (mCommandScript)
1750 alarm->setProcedureAlarm(QString(), mText);
1751 else
1752 setProcedureAlarm(alarm, mText);
1753 display = mCommandDisplay;
1754 break;
1755 case KAEvent::EMAIL:
1756 alarm->setEmailAlarm(mEmailSubject, mText, mEmailAddresses, mEmailAttachments);
1757 if (mEmailFromIdentity)
1758 flags << KAEventPrivate::EMAIL_ID_FLAG << QString::number(mEmailFromIdentity);
1759 break;
1760 case KAEvent::AUDIO:
1761 setAudioAlarm(alarm);
1762 if (mRepeatSoundPause >= 0)
1763 {
1764 alltypes += SOUND_REPEAT_TYPE;
1765 if (type == MAIN_ALARM)
1766 alltypes += QString::number(mRepeatSoundPause);
1767 }
1768 break;
1769 }
1770 if (display)
1771 alarm->setCustomProperty(KACalendar::APPNAME, FONT_COLOUR_PROPERTY,
1772 QString::fromLatin1("%1;%2;%3").arg(mBgColour.name())
1773 .arg(mFgColour.name())
1774 .arg(mUseDefaultFont ? QString() : mFont.toString()));
1775 break;
1776 }
1777 case DEFERRED_ALARM:
1778 case DEFERRED_REMINDER_ALARM:
1779 case AT_LOGIN_ALARM:
1780 case DISPLAYING_ALARM:
1781 break;
1782 }
1783 alltypes += types;
1784 if (!alltypes.isEmpty())
1785 alarm->setCustomProperty(KACalendar::APPNAME, TYPE_PROPERTY, alltypes.join(QLatin1String(",")));
1786 if (!flags.isEmpty())
1787 alarm->setCustomProperty(KACalendar::APPNAME, FLAGS_PROPERTY, flags.join(SC));
1788 return alarm;
1789}
1790
1791bool KAEvent::isValid() const
1792{
1793 return d->mAlarmCount && (d->mAlarmCount != 1 || !d->mRepeatAtLogin);
1794}
1795
1796void KAEvent::setEnabled(bool enable)
1797{
1798 d->mEnabled = enable;
1799}
1800
1801bool KAEvent::enabled() const
1802{
1803 return d->mEnabled;
1804}
1805
1806#ifndef KALARMCAL_USE_KRESOURCES
1807void KAEvent::setReadOnly(bool ro)
1808{
1809 d->mReadOnly = ro;
1810}
1811
1812bool KAEvent::isReadOnly() const
1813{
1814 return d->mReadOnly;
1815}
1816#endif
1817
1818void KAEvent::setArchive()
1819{
1820 d->mArchive = true;
1821}
1822
1823bool KAEvent::toBeArchived() const
1824{
1825 return d->mArchive;
1826}
1827
1828bool KAEvent::mainExpired() const
1829{
1830 return d->mMainExpired;
1831}
1832
1833bool KAEvent::expired() const
1834{
1835 return (d->mDisplaying && d->mMainExpired) || d->mCategory == CalEvent::ARCHIVED;
1836}
1837
1838KAEvent::Flags KAEvent::flags() const
1839{
1840 return d->flags();
1841}
1842
1843KAEvent::Flags KAEventPrivate::flags() const
1844{
1845 KAEvent::Flags result(0);
1846 if (mBeep) result |= KAEvent::BEEP;
1847 if (mRepeatSoundPause >= 0) result |= KAEvent::REPEAT_SOUND;
1848 if (mEmailBcc) result |= KAEvent::EMAIL_BCC;
1849 if (mStartDateTime.isDateOnly()) result |= KAEvent::ANY_TIME;
1850 if (mSpeak) result |= KAEvent::SPEAK;
1851 if (mRepeatAtLogin) result |= KAEvent::REPEAT_AT_LOGIN;
1852 if (mConfirmAck) result |= KAEvent::CONFIRM_ACK;
1853 if (mUseDefaultFont) result |= KAEvent::DEFAULT_FONT;
1854 if (mCommandScript) result |= KAEvent::SCRIPT;
1855 if (mCommandXterm) result |= KAEvent::EXEC_IN_XTERM;
1856 if (mCommandDisplay) result |= KAEvent::DISPLAY_COMMAND;
1857 if (mCopyToKOrganizer) result |= KAEvent::COPY_KORGANIZER;
1858 if (mExcludeHolidays) result |= KAEvent::EXCL_HOLIDAYS;
1859 if (mWorkTimeOnly) result |= KAEvent::WORK_TIME_ONLY;
1860 if (mReminderOnceOnly) result |= KAEvent::REMINDER_ONCE;
1861 if (mAutoClose) result |= KAEvent::AUTO_CLOSE;
1862 if (!mEnabled) result |= KAEvent::DISABLED;
1863 return result;
1864}
1865
1866/******************************************************************************
1867* Change the type of an event.
1868* If it is being set to archived, set the archived indication in the event ID;
1869* otherwise, remove the archived indication from the event ID.
1870*/
1871void KAEvent::setCategory(CalEvent::Type s)
1872{
1873 d->setCategory(s);
1874}
1875
1876void KAEventPrivate::setCategory(CalEvent::Type s)
1877{
1878 if (s == mCategory)
1879 return;
1880 mEventID = CalEvent::uid(mEventID, s);
1881 mCategory = s;
1882 mTriggerChanged = true; // templates and archived don't have trigger times
1883}
1884
1885CalEvent::Type KAEvent::category() const
1886{
1887 return d->mCategory;
1888}
1889
1890void KAEvent::setEventId(const QString& id)
1891{
1892 d->mEventID = id;
1893}
1894
1895QString KAEvent::id() const
1896{
1897 return d->mEventID;
1898}
1899
1900void KAEvent::incrementRevision()
1901{
1902 ++d->mRevision;
1903}
1904
1905int KAEvent::revision() const
1906{
1907 return d->mRevision;
1908}
1909
1910#ifndef KALARMCAL_USE_KRESOURCES
1911void KAEvent::setCollectionId(Akonadi::Collection::Id id)
1912{
1913 d->mCollectionId = id;
1914}
1915
1916void KAEvent::setCollectionId_const(Akonadi::Collection::Id id) const
1917{
1918 d->mCollectionId = id;
1919}
1920
1921Akonadi::Collection::Id KAEvent::collectionId() const
1922{
1923 // A displaying alarm contains the event's original collection ID
1924 return d->mDisplaying ? -1 : d->mCollectionId;
1925}
1926
1927void KAEvent::setItemId(Akonadi::Item::Id id)
1928{
1929 d->mItemId = id;
1930}
1931
1932Akonadi::Item::Id KAEvent::itemId() const
1933{
1934 return d->mItemId;
1935}
1936
1937/******************************************************************************
1938* Initialise an Item with the event.
1939* Note that the event is not updated with the Item ID.
1940* Reply = true if successful,
1941* false if event's category does not match collection's mime types.
1942*/
1943bool KAEvent::setItemPayload(Akonadi::Item& item, const QStringList& collectionMimeTypes) const
1944{
1945 QString mimetype;
1946 switch (d->mCategory)
1947 {
1948 case CalEvent::ACTIVE: mimetype = MIME_ACTIVE; break;
1949 case CalEvent::ARCHIVED: mimetype = MIME_ARCHIVED; break;
1950 case CalEvent::TEMPLATE: mimetype = MIME_TEMPLATE; break;
1951 default: Q_ASSERT(0); return false;
1952 }
1953 if (!collectionMimeTypes.contains(mimetype))
1954 return false;
1955 item.setMimeType(mimetype);
1956 item.setPayload<KAEvent>(*this);
1957 return true;
1958}
1959
1960void KAEvent::setCompatibility(KACalendar::Compat c)
1961{
1962 d->mCompatibility = c;
1963}
1964
1965KACalendar::Compat KAEvent::compatibility() const
1966{
1967 return d->mCompatibility;
1968}
1969
1970QMap<QByteArray, QString> KAEvent::customProperties() const
1971{
1972 return d->mCustomProperties;
1973}
1974
1975#else
1976void KAEvent::setResource(AlarmResource* r)
1977{
1978 d->mResource = r;
1979}
1980
1981AlarmResource* KAEvent::resource() const
1982{
1983 return d->mResource;
1984}
1985#endif
1986
1987KAEvent::SubAction KAEvent::actionSubType() const
1988{
1989 return d->mActionSubType;
1990}
1991
1992KAEvent::Actions KAEvent::actionTypes() const
1993{
1994 switch (d->mActionSubType)
1995 {
1996 case MESSAGE:
1997 case FILE: return ACT_DISPLAY;
1998 case COMMAND: return d->mCommandDisplay ? ACT_DISPLAY_COMMAND : ACT_COMMAND;
1999 case EMAIL: return ACT_EMAIL;
2000 case AUDIO: return ACT_AUDIO;
2001 default: return ACT_NONE;
2002 }
2003}
2004
2005void KAEvent::setLateCancel(int minutes)
2006{
2007 if (d->mRepeatAtLogin)
2008 minutes = 0;
2009 d->mLateCancel = minutes;
2010 if (!minutes)
2011 d->mAutoClose = false;
2012}
2013
2014int KAEvent::lateCancel() const
2015{
2016 return d->mLateCancel;
2017}
2018
2019void KAEvent::setAutoClose(bool ac)
2020{
2021 d->mAutoClose = ac;
2022}
2023
2024bool KAEvent::autoClose() const
2025{
2026 return d->mAutoClose;
2027}
2028
2029void KAEvent::setKMailSerialNumber(unsigned long n)
2030{
2031 d->mKMailSerialNumber = n;
2032}
2033
2034unsigned long KAEvent::kmailSerialNumber() const
2035{
2036 return d->mKMailSerialNumber;
2037}
2038
2039QString KAEvent::cleanText() const
2040{
2041 return d->mText;
2042}
2043
2044QString KAEvent::message() const
2045{
2046 return (d->mActionSubType == MESSAGE
2047 || d->mActionSubType == EMAIL) ? d->mText : QString();
2048}
2049
2050QString KAEvent::displayMessage() const
2051{
2052 return (d->mActionSubType == MESSAGE) ? d->mText : QString();
2053}
2054
2055QString KAEvent::fileName() const
2056{
2057 return (d->mActionSubType == FILE) ? d->mText : QString();
2058}
2059
2060QColor KAEvent::bgColour() const
2061{
2062 return d->mBgColour;
2063}
2064
2065QColor KAEvent::fgColour() const
2066{
2067 return d->mFgColour;
2068}
2069
2070void KAEvent::setDefaultFont(const QFont& f)
2071{
2072 KAEventPrivate::mDefaultFont = f;
2073}
2074
2075bool KAEvent::useDefaultFont() const
2076{
2077 return d->mUseDefaultFont;
2078}
2079
2080QFont KAEvent::font() const
2081{
2082 return d->mUseDefaultFont ? KAEventPrivate::mDefaultFont : d->mFont;
2083}
2084
2085QString KAEvent::command() const
2086{
2087 return (d->mActionSubType == COMMAND) ? d->mText : QString();
2088}
2089
2090bool KAEvent::commandScript() const
2091{
2092 return d->mCommandScript;
2093}
2094
2095bool KAEvent::commandXterm() const
2096{
2097 return d->mCommandXterm;
2098}
2099
2100bool KAEvent::commandDisplay() const
2101{
2102 return d->mCommandDisplay;
2103}
2104
2105#ifndef KALARMCAL_USE_KRESOURCES
2106void KAEvent::setCommandError(CmdErrType t) const
2107{
2108 d->mCommandError = t;
2109}
2110
2111#else
2112/******************************************************************************
2113* Set the command last error status.
2114* If 'writeConfig' is true, the status is written to the config file.
2115*/
2116void KAEvent::setCommandError(CmdErrType t, bool writeConfig) const
2117{
2118 d->setCommandError(t, writeConfig);
2119}
2120
2121void KAEventPrivate::setCommandError(KAEvent::CmdErrType error, bool writeConfig) const
2122{
2123 kDebug() << mEventID << "," << error;
2124 if (error == mCommandError)
2125 return;
2126 mCommandError = error;
2127 if (writeConfig)
2128 {
2129 KConfigGroup config(KGlobal::config(), mCmdErrConfigGroup);
2130 if (mCommandError == KAEvent::CMD_NO_ERROR)
2131 config.deleteEntry(mEventID);
2132 else
2133 {
2134 QString errtext;
2135 switch (mCommandError)
2136 {
2137 case KAEvent::CMD_ERROR: errtext = CMD_ERROR_VALUE; break;
2138 case KAEvent::CMD_ERROR_PRE: errtext = CMD_ERROR_PRE_VALUE; break;
2139 case KAEvent::CMD_ERROR_POST: errtext = CMD_ERROR_POST_VALUE; break;
2140 case KAEvent::CMD_ERROR_PRE_POST:
2141 errtext = CMD_ERROR_PRE_VALUE + ',' + CMD_ERROR_POST_VALUE;
2142 break;
2143 default:
2144 break;
2145 }
2146 config.writeEntry(mEventID, errtext);
2147 }
2148 config.sync();
2149 }
2150}
2151
2152/******************************************************************************
2153* Initialise the command last error status of the alarm from the config file.
2154*/
2155void KAEvent::setCommandError(const QString& configString)
2156{
2157 d->setCommandError(configString);
2158}
2159
2160void KAEventPrivate::setCommandError(const QString& configString)
2161{
2162 mCommandError = KAEvent::CMD_NO_ERROR;
2163 const QStringList errs = configString.split(',');
2164 if (errs.indexOf(CMD_ERROR_VALUE) >= 0)
2165 mCommandError = KAEvent::CMD_ERROR;
2166 else
2167 {
2168 if (errs.indexOf(CMD_ERROR_PRE_VALUE) >= 0)
2169 mCommandError = KAEvent::CMD_ERROR_PRE;
2170 if (errs.indexOf(CMD_ERROR_POST_VALUE) >= 0)
2171 mCommandError = static_cast<KAEvent::CmdErrType>(mCommandError | KAEvent::CMD_ERROR_POST);
2172 }
2173}
2174
2175QString KAEvent::commandErrorConfigGroup()
2176{
2177 return KAEventPrivate::mCmdErrConfigGroup;
2178}
2179#endif
2180
2181KAEvent::CmdErrType KAEvent::commandError() const
2182{
2183 return d->mCommandError;
2184}
2185
2186void KAEvent::setLogFile(const QString& logfile)
2187{
2188 d->mLogFile = logfile;
2189 if (!logfile.isEmpty())
2190 d->mCommandDisplay = d->mCommandXterm = false;
2191}
2192
2193QString KAEvent::logFile() const
2194{
2195 return d->mLogFile;
2196}
2197
2198bool KAEvent::confirmAck() const
2199{
2200 return d->mConfirmAck;
2201}
2202
2203bool KAEvent::copyToKOrganizer() const
2204{
2205 return d->mCopyToKOrganizer;
2206}
2207
2208#ifndef KALARMCAL_USE_KRESOURCES
2209void KAEvent::setEmail(uint from, const KCalCore::Person::List& addresses, const QString& subject,
2210 const QStringList& attachments)
2211#else
2212void KAEvent::setEmail(uint from, const QList<KCal::Person>& addresses, const QString& subject,
2213 const QStringList& attachments)
2214#endif
2215{
2216 d->mEmailFromIdentity = from;
2217 d->mEmailAddresses = addresses;
2218 d->mEmailSubject = subject;
2219 d->mEmailAttachments = attachments;
2220}
2221
2222QString KAEvent::emailMessage() const
2223{
2224 return (d->mActionSubType == EMAIL) ? d->mText : QString();
2225}
2226
2227uint KAEvent::emailFromId() const
2228{
2229 return d->mEmailFromIdentity;
2230}
2231
2232#ifndef KALARMCAL_USE_KRESOURCES
2233KCalCore::Person::List KAEvent::emailAddressees() const
2234#else
2235QList<KCal::Person> KAEvent::emailAddressees() const
2236#endif
2237{
2238 return d->mEmailAddresses;
2239}
2240
2241QStringList KAEvent::emailAddresses() const
2242{
2243 return static_cast<QStringList>(d->mEmailAddresses);
2244}
2245
2246QString KAEvent::emailAddresses(const QString& sep) const
2247{
2248 return d->mEmailAddresses.join(sep);
2249}
2250
2251#ifndef KALARMCAL_USE_KRESOURCES
2252QString KAEvent::joinEmailAddresses(const KCalCore::Person::List& addresses, const QString& separator)
2253#else
2254QString KAEvent::joinEmailAddresses(const QList<KCal::Person>& addresses, const QString& separator)
2255#endif
2256{
2257 return EmailAddressList(addresses).join(separator);
2258}
2259
2260QStringList KAEvent::emailPureAddresses() const
2261{
2262 return d->mEmailAddresses.pureAddresses();
2263}
2264
2265QString KAEvent::emailPureAddresses(const QString& sep) const
2266{
2267 return d->mEmailAddresses.pureAddresses(sep);
2268}
2269
2270QString KAEvent::emailSubject() const
2271{
2272 return d->mEmailSubject;
2273}
2274
2275QStringList KAEvent::emailAttachments() const
2276{
2277 return d->mEmailAttachments;
2278}
2279
2280QString KAEvent::emailAttachments(const QString& sep) const
2281{
2282 return d->mEmailAttachments.join(sep);
2283}
2284
2285bool KAEvent::emailBcc() const
2286{
2287 return d->mEmailBcc;
2288}
2289
2290void KAEvent::setAudioFile(const QString& filename, float volume, float fadeVolume, int fadeSeconds, int repeatPause, bool allowEmptyFile)
2291{
2292 d->setAudioFile(filename, volume, fadeVolume, fadeSeconds, repeatPause, allowEmptyFile);
2293}
2294
2295void KAEventPrivate::setAudioFile(const QString& filename, float volume, float fadeVolume, int fadeSeconds, int repeatPause, bool allowEmptyFile)
2296{
2297 mAudioFile = filename;
2298 mSoundVolume = (!allowEmptyFile && filename.isEmpty()) ? -1 : volume;
2299 if (mSoundVolume >= 0)
2300 {
2301 mFadeVolume = (fadeSeconds > 0) ? fadeVolume : -1;
2302 mFadeSeconds = (mFadeVolume >= 0) ? fadeSeconds : 0;
2303 }
2304 else
2305 {
2306 mFadeVolume = -1;
2307 mFadeSeconds = 0;
2308 }
2309 mRepeatSoundPause = repeatPause;
2310}
2311
2312QString KAEvent::audioFile() const
2313{
2314 return d->mAudioFile;
2315}
2316
2317float KAEvent::soundVolume() const
2318{
2319 return d->mSoundVolume;
2320}
2321
2322float KAEvent::fadeVolume() const
2323{
2324 return d->mSoundVolume >= 0 && d->mFadeSeconds ? d->mFadeVolume : -1;
2325}
2326
2327int KAEvent::fadeSeconds() const
2328{
2329 return d->mSoundVolume >= 0 && d->mFadeVolume >= 0 ? d->mFadeSeconds : 0;
2330}
2331
2332bool KAEvent::repeatSound() const
2333{
2334 return d->mRepeatSoundPause >= 0;
2335}
2336
2337int KAEvent::repeatSoundPause() const
2338{
2339 return d->mRepeatSoundPause;
2340}
2341
2342bool KAEvent::beep() const
2343{
2344 return d->mBeep;
2345}
2346
2347bool KAEvent::speak() const
2348{
2349 return (d->mActionSubType == MESSAGE
2350 || (d->mActionSubType == COMMAND && d->mCommandDisplay))
2351 && d->mSpeak;
2352}
2353
2354/******************************************************************************
2355* Set the event to be an alarm template.
2356*/
2357void KAEvent::setTemplate(const QString& name, int afterTime)
2358{
2359 d->setCategory(CalEvent::TEMPLATE);
2360 d->mTemplateName = name;
2361 d->mTemplateAfterTime = afterTime;
2362 d->mTriggerChanged = true; // templates and archived don't have trigger times
2363}
2364
2365bool KAEvent::isTemplate() const
2366{
2367 return !d->mTemplateName.isEmpty();
2368}
2369
2370QString KAEvent::templateName() const
2371{
2372 return d->mTemplateName;
2373}
2374
2375bool KAEvent::usingDefaultTime() const
2376{
2377 return d->mTemplateAfterTime == 0;
2378}
2379
2380int KAEvent::templateAfterTime() const
2381{
2382 return d->mTemplateAfterTime;
2383}
2384
2385void KAEvent::setActions(const QString& pre, const QString& post, ExtraActionOptions options)
2386{
2387 d->mPreAction = pre;
2388 d->mPostAction = post;
2389 d->mExtraActionOptions = options;
2390}
2391
2392void KAEvent::setActions(const QString& pre, const QString& post, bool cancelOnError, bool dontShowError)
2393{
2394 ExtraActionOptions opts(0);
2395 if (cancelOnError)
2396 opts |= CancelOnPreActError;
2397 if (dontShowError)
2398 opts |= DontShowPreActError;
2399 setActions(pre, post, opts);
2400}
2401
2402QString KAEvent::preAction() const
2403{
2404 return d->mPreAction;
2405}
2406
2407QString KAEvent::postAction() const
2408{
2409 return d->mPostAction;
2410}
2411
2412KAEvent::ExtraActionOptions KAEvent::extraActionOptions() const
2413{
2414 return d->mExtraActionOptions;
2415}
2416
2417bool KAEvent::cancelOnPreActionError() const
2418{
2419 return d->mExtraActionOptions & CancelOnPreActError;
2420}
2421
2422bool KAEvent::dontShowPreActionError() const
2423{
2424 return d->mExtraActionOptions & DontShowPreActError;
2425}
2426
2427/******************************************************************************
2428* Set a reminder.
2429* 'minutes' = number of minutes BEFORE the main alarm.
2430*/
2431void KAEvent::setReminder(int minutes, bool onceOnly)
2432{
2433 d->setReminder(minutes, onceOnly);
2434}
2435
2436void KAEventPrivate::setReminder(int minutes, bool onceOnly)
2437{
2438 if (minutes > 0 && mRepeatAtLogin)
2439 minutes = 0;
2440 if (minutes != mReminderMinutes || (minutes && mReminderActive != ACTIVE_REMINDER))
2441 {
2442 if (minutes && mReminderActive == NO_REMINDER)
2443 ++mAlarmCount;
2444 else if (!minutes && mReminderActive != NO_REMINDER)
2445 --mAlarmCount;
2446 mReminderMinutes = minutes;
2447 mReminderActive = minutes ? ACTIVE_REMINDER : NO_REMINDER;
2448 mReminderOnceOnly = onceOnly;
2449 mReminderAfterTime = DateTime();
2450 mTriggerChanged = true;
2451 }
2452}
2453
2454/******************************************************************************
2455* Activate the event's reminder which occurs AFTER the given main alarm time.
2456* Reply = true if successful (i.e. reminder falls before the next main alarm).
2457*/
2458void KAEvent::activateReminderAfter(const DateTime& mainAlarmTime)
2459{
2460 d->activateReminderAfter(mainAlarmTime);
2461}
2462
2463void KAEventPrivate::activateReminderAfter(const DateTime& mainAlarmTime)
2464{
2465 if (mReminderMinutes >= 0 || mReminderActive == ACTIVE_REMINDER || !mainAlarmTime.isValid())
2466 return;
2467 // There is a reminder AFTER the main alarm.
2468 if (checkRecur() != KARecurrence::NO_RECUR)
2469 {
2470 // For a recurring alarm, the given alarm time must be a recurrence, not a sub-repetition.
2471 DateTime next;
2472 //???? For some unknown reason, addSecs(-1) returns the recurrence after the next,
2473 //???? so addSecs(-60) is used instead.
2474 if (nextRecurrence(mainAlarmTime.addSecs(-60).effectiveKDateTime(), next) == KAEvent::NO_OCCURRENCE
2475 || mainAlarmTime != next)
2476 return;
2477 }
2478 else if (!mRepeatAtLogin)
2479 {
2480 // For a non-recurring alarm, the given alarm time must be the main alarm time.
2481 if (mainAlarmTime != mStartDateTime)
2482 return;
2483 }
2484
2485 const DateTime reminderTime = mainAlarmTime.addMins(-mReminderMinutes);
2486 DateTime next;
2487 if (nextOccurrence(mainAlarmTime.effectiveKDateTime(), next, KAEvent::RETURN_REPETITION) != KAEvent::NO_OCCURRENCE
2488 && reminderTime >= next)
2489 return; // the reminder time is after the next occurrence of the main alarm
2490
2491 kDebug() << "Setting reminder at" << reminderTime.effectiveKDateTime().dateTime();
2492 activate_reminder(true);
2493 mReminderAfterTime = reminderTime;
2494}
2495
2496int KAEvent::reminderMinutes() const
2497{
2498 return d->mReminderMinutes;
2499}
2500
2501bool KAEvent::reminderActive() const
2502{
2503 return d->mReminderActive == KAEventPrivate::ACTIVE_REMINDER;
2504}
2505
2506bool KAEvent::reminderOnceOnly() const
2507{
2508 return d->mReminderOnceOnly;
2509}
2510
2511bool KAEvent::reminderDeferral() const
2512{
2513 return d->mDeferral == KAEventPrivate::REMINDER_DEFERRAL;
2514}
2515
2516/******************************************************************************
2517* Defer the event to the specified time.
2518* If the main alarm time has passed, the main alarm is marked as expired.
2519* If 'adjustRecurrence' is true, ensure that the next scheduled recurrence is
2520* after the current time.
2521*/
2522void KAEvent::defer(const DateTime& dt, bool reminder, bool adjustRecurrence)
2523{
2524 return d->defer(dt, reminder, adjustRecurrence);
2525}
2526
2527void KAEventPrivate::defer(const DateTime& dateTime, bool reminder, bool adjustRecurrence)
2528{
2529 startChanges(); // prevent multiple trigger time evaluation here
2530 bool setNextRepetition = false;
2531 bool checkRepetition = false;
2532 bool checkReminderAfter = false;
2533 if (checkRecur() == KARecurrence::NO_RECUR)
2534 {
2535 // Deferring a non-recurring alarm
2536 if (mReminderMinutes)
2537 {
2538 bool deferReminder = false;
2539 if (mReminderMinutes > 0)
2540 {
2541 // There's a reminder BEFORE the main alarm
2542 if (dateTime < mNextMainDateTime.effectiveKDateTime())
2543 deferReminder = true;
2544 else if (mReminderActive == ACTIVE_REMINDER || mDeferral == REMINDER_DEFERRAL)
2545 {
2546 // Deferring past the main alarm time, so adjust any existing deferral
2547 set_deferral(NO_DEFERRAL);
2548 mTriggerChanged = true;
2549 }
2550 }
2551 else if (mReminderMinutes < 0 && reminder)
2552 deferReminder = true; // deferring a reminder AFTER the main alarm
2553 if (deferReminder)
2554 {
2555 set_deferral(REMINDER_DEFERRAL); // defer reminder alarm
2556 mDeferralTime = dateTime;
2557 mTriggerChanged = true;
2558 }
2559 if (mReminderActive == ACTIVE_REMINDER)
2560 {
2561 activate_reminder(false);
2562 mTriggerChanged = true;
2563 }
2564 }
2565 if (mDeferral != REMINDER_DEFERRAL)
2566 {
2567 // We're deferring the main alarm.
2568 // Main alarm has now expired.
2569 mNextMainDateTime = mDeferralTime = dateTime;
2570 set_deferral(NORMAL_DEFERRAL);
2571 mTriggerChanged = true;
2572 checkReminderAfter = true;
2573 if (!mMainExpired)
2574 {
2575 // Mark the alarm as expired now
2576 mMainExpired = true;
2577 --mAlarmCount;
2578 if (mRepeatAtLogin)
2579 {
2580 // Remove the repeat-at-login alarm, but keep a note of it for archiving purposes
2581 mArchiveRepeatAtLogin = true;
2582 mRepeatAtLogin = false;
2583 --mAlarmCount;
2584 }
2585 }
2586 }
2587 }
2588 else if (reminder)
2589 {
2590 // Deferring a reminder for a recurring alarm
2591 if (dateTime >= mNextMainDateTime.effectiveKDateTime())
2592 {
2593 // Trying to defer it past the next main alarm (regardless of whether
2594 // the reminder triggered before or after the main alarm).
2595 set_deferral(NO_DEFERRAL); // (error)
2596 }
2597 else
2598 {
2599 set_deferral(REMINDER_DEFERRAL);
2600 mDeferralTime = dateTime;
2601 checkRepetition = true;
2602 }
2603 mTriggerChanged = true;
2604 }
2605 else
2606 {
2607 // Deferring a recurring alarm
2608 mDeferralTime = dateTime;
2609 if (mDeferral == NO_DEFERRAL)
2610 set_deferral(NORMAL_DEFERRAL);
2611 mTriggerChanged = true;
2612 checkReminderAfter = true;
2613 if (adjustRecurrence)
2614 {
2615 const KDateTime now = KDateTime::currentUtcDateTime();
2616 if (mainEndRepeatTime() < now)
2617 {
2618 // The last repetition (if any) of the current recurrence has already passed.
2619 // Adjust to the next scheduled recurrence after now.
2620 if (!mMainExpired && setNextOccurrence(now) == KAEvent::NO_OCCURRENCE)
2621 {
2622 mMainExpired = true;
2623 --mAlarmCount;
2624 }
2625 }
2626 else
2627 setNextRepetition = mRepetition;
2628 }
2629 else
2630 checkRepetition = true;
2631 }
2632 if (checkReminderAfter && mReminderMinutes < 0 && mReminderActive != NO_REMINDER)
2633 {
2634 // Enable/disable the active reminder AFTER the main alarm,
2635 // depending on whether the deferral is before or after the reminder.
2636 mReminderActive = (mDeferralTime < mReminderAfterTime) ? ACTIVE_REMINDER : HIDDEN_REMINDER;
2637 }
2638 if (checkRepetition)
2639 setNextRepetition = (mRepetition && mDeferralTime < mainEndRepeatTime());
2640 if (setNextRepetition)
2641 {
2642 // The alarm is repeated, and we're deferring to a time before the last repetition.
2643 // Set the next scheduled repetition to the one after the deferral.
2644 if (mNextMainDateTime >= mDeferralTime)
2645 mNextRepeat = 0;
2646 else
2647 mNextRepeat = mRepetition.nextRepeatCount(mNextMainDateTime.kDateTime(), mDeferralTime.kDateTime());
2648 mTriggerChanged = true;
2649 }
2650 endChanges();
2651}
2652
2653/******************************************************************************
2654* Cancel any deferral alarm.
2655*/
2656void KAEvent::cancelDefer()
2657{
2658 d->cancelDefer();
2659}
2660
2661void KAEventPrivate::cancelDefer()
2662{
2663 if (mDeferral != NO_DEFERRAL)
2664 {
2665 mDeferralTime = DateTime();
2666 set_deferral(NO_DEFERRAL);
2667 mTriggerChanged = true;
2668 }
2669}
2670
2671void KAEvent::setDeferDefaultMinutes(int minutes, bool dateOnly)
2672{
2673 d->mDeferDefaultMinutes = minutes;
2674 d->mDeferDefaultDateOnly = dateOnly;
2675}
2676
2677bool KAEvent::deferred() const
2678{
2679 return d->mDeferral > 0;
2680}
2681
2682DateTime KAEvent::deferDateTime() const
2683{
2684 return d->mDeferralTime;
2685}
2686
2687/******************************************************************************
2688* Find the latest time which the alarm can currently be deferred to.
2689*/
2690DateTime KAEvent::deferralLimit(DeferLimitType* limitType) const
2691{
2692 return d->deferralLimit(limitType);
2693}
2694
2695DateTime KAEventPrivate::deferralLimit(KAEvent::DeferLimitType* limitType) const
2696{
2697 KAEvent::DeferLimitType ltype = KAEvent::LIMIT_NONE;
2698 DateTime endTime;
2699 if (checkRecur() != KARecurrence::NO_RECUR)
2700 {
2701 // It's a recurring alarm. Find the latest time it can be deferred to:
2702 // it cannot be deferred past its next occurrence or sub-repetition,
2703 // or any advance reminder before that.
2704 DateTime reminderTime;
2705 const KDateTime now = KDateTime::currentUtcDateTime();
2706 const KAEvent::OccurType type = nextOccurrence(now, endTime, KAEvent::RETURN_REPETITION);
2707 if (type & KAEvent::OCCURRENCE_REPEAT)
2708 ltype = KAEvent::LIMIT_REPETITION;
2709 else if (type == KAEvent::NO_OCCURRENCE)
2710 ltype = KAEvent::LIMIT_NONE;
2711 else if (mReminderActive == ACTIVE_REMINDER && mReminderMinutes > 0
2712 && (now < (reminderTime = endTime.addMins(-mReminderMinutes))))
2713 {
2714 endTime = reminderTime;
2715 ltype = KAEvent::LIMIT_REMINDER;
2716 }
2717 else
2718 ltype = KAEvent::LIMIT_RECURRENCE;
2719 }
2720 else if (mReminderMinutes < 0)
2721 {
2722 // There is a reminder alarm which occurs AFTER the main alarm.
2723 // Don't allow the reminder to be deferred past the next main alarm time.
2724 if (KDateTime::currentUtcDateTime() < mNextMainDateTime.effectiveKDateTime())
2725 {
2726 endTime = mNextMainDateTime;
2727 ltype = KAEvent::LIMIT_MAIN;
2728 }
2729 }
2730 else if (mReminderMinutes > 0
2731 && KDateTime::currentUtcDateTime() < mNextMainDateTime.effectiveKDateTime())
2732 {
2733 // It's a reminder BEFORE the main alarm.
2734 // Don't allow it to be deferred past its main alarm time.
2735 endTime = mNextMainDateTime;
2736 ltype = KAEvent::LIMIT_MAIN;
2737 }
2738 if (ltype != KAEvent::LIMIT_NONE)
2739 endTime = endTime.addMins(-1);
2740 if (limitType)
2741 *limitType = ltype;
2742 return endTime;
2743}
2744
2745int KAEvent::deferDefaultMinutes() const
2746{
2747 return d->mDeferDefaultMinutes;
2748}
2749
2750bool KAEvent::deferDefaultDateOnly() const
2751{
2752 return d->mDeferDefaultDateOnly;
2753}
2754
2755DateTime KAEvent::startDateTime() const
2756{
2757 return d->mStartDateTime;
2758}
2759
2760void KAEvent::setTime(const KDateTime& dt)
2761{
2762 d->mNextMainDateTime = dt;
2763 d->mTriggerChanged = true;
2764}
2765
2766DateTime KAEvent::mainDateTime(bool withRepeats) const
2767{
2768 return d->mainDateTime(withRepeats);
2769}
2770
2771QTime KAEvent::mainTime() const
2772{
2773 return d->mNextMainDateTime.effectiveTime();
2774}
2775
2776DateTime KAEvent::mainEndRepeatTime() const
2777{
2778 return d->mainEndRepeatTime();
2779}
2780
2781/******************************************************************************
2782* Set the start-of-day time for date-only alarms.
2783*/
2784void KAEvent::setStartOfDay(const QTime& startOfDay)
2785{
2786 DateTime::setStartOfDay(startOfDay);
2787#ifdef __GNUC__
2788#warning Does this need all trigger times for date-only alarms to be recalculated?
2789#endif
2790}
2791
2792/******************************************************************************
2793* Called when the user changes the start-of-day time.
2794* Adjust the start time of the recurrence to match, for each date-only event in
2795* a list.
2796*/
2797void KAEvent::adjustStartOfDay(const KAEvent::List& events)
2798{
2799 for (int i = 0, end = events.count(); i < end; ++i)
2800 {
2801 KAEventPrivate* const p = events[i]->d;
2802 if (p->mStartDateTime.isDateOnly() && p->checkRecur() != KARecurrence::NO_RECUR)
2803 p->mRecurrence->setStartDateTime(p->mStartDateTime.effectiveKDateTime(), true);
2804 }
2805}
2806
2807DateTime KAEvent::nextTrigger(TriggerType type) const
2808{
2809 d->calcTriggerTimes();
2810 switch (type)
2811 {
2812 case ALL_TRIGGER: return d->mAllTrigger;
2813 case MAIN_TRIGGER: return d->mMainTrigger;
2814 case ALL_WORK_TRIGGER: return d->mAllWorkTrigger;
2815 case WORK_TRIGGER: return d->mMainWorkTrigger;
2816 case DISPLAY_TRIGGER:
2817 {
2818 const bool reminderAfter = d->mMainExpired && d->mReminderActive && d->mReminderMinutes < 0;
2819 return d->checkRecur() != KARecurrence::NO_RECUR && (d->mWorkTimeOnly || d->mExcludeHolidays)
2820 ? (reminderAfter ? d->mAllWorkTrigger : d->mMainWorkTrigger)
2821 : (reminderAfter ? d->mAllTrigger : d->mMainTrigger);
2822 }
2823 default: return DateTime();
2824 }
2825}
2826
2827void KAEvent::setCreatedDateTime(const KDateTime& dt)
2828{
2829 d->mCreatedDateTime = dt;
2830}
2831
2832KDateTime KAEvent::createdDateTime() const
2833{
2834 return d->mCreatedDateTime;
2835}
2836
2837/******************************************************************************
2838* Set or clear repeat-at-login.
2839*/
2840void KAEvent::setRepeatAtLogin(bool rl)
2841{
2842 d->setRepeatAtLogin(rl);
2843}
2844
2845void KAEventPrivate::setRepeatAtLogin(bool rl)
2846{
2847 if (rl && !mRepeatAtLogin)
2848 {
2849 setRepeatAtLoginTrue(true); // clear incompatible statuses
2850 ++mAlarmCount;
2851 }
2852 else if (!rl && mRepeatAtLogin)
2853 --mAlarmCount;
2854 mRepeatAtLogin = rl;
2855 mTriggerChanged = true;
2856}
2857
2858/******************************************************************************
2859* Clear incompatible statuses when repeat-at-login is set.
2860*/
2861void KAEventPrivate::setRepeatAtLoginTrue(bool clearReminder)
2862{
2863 clearRecur(); // clear recurrences
2864 if (mReminderMinutes >= 0 && clearReminder)
2865 setReminder(0, false); // clear pre-alarm reminder
2866 mLateCancel = 0;
2867 mAutoClose = false;
2868 mCopyToKOrganizer = false;
2869}
2870
2871bool KAEvent::repeatAtLogin(bool includeArchived) const
2872{
2873 return d->mRepeatAtLogin || (includeArchived && d->mArchiveRepeatAtLogin);
2874}
2875
2876void KAEvent::setExcludeHolidays(bool ex)
2877{
2878 d->mExcludeHolidays = ex ? KAEventPrivate::mHolidays : 0;
2879 // Option only affects recurring alarms
2880 d->mTriggerChanged = (d->checkRecur() != KARecurrence::NO_RECUR);
2881}
2882
2883bool KAEvent::holidaysExcluded() const
2884{
2885 return d->mExcludeHolidays;
2886}
2887
2888/******************************************************************************
2889* Set a new holiday region.
2890* Alarms which exclude holidays record the pointer to the holiday definition
2891* at the time their next trigger times were last calculated. The change in
2892* holiday definition pointer will cause their next trigger times to be
2893* recalculated.
2894*/
2895void KAEvent::setHolidays(const HolidayRegion& h)
2896{
2897 KAEventPrivate::mHolidays = &h;
2898}
2899
2900void KAEvent::setWorkTimeOnly(bool wto)
2901{
2902 d->mWorkTimeOnly = wto;
2903 // Option only affects recurring alarms
2904 d->mTriggerChanged = (d->checkRecur() != KARecurrence::NO_RECUR);
2905}
2906
2907bool KAEvent::workTimeOnly() const
2908{
2909 return d->mWorkTimeOnly;
2910}
2911
2912/******************************************************************************
2913* Check whether a date/time is during working hours and/or holidays, depending
2914* on the flags set for the specified event.
2915*/
2916bool KAEvent::isWorkingTime(const KDateTime& dt) const
2917{
2918 return d->isWorkingTime(dt);
2919}
2920
2921bool KAEventPrivate::isWorkingTime(const KDateTime& dt) const
2922{
2923 if ((mWorkTimeOnly && !mWorkDays.testBit(dt.date().dayOfWeek() - 1))
2924 || (mExcludeHolidays && mHolidays && mHolidays->isHoliday(dt.date())))
2925 return false;
2926 if (!mWorkTimeOnly)
2927 return true;
2928 return dt.isDateOnly()
2929 || (dt.time() >= mWorkDayStart && dt.time() < mWorkDayEnd);
2930}
2931
2932/******************************************************************************
2933* Set new working days and times.
2934* Increment a counter so that working-time-only alarms can detect that they
2935* need to update their next trigger time.
2936*/
2937void KAEvent::setWorkTime(const QBitArray& days, const QTime& start, const QTime& end)
2938{
2939 if (days != KAEventPrivate::mWorkDays || start != KAEventPrivate::mWorkDayStart || end != KAEventPrivate::mWorkDayEnd)
2940 {
2941 KAEventPrivate::mWorkDays = days;
2942 KAEventPrivate::mWorkDayStart = start;
2943 KAEventPrivate::mWorkDayEnd = end;
2944 if (!++KAEventPrivate::mWorkTimeIndex)
2945 ++KAEventPrivate::mWorkTimeIndex;
2946 }
2947}
2948
2949/******************************************************************************
2950* Clear the event's recurrence and alarm repetition data.
2951*/
2952void KAEvent::setNoRecur()
2953{
2954 d->clearRecur();
2955}
2956
2957void KAEventPrivate::clearRecur()
2958{
2959 if (mRecurrence || mRepetition)
2960 {
2961 delete mRecurrence;
2962 mRecurrence = 0;
2963 mRepetition.set(0, 0);
2964 mTriggerChanged = true;
2965 }
2966 mNextRepeat = 0;
2967}
2968
2969/******************************************************************************
2970* Initialise the event's recurrence from a KCal::Recurrence.
2971* The event's start date/time is not changed.
2972*/
2973void KAEvent::setRecurrence(const KARecurrence& recurrence)
2974{
2975 d->setRecurrence(recurrence);
2976}
2977
2978void KAEventPrivate::setRecurrence(const KARecurrence& recurrence)
2979{
2980 startChanges(); // prevent multiple trigger time evaluation here
2981 if (recurrence.recurs())
2982 {
2983 delete mRecurrence;
2984 mRecurrence = new KARecurrence(recurrence);
2985 mRecurrence->setStartDateTime(mStartDateTime.effectiveKDateTime(), mStartDateTime.isDateOnly());
2986 mTriggerChanged = true;
2987
2988 // Adjust sub-repetition values to fit the recurrence.
2989 setRepetition(mRepetition);
2990 }
2991 else
2992 clearRecur();
2993
2994 endChanges();
2995}
2996
2997/******************************************************************************
2998* Set the recurrence to recur at a minutes interval.
2999* Parameters:
3000* freq = how many minutes between recurrences.
3001* count = number of occurrences, including first and last.
3002* = -1 to recur indefinitely.
3003* = 0 to use 'end' instead.
3004* end = end date/time (invalid to use 'count' instead).
3005* Reply = false if no recurrence was set up.
3006*/
3007bool KAEvent::setRecurMinutely(int freq, int count, const KDateTime& end)
3008{
3009 const bool success = d->setRecur(RecurrenceRule::rMinutely, freq, count, end);
3010 d->mTriggerChanged = true;
3011 return success;
3012}
3013
3014/******************************************************************************
3015* Set the recurrence to recur daily.
3016* Parameters:
3017* freq = how many days between recurrences.
3018* days = which days of the week alarms are allowed to occur on.
3019* count = number of occurrences, including first and last.
3020* = -1 to recur indefinitely.
3021* = 0 to use 'end' instead.
3022* end = end date (invalid to use 'count' instead).
3023* Reply = false if no recurrence was set up.
3024*/
3025bool KAEvent::setRecurDaily(int freq, const QBitArray& days, int count, const QDate& end)
3026{
3027 const bool success = d->setRecur(RecurrenceRule::rDaily, freq, count, end);
3028 if (success)
3029 {
3030 int n = 0;
3031 for (int i = 0; i < 7; ++i)
3032 {
3033 if (days.testBit(i))
3034 ++n;
3035 }
3036 if (n < 7)
3037 d->mRecurrence->addWeeklyDays(days);
3038 }
3039 d->mTriggerChanged = true;
3040 return success;
3041}
3042
3043/******************************************************************************
3044* Set the recurrence to recur weekly, on the specified weekdays.
3045* Parameters:
3046* freq = how many weeks between recurrences.
3047* days = which days of the week alarms should occur on.
3048* count = number of occurrences, including first and last.
3049* = -1 to recur indefinitely.
3050* = 0 to use 'end' instead.
3051* end = end date (invalid to use 'count' instead).
3052* Reply = false if no recurrence was set up.
3053*/
3054bool KAEvent::setRecurWeekly(int freq, const QBitArray& days, int count, const QDate& end)
3055{
3056 const bool success = d->setRecur(RecurrenceRule::rWeekly, freq, count, end);
3057 if (success)
3058 d->mRecurrence->addWeeklyDays(days);
3059 d->mTriggerChanged = true;
3060 return success;
3061}
3062
3063/******************************************************************************
3064* Set the recurrence to recur monthly, on the specified days within the month.
3065* Parameters:
3066* freq = how many months between recurrences.
3067* days = which days of the month alarms should occur on.
3068* count = number of occurrences, including first and last.
3069* = -1 to recur indefinitely.
3070* = 0 to use 'end' instead.
3071* end = end date (invalid to use 'count' instead).
3072* Reply = false if no recurrence was set up.
3073*/
3074bool KAEvent::setRecurMonthlyByDate(int freq, const QVector<int>& days, int count, const QDate& end)
3075{
3076 const bool success = d->setRecur(RecurrenceRule::rMonthly, freq, count, end);
3077 if (success)
3078 {
3079 for (int i = 0, end = days.count(); i < end; ++i)
3080 d->mRecurrence->addMonthlyDate(days[i]);
3081 }
3082 d->mTriggerChanged = true;
3083 return success;
3084}
3085
3086/******************************************************************************
3087* Set the recurrence to recur monthly, on the specified weekdays in the
3088* specified weeks of the month.
3089* Parameters:
3090* freq = how many months between recurrences.
3091* posns = which days of the week/weeks of the month alarms should occur on.
3092* count = number of occurrences, including first and last.
3093* = -1 to recur indefinitely.
3094* = 0 to use 'end' instead.
3095* end = end date (invalid to use 'count' instead).
3096* Reply = false if no recurrence was set up.
3097*/
3098bool KAEvent::setRecurMonthlyByPos(int freq, const QVector<MonthPos>& posns, int count, const QDate& end)
3099{
3100 const bool success = d->setRecur(RecurrenceRule::rMonthly, freq, count, end);
3101 if (success)
3102 {
3103 for (int i = 0, end = posns.count(); i < end; ++i)
3104 d->mRecurrence->addMonthlyPos(posns[i].weeknum, posns[i].days);
3105 }
3106 d->mTriggerChanged = true;
3107 return success;
3108}
3109
3110/******************************************************************************
3111* Set the recurrence to recur annually, on the specified start date in each
3112* of the specified months.
3113* Parameters:
3114* freq = how many years between recurrences.
3115* months = which months of the year alarms should occur on.
3116* day = day of month, or 0 to use start date
3117* feb29 = when February 29th should recur in non-leap years.
3118* count = number of occurrences, including first and last.
3119* = -1 to recur indefinitely.
3120* = 0 to use 'end' instead.
3121* end = end date (invalid to use 'count' instead).
3122* Reply = false if no recurrence was set up.
3123*/
3124bool KAEvent::setRecurAnnualByDate(int freq, const QVector<int>& months, int day, KARecurrence::Feb29Type feb29, int count, const QDate& end)
3125{
3126 const bool success = d->setRecur(RecurrenceRule::rYearly, freq, count, end, feb29);
3127 if (success)
3128 {
3129 for (int i = 0, end = months.count(); i < end; ++i)
3130 d->mRecurrence->addYearlyMonth(months[i]);
3131 if (day)
3132 d->mRecurrence->addMonthlyDate(day);
3133 }
3134 d->mTriggerChanged = true;
3135 return success;
3136}
3137
3138/******************************************************************************
3139* Set the recurrence to recur annually, on the specified weekdays in the
3140* specified weeks of the specified months.
3141* Parameters:
3142* freq = how many years between recurrences.
3143* posns = which days of the week/weeks of the month alarms should occur on.
3144* months = which months of the year alarms should occur on.
3145* count = number of occurrences, including first and last.
3146* = -1 to recur indefinitely.
3147* = 0 to use 'end' instead.
3148* end = end date (invalid to use 'count' instead).
3149* Reply = false if no recurrence was set up.
3150*/
3151bool KAEvent::setRecurAnnualByPos(int freq, const QVector<MonthPos>& posns, const QVector<int>& months, int count, const QDate& end)
3152{
3153 const bool success = d->setRecur(RecurrenceRule::rYearly, freq, count, end);
3154 if (success)
3155 {
3156 int i = 0;
3157 int iend;
3158 for (iend = months.count(); i < iend; ++i)
3159 d->mRecurrence->addYearlyMonth(months[i]);
3160 for (i = 0, iend = posns.count(); i < iend; ++i)
3161 d->mRecurrence->addYearlyPos(posns[i].weeknum, posns[i].days);
3162 }
3163 d->mTriggerChanged = true;
3164 return success;
3165}
3166
3167/******************************************************************************
3168* Initialise the event's recurrence data.
3169* Parameters:
3170* freq = how many intervals between recurrences.
3171* count = number of occurrences, including first and last.
3172* = -1 to recur indefinitely.
3173* = 0 to use 'end' instead.
3174* end = end date/time (invalid to use 'count' instead).
3175* Reply = false if no recurrence was set up.
3176*/
3177bool KAEventPrivate::setRecur(RecurrenceRule::PeriodType recurType, int freq, int count, const QDate& end, KARecurrence::Feb29Type feb29)
3178{
3179 KDateTime edt = mNextMainDateTime.kDateTime();
3180 edt.setDate(end);
3181 return setRecur(recurType, freq, count, edt, feb29);
3182}
3183bool KAEventPrivate::setRecur(RecurrenceRule::PeriodType recurType, int freq, int count, const KDateTime& end, KARecurrence::Feb29Type feb29)
3184{
3185 if (count >= -1 && (count || end.date().isValid()))
3186 {
3187 if (!mRecurrence)
3188 mRecurrence = new KARecurrence;
3189 if (mRecurrence->init(recurType, freq, count, mNextMainDateTime.kDateTime(), end, feb29))
3190 return true;
3191 }
3192 clearRecur();
3193 return false;
3194}
3195
3196bool KAEvent::recurs() const
3197{
3198 return d->checkRecur() != KARecurrence::NO_RECUR;
3199}
3200
3201KARecurrence::Type KAEvent::recurType() const
3202{
3203 return d->checkRecur();
3204}
3205
3206KARecurrence* KAEvent::recurrence() const
3207{
3208 return d->mRecurrence;
3209}
3210
3211/******************************************************************************
3212* Return the recurrence interval in units of the recurrence period type.
3213*/
3214int KAEvent::recurInterval() const
3215{
3216 if (d->mRecurrence)
3217 {
3218 switch (d->mRecurrence->type())
3219 {
3220 case KARecurrence::MINUTELY:
3221 case KARecurrence::DAILY:
3222 case KARecurrence::WEEKLY:
3223 case KARecurrence::MONTHLY_DAY:
3224 case KARecurrence::MONTHLY_POS:
3225 case KARecurrence::ANNUAL_DATE:
3226 case KARecurrence::ANNUAL_POS:
3227 return d->mRecurrence->frequency();
3228 default:
3229 break;
3230 }
3231 }
3232 return 0;
3233}
3234
3235Duration KAEvent::longestRecurrenceInterval() const
3236{
3237 return d->mRecurrence ? d->mRecurrence->longestInterval() : Duration(0);
3238}
3239
3240/******************************************************************************
3241* Adjust the event date/time to the first recurrence of the event, on or after
3242* start date/time. The event start date may not be a recurrence date, in which
3243* case a later date will be set.
3244*/
3245void KAEvent::setFirstRecurrence()
3246{
3247 d->setFirstRecurrence();
3248}
3249
3250void KAEventPrivate::setFirstRecurrence()
3251{
3252 switch (checkRecur())
3253 {
3254 case KARecurrence::NO_RECUR:
3255 case KARecurrence::MINUTELY:
3256 return;
3257 case KARecurrence::ANNUAL_DATE:
3258 case KARecurrence::ANNUAL_POS:
3259 if (mRecurrence->yearMonths().isEmpty())
3260 return; // (presumably it's a template)
3261 break;
3262 case KARecurrence::DAILY:
3263 case KARecurrence::WEEKLY:
3264 case KARecurrence::MONTHLY_POS:
3265 case KARecurrence::MONTHLY_DAY:
3266 break;
3267 }
3268 const KDateTime recurStart = mRecurrence->startDateTime();
3269 if (mRecurrence->recursOn(recurStart.date(), recurStart.timeSpec()))
3270 return; // it already recurs on the start date
3271
3272 // Set the frequency to 1 to find the first possible occurrence
3273 const int frequency = mRecurrence->frequency();
3274 mRecurrence->setFrequency(1);
3275 DateTime next;
3276 nextRecurrence(mNextMainDateTime.effectiveKDateTime(), next);
3277 if (!next.isValid())
3278 mRecurrence->setStartDateTime(recurStart, mStartDateTime.isDateOnly()); // reinstate the old value
3279 else
3280 {
3281 mRecurrence->setStartDateTime(next.effectiveKDateTime(), next.isDateOnly());
3282 mStartDateTime = mNextMainDateTime = next;
3283 mTriggerChanged = true;
3284 }
3285 mRecurrence->setFrequency(frequency); // restore the frequency
3286}
3287
3288/******************************************************************************
3289* Return the recurrence interval as text suitable for display.
3290*/
3291QString KAEvent::recurrenceText(bool brief) const
3292{
3293 if (d->mRepeatAtLogin)
3294 return brief ? i18nc("@info/plain Brief form of 'At Login'", "Login") : i18nc("@info/plain", "At login");
3295 if (d->mRecurrence)
3296 {
3297 const int frequency = d->mRecurrence->frequency();
3298 switch (d->mRecurrence->defaultRRuleConst()->recurrenceType())
3299 {
3300 case RecurrenceRule::rMinutely:
3301 if (frequency < 60)
3302 return i18ncp("@info/plain", "1 Minute", "%1 Minutes", frequency);
3303 else if (frequency % 60 == 0)
3304 return i18ncp("@info/plain", "1 Hour", "%1 Hours", frequency/60);
3305 else
3306 {
3307 QString mins;
3308 return i18nc("@info/plain Hours and minutes", "%1h %2m", frequency/60, mins.sprintf("%02d", frequency%60));
3309 }
3310 case RecurrenceRule::rDaily:
3311 return i18ncp("@info/plain", "1 Day", "%1 Days", frequency);
3312 case RecurrenceRule::rWeekly:
3313 return i18ncp("@info/plain", "1 Week", "%1 Weeks", frequency);
3314 case RecurrenceRule::rMonthly:
3315 return i18ncp("@info/plain", "1 Month", "%1 Months", frequency);
3316 case RecurrenceRule::rYearly:
3317 return i18ncp("@info/plain", "1 Year", "%1 Years", frequency);
3318 case RecurrenceRule::rNone:
3319 default:
3320 break;
3321 }
3322 }
3323 return brief ? QString() : i18nc("@info/plain No recurrence", "None");
3324}
3325
3326/******************************************************************************
3327* Initialise the event's sub-repetition.
3328* The repetition length is adjusted if necessary to fit the recurrence interval.
3329* If the event doesn't recur, the sub-repetition is cleared.
3330* Reply = false if a non-daily interval was specified for a date-only recurrence.
3331*/
3332bool KAEvent::setRepetition(const Repetition& r)
3333{
3334 return d->setRepetition(r);
3335}
3336
3337bool KAEventPrivate::setRepetition(const Repetition& repetition)
3338{
3339 // Don't set mRepetition to zero at the start of this function, in case the
3340 // 'repetition' parameter passed in is a reference to mRepetition.
3341 mNextRepeat = 0;
3342 if (repetition && !mRepeatAtLogin)
3343 {
3344 Q_ASSERT(checkRecur() != KARecurrence::NO_RECUR);
3345 if (!repetition.isDaily() && mStartDateTime.isDateOnly())
3346 {
3347 mRepetition.set(0, 0);
3348 return false; // interval must be in units of days for date-only alarms
3349 }
3350 Duration longestInterval = mRecurrence->longestInterval();
3351 if (repetition.duration() >= longestInterval)
3352 {
3353 const int count = mStartDateTime.isDateOnly()
3354 ? (longestInterval.asDays() - 1) / repetition.intervalDays()
3355 : (longestInterval.asSeconds() - 1) / repetition.intervalSeconds();
3356 mRepetition.set(repetition.interval(), count);
3357 }
3358 else
3359 mRepetition = repetition;
3360 mTriggerChanged = true;
3361 }
3362 else if (mRepetition)
3363 {
3364 mRepetition.set(0, 0);
3365 mTriggerChanged = true;
3366 }
3367 return true;
3368}
3369
3370Repetition KAEvent::repetition() const
3371{
3372 return d->mRepetition;
3373}
3374
3375int KAEvent::nextRepetition() const
3376{
3377 return d->mNextRepeat;
3378}
3379
3380/******************************************************************************
3381* Return the repetition interval as text suitable for display.
3382*/
3383QString KAEvent::repetitionText(bool brief) const
3384{
3385 if (d->mRepetition)
3386 {
3387 if (!d->mRepetition.isDaily())
3388 {
3389 const int minutes = d->mRepetition.intervalMinutes();
3390 if (minutes < 60)
3391 return i18ncp("@info/plain", "1 Minute", "%1 Minutes", minutes);
3392 if (minutes % 60 == 0)
3393 return i18ncp("@info/plain", "1 Hour", "%1 Hours", minutes/60);
3394 QString mins;
3395 return i18nc("@info/plain Hours and minutes", "%1h %2m", minutes/60, mins.sprintf("%02d", minutes%60));
3396 }
3397 const int days = d->mRepetition.intervalDays();
3398 if (days % 7)
3399 return i18ncp("@info/plain", "1 Day", "%1 Days", days);
3400 return i18ncp("@info/plain", "1 Week", "%1 Weeks", days / 7);
3401 }
3402 return brief ? QString() : i18nc("@info/plain No repetition", "None");
3403}
3404
3405/******************************************************************************
3406* Determine whether the event will occur after the specified date/time.
3407* If 'includeRepetitions' is true and the alarm has a sub-repetition, it
3408* returns true if any repetitions occur after the specified date/time.
3409*/
3410bool KAEvent::occursAfter(const KDateTime& preDateTime, bool includeRepetitions) const
3411{
3412 return d->occursAfter(preDateTime, includeRepetitions);
3413}
3414
3415bool KAEventPrivate::occursAfter(const KDateTime& preDateTime, bool includeRepetitions) const
3416{
3417 KDateTime dt;
3418 if (checkRecur() != KARecurrence::NO_RECUR)
3419 {
3420 if (mRecurrence->duration() < 0)
3421 return true; // infinite recurrence
3422 dt = mRecurrence->endDateTime();
3423 }
3424 else
3425 dt = mNextMainDateTime.effectiveKDateTime();
3426 if (mStartDateTime.isDateOnly())
3427 {
3428 QDate pre = preDateTime.date();
3429 if (preDateTime.toTimeSpec(mStartDateTime.timeSpec()).time() < DateTime::startOfDay())
3430 pre = pre.addDays(-1); // today's recurrence (if today recurs) is still to come
3431 if (pre < dt.date())
3432 return true;
3433 }
3434 else if (preDateTime < dt)
3435 return true;
3436
3437 if (includeRepetitions && mRepetition)
3438 {
3439 if (preDateTime < mRepetition.duration().end(dt))
3440 return true;
3441 }
3442 return false;
3443}
3444
3445/******************************************************************************
3446* Set the date/time of the event to the next scheduled occurrence after the
3447* specified date/time, provided that this is later than its current date/time.
3448* Any reminder alarm is adjusted accordingly.
3449* If the alarm has a sub-repetition, and a repetition of a previous recurrence
3450* occurs after the specified date/time, that repetition is set as the next
3451* occurrence.
3452*/
3453KAEvent::OccurType KAEvent::setNextOccurrence(const KDateTime& preDateTime)
3454{
3455 return d->setNextOccurrence(preDateTime);
3456}
3457
3458KAEvent::OccurType KAEventPrivate::setNextOccurrence(const KDateTime& preDateTime)
3459{
3460 if (preDateTime < mNextMainDateTime.effectiveKDateTime())
3461 return KAEvent::FIRST_OR_ONLY_OCCURRENCE; // it might not be the first recurrence - tant pis
3462 KDateTime pre = preDateTime;
3463 // If there are repetitions, adjust the comparison date/time so that
3464 // we find the earliest recurrence which has a repetition falling after
3465 // the specified preDateTime.
3466 if (mRepetition)
3467 pre = mRepetition.duration(-mRepetition.count()).end(preDateTime);
3468
3469 DateTime afterPre; // next recurrence after 'pre'
3470 KAEvent::OccurType type;
3471 if (pre < mNextMainDateTime.effectiveKDateTime())
3472 {
3473 afterPre = mNextMainDateTime;
3474 type = KAEvent::FIRST_OR_ONLY_OCCURRENCE; // may not actually be the first occurrence
3475 }
3476 else if (checkRecur() != KARecurrence::NO_RECUR)
3477 {
3478 type = nextRecurrence(pre, afterPre);
3479 if (type == KAEvent::NO_OCCURRENCE)
3480 return KAEvent::NO_OCCURRENCE;
3481 if (type != KAEvent::FIRST_OR_ONLY_OCCURRENCE && afterPre != mNextMainDateTime)
3482 {
3483 // Need to reschedule the next trigger date/time
3484 mNextMainDateTime = afterPre;
3485 if (mReminderMinutes > 0 && (mDeferral == REMINDER_DEFERRAL || mReminderActive != ACTIVE_REMINDER))
3486 {
3487 // Reinstate the advance reminder for the rescheduled recurrence.
3488 // Note that a reminder AFTER the main alarm will be left active.
3489 activate_reminder(!mReminderOnceOnly);
3490 }
3491 if (mDeferral == REMINDER_DEFERRAL)
3492 set_deferral(NO_DEFERRAL);
3493 mTriggerChanged = true;
3494 }
3495 }
3496 else
3497 return KAEvent::NO_OCCURRENCE;
3498
3499 if (mRepetition)
3500 {
3501 if (afterPre <= preDateTime)
3502 {
3503 // The next occurrence is a sub-repetition.
3504 type = static_cast<KAEvent::OccurType>(type | KAEvent::OCCURRENCE_REPEAT);
3505 mNextRepeat = mRepetition.nextRepeatCount(afterPre.effectiveKDateTime(), preDateTime);
3506 // Repetitions can't have a reminder, so remove any.
3507 activate_reminder(false);
3508 if (mDeferral == REMINDER_DEFERRAL)
3509 set_deferral(NO_DEFERRAL);
3510 mTriggerChanged = true;
3511 }
3512 else if (mNextRepeat)
3513 {
3514 // The next occurrence is the main occurrence, not a repetition
3515 mNextRepeat = 0;
3516 mTriggerChanged = true;
3517 }
3518 }
3519 return type;
3520}
3521
3522/******************************************************************************
3523* Get the date/time of the next occurrence of the event, after the specified
3524* date/time.
3525* 'result' = date/time of next occurrence, or invalid date/time if none.
3526*/
3527KAEvent::OccurType KAEvent::nextOccurrence(const KDateTime& preDateTime, DateTime& result, OccurOption o) const
3528{
3529 return d->nextOccurrence(preDateTime, result, o);
3530}
3531
3532KAEvent::OccurType KAEventPrivate::nextOccurrence(const KDateTime& preDateTime, DateTime& result,
3533 KAEvent::OccurOption includeRepetitions) const
3534{
3535 KDateTime pre = preDateTime;
3536 if (includeRepetitions != KAEvent::IGNORE_REPETITION)
3537 { // RETURN_REPETITION or ALLOW_FOR_REPETITION
3538 if (!mRepetition)
3539 includeRepetitions = KAEvent::IGNORE_REPETITION;
3540 else
3541 pre = mRepetition.duration(-mRepetition.count()).end(preDateTime);
3542 }
3543
3544 KAEvent::OccurType type;
3545 const bool recurs = (checkRecur() != KARecurrence::NO_RECUR);
3546 if (recurs)
3547 type = nextRecurrence(pre, result);
3548 else if (pre < mNextMainDateTime.effectiveKDateTime())
3549 {
3550 result = mNextMainDateTime;
3551 type = KAEvent::FIRST_OR_ONLY_OCCURRENCE;
3552 }
3553 else
3554 {
3555 result = DateTime();
3556 type = KAEvent::NO_OCCURRENCE;
3557 }
3558
3559 if (type != KAEvent::NO_OCCURRENCE && result <= preDateTime && includeRepetitions != KAEvent::IGNORE_REPETITION)
3560 { // RETURN_REPETITION or ALLOW_FOR_REPETITION
3561 // The next occurrence is a sub-repetition
3562 int repetition = mRepetition.nextRepeatCount(result.kDateTime(), preDateTime);
3563 const DateTime repeatDT = mRepetition.duration(repetition).end(result.kDateTime());
3564 if (recurs)
3565 {
3566 // We've found a recurrence before the specified date/time, which has
3567 // a sub-repetition after the date/time.
3568 // However, if the intervals between recurrences vary, we could possibly
3569 // have missed a later recurrence which fits the criterion, so check again.
3570 DateTime dt;
3571 const KAEvent::OccurType newType = previousOccurrence(repeatDT.effectiveKDateTime(), dt, false);
3572 if (dt > result)
3573 {
3574 type = newType;
3575 result = dt;
3576 if (includeRepetitions == KAEvent::RETURN_REPETITION && result <= preDateTime)
3577 {
3578 // The next occurrence is a sub-repetition
3579 repetition = mRepetition.nextRepeatCount(result.kDateTime(), preDateTime);
3580 result = mRepetition.duration(repetition).end(result.kDateTime());
3581 type = static_cast<KAEvent::OccurType>(type | KAEvent::OCCURRENCE_REPEAT);
3582 }
3583 return type;
3584 }
3585 }
3586 if (includeRepetitions == KAEvent::RETURN_REPETITION)
3587 {
3588 // The next occurrence is a sub-repetition
3589 result = repeatDT;
3590 type = static_cast<KAEvent::OccurType>(type | KAEvent::OCCURRENCE_REPEAT);
3591 }
3592 }
3593 return type;
3594}
3595
3596/******************************************************************************
3597* Get the date/time of the last previous occurrence of the event, before the
3598* specified date/time.
3599* If 'includeRepetitions' is true and the alarm has a sub-repetition, the
3600* last previous repetition is returned if appropriate.
3601* 'result' = date/time of previous occurrence, or invalid date/time if none.
3602*/
3603KAEvent::OccurType KAEvent::previousOccurrence(const KDateTime& afterDateTime, DateTime& result, bool includeRepetitions) const
3604{
3605 return d->previousOccurrence(afterDateTime, result, includeRepetitions);
3606}
3607
3608KAEvent::OccurType KAEventPrivate::previousOccurrence(const KDateTime& afterDateTime, DateTime& result,
3609 bool includeRepetitions) const
3610{
3611 Q_ASSERT(!afterDateTime.isDateOnly());
3612 if (mStartDateTime >= afterDateTime)
3613 {
3614 result = KDateTime();
3615 return KAEvent::NO_OCCURRENCE; // the event starts after the specified date/time
3616 }
3617
3618 // Find the latest recurrence of the event
3619 KAEvent::OccurType type;
3620 if (checkRecur() == KARecurrence::NO_RECUR)
3621 {
3622 result = mStartDateTime;
3623 type = KAEvent::FIRST_OR_ONLY_OCCURRENCE;
3624 }
3625 else
3626 {
3627 const KDateTime recurStart = mRecurrence->startDateTime();
3628 KDateTime after = afterDateTime.toTimeSpec(mStartDateTime.timeSpec());
3629 if (mStartDateTime.isDateOnly() && afterDateTime.time() > DateTime::startOfDay())
3630 after = after.addDays(1); // today's recurrence (if today recurs) has passed
3631 const KDateTime dt = mRecurrence->getPreviousDateTime(after);
3632 result = dt;
3633 result.setDateOnly(mStartDateTime.isDateOnly());
3634 if (!dt.isValid())
3635 return KAEvent::NO_OCCURRENCE;
3636 if (dt == recurStart)
3637 type = KAEvent::FIRST_OR_ONLY_OCCURRENCE;
3638 else if (mRecurrence->getNextDateTime(dt).isValid())
3639 type = result.isDateOnly() ? KAEvent::RECURRENCE_DATE : KAEvent::RECURRENCE_DATE_TIME;
3640 else
3641 type = KAEvent::LAST_RECURRENCE;
3642 }
3643
3644 if (includeRepetitions && mRepetition)
3645 {
3646 // Find the latest repetition which is before the specified time.
3647 const int repetition = mRepetition.previousRepeatCount(result.effectiveKDateTime(), afterDateTime);
3648 if (repetition > 0)
3649 {
3650 result = mRepetition.duration(qMin(repetition, mRepetition.count())).end(result.kDateTime());
3651 return static_cast<KAEvent::OccurType>(type | KAEvent::OCCURRENCE_REPEAT);
3652 }
3653 }
3654 return type;
3655}
3656
3657/******************************************************************************
3658* Set the event to be a copy of the specified event, making the specified
3659* alarm the 'displaying' alarm.
3660* The purpose of setting up a 'displaying' alarm is to be able to reinstate
3661* the alarm message in case of a crash, or to reinstate it should the user
3662* choose to defer the alarm. Note that even repeat-at-login alarms need to be
3663* saved in case their end time expires before the next login.
3664* Reply = true if successful, false if alarm was not copied.
3665*/
3666#ifndef KALARMCAL_USE_KRESOURCES
3667bool KAEvent::setDisplaying(const KAEvent& e, KAAlarm::Type t, Akonadi::Collection::Id id, const KDateTime& dt, bool showEdit, bool showDefer)
3668#else
3669bool KAEvent::setDisplaying(const KAEvent& e, KAAlarm::Type t, const QString& id, const KDateTime& dt, bool showEdit, bool showDefer)
3670#endif
3671{
3672 return d->setDisplaying(*e.d, t, id, dt, showEdit, showDefer);
3673}
3674
3675#ifndef KALARMCAL_USE_KRESOURCES
3676bool KAEventPrivate::setDisplaying(const KAEventPrivate& event, KAAlarm::Type alarmType, Akonadi::Collection::Id collectionId,
3677 const KDateTime& repeatAtLoginTime, bool showEdit, bool showDefer)
3678#else
3679bool KAEventPrivate::setDisplaying(const KAEventPrivate& event, KAAlarm::Type alarmType, const QString& resourceID,
3680 const KDateTime& repeatAtLoginTime, bool showEdit, bool showDefer)
3681#endif
3682{
3683 if (!mDisplaying
3684 && (alarmType == KAAlarm::MAIN_ALARM
3685 || alarmType == KAAlarm::REMINDER_ALARM
3686 || alarmType == KAAlarm::DEFERRED_REMINDER_ALARM
3687 || alarmType == KAAlarm::DEFERRED_ALARM
3688 || alarmType == KAAlarm::AT_LOGIN_ALARM))
3689 {
3690//kDebug()<<event.id()<<","<<(alarmType==KAAlarm::MAIN_ALARM?"MAIN":alarmType==KAAlarm::REMINDER_ALARM?"REMINDER":alarmType==KAAlarm::DEFERRED_REMINDER_ALARM?"REMINDER_DEFERRAL":alarmType==KAAlarm::DEFERRED_ALARM?"DEFERRAL":"LOGIN")<<"): time="<<repeatAtLoginTime.toString();
3691 KAAlarm al = event.alarm(alarmType);
3692 if (al.isValid())
3693 {
3694 *this = event;
3695 // Change the event ID to avoid duplicating the same unique ID as the original event
3696 setCategory(CalEvent::DISPLAYING);
3697#ifndef KALARMCAL_USE_KRESOURCES
3698 mItemId = -1; // the display event doesn't have an associated Item
3699 mCollectionId = collectionId; // original collection ID which contained the event
3700#else
3701 mOriginalResourceId = resourceID;
3702#endif
3703 mDisplayingDefer = showDefer;
3704 mDisplayingEdit = showEdit;
3705 mDisplaying = true;
3706 mDisplayingTime = (alarmType == KAAlarm::AT_LOGIN_ALARM) ? repeatAtLoginTime : al.dateTime().kDateTime();
3707 switch (al.type())
3708 {
3709 case KAAlarm::AT_LOGIN_ALARM: mDisplayingFlags = KAEvent::REPEAT_AT_LOGIN; break;
3710 case KAAlarm::REMINDER_ALARM: mDisplayingFlags = REMINDER; break;
3711 case KAAlarm::DEFERRED_REMINDER_ALARM: mDisplayingFlags = al.timedDeferral() ? (REMINDER | TIME_DEFERRAL) : (REMINDER | DATE_DEFERRAL); break;
3712 case KAAlarm::DEFERRED_ALARM: mDisplayingFlags = al.timedDeferral() ? TIME_DEFERRAL : DATE_DEFERRAL; break;
3713 default: mDisplayingFlags = 0; break;
3714 }
3715 ++mAlarmCount;
3716 return true;
3717 }
3718 }
3719 return false;
3720}
3721
3722/******************************************************************************
3723* Reinstate the original event from the 'displaying' event.
3724*/
3725#ifndef KALARMCAL_USE_KRESOURCES
3726void KAEvent::reinstateFromDisplaying(const KCalCore::Event::Ptr& e, Akonadi::Collection::Id& id, bool& showEdit, bool& showDefer)
3727#else
3728void KAEvent::reinstateFromDisplaying(const KCal::Event* e, QString& id, bool& showEdit, bool& showDefer)
3729#endif
3730{
3731 d->reinstateFromDisplaying(e, id, showEdit, showDefer);
3732}
3733
3734#ifndef KALARMCAL_USE_KRESOURCES
3735void KAEventPrivate::reinstateFromDisplaying(const Event::Ptr& kcalEvent, Akonadi::Collection::Id& collectionId, bool& showEdit, bool& showDefer)
3736#else
3737void KAEventPrivate::reinstateFromDisplaying(const Event* kcalEvent, QString& resourceID, bool& showEdit, bool& showDefer)
3738#endif
3739{
3740 set(kcalEvent);
3741 if (mDisplaying)
3742 {
3743 // Retrieve the original event's unique ID
3744 setCategory(CalEvent::ACTIVE);
3745#ifndef KALARMCAL_USE_KRESOURCES
3746 collectionId = mCollectionId;
3747 mCollectionId = -1;
3748#else
3749 resourceID = mOriginalResourceId;
3750 mOriginalResourceId.clear();
3751#endif
3752 showDefer = mDisplayingDefer;
3753 showEdit = mDisplayingEdit;
3754 mDisplaying = false;
3755 --mAlarmCount;
3756 }
3757}
3758
3759/******************************************************************************
3760* Return the original alarm which the displaying alarm refers to.
3761* Note that the caller is responsible for ensuring that the event was a
3762* displaying event, since this is normally called after
3763* reinstateFromDisplaying(), which clears mDisplaying.
3764*/
3765KAAlarm KAEvent::convertDisplayingAlarm() const
3766{
3767 KAAlarm al = alarm(KAAlarm::DISPLAYING_ALARM);
3768 KAAlarm::Private* const al_d = al.d;
3769 const int displayingFlags = d->mDisplayingFlags;
3770 if (displayingFlags & REPEAT_AT_LOGIN)
3771 {
3772 al_d->mRepeatAtLogin = true;
3773 al_d->mType = KAAlarm::AT_LOGIN_ALARM;
3774 }
3775 else if (displayingFlags & KAEventPrivate::DEFERRAL)
3776 {
3777 al_d->mDeferred = true;
3778 al_d->mTimedDeferral = (displayingFlags & KAEventPrivate::TIMED_FLAG);
3779 al_d->mType = (displayingFlags & KAEventPrivate::REMINDER) ? KAAlarm::DEFERRED_REMINDER_ALARM : KAAlarm::DEFERRED_ALARM;
3780 }
3781 else if (displayingFlags & KAEventPrivate::REMINDER)
3782 al_d->mType = KAAlarm::REMINDER_ALARM;
3783 else
3784 al_d->mType = KAAlarm::MAIN_ALARM;
3785 return al;
3786}
3787
3788bool KAEvent::displaying() const
3789{
3790 return d->mDisplaying;
3791}
3792
3793/******************************************************************************
3794* Return the alarm of the specified type.
3795*/
3796KAAlarm KAEvent::alarm(KAAlarm::Type t) const
3797{
3798 return d->alarm(t);
3799}
3800
3801KAAlarm KAEventPrivate::alarm(KAAlarm::Type type) const
3802{
3803 checkRecur(); // ensure recurrence/repetition data is consistent
3804 KAAlarm al; // this sets type to INVALID_ALARM
3805 KAAlarm::Private* const al_d = al.d;
3806 if (mAlarmCount)
3807 {
3808 al_d->mActionType = static_cast<KAAlarm::Action>(mActionSubType);
3809 al_d->mRepeatAtLogin = false;
3810 al_d->mDeferred = false;
3811 switch (type)
3812 {
3813 case KAAlarm::MAIN_ALARM:
3814 if (!mMainExpired)
3815 {
3816 al_d->mType = KAAlarm::MAIN_ALARM;
3817 al_d->mNextMainDateTime = mNextMainDateTime;
3818 al_d->mRepetition = mRepetition;
3819 al_d->mNextRepeat = mNextRepeat;
3820 }
3821 break;
3822 case KAAlarm::REMINDER_ALARM:
3823 if (mReminderActive == ACTIVE_REMINDER)
3824 {
3825 al_d->mType = KAAlarm::REMINDER_ALARM;
3826 if (mReminderMinutes < 0)
3827 al_d->mNextMainDateTime = mReminderAfterTime;
3828 else if (mReminderOnceOnly)
3829 al_d->mNextMainDateTime = mStartDateTime.addMins(-mReminderMinutes);
3830 else
3831 al_d->mNextMainDateTime = mNextMainDateTime.addMins(-mReminderMinutes);
3832 }
3833 break;
3834 case KAAlarm::DEFERRED_REMINDER_ALARM:
3835 if (mDeferral != REMINDER_DEFERRAL)
3836 break;
3837 // fall through to DEFERRED_ALARM
3838 case KAAlarm::DEFERRED_ALARM:
3839 if (mDeferral != NO_DEFERRAL)
3840 {
3841 al_d->mType = (mDeferral == REMINDER_DEFERRAL) ? KAAlarm::DEFERRED_REMINDER_ALARM : KAAlarm::DEFERRED_ALARM;
3842 al_d->mNextMainDateTime = mDeferralTime;
3843 al_d->mDeferred = true;
3844 al_d->mTimedDeferral = !mDeferralTime.isDateOnly();
3845 }
3846 break;
3847 case KAAlarm::AT_LOGIN_ALARM:
3848 if (mRepeatAtLogin)
3849 {
3850 al_d->mType = KAAlarm::AT_LOGIN_ALARM;
3851 al_d->mNextMainDateTime = mAtLoginDateTime;
3852 al_d->mRepeatAtLogin = true;
3853 }
3854 break;
3855 case KAAlarm::DISPLAYING_ALARM:
3856 if (mDisplaying)
3857 {
3858 al_d->mType = KAAlarm::DISPLAYING_ALARM;
3859 al_d->mNextMainDateTime = mDisplayingTime;
3860 }
3861 break;
3862 case KAAlarm::INVALID_ALARM:
3863 default:
3864 break;
3865 }
3866 }
3867 return al;
3868}
3869
3870/******************************************************************************
3871* Return the main alarm for the event.
3872* If the main alarm does not exist, one of the subsidiary ones is returned if
3873* possible.
3874* N.B. a repeat-at-login alarm can only be returned if it has been read from/
3875* written to the calendar file.
3876*/
3877KAAlarm KAEvent::firstAlarm() const
3878{
3879 return d->firstAlarm();
3880}
3881
3882KAAlarm KAEventPrivate::firstAlarm() const
3883{
3884 if (mAlarmCount)
3885 {
3886 if (!mMainExpired)
3887 return alarm(KAAlarm::MAIN_ALARM);
3888 return nextAlarm(KAAlarm::MAIN_ALARM);
3889 }
3890 return KAAlarm();
3891}
3892
3893/******************************************************************************
3894* Return the next alarm for the event, after the specified alarm.
3895* N.B. a repeat-at-login alarm can only be returned if it has been read from/
3896* written to the calendar file.
3897*/
3898KAAlarm KAEvent::nextAlarm(const KAAlarm& previousAlarm) const
3899{
3900 return d->nextAlarm(previousAlarm.type());
3901}
3902
3903KAAlarm KAEvent::nextAlarm(KAAlarm::Type previousType) const
3904{
3905 return d->nextAlarm(previousType);
3906}
3907
3908KAAlarm KAEventPrivate::nextAlarm(KAAlarm::Type previousType) const
3909{
3910 switch (previousType)
3911 {
3912 case KAAlarm::MAIN_ALARM:
3913 if (mReminderActive == ACTIVE_REMINDER)
3914 return alarm(KAAlarm::REMINDER_ALARM);
3915 // fall through to REMINDER_ALARM
3916 case KAAlarm::REMINDER_ALARM:
3917 // There can only be one deferral alarm
3918 if (mDeferral == REMINDER_DEFERRAL)
3919 return alarm(KAAlarm::DEFERRED_REMINDER_ALARM);
3920 if (mDeferral == NORMAL_DEFERRAL)
3921 return alarm(KAAlarm::DEFERRED_ALARM);
3922 // fall through to DEFERRED_ALARM
3923 case KAAlarm::DEFERRED_REMINDER_ALARM:
3924 case KAAlarm::DEFERRED_ALARM:
3925 if (mRepeatAtLogin)
3926 return alarm(KAAlarm::AT_LOGIN_ALARM);
3927 // fall through to AT_LOGIN_ALARM
3928 case KAAlarm::AT_LOGIN_ALARM:
3929 if (mDisplaying)
3930 return alarm(KAAlarm::DISPLAYING_ALARM);
3931 // fall through to DISPLAYING_ALARM
3932 case KAAlarm::DISPLAYING_ALARM:
3933 // fall through to default
3934 case KAAlarm::INVALID_ALARM:
3935 default:
3936 break;
3937 }
3938 return KAAlarm();
3939}
3940
3941int KAEvent::alarmCount() const
3942{
3943 return d->mAlarmCount;
3944}
3945
3946/******************************************************************************
3947* Remove the alarm of the specified type from the event.
3948* This must only be called to remove an alarm which has expired, not to
3949* reconfigure the event.
3950*/
3951void KAEvent::removeExpiredAlarm(KAAlarm::Type type)
3952{
3953 d->removeExpiredAlarm(type);
3954}
3955
3956void KAEventPrivate::removeExpiredAlarm(KAAlarm::Type type)
3957{
3958 const int count = mAlarmCount;
3959 switch (type)
3960 {
3961 case KAAlarm::MAIN_ALARM:
3962 if (!mReminderActive || mReminderMinutes > 0)
3963 {
3964 mAlarmCount = 0; // removing main alarm - also remove subsidiary alarms
3965 break;
3966 }
3967 // There is a reminder after the main alarm - retain the
3968 // reminder and remove other subsidiary alarms.
3969 mMainExpired = true; // mark the alarm as expired now
3970 --mAlarmCount;
3971 set_deferral(NO_DEFERRAL);
3972 if (mDisplaying)
3973 {
3974 mDisplaying = false;
3975 --mAlarmCount;
3976 }
3977 // fall through to AT_LOGIN_ALARM
3978 case KAAlarm::AT_LOGIN_ALARM:
3979 if (mRepeatAtLogin)
3980 {
3981 // Remove the at-login alarm, but keep a note of it for archiving purposes
3982 mArchiveRepeatAtLogin = true;
3983 mRepeatAtLogin = false;
3984 --mAlarmCount;
3985 }
3986 break;
3987 case KAAlarm::REMINDER_ALARM:
3988 // Remove any reminder alarm, but keep a note of it for archiving purposes
3989 // and for restoration after the next recurrence.
3990 activate_reminder(false);
3991 break;
3992 case KAAlarm::DEFERRED_REMINDER_ALARM:
3993 case KAAlarm::DEFERRED_ALARM:
3994 set_deferral(NO_DEFERRAL);
3995 break;
3996 case KAAlarm::DISPLAYING_ALARM:
3997 if (mDisplaying)
3998 {
3999 mDisplaying = false;
4000 --mAlarmCount;
4001 }
4002 break;
4003 case KAAlarm::INVALID_ALARM:
4004 default:
4005 break;
4006 }
4007 if (mAlarmCount != count)
4008 mTriggerChanged = true;
4009}
4010
4011void KAEvent::startChanges()
4012{
4013 d->startChanges();
4014}
4015
4016/******************************************************************************
4017* Indicate that changes to the instance are complete.
4018* This allows trigger times to be recalculated if any changes have occurred.
4019*/
4020void KAEvent::endChanges()
4021{
4022 d->endChanges();
4023}
4024
4025void KAEventPrivate::endChanges()
4026{
4027 if (mChangeCount > 0)
4028 --mChangeCount;
4029}
4030
4031#ifndef KALARMCAL_USE_KRESOURCES
4032/******************************************************************************
4033* Return a list of pointers to KAEvent objects.
4034*/
4035KAEvent::List KAEvent::ptrList(QVector<KAEvent>& objList)
4036{
4037 KAEvent::List ptrs;
4038 for (int i = 0, count = objList.count(); i < count; ++i)
4039 ptrs += &objList[i];
4040 return ptrs;
4041}
4042#endif
4043
4044void KAEvent::dumpDebug() const
4045{
4046#ifndef KDE_NO_DEBUG_OUTPUT
4047 d->dumpDebug();
4048#endif
4049}
4050
4051#ifndef KDE_NO_DEBUG_OUTPUT
4052void KAEventPrivate::dumpDebug() const
4053{
4054 kDebug() << "KAEvent dump:";
4055#ifdef KALARMCAL_USE_KRESOURCES
4056 if (mResource) { kDebug() << "-- mResource:" << (void*)mResource; }
4057#endif
4058 kDebug() << "-- mEventID:" << mEventID;
4059 kDebug() << "-- mActionSubType:" << (mActionSubType == KAEvent::MESSAGE ? "MESSAGE" : mActionSubType == KAEvent::FILE ? "FILE" : mActionSubType == KAEvent::COMMAND ? "COMMAND" : mActionSubType == KAEvent::EMAIL ? "EMAIL" : mActionSubType == KAEvent::AUDIO ? "AUDIO" : "??");
4060 kDebug() << "-- mNextMainDateTime:" << mNextMainDateTime.toString();
4061 kDebug() << "-- mCommandError:" << mCommandError;
4062 kDebug() << "-- mAllTrigger:" << mAllTrigger.toString();
4063 kDebug() << "-- mMainTrigger:" << mMainTrigger.toString();
4064 kDebug() << "-- mAllWorkTrigger:" << mAllWorkTrigger.toString();
4065 kDebug() << "-- mMainWorkTrigger:" << mMainWorkTrigger.toString();
4066 kDebug() << "-- mCategory:" << mCategory;
4067 if (!mTemplateName.isEmpty())
4068 {
4069 kDebug() << "-- mTemplateName:" << mTemplateName;
4070 kDebug() << "-- mTemplateAfterTime:" << mTemplateAfterTime;
4071 }
4072 kDebug() << "-- mText:" << mText;
4073 if (mActionSubType == KAEvent::MESSAGE || mActionSubType == KAEvent::FILE)
4074 {
4075 kDebug() << "-- mBgColour:" << mBgColour.name();
4076 kDebug() << "-- mFgColour:" << mFgColour.name();
4077 kDebug() << "-- mUseDefaultFont:" << mUseDefaultFont;
4078 if (!mUseDefaultFont)
4079 kDebug() << "-- mFont:" << mFont.toString();
4080 kDebug() << "-- mSpeak:" << mSpeak;
4081 kDebug() << "-- mAudioFile:" << mAudioFile;
4082 kDebug() << "-- mPreAction:" << mPreAction;
4083 kDebug() << "-- mExecPreActOnDeferral:" << (mExtraActionOptions & KAEvent::ExecPreActOnDeferral);
4084 kDebug() << "-- mCancelOnPreActErr:" << (mExtraActionOptions & KAEvent::CancelOnPreActError);
4085 kDebug() << "-- mDontShowPreActErr:" << (mExtraActionOptions & KAEvent::DontShowPreActError);
4086 kDebug() << "-- mPostAction:" << mPostAction;
4087 kDebug() << "-- mLateCancel:" << mLateCancel;
4088 kDebug() << "-- mAutoClose:" << mAutoClose;
4089 }
4090 else if (mActionSubType == KAEvent::COMMAND)
4091 {
4092 kDebug() << "-- mCommandScript:" << mCommandScript;
4093 kDebug() << "-- mCommandXterm:" << mCommandXterm;
4094 kDebug() << "-- mCommandDisplay:" << mCommandDisplay;
4095 kDebug() << "-- mLogFile:" << mLogFile;
4096 }
4097 else if (mActionSubType == KAEvent::EMAIL)
4098 {
4099 kDebug() << "-- mEmail: FromKMail:" << mEmailFromIdentity;
4100 kDebug() << "-- Addresses:" << mEmailAddresses.join(QLatin1String(","));
4101 kDebug() << "-- Subject:" << mEmailSubject;
4102 kDebug() << "-- Attachments:" << mEmailAttachments.join(QLatin1String(","));
4103 kDebug() << "-- Bcc:" << mEmailBcc;
4104 }
4105 else if (mActionSubType == KAEvent::AUDIO)
4106 kDebug() << "-- mAudioFile:" << mAudioFile;
4107 kDebug() << "-- mBeep:" << mBeep;
4108 if (mActionSubType == KAEvent::AUDIO || !mAudioFile.isEmpty())
4109 {
4110 if (mSoundVolume >= 0)
4111 {
4112 kDebug() << "-- mSoundVolume:" << mSoundVolume;
4113 if (mFadeVolume >= 0)
4114 {
4115 kDebug() << "-- mFadeVolume:" << mFadeVolume;
4116 kDebug() << "-- mFadeSeconds:" << mFadeSeconds;
4117 }
4118 else
4119 kDebug() << "-- mFadeVolume:-:";
4120 }
4121 else
4122 kDebug() << "-- mSoundVolume:-:";
4123 kDebug() << "-- mRepeatSoundPause:" << mRepeatSoundPause;
4124 }
4125 kDebug() << "-- mKMailSerialNumber:" << mKMailSerialNumber;
4126 kDebug() << "-- mCopyToKOrganizer:" << mCopyToKOrganizer;
4127 kDebug() << "-- mExcludeHolidays:" << (bool)mExcludeHolidays;
4128 kDebug() << "-- mWorkTimeOnly:" << mWorkTimeOnly;
4129 kDebug() << "-- mStartDateTime:" << mStartDateTime.toString();
4130 kDebug() << "-- mCreatedDateTime:" << mCreatedDateTime;
4131 kDebug() << "-- mRepeatAtLogin:" << mRepeatAtLogin;
4132 if (mRepeatAtLogin)
4133 kDebug() << "-- mAtLoginDateTime:" << mAtLoginDateTime;
4134 kDebug() << "-- mArchiveRepeatAtLogin:" << mArchiveRepeatAtLogin;
4135 kDebug() << "-- mConfirmAck:" << mConfirmAck;
4136 kDebug() << "-- mEnabled:" << mEnabled;
4137#ifndef KALARMCAL_USE_KRESOURCES
4138 kDebug() << "-- mItemId:" << mItemId;
4139 kDebug() << "-- mCollectionId:" << mCollectionId;
4140 kDebug() << "-- mCompatibility:" << mCompatibility;
4141 kDebug() << "-- mReadOnly:" << mReadOnly;
4142#endif
4143 if (mReminderMinutes)
4144 {
4145 kDebug() << "-- mReminderMinutes:" << mReminderMinutes;
4146 kDebug() << "-- mReminderActive:" << (mReminderActive == ACTIVE_REMINDER ? "active" : mReminderActive == HIDDEN_REMINDER ? "hidden" : "no");
4147 kDebug() << "-- mReminderOnceOnly:" << mReminderOnceOnly;
4148 }
4149 else if (mDeferral > 0)
4150 {
4151 kDebug() << "-- mDeferral:" << (mDeferral == NORMAL_DEFERRAL ? "normal" : "reminder");
4152 kDebug() << "-- mDeferralTime:" << mDeferralTime.toString();
4153 }
4154 kDebug() << "-- mDeferDefaultMinutes:" << mDeferDefaultMinutes;
4155 if (mDeferDefaultMinutes)
4156 kDebug() << "-- mDeferDefaultDateOnly:" << mDeferDefaultDateOnly;
4157 if (mDisplaying)
4158 {
4159 kDebug() << "-- mDisplayingTime:" << mDisplayingTime.toString();
4160 kDebug() << "-- mDisplayingFlags:" << mDisplayingFlags;
4161 kDebug() << "-- mDisplayingDefer:" << mDisplayingDefer;
4162 kDebug() << "-- mDisplayingEdit:" << mDisplayingEdit;
4163 }
4164 kDebug() << "-- mRevision:" << mRevision;
4165 kDebug() << "-- mRecurrence:" << mRecurrence;
4166 if (!mRepetition)
4167 kDebug() << "-- mRepetition: 0";
4168 else if (mRepetition.isDaily())
4169 kDebug() << "-- mRepetition: count:" << mRepetition.count() << ", interval:" << mRepetition.intervalDays() << "days";
4170 else
4171 kDebug() << "-- mRepetition: count:" << mRepetition.count() << ", interval:" << mRepetition.intervalMinutes() << "minutes";
4172 kDebug() << "-- mNextRepeat:" << mNextRepeat;
4173 kDebug() << "-- mAlarmCount:" << mAlarmCount;
4174 kDebug() << "-- mMainExpired:" << mMainExpired;
4175 kDebug() << "-- mDisplaying:" << mDisplaying;
4176 kDebug() << "KAEvent dump end";
4177}
4178#endif
4179
4180/******************************************************************************
4181* Fetch the start and next date/time for a KCal::Event.
4182* Reply = next main date/time.
4183*/
4184#ifndef KALARMCAL_USE_KRESOURCES
4185DateTime KAEventPrivate::readDateTime(const Event::Ptr& event, bool dateOnly, DateTime& start)
4186#else
4187DateTime KAEventPrivate::readDateTime(const Event* event, bool dateOnly, DateTime& start)
4188#endif
4189{
4190 start = event->dtStart();
4191 if (dateOnly)
4192 {
4193 // A date-only event is indicated by the X-KDE-KALARM-FLAGS:DATE property, not
4194 // by a date-only start date/time (for the reasons given in updateKCalEvent()).
4195 start.setDateOnly(true);
4196 }
4197 DateTime next = start;
4198 const int SZ_YEAR = 4; // number of digits in year value
4199 const int SZ_MONTH = 2; // number of digits in month value
4200 const int SZ_DAY = 2; // number of digits in day value
4201 const int SZ_DATE = SZ_YEAR + SZ_MONTH + SZ_DAY; // total size of date value
4202 const int IX_TIME = SZ_DATE + 1; // offset to time value
4203 const int SZ_HOUR = 2; // number of digits in hour value
4204 const int SZ_MIN = 2; // number of digits in minute value
4205 const int SZ_SEC = 2; // number of digits in second value
4206 const int SZ_TIME = SZ_HOUR + SZ_MIN + SZ_SEC; // total size of time value
4207 const QString prop = event->customProperty(KACalendar::APPNAME, KAEventPrivate::NEXT_RECUR_PROPERTY);
4208 if (prop.length() >= SZ_DATE)
4209 {
4210 // The next due recurrence time is specified
4211 const QDate d(prop.left(SZ_YEAR).toInt(),
4212 prop.mid(SZ_YEAR, SZ_MONTH).toInt(),
4213 prop.mid(SZ_YEAR + SZ_MONTH, SZ_DAY).toInt());
4214 if (d.isValid())
4215 {
4216 if (dateOnly && prop.length() == SZ_DATE)
4217 next.setDate(d);
4218 else if (!dateOnly && prop.length() == IX_TIME + SZ_TIME && prop[SZ_DATE] == QLatin1Char('T'))
4219 {
4220 const QTime t(prop.mid(IX_TIME, SZ_HOUR).toInt(),
4221 prop.mid(IX_TIME + SZ_HOUR, SZ_MIN).toInt(),
4222 prop.mid(IX_TIME + SZ_HOUR + SZ_MIN, SZ_SEC).toInt());
4223 if (t.isValid())
4224 {
4225 next.setDate(d);
4226 next.setTime(t);
4227 }
4228 }
4229 if (next < start)
4230 next = start; // ensure next recurrence time is valid
4231 }
4232 }
4233 return next;
4234}
4235
4236/******************************************************************************
4237* Parse the alarms for a KCal::Event.
4238* Reply = map of alarm data, indexed by KAAlarm::Type
4239*/
4240#ifndef KALARMCAL_USE_KRESOURCES
4241void KAEventPrivate::readAlarms(const Event::Ptr& event, AlarmMap* alarmMap, bool cmdDisplay)
4242#else
4243void KAEventPrivate::readAlarms(const Event* event, AlarmMap* alarmMap, bool cmdDisplay)
4244#endif
4245{
4246 const Alarm::List alarms = event->alarms();
4247
4248 // Check if it's an audio event with no display alarm
4249 bool audioOnly = false;
4250 for (int i = 0, end = alarms.count(); i < end; ++i)
4251 {
4252 switch (alarms[i]->type())
4253 {
4254 case Alarm::Display:
4255 case Alarm::Procedure:
4256 audioOnly = false;
4257 i = end; // exit from the 'for' loop
4258 break;
4259 case Alarm::Audio:
4260 audioOnly = true;
4261 break;
4262 default:
4263 break;
4264 }
4265 }
4266
4267 for (int i = 0, end = alarms.count(); i < end; ++i)
4268 {
4269 // Parse the next alarm's text
4270 AlarmData data;
4271 readAlarm(alarms[i], data, audioOnly, cmdDisplay);
4272 if (data.type != INVALID_ALARM)
4273 alarmMap->insert(data.type, data);
4274 }
4275}
4276
4277/******************************************************************************
4278* Parse a KCal::Alarm.
4279* If 'audioMain' is true, the event contains an audio alarm but no display alarm.
4280* Reply = alarm ID (sequence number)
4281*/
4282#ifndef KALARMCAL_USE_KRESOURCES
4283void KAEventPrivate::readAlarm(const Alarm::Ptr& alarm, AlarmData& data, bool audioMain, bool cmdDisplay)
4284#else
4285void KAEventPrivate::readAlarm(const Alarm* alarm, AlarmData& data, bool audioMain, bool cmdDisplay)
4286#endif
4287{
4288 // Parse the next alarm's text
4289 data.alarm = alarm;
4290 data.displayingFlags = 0;
4291 data.isEmailText = false;
4292 data.speak = false;
4293 data.hiddenReminder = false;
4294 data.timedDeferral = false;
4295 data.nextRepeat = 0;
4296 data.repeatSoundPause = -1;
4297 if (alarm->repeatCount())
4298 {
4299 bool ok;
4300 const QString property = alarm->customProperty(KACalendar::APPNAME, KAEventPrivate::NEXT_REPEAT_PROPERTY);
4301 int n = static_cast<int>(property.toUInt(&ok));
4302 if (ok)
4303 data.nextRepeat = n;
4304 }
4305 QString property = alarm->customProperty(KACalendar::APPNAME, KAEventPrivate::FLAGS_PROPERTY);
4306 const QStringList flags = property.split(KAEventPrivate::SC, QString::SkipEmptyParts);
4307 switch (alarm->type())
4308 {
4309 case Alarm::Procedure:
4310 data.action = KAAlarm::COMMAND;
4311 data.cleanText = alarm->programFile();
4312 data.commandScript = data.cleanText.isEmpty(); // blank command indicates a script
4313 if (!alarm->programArguments().isEmpty())
4314 {
4315 if (!data.commandScript)
4316 data.cleanText += QLatin1Char(' ');
4317 data.cleanText += alarm->programArguments();
4318 }
4319 data.extraActionOptions = 0;
4320 if (flags.contains(KAEventPrivate::EXEC_ON_DEFERRAL_FLAG))
4321 data.extraActionOptions |= KAEvent::ExecPreActOnDeferral;
4322 if (flags.contains(KAEventPrivate::CANCEL_ON_ERROR_FLAG))
4323 data.extraActionOptions |= KAEvent::CancelOnPreActError;
4324 if (flags.contains(KAEventPrivate::DONT_SHOW_ERROR_FLAG))
4325 data.extraActionOptions |= KAEvent::DontShowPreActError;
4326 if (!cmdDisplay)
4327 break;
4328 // fall through to Display
4329 case Alarm::Display:
4330 {
4331 if (alarm->type() == Alarm::Display)
4332 {
4333 data.action = KAAlarm::MESSAGE;
4334 data.cleanText = AlarmText::fromCalendarText(alarm->text(), data.isEmailText);
4335 }
4336 const QString property = alarm->customProperty(KACalendar::APPNAME, KAEventPrivate::FONT_COLOUR_PROPERTY);
4337 const QStringList list = property.split(QLatin1Char(';'), QString::KeepEmptyParts);
4338 data.bgColour = QColor(255, 255, 255); // white
4339 data.fgColour = QColor(0, 0, 0); // black
4340 const int n = list.count();
4341 if (n > 0)
4342 {
4343 if (!list[0].isEmpty())
4344 {
4345 QColor c(list[0]);
4346 if (c.isValid())
4347 data.bgColour = c;
4348 }
4349 if (n > 1 && !list[1].isEmpty())
4350 {
4351 QColor c(list[1]);
4352 if (c.isValid())
4353 data.fgColour = c;
4354 }
4355 }
4356 data.defaultFont = (n <= 2 || list[2].isEmpty());
4357 if (!data.defaultFont)
4358 data.font.fromString(list[2]);
4359 break;
4360 }
4361 case Alarm::Email:
4362 {
4363 data.action = KAAlarm::EMAIL;
4364 data.cleanText = alarm->mailText();
4365 const int i = flags.indexOf(KAEventPrivate::EMAIL_ID_FLAG);
4366 data.emailFromId = (i >= 0 && i + 1 < flags.count()) ? flags[i + 1].toUInt() : 0;
4367 break;
4368 }
4369 case Alarm::Audio:
4370 {
4371 data.action = KAAlarm::AUDIO;
4372 data.cleanText = alarm->audioFile();
4373 data.repeatSoundPause = (alarm->repeatCount() == -2) ? alarm->snoozeTime().asSeconds()
4374 : (alarm->repeatCount() == -1) ? 0 : -1;
4375 data.soundVolume = -1;
4376 data.fadeVolume = -1;
4377 data.fadeSeconds = 0;
4378 QString property = alarm->customProperty(KACalendar::APPNAME, KAEventPrivate::VOLUME_PROPERTY);
4379 if (!property.isEmpty())
4380 {
4381 bool ok;
4382 float fadeVolume;
4383 int fadeSecs = 0;
4384 const QStringList list = property.split(QLatin1Char(';'), QString::KeepEmptyParts);
4385 data.soundVolume = list[0].toFloat(&ok);
4386 if (!ok || data.soundVolume > 1.0f)
4387 data.soundVolume = -1;
4388 if (data.soundVolume >= 0 && list.count() >= 3)
4389 {
4390 fadeVolume = list[1].toFloat(&ok);
4391 if (ok)
4392 fadeSecs = static_cast<int>(list[2].toUInt(&ok));
4393 if (ok && fadeVolume >= 0 && fadeVolume <= 1.0f && fadeSecs > 0)
4394 {
4395 data.fadeVolume = fadeVolume;
4396 data.fadeSeconds = fadeSecs;
4397 }
4398 }
4399 }
4400 if (!audioMain)
4401 {
4402 data.type = AUDIO_ALARM;
4403 data.speak = flags.contains(KAEventPrivate::SPEAK_FLAG);
4404 return;
4405 }
4406 break;
4407 }
4408 case Alarm::Invalid:
4409 data.type = INVALID_ALARM;
4410 return;
4411 }
4412
4413 bool atLogin = false;
4414 bool reminder = false;
4415 bool deferral = false;
4416 bool dateDeferral = false;
4417 bool repeatSound = false;
4418 data.type = MAIN_ALARM;
4419 property = alarm->customProperty(KACalendar::APPNAME, KAEventPrivate::TYPE_PROPERTY);
4420 const QStringList types = property.split(QLatin1Char(','), QString::SkipEmptyParts);
4421 for (int i = 0, end = types.count(); i < end; ++i)
4422 {
4423 const QString type = types[i];
4424 if (type == KAEventPrivate::AT_LOGIN_TYPE)
4425 atLogin = true;
4426 else if (type == KAEventPrivate::FILE_TYPE && data.action == KAAlarm::MESSAGE)
4427 data.action = KAAlarm::FILE;
4428 else if (type == KAEventPrivate::REMINDER_TYPE)
4429 reminder = true;
4430 else if (type == KAEventPrivate::TIME_DEFERRAL_TYPE)
4431 deferral = true;
4432 else if (type == KAEventPrivate::DATE_DEFERRAL_TYPE)
4433 dateDeferral = deferral = true;
4434 else if (type == KAEventPrivate::DISPLAYING_TYPE)
4435 data.type = DISPLAYING_ALARM;
4436 else if (type == KAEventPrivate::PRE_ACTION_TYPE && data.action == KAAlarm::COMMAND)
4437 data.type = PRE_ACTION_ALARM;
4438 else if (type == KAEventPrivate::POST_ACTION_TYPE && data.action == KAAlarm::COMMAND)
4439 data.type = POST_ACTION_ALARM;
4440 else if (type == KAEventPrivate::SOUND_REPEAT_TYPE && data.action == KAAlarm::AUDIO)
4441 {
4442 repeatSound = true;
4443 if (i + 1 < end)
4444 {
4445 bool ok;
4446 uint n = types[i + 1].toUInt(&ok);
4447 if (ok)
4448 {
4449 data.repeatSoundPause = n;
4450 ++i;
4451 }
4452 }
4453 }
4454 }
4455 if (repeatSound && data.repeatSoundPause < 0)
4456 data.repeatSoundPause = 0;
4457 else if (!repeatSound)
4458 data.repeatSoundPause = -1;
4459
4460 if (reminder)
4461 {
4462 if (data.type == MAIN_ALARM)
4463 {
4464 data.type = deferral ? DEFERRED_REMINDER_ALARM : REMINDER_ALARM;
4465 data.timedDeferral = (deferral && !dateDeferral);
4466 }
4467 else if (data.type == DISPLAYING_ALARM)
4468 data.displayingFlags = dateDeferral ? REMINDER | DATE_DEFERRAL
4469 : deferral ? REMINDER | TIME_DEFERRAL : REMINDER;
4470 else if (data.type == REMINDER_ALARM
4471 && flags.contains(KAEventPrivate::HIDDEN_REMINDER_FLAG))
4472 data.hiddenReminder = true;
4473 }
4474 else if (deferral)
4475 {
4476 if (data.type == MAIN_ALARM)
4477 {
4478 data.type = DEFERRED_ALARM;
4479 data.timedDeferral = !dateDeferral;
4480 }
4481 else if (data.type == DISPLAYING_ALARM)
4482 data.displayingFlags = dateDeferral ? DATE_DEFERRAL : TIME_DEFERRAL;
4483 }
4484 if (atLogin)
4485 {
4486 if (data.type == MAIN_ALARM)
4487 data.type = AT_LOGIN_ALARM;
4488 else if (data.type == DISPLAYING_ALARM)
4489 data.displayingFlags = KAEvent::REPEAT_AT_LOGIN;
4490 }
4491//kDebug()<<"text="<<alarm->text()<<", time="<<alarm->time().toString()<<", valid time="<<alarm->time().isValid();
4492}
4493
4494/******************************************************************************
4495* Calculate the next trigger times of the alarm.
4496* This should only be called when changes have actually occurred which might
4497* affect the event's trigger times.
4498* mMainTrigger is set to the next scheduled recurrence/sub-repetition, or the
4499* deferral time if a deferral is pending.
4500* mAllTrigger is the same as mMainTrigger, but takes account of reminders.
4501* mMainWorkTrigger is set to the next scheduled recurrence/sub-repetition
4502* which occurs in working hours, if working-time-only is set.
4503* mAllWorkTrigger is the same as mMainWorkTrigger, but takes account of reminders.
4504*/
4505void KAEventPrivate::calcTriggerTimes() const
4506{
4507 if (mChangeCount)
4508 return;
4509#ifdef __GNUC__
4510#warning May need to set date-only alarms to after start-of-day time in working-time checks
4511#endif
4512 bool recurs = (checkRecur() != KARecurrence::NO_RECUR);
4513 if ((recurs && mWorkTimeOnly && mWorkTimeOnly != mWorkTimeIndex)
4514 || (recurs && mExcludeHolidays && mExcludeHolidays != mHolidays))
4515 {
4516 // It's a work time alarm, and work days/times have changed, or
4517 // it excludes holidays, and the holidays definition has changed.
4518 mTriggerChanged = true;
4519 }
4520 else if (!mTriggerChanged)
4521 return;
4522 mTriggerChanged = false;
4523 if (recurs && mWorkTimeOnly)
4524 mWorkTimeOnly = mWorkTimeIndex; // note which work time definition was used in calculation
4525 if (recurs && mExcludeHolidays)
4526 mExcludeHolidays = mHolidays; // note which holiday definition was used in calculation
4527
4528 if (mCategory == CalEvent::ARCHIVED || mCategory == CalEvent::TEMPLATE)
4529 {
4530 // It's a template or archived
4531 mAllTrigger = mMainTrigger = mAllWorkTrigger = mMainWorkTrigger = KDateTime();
4532 }
4533 else if (mDeferral == NORMAL_DEFERRAL)
4534 {
4535 // For a deferred alarm, working time setting is ignored
4536 mAllTrigger = mMainTrigger = mAllWorkTrigger = mMainWorkTrigger = mDeferralTime;
4537 }
4538 else
4539 {
4540 mMainTrigger = mainDateTime(true); // next recurrence or sub-repetition
4541 mAllTrigger = (mDeferral == REMINDER_DEFERRAL) ? mDeferralTime
4542 : (mReminderActive != ACTIVE_REMINDER) ? mMainTrigger
4543 : (mReminderMinutes < 0) ? mReminderAfterTime
4544 : mMainTrigger.addMins(-mReminderMinutes);
4545 // It's not deferred.
4546 // If only-during-working-time is set and it recurs, it won't actually trigger
4547 // unless it falls during working hours.
4548 if ((!mWorkTimeOnly && !mExcludeHolidays)
4549 || !recurs
4550 || isWorkingTime(mMainTrigger.kDateTime()))
4551 {
4552 // It only occurs once, or it complies with any working hours/holiday
4553 // restrictions.
4554 mMainWorkTrigger = mMainTrigger;
4555 mAllWorkTrigger = mAllTrigger;
4556 }
4557 else if (mWorkTimeOnly)
4558 {
4559 // The alarm is restricted to working hours.
4560 // Finding the next occurrence during working hours can sometimes take a long time,
4561 // so mark the next actual trigger as invalid until the calculation completes.
4562 // Note that reminders are only triggered if the main alarm is during working time.
4563 if (!mExcludeHolidays)
4564 {
4565 // There are no holiday restrictions.
4566 calcNextWorkingTime(mMainTrigger);
4567 }
4568 else if (mHolidays)
4569 {
4570 // Holidays are excluded.
4571 DateTime nextTrigger = mMainTrigger;
4572 KDateTime kdt;
4573 for (int i = 0; i < 20; ++i)
4574 {
4575 calcNextWorkingTime(nextTrigger);
4576 if (!mHolidays->isHoliday(mMainWorkTrigger.date()))
4577 return; // found a non-holiday occurrence
4578 kdt = mMainWorkTrigger.effectiveKDateTime();
4579 kdt.setTime(QTime(23,59,59));
4580 const KAEvent::OccurType type = nextOccurrence(kdt, nextTrigger, KAEvent::RETURN_REPETITION);
4581 if (!nextTrigger.isValid())
4582 break;
4583 if (isWorkingTime(nextTrigger.kDateTime()))
4584 {
4585 const int reminder = (mReminderMinutes > 0) ? mReminderMinutes : 0; // only interested in reminders BEFORE the alarm
4586 mMainWorkTrigger = nextTrigger;
4587 mAllWorkTrigger = (type & KAEvent::OCCURRENCE_REPEAT) ? mMainWorkTrigger : mMainWorkTrigger.addMins(-reminder);
4588 return; // found a non-holiday occurrence
4589 }
4590 }
4591 mMainWorkTrigger = mAllWorkTrigger = DateTime();
4592 }
4593 }
4594 else if (mExcludeHolidays && mHolidays)
4595 {
4596 // Holidays are excluded.
4597 DateTime nextTrigger = mMainTrigger;
4598 KDateTime kdt;
4599 for (int i = 0; i < 20; ++i)
4600 {
4601 kdt = nextTrigger.effectiveKDateTime();
4602 kdt.setTime(QTime(23,59,59));
4603 const KAEvent::OccurType type = nextOccurrence(kdt, nextTrigger, KAEvent::RETURN_REPETITION);
4604 if (!nextTrigger.isValid())
4605 break;
4606 if (!mHolidays->isHoliday(nextTrigger.date()))
4607 {
4608 const int reminder = (mReminderMinutes > 0) ? mReminderMinutes : 0; // only interested in reminders BEFORE the alarm
4609 mMainWorkTrigger = nextTrigger;
4610 mAllWorkTrigger = (type & KAEvent::OCCURRENCE_REPEAT) ? mMainWorkTrigger : mMainWorkTrigger.addMins(-reminder);
4611 return; // found a non-holiday occurrence
4612 }
4613 }
4614 mMainWorkTrigger = mAllWorkTrigger = DateTime();
4615 }
4616 }
4617}
4618
4619/******************************************************************************
4620* Return the time of the next scheduled occurrence of the event during working
4621* hours, for an alarm which is restricted to working hours.
4622* On entry, 'nextTrigger' = the next recurrence or repetition (as returned by
4623* mainDateTime(true) ).
4624*/
4625void KAEventPrivate::calcNextWorkingTime(const DateTime& nextTrigger) const
4626{
4627 kDebug() << "next=" << nextTrigger.kDateTime().dateTime();
4628 mMainWorkTrigger = mAllWorkTrigger = DateTime();
4629
4630 for (int i = 0; ; ++i)
4631 {
4632 if (i >= 7)
4633 return; // no working days are defined
4634 if (mWorkDays.testBit(i))
4635 break;
4636 }
4637 const KARecurrence::Type recurType = checkRecur();
4638 KDateTime kdt = nextTrigger.effectiveKDateTime();
4639 const int reminder = (mReminderMinutes > 0) ? mReminderMinutes : 0; // only interested in reminders BEFORE the alarm
4640 // Check if it always falls on the same day(s) of the week.
4641 const RecurrenceRule* rrule = mRecurrence->defaultRRuleConst();
4642 if (!rrule)
4643 return; // no recurrence rule!
4644 unsigned allDaysMask = 0x7F; // mask bits for all days of week
4645 bool noWorkPos = false; // true if no recurrence day position is working day
4646 const QList<RecurrenceRule::WDayPos> pos = rrule->byDays();
4647 const int nDayPos = pos.count(); // number of day positions
4648 if (nDayPos)
4649 {
4650 noWorkPos = true;
4651 allDaysMask = 0;
4652 for (int i = 0; i < nDayPos; ++i)
4653 {
4654 const int day = pos[i].day() - 1; // Monday = 0
4655 if (mWorkDays.testBit(day))
4656 noWorkPos = false; // found a working day occurrence
4657 allDaysMask |= 1 << day;
4658 }
4659 if (noWorkPos && !mRepetition)
4660 return; // never occurs on a working day
4661 }
4662 DateTime newdt;
4663
4664 if (mStartDateTime.isDateOnly())
4665 {
4666 // It's a date-only alarm.
4667 // Sub-repetitions also have to be date-only.
4668 const int repeatFreq = mRepetition.intervalDays();
4669 const bool weeklyRepeat = mRepetition && !(repeatFreq % 7);
4670 const Duration interval = mRecurrence->regularInterval();
4671 if ((interval && !(interval.asDays() % 7))
4672 || nDayPos == 1)
4673 {
4674 // It recurs on the same day each week
4675 if (!mRepetition || weeklyRepeat)
4676 return; // any repetitions are also weekly
4677
4678 // It's a weekly recurrence with a non-weekly sub-repetition.
4679 // Check one cycle of repetitions for the next one that lands
4680 // on a working day.
4681 KDateTime dt(nextTrigger.kDateTime().addDays(1));
4682 dt.setTime(QTime(0,0,0));
4683 previousOccurrence(dt, newdt, false);
4684 if (!newdt.isValid())
4685 return; // this should never happen
4686 kdt = newdt.effectiveKDateTime();
4687 const int day = kdt.date().dayOfWeek() - 1; // Monday = 0
4688 for (int repeatNum = mNextRepeat + 1; ; ++repeatNum)
4689 {
4690 if (repeatNum > mRepetition.count())
4691 repeatNum = 0;
4692 if (repeatNum == mNextRepeat)
4693 break;
4694 if (!repeatNum)
4695 {
4696 nextOccurrence(newdt.kDateTime(), newdt, KAEvent::IGNORE_REPETITION);
4697 if (mWorkDays.testBit(day))
4698 {
4699 mMainWorkTrigger = newdt;
4700 mAllWorkTrigger = mMainWorkTrigger.addMins(-reminder);
4701 return;
4702 }
4703 kdt = newdt.effectiveKDateTime();
4704 }
4705 else
4706 {
4707 const int inc = repeatFreq * repeatNum;
4708 if (mWorkDays.testBit((day + inc) % 7))
4709 {
4710 kdt = kdt.addDays(inc);
4711 kdt.setDateOnly(true);
4712 mMainWorkTrigger = mAllWorkTrigger = kdt;
4713 return;
4714 }
4715 }
4716 }
4717 return;
4718 }
4719 if (!mRepetition || weeklyRepeat)
4720 {
4721 // It's a date-only alarm with either no sub-repetition or a
4722 // sub-repetition which always falls on the same day of the week
4723 // as the recurrence (if any).
4724 unsigned days = 0;
4725 for ( ; ; )
4726 {
4727 kdt.setTime(QTime(23,59,59));
4728 nextOccurrence(kdt, newdt, KAEvent::IGNORE_REPETITION);
4729 if (!newdt.isValid())
4730 return;
4731 kdt = newdt.effectiveKDateTime();
4732 const int day = kdt.date().dayOfWeek() - 1;
4733 if (mWorkDays.testBit(day))
4734 break; // found a working day occurrence
4735 // Prevent indefinite looping (which should never happen anyway)
4736 if ((days & allDaysMask) == allDaysMask)
4737 return; // found a recurrence on every possible day of the week!?!
4738 days |= 1 << day;
4739 }
4740 kdt.setDateOnly(true);
4741 mMainWorkTrigger = kdt;
4742 mAllWorkTrigger = kdt.addSecs(-60 * reminder);
4743 return;
4744 }
4745
4746 // It's a date-only alarm which recurs on different days of the week,
4747 // as does the sub-repetition.
4748 // Find the previous recurrence (as opposed to sub-repetition)
4749 unsigned days = 1 << (kdt.date().dayOfWeek() - 1);
4750 KDateTime dt(nextTrigger.kDateTime().addDays(1));
4751 dt.setTime(QTime(0,0,0));
4752 previousOccurrence(dt, newdt, false);
4753 if (!newdt.isValid())
4754 return; // this should never happen
4755 kdt = newdt.effectiveKDateTime();
4756 int day = kdt.date().dayOfWeek() - 1; // Monday = 0
4757 for (int repeatNum = mNextRepeat; ; repeatNum = 0)
4758 {
4759 while (++repeatNum <= mRepetition.count())
4760 {
4761 const int inc = repeatFreq * repeatNum;
4762 if (mWorkDays.testBit((day + inc) % 7))
4763 {
4764 kdt = kdt.addDays(inc);
4765 kdt.setDateOnly(true);
4766 mMainWorkTrigger = mAllWorkTrigger = kdt;
4767 return;
4768 }
4769 if ((days & allDaysMask) == allDaysMask)
4770 return; // found an occurrence on every possible day of the week!?!
4771 days |= 1 << day;
4772 }
4773 nextOccurrence(kdt, newdt, KAEvent::IGNORE_REPETITION);
4774 if (!newdt.isValid())
4775 return;
4776 kdt = newdt.effectiveKDateTime();
4777 day = kdt.date().dayOfWeek() - 1;
4778 if (mWorkDays.testBit(day))
4779 {
4780 kdt.setDateOnly(true);
4781 mMainWorkTrigger = kdt;
4782 mAllWorkTrigger = kdt.addSecs(-60 * reminder);
4783 return;
4784 }
4785 if ((days & allDaysMask) == allDaysMask)
4786 return; // found an occurrence on every possible day of the week!?!
4787 days |= 1 << day;
4788 }
4789 return;
4790 }
4791
4792 // It's a date-time alarm.
4793
4794 /* Check whether the recurrence or sub-repetition occurs at the same time
4795 * every day. Note that because of seasonal time changes, a recurrence
4796 * defined in terms of minutes will vary its time of day even if its value
4797 * is a multiple of a day (24*60 minutes). Sub-repetitions are considered
4798 * to repeat at the same time of day regardless of time changes if they
4799 * are multiples of a day, which doesn't strictly conform to the iCalendar
4800 * format because this only allows their interval to be recorded in seconds.
4801 */
4802 const bool recurTimeVaries = (recurType == KARecurrence::MINUTELY);
4803 const bool repeatTimeVaries = (mRepetition && !mRepetition.isDaily());
4804
4805 if (!recurTimeVaries && !repeatTimeVaries)
4806 {
4807 // The alarm always occurs at the same time of day.
4808 // Check whether it can ever occur during working hours.
4809 if (!mayOccurDailyDuringWork(kdt))
4810 return; // never occurs during working hours
4811
4812 // Find the next working day it occurs on
4813 bool repetition = false;
4814 unsigned days = 0;
4815 for ( ; ; )
4816 {
4817 KAEvent::OccurType type = nextOccurrence(kdt, newdt, KAEvent::RETURN_REPETITION);
4818 if (!newdt.isValid())
4819 return;
4820 repetition = (type & KAEvent::OCCURRENCE_REPEAT);
4821 kdt = newdt.effectiveKDateTime();
4822 const int day = kdt.date().dayOfWeek() - 1;
4823 if (mWorkDays.testBit(day))
4824 break; // found a working day occurrence
4825 // Prevent indefinite looping (which should never happen anyway)
4826 if (!repetition)
4827 {
4828 if ((days & allDaysMask) == allDaysMask)
4829 return; // found a recurrence on every possible day of the week!?!
4830 days |= 1 << day;
4831 }
4832 }
4833 mMainWorkTrigger = nextTrigger;
4834 mMainWorkTrigger.setDate(kdt.date());
4835 mAllWorkTrigger = repetition ? mMainWorkTrigger : mMainWorkTrigger.addMins(-reminder);
4836 return;
4837 }
4838
4839 // The alarm occurs at different times of day.
4840 // We may need to check for a full annual cycle of seasonal time changes, in
4841 // case it only occurs during working hours after a time change.
4842 KTimeZone tz = kdt.timeZone();
4843 if (tz.isValid() && tz.type() == "KSystemTimeZone")
4844 {
4845 // It's a system time zone, so fetch full transition information
4846 const KTimeZone ktz = KSystemTimeZones::readZone(tz.name());
4847 if (ktz.isValid())
4848 tz = ktz;
4849 }
4850 const QList<KTimeZone::Transition> tzTransitions = tz.transitions();
4851
4852 if (recurTimeVaries)
4853 {
4854 /* The alarm recurs at regular clock intervals, at different times of day.
4855 * Note that for this type of recurrence, it's necessary to avoid the
4856 * performance overhead of Recurrence class calls since these can in the
4857 * worst case cause the program to hang for a significant length of time.
4858 * In this case, we can calculate the next recurrence by simply adding the
4859 * recurrence interval, since KAlarm offers no facility to regularly miss
4860 * recurrences. (But exception dates/times need to be taken into account.)
4861 */
4862 KDateTime kdtRecur;
4863 int repeatFreq = 0;
4864 int repeatNum = 0;
4865 if (mRepetition)
4866 {
4867 // It's a repetition inside a recurrence, each of which occurs
4868 // at different times of day (bearing in mind that the repetition
4869 // may occur at daily intervals after each recurrence).
4870 // Find the previous recurrence (as opposed to sub-repetition)
4871 repeatFreq = mRepetition.intervalSeconds();
4872 previousOccurrence(kdt.addSecs(1), newdt, false);
4873 if (!newdt.isValid())
4874 return; // this should never happen
4875 kdtRecur = newdt.effectiveKDateTime();
4876 repeatNum = kdtRecur.secsTo(kdt) / repeatFreq;
4877 kdt = kdtRecur.addSecs(repeatNum * repeatFreq);
4878 }
4879 else
4880 {
4881 // There is no sub-repetition.
4882 // (N.B. Sub-repetitions can't exist without a recurrence.)
4883 // Check until the original time wraps round, but ensure that
4884 // if there are seasonal time changes, that all other subsequent
4885 // time offsets within the next year are checked.
4886 // This does not guarantee to find the next working time,
4887 // particularly if there are exceptions, but it's a
4888 // reasonable try.
4889 kdtRecur = kdt;
4890 }
4891 QTime firstTime = kdtRecur.time();
4892 int firstOffset = kdtRecur.utcOffset();
4893 int currentOffset = firstOffset;
4894 int dayRecur = kdtRecur.date().dayOfWeek() - 1; // Monday = 0
4895 int firstDay = dayRecur;
4896 QDate finalDate;
4897 const bool subdaily = (repeatFreq < 24*3600);
4898// int period = mRecurrence->frequency() % (24*60); // it is by definition a MINUTELY recurrence
4899// int limit = (24*60 + period - 1) / period; // number of times until recurrence wraps round
4900 int transitionIndex = -1;
4901 for (int n = 0; n < 7*24*60; ++n)
4902 {
4903 if (mRepetition)
4904 {
4905 // Check the sub-repetitions for this recurrence
4906 for ( ; ; )
4907 {
4908 // Find the repeat count to the next start of the working day
4909 const int inc = subdaily ? nextWorkRepetition(kdt) : 1;
4910 repeatNum += inc;
4911 if (repeatNum > mRepetition.count())
4912 break;
4913 kdt = kdt.addSecs(inc * repeatFreq);
4914 const QTime t = kdt.time();
4915 if (t >= mWorkDayStart && t < mWorkDayEnd)
4916 {
4917 if (mWorkDays.testBit(kdt.date().dayOfWeek() - 1))
4918 {
4919 mMainWorkTrigger = mAllWorkTrigger = kdt;
4920 return;
4921 }
4922 }
4923 }
4924 repeatNum = 0;
4925 }
4926 nextOccurrence(kdtRecur, newdt, KAEvent::IGNORE_REPETITION);
4927 if (!newdt.isValid())
4928 return;
4929 kdtRecur = newdt.effectiveKDateTime();
4930 dayRecur = kdtRecur.date().dayOfWeek() - 1; // Monday = 0
4931 const QTime t = kdtRecur.time();
4932 if (t >= mWorkDayStart && t < mWorkDayEnd)
4933 {
4934 if (mWorkDays.testBit(dayRecur))
4935 {
4936 mMainWorkTrigger = kdtRecur;
4937 mAllWorkTrigger = kdtRecur.addSecs(-60 * reminder);
4938 return;
4939 }
4940 }
4941 if (kdtRecur.utcOffset() != currentOffset)
4942 currentOffset = kdtRecur.utcOffset();
4943 if (t == firstTime && dayRecur == firstDay && currentOffset == firstOffset)
4944 {
4945 // We've wrapped round to the starting day and time.
4946 // If there are seasonal time changes, check for up
4947 // to the next year in other time offsets in case the
4948 // alarm occurs inside working hours then.
4949 if (!finalDate.isValid())
4950 finalDate = kdtRecur.date();
4951 const int i = tz.transitionIndex(kdtRecur.toUtc().dateTime());
4952 if (i < 0)
4953 return;
4954 if (i > transitionIndex)
4955 transitionIndex = i;
4956 if (++transitionIndex >= static_cast<int>(tzTransitions.count()))
4957 return;
4958 previousOccurrence(KDateTime(tzTransitions[transitionIndex].time(), KDateTime::UTC), newdt, KAEvent::IGNORE_REPETITION);
4959 kdtRecur = newdt.effectiveKDateTime();
4960 if (finalDate.daysTo(kdtRecur.date()) > 365)
4961 return;
4962 firstTime = kdtRecur.time();
4963 firstOffset = kdtRecur.utcOffset();
4964 currentOffset = firstOffset;
4965 firstDay = kdtRecur.date().dayOfWeek() - 1;
4966 }
4967 kdt = kdtRecur;
4968 }
4969//kDebug()<<"-----exit loop: count="<<limit<<endl;
4970 return; // too many iterations
4971 }
4972
4973 if (repeatTimeVaries)
4974 {
4975 /* There's a sub-repetition which occurs at different times of
4976 * day, inside a recurrence which occurs at the same time of day.
4977 * We potentially need to check recurrences starting on each day.
4978 * Then, it is still possible that a working time sub-repetition
4979 * could occur immediately after a seasonal time change.
4980 */
4981 // Find the previous recurrence (as opposed to sub-repetition)
4982 const int repeatFreq = mRepetition.intervalSeconds();
4983 previousOccurrence(kdt.addSecs(1), newdt, false);
4984 if (!newdt.isValid())
4985 return; // this should never happen
4986 KDateTime kdtRecur = newdt.effectiveKDateTime();
4987 const bool recurDuringWork = (kdtRecur.time() >= mWorkDayStart && kdtRecur.time() < mWorkDayEnd);
4988
4989 // Use the previous recurrence as a base for checking whether
4990 // our tests have wrapped round to the same time/day of week.
4991 const bool subdaily = (repeatFreq < 24*3600);
4992 unsigned days = 0;
4993 bool checkTimeChangeOnly = false;
4994 int transitionIndex = -1;
4995 for (int limit = 10; --limit >= 0; )
4996 {
4997 // Check the next seasonal time change (for an arbitrary 10 times,
4998 // even though that might not guarantee the correct result)
4999 QDate dateRecur = kdtRecur.date();
5000 int dayRecur = dateRecur.dayOfWeek() - 1; // Monday = 0
5001 int repeatNum = kdtRecur.secsTo(kdt) / repeatFreq;
5002 kdt = kdtRecur.addSecs(repeatNum * repeatFreq);
5003
5004 // Find the next recurrence, which sets the limit on possible sub-repetitions.
5005 // Note that for a monthly recurrence, for example, a sub-repetition could
5006 // be defined which is longer than the recurrence interval in short months.
5007 // In these cases, the sub-repetition is truncated by the following
5008 // recurrence.
5009 nextOccurrence(kdtRecur, newdt, KAEvent::IGNORE_REPETITION);
5010 KDateTime kdtNextRecur = newdt.effectiveKDateTime();
5011
5012 int repeatsToCheck = mRepetition.count();
5013 int repeatsDuringWork = 0; // 0=unknown, 1=does, -1=never
5014 for ( ; ; )
5015 {
5016 // Check the sub-repetitions for this recurrence
5017 if (repeatsDuringWork >= 0)
5018 {
5019 for ( ; ; )
5020 {
5021 // Find the repeat count to the next start of the working day
5022 int inc = subdaily ? nextWorkRepetition(kdt) : 1;
5023 repeatNum += inc;
5024 const bool pastEnd = (repeatNum > mRepetition.count());
5025 if (pastEnd)
5026 inc -= repeatNum - mRepetition.count();
5027 repeatsToCheck -= inc;
5028 kdt = kdt.addSecs(inc * repeatFreq);
5029 if (kdtNextRecur.isValid() && kdt >= kdtNextRecur)
5030 {
5031 // This sub-repetition is past the next recurrence,
5032 // so start the check again from the next recurrence.
5033 repeatsToCheck = mRepetition.count();
5034 break;
5035 }
5036 if (pastEnd)
5037 break;
5038 const QTime t = kdt.time();
5039 if (t >= mWorkDayStart && t < mWorkDayEnd)
5040 {
5041 if (mWorkDays.testBit(kdt.date().dayOfWeek() - 1))
5042 {
5043 mMainWorkTrigger = mAllWorkTrigger = kdt;
5044 return;
5045 }
5046 repeatsDuringWork = 1;
5047 }
5048 else if (!repeatsDuringWork && repeatsToCheck <= 0)
5049 {
5050 // Sub-repetitions never occur during working hours
5051 repeatsDuringWork = -1;
5052 break;
5053 }
5054 }
5055 }
5056 repeatNum = 0;
5057 if (repeatsDuringWork < 0 && !recurDuringWork)
5058 break; // it never occurs during working hours
5059
5060 // Check the next recurrence
5061 if (!kdtNextRecur.isValid())
5062 return;
5063 if (checkTimeChangeOnly || (days & allDaysMask) == allDaysMask)
5064 break; // found a recurrence on every possible day of the week!?!
5065 kdtRecur = kdtNextRecur;
5066 nextOccurrence(kdtRecur, newdt, KAEvent::IGNORE_REPETITION);
5067 kdtNextRecur = newdt.effectiveKDateTime();
5068 dateRecur = kdtRecur.date();
5069 dayRecur = dateRecur.dayOfWeek() - 1;
5070 if (recurDuringWork && mWorkDays.testBit(dayRecur))
5071 {
5072 mMainWorkTrigger = kdtRecur;
5073 mAllWorkTrigger = kdtRecur.addSecs(-60 * reminder);
5074 return;
5075 }
5076 days |= 1 << dayRecur;
5077 kdt = kdtRecur;
5078 }
5079
5080 // Find the next recurrence before a seasonal time change,
5081 // and ensure the time change is after the last one processed.
5082 checkTimeChangeOnly = true;
5083 const int i = tz.transitionIndex(kdtRecur.toUtc().dateTime());
5084 if (i < 0)
5085 return;
5086 if (i > transitionIndex)
5087 transitionIndex = i;
5088 if (++transitionIndex >= static_cast<int>(tzTransitions.count()))
5089 return;
5090 kdt = KDateTime(tzTransitions[transitionIndex].time(), KDateTime::UTC);
5091 previousOccurrence(kdt, newdt, KAEvent::IGNORE_REPETITION);
5092 kdtRecur = newdt.effectiveKDateTime();
5093 }
5094 return; // not found - give up
5095 }
5096}
5097
5098/******************************************************************************
5099* Find the repeat count to the next start of a working day.
5100* This allows for possible daylight saving time changes during the repetition.
5101* Use for repetitions which occur at different times of day.
5102*/
5103int KAEventPrivate::nextWorkRepetition(const KDateTime& pre) const
5104{
5105 KDateTime nextWork(pre);
5106 if (pre.time() < mWorkDayStart)
5107 nextWork.setTime(mWorkDayStart);
5108 else
5109 {
5110 const int preDay = pre.date().dayOfWeek() - 1; // Monday = 0
5111 for (int n = 1; ; ++n)
5112 {
5113 if (n >= 7)
5114 return mRepetition.count() + 1; // should never happen
5115 if (mWorkDays.testBit((preDay + n) % 7))
5116 {
5117 nextWork = nextWork.addDays(n);
5118 nextWork.setTime(mWorkDayStart);
5119 break;
5120 }
5121 }
5122 }
5123 return (pre.secsTo(nextWork) - 1) / mRepetition.intervalSeconds() + 1;
5124}
5125
5126/******************************************************************************
5127* Check whether an alarm which recurs at the same time of day can possibly
5128* occur during working hours.
5129* This does not determine whether it actually does, but rather whether it could
5130* potentially given enough repetitions.
5131* Reply = false if it can never occur during working hours, true if it might.
5132*/
5133bool KAEventPrivate::mayOccurDailyDuringWork(const KDateTime& kdt) const
5134{
5135 if (!kdt.isDateOnly()
5136 && (kdt.time() < mWorkDayStart || kdt.time() >= mWorkDayEnd))
5137 return false; // its time is outside working hours
5138 // Check if it always occurs on the same day of the week
5139 const Duration interval = mRecurrence->regularInterval();
5140 if (interval && interval.isDaily() && !(interval.asDays() % 7))
5141 {
5142 // It recurs weekly
5143 if (!mRepetition || (mRepetition.isDaily() && !(mRepetition.intervalDays() % 7)))
5144 return false; // any repetitions are also weekly
5145 // Repetitions are daily. Check if any occur on working days
5146 // by checking the first recurrence and up to 6 repetitions.
5147 int day = mRecurrence->startDateTime().date().dayOfWeek() - 1; // Monday = 0
5148 const int repeatDays = mRepetition.intervalDays();
5149 const int maxRepeat = (mRepetition.count() < 6) ? mRepetition.count() : 6;
5150 for (int i = 0; !mWorkDays.testBit(day); ++i, day = (day + repeatDays) % 7)
5151 {
5152 if (i >= maxRepeat)
5153 return false; // no working day occurrences
5154 }
5155 }
5156 return true;
5157}
5158
5159/******************************************************************************
5160* Set the specified alarm to be an audio alarm with the given file name.
5161*/
5162#ifndef KALARMCAL_USE_KRESOURCES
5163void KAEventPrivate::setAudioAlarm(const Alarm::Ptr& alarm) const
5164#else
5165void KAEventPrivate::setAudioAlarm(Alarm* alarm) const
5166#endif
5167{
5168 alarm->setAudioAlarm(mAudioFile); // empty for a beep or for speaking
5169 if (mSoundVolume >= 0)
5170 alarm->setCustomProperty(KACalendar::APPNAME, VOLUME_PROPERTY,
5171 QString::fromLatin1("%1;%2;%3;%4").arg(QString::number(mSoundVolume, 'f', 2))
5172 .arg(QString::number(mFadeVolume, 'f', 2))
5173 .arg(mFadeSeconds));
5174}
5175
5176/******************************************************************************
5177* Get the date/time of the next recurrence of the event, after the specified
5178* date/time.
5179* 'result' = date/time of next occurrence, or invalid date/time if none.
5180*/
5181KAEvent::OccurType KAEventPrivate::nextRecurrence(const KDateTime& preDateTime, DateTime& result) const
5182{
5183 const KDateTime recurStart = mRecurrence->startDateTime();
5184 KDateTime pre = preDateTime.toTimeSpec(mStartDateTime.timeSpec());
5185 if (mStartDateTime.isDateOnly() && !pre.isDateOnly() && pre.time() < DateTime::startOfDay())
5186 {
5187 pre = pre.addDays(-1); // today's recurrence (if today recurs) is still to come
5188 pre.setTime(DateTime::startOfDay());
5189 }
5190 const KDateTime dt = mRecurrence->getNextDateTime(pre);
5191 result = dt;
5192 result.setDateOnly(mStartDateTime.isDateOnly());
5193 if (!dt.isValid())
5194 return KAEvent::NO_OCCURRENCE;
5195 if (dt == recurStart)
5196 return KAEvent::FIRST_OR_ONLY_OCCURRENCE;
5197 if (mRecurrence->duration() >= 0 && dt == mRecurrence->endDateTime())
5198 return KAEvent::LAST_RECURRENCE;
5199 return result.isDateOnly() ? KAEvent::RECURRENCE_DATE : KAEvent::RECURRENCE_DATE_TIME;
5200}
5201
5202/******************************************************************************
5203* Validate the event's recurrence data, correcting any inconsistencies (which
5204* should never occur!).
5205* Reply = recurrence period type.
5206*/
5207KARecurrence::Type KAEventPrivate::checkRecur() const
5208{
5209 if (mRecurrence)
5210 {
5211 KARecurrence::Type type = mRecurrence->type();
5212 switch (type)
5213 {
5214 case KARecurrence::MINUTELY: // hourly
5215 case KARecurrence::DAILY: // daily
5216 case KARecurrence::WEEKLY: // weekly on multiple days of week
5217 case KARecurrence::MONTHLY_DAY: // monthly on multiple dates in month
5218 case KARecurrence::MONTHLY_POS: // monthly on multiple nth day of week
5219 case KARecurrence::ANNUAL_DATE: // annually on multiple months (day of month = start date)
5220 case KARecurrence::ANNUAL_POS: // annually on multiple nth day of week in multiple months
5221 return type;
5222 default:
5223 if (mRecurrence)
5224 const_cast<KAEventPrivate*>(this)->clearRecur(); // this shouldn't ever be necessary!!
5225 break;
5226 }
5227 }
5228 if (mRepetition) // can't have a repetition without a recurrence
5229 const_cast<KAEventPrivate*>(this)->clearRecur(); // this shouldn't ever be necessary!!
5230 return KARecurrence::NO_RECUR;
5231}
5232
5233/******************************************************************************
5234* If the calendar was written by a previous version of KAlarm, do any
5235* necessary format conversions on the events to ensure that when the calendar
5236* is saved, no information is lost or corrupted.
5237* Reply = true if any conversions were done.
5238*/
5239#ifndef KALARMCAL_USE_KRESOURCES
5240bool KAEvent::convertKCalEvents(const Calendar::Ptr& calendar, int calendarVersion)
5241#else
5242bool KAEvent::convertKCalEvents(CalendarLocal& calendar, int calendarVersion)
5243#endif
5244{
5245 // KAlarm pre-0.9 codes held in the alarm's DESCRIPTION property
5246 static const QChar SEPARATOR = QLatin1Char(';');
5247 static const QChar LATE_CANCEL_CODE = QLatin1Char('C');
5248 static const QChar AT_LOGIN_CODE = QLatin1Char('L'); // subsidiary alarm at every login
5249 static const QChar DEFERRAL_CODE = QLatin1Char('D'); // extra deferred alarm
5250 static const QString TEXT_PREFIX = QLatin1String("TEXT:");
5251 static const QString FILE_PREFIX = QLatin1String("FILE:");
5252 static const QString COMMAND_PREFIX = QLatin1String("CMD:");
5253
5254 // KAlarm pre-0.9.2 codes held in the event's CATEGORY property
5255 static const QString BEEP_CATEGORY = QLatin1String("BEEP");
5256
5257 // KAlarm pre-1.1.1 LATECANCEL category with no parameter
5258 static const QString LATE_CANCEL_CAT = QLatin1String("LATECANCEL");
5259
5260 // KAlarm pre-1.3.0 TMPLDEFTIME category with no parameter
5261 static const QString TEMPL_DEF_TIME_CAT = QLatin1String("TMPLDEFTIME");
5262
5263 // KAlarm pre-1.3.1 XTERM category
5264 static const QString EXEC_IN_XTERM_CAT = QLatin1String("XTERM");
5265
5266 // KAlarm pre-1.9.0 categories
5267 static const QString DATE_ONLY_CATEGORY = QLatin1String("DATE");
5268 static const QString EMAIL_BCC_CATEGORY = QLatin1String("BCC");
5269 static const QString CONFIRM_ACK_CATEGORY = QLatin1String("ACKCONF");
5270 static const QString KORGANIZER_CATEGORY = QLatin1String("KORG");
5271 static const QString DEFER_CATEGORY = QLatin1String("DEFER;");
5272 static const QString ARCHIVE_CATEGORY = QLatin1String("SAVE");
5273 static const QString ARCHIVE_CATEGORIES = QLatin1String("SAVE:");
5274 static const QString LATE_CANCEL_CATEGORY = QLatin1String("LATECANCEL;");
5275 static const QString AUTO_CLOSE_CATEGORY = QLatin1String("LATECLOSE;");
5276 static const QString TEMPL_AFTER_TIME_CATEGORY = QLatin1String("TMPLAFTTIME;");
5277 static const QString KMAIL_SERNUM_CATEGORY = QLatin1String("KMAIL:");
5278 static const QString LOG_CATEGORY = QLatin1String("LOG:");
5279
5280 // KAlarm pre-1.5.0/1.9.9 properties
5281 static const QByteArray KMAIL_ID_PROPERTY("KMAILID"); // X-KDE-KALARM-KMAILID property
5282
5283 // KAlarm pre-2.6.0 properties
5284 static const QByteArray ARCHIVE_PROPERTY("ARCHIVE"); // X-KDE-KALARM-ARCHIVE property
5285 static const QString ARCHIVE_REMINDER_ONCE_TYPE = QLatin1String("ONCE");
5286 static const QString REMINDER_ONCE_TYPE = QLatin1String("REMINDER_ONCE");
5287 static const QByteArray EMAIL_ID_PROPERTY("EMAILID"); // X-KDE-KALARM-EMAILID property
5288 static const QByteArray SPEAK_PROPERTY("SPEAK"); // X-KDE-KALARM-SPEAK property
5289 static const QByteArray CANCEL_ON_ERROR_PROPERTY("ERRCANCEL");// X-KDE-KALARM-ERRCANCEL property
5290 static const QByteArray DONT_SHOW_ERROR_PROPERTY("ERRNOSHOW");// X-KDE-KALARM-ERRNOSHOW property
5291
5292 bool adjustSummerTime = false;
5293 if (calendarVersion == -Version(0,5,7))
5294 {
5295 // The calendar file was written by the KDE 3.0.0 version of KAlarm 0.5.7.
5296 // Summer time was ignored when converting to UTC.
5297 calendarVersion = -calendarVersion;
5298 adjustSummerTime = true;
5299 }
5300
5301 if (calendarVersion >= currentCalendarVersion())
5302 return false;
5303
5304 kDebug() << "Adjusting version" << calendarVersion;
5305 const bool pre_0_7 = (calendarVersion < Version(0,7,0));
5306 const bool pre_0_9 = (calendarVersion < Version(0,9,0));
5307 const bool pre_0_9_2 = (calendarVersion < Version(0,9,2));
5308 const bool pre_1_1_1 = (calendarVersion < Version(1,1,1));
5309 const bool pre_1_2_1 = (calendarVersion < Version(1,2,1));
5310 const bool pre_1_3_0 = (calendarVersion < Version(1,3,0));
5311 const bool pre_1_3_1 = (calendarVersion < Version(1,3,1));
5312 const bool pre_1_4_14 = (calendarVersion < Version(1,4,14));
5313 const bool pre_1_5_0 = (calendarVersion < Version(1,5,0));
5314 const bool pre_1_9_0 = (calendarVersion < Version(1,9,0));
5315 const bool pre_1_9_2 = (calendarVersion < Version(1,9,2));
5316 const bool pre_1_9_7 = (calendarVersion < Version(1,9,7));
5317 const bool pre_1_9_9 = (calendarVersion < Version(1,9,9));
5318 const bool pre_1_9_10 = (calendarVersion < Version(1,9,10));
5319 const bool pre_2_2_9 = (calendarVersion < Version(2,2,9));
5320 const bool pre_2_3_0 = (calendarVersion < Version(2,3,0));
5321 const bool pre_2_3_2 = (calendarVersion < Version(2,3,2));
5322 const bool pre_2_7_0 = (calendarVersion < Version(2,7,0));
5323 Q_ASSERT(currentCalendarVersion() == Version(2,7,0));
5324
5325 KTimeZone localZone;
5326 if (pre_1_9_2)
5327 localZone = KSystemTimeZones::local();
5328
5329 bool converted = false;
5330#ifndef KALARMCAL_USE_KRESOURCES
5331 const Event::List events = calendar->rawEvents();
5332#else
5333 const Event::List events = calendar.rawEvents();
5334#endif
5335 for (int ei = 0, eend = events.count(); ei < eend; ++ei)
5336 {
5337#ifndef KALARMCAL_USE_KRESOURCES
5338 Event::Ptr event = events[ei];
5339#else
5340 Event* event = events[ei];
5341#endif
5342 const Alarm::List alarms = event->alarms();
5343 if (alarms.isEmpty())
5344 continue; // KAlarm isn't interested in events without alarms
5345 event->startUpdates(); // prevent multiple update notifications
5346 const bool readOnly = event->isReadOnly();
5347 if (readOnly)
5348 event->setReadOnly(false);
5349 QStringList cats = event->categories();
5350 bool addLateCancel = false;
5351 QStringList flags;
5352
5353 if (pre_0_7 && event->allDay())
5354 {
5355 // It's a KAlarm pre-0.7 calendar file.
5356 // Ensure that when the calendar is saved, the alarm time isn't lost.
5357 event->setAllDay(false);
5358 }
5359
5360 if (pre_0_9)
5361 {
5362 /*
5363 * It's a KAlarm pre-0.9 calendar file.
5364 * All alarms were of type DISPLAY. Instead of the X-KDE-KALARM-TYPE
5365 * alarm property, characteristics were stored as a prefix to the
5366 * alarm DESCRIPTION property, as follows:
5367 * SEQNO;[FLAGS];TYPE:TEXT
5368 * where
5369 * SEQNO = sequence number of alarm within the event
5370 * FLAGS = C for late-cancel, L for repeat-at-login, D for deferral
5371 * TYPE = TEXT or FILE or CMD
5372 * TEXT = message text, file name/URL or command
5373 */
5374 for (int ai = 0, aend = alarms.count(); ai < aend; ++ai)
5375 {
5376#ifndef KALARMCAL_USE_KRESOURCES
5377 Alarm::Ptr alarm = alarms[ai];
5378#else
5379 Alarm* alarm = alarms[ai];
5380#endif
5381 bool atLogin = false;
5382 bool deferral = false;
5383 bool lateCancel = false;
5384 KAAlarm::Action action = KAAlarm::MESSAGE;
5385 const QString txt = alarm->text();
5386 const int length = txt.length();
5387 int i = 0;
5388 if (txt[0].isDigit())
5389 {
5390 while (++i < length && txt[i].isDigit()) ;
5391 if (i < length && txt[i++] == SEPARATOR)
5392 {
5393 while (i < length)
5394 {
5395 const QChar ch = txt[i++];
5396 if (ch == SEPARATOR)
5397 break;
5398 if (ch == LATE_CANCEL_CODE)
5399 lateCancel = true;
5400 else if (ch == AT_LOGIN_CODE)
5401 atLogin = true;
5402 else if (ch == DEFERRAL_CODE)
5403 deferral = true;
5404 }
5405 }
5406 else
5407 i = 0; // invalid prefix
5408 }
5409 if (txt.indexOf(TEXT_PREFIX, i) == i)
5410 i += TEXT_PREFIX.length();
5411 else if (txt.indexOf(FILE_PREFIX, i) == i)
5412 {
5413 action = KAAlarm::FILE;
5414 i += FILE_PREFIX.length();
5415 }
5416 else if (txt.indexOf(COMMAND_PREFIX, i) == i)
5417 {
5418 action = KAAlarm::COMMAND;
5419 i += COMMAND_PREFIX.length();
5420 }
5421 else
5422 i = 0;
5423 const QString altxt = txt.mid(i);
5424
5425 QStringList types;
5426 switch (action)
5427 {
5428 case KAAlarm::FILE:
5429 types += KAEventPrivate::FILE_TYPE;
5430 // fall through to MESSAGE
5431 case KAAlarm::MESSAGE:
5432 alarm->setDisplayAlarm(altxt);
5433 break;
5434 case KAAlarm::COMMAND:
5435 setProcedureAlarm(alarm, altxt);
5436 break;
5437 case KAAlarm::EMAIL: // email alarms were introduced in KAlarm 0.9
5438 case KAAlarm::AUDIO: // audio alarms (with no display) were introduced in KAlarm 2.3.2
5439 break;
5440 }
5441 if (atLogin)
5442 {
5443 types += KAEventPrivate::AT_LOGIN_TYPE;
5444 lateCancel = false;
5445 }
5446 else if (deferral)
5447 types += KAEventPrivate::TIME_DEFERRAL_TYPE;
5448 if (lateCancel)
5449 addLateCancel = true;
5450 if (types.count() > 0)
5451 alarm->setCustomProperty(KACalendar::APPNAME, KAEventPrivate::TYPE_PROPERTY, types.join(QLatin1String(",")));
5452
5453 if (pre_0_7 && alarm->repeatCount() > 0 && alarm->snoozeTime().value() > 0)
5454 {
5455 // It's a KAlarm pre-0.7 calendar file.
5456 // Minutely recurrences were stored differently.
5457 Recurrence* recur = event->recurrence();
5458 if (recur && recur->recurs())
5459 {
5460 recur->setMinutely(alarm->snoozeTime().asSeconds() / 60);
5461 recur->setDuration(alarm->repeatCount() + 1);
5462 alarm->setRepeatCount(0);
5463 alarm->setSnoozeTime(0);
5464 }
5465 }
5466
5467 if (adjustSummerTime)
5468 {
5469 // The calendar file was written by the KDE 3.0.0 version of KAlarm 0.5.7.
5470 // Summer time was ignored when converting to UTC.
5471 KDateTime dt = alarm->time();
5472 const time_t t = dt.toTime_t();
5473 const struct tm* dtm = localtime(&t);
5474 if (dtm->tm_isdst)
5475 {
5476 dt = dt.addSecs(-3600);
5477 alarm->setTime(dt);
5478 }
5479 }
5480 }
5481 }
5482
5483 if (pre_0_9_2)
5484 {
5485 /*
5486 * It's a KAlarm pre-0.9.2 calendar file.
5487 * For the archive calendar, set the CREATED time to the DTEND value.
5488 * Convert date-only DTSTART to date/time, and add category "DATE".
5489 * Set the DTEND time to the DTSTART time.
5490 * Convert all alarm times to DTSTART offsets.
5491 * For display alarms, convert the first unlabelled category to an
5492 * X-KDE-KALARM-FONTCOLOUR property.
5493 * Convert BEEP category into an audio alarm with no audio file.
5494 */
5495 if (CalEvent::status(event) == CalEvent::ARCHIVED)
5496 event->setCreated(event->dtEnd());
5497 KDateTime start = event->dtStart();
5498 if (event->allDay())
5499 {
5500 event->setAllDay(false);
5501 start.setTime(QTime(0, 0));
5502 flags += KAEventPrivate::DATE_ONLY_FLAG;
5503 }
5504 event->setDtEnd(KDateTime());
5505
5506 for (int ai = 0, aend = alarms.count(); ai < aend; ++ai)
5507 {
5508#ifndef KALARMCAL_USE_KRESOURCES
5509 Alarm::Ptr alarm = alarms[ai];
5510#else
5511 Alarm* alarm = alarms[ai];
5512#endif
5513 alarm->setStartOffset(start.secsTo(alarm->time()));
5514 }
5515
5516 if (!cats.isEmpty())
5517 {
5518 for (int ai = 0, aend = alarms.count(); ai < aend; ++ai)
5519 {
5520#ifndef KALARMCAL_USE_KRESOURCES
5521 Alarm::Ptr alarm = alarms[ai];
5522#else
5523 Alarm* alarm = alarms[ai];
5524#endif
5525 if (alarm->type() == Alarm::Display)
5526 alarm->setCustomProperty(KACalendar::APPNAME, KAEventPrivate::FONT_COLOUR_PROPERTY,
5527 QString::fromLatin1("%1;;").arg(cats.at(0)));
5528 }
5529 cats.removeAt(0);
5530 }
5531
5532 for (int i = 0, end = cats.count(); i < end; ++i)
5533 {
5534 if (cats.at(i) == BEEP_CATEGORY)
5535 {
5536 cats.removeAt(i);
5537
5538#ifndef KALARMCAL_USE_KRESOURCES
5539 Alarm::Ptr alarm = event->newAlarm();
5540#else
5541 Alarm* alarm = event->newAlarm();
5542#endif
5543 alarm->setEnabled(true);
5544 alarm->setAudioAlarm();
5545 KDateTime dt = event->dtStart(); // default
5546
5547 // Parse and order the alarms to know which one's date/time to use
5548 KAEventPrivate::AlarmMap alarmMap;
5549 KAEventPrivate::readAlarms(event, &alarmMap);
5550 KAEventPrivate::AlarmMap::ConstIterator it = alarmMap.constBegin();
5551 if (it != alarmMap.constEnd())
5552 {
5553 dt = it.value().alarm->time();
5554 break;
5555 }
5556 alarm->setStartOffset(start.secsTo(dt));
5557 break;
5558 }
5559 }
5560 }
5561
5562 if (pre_1_1_1)
5563 {
5564 /*
5565 * It's a KAlarm pre-1.1.1 calendar file.
5566 * Convert simple LATECANCEL category to LATECANCEL:n where n = minutes late.
5567 */
5568 int i;
5569 while ((i = cats.indexOf(LATE_CANCEL_CAT)) >= 0)
5570 {
5571 cats.removeAt(i);
5572 addLateCancel = true;
5573 }
5574 }
5575
5576 if (pre_1_2_1)
5577 {
5578 /*
5579 * It's a KAlarm pre-1.2.1 calendar file.
5580 * Convert email display alarms from translated to untranslated header prefixes.
5581 */
5582 for (int ai = 0, aend = alarms.count(); ai < aend; ++ai)
5583 {
5584#ifndef KALARMCAL_USE_KRESOURCES
5585 Alarm::Ptr alarm = alarms[ai];
5586#else
5587 Alarm* alarm = alarms[ai];
5588#endif
5589 if (alarm->type() == Alarm::Display)
5590 {
5591 const QString oldtext = alarm->text();
5592 const QString newtext = AlarmText::toCalendarText(oldtext);
5593 if (oldtext != newtext)
5594 alarm->setDisplayAlarm(newtext);
5595 }
5596 }
5597 }
5598
5599 if (pre_1_3_0)
5600 {
5601 /*
5602 * It's a KAlarm pre-1.3.0 calendar file.
5603 * Convert simple TMPLDEFTIME category to TMPLAFTTIME:n where n = minutes after.
5604 */
5605 int i;
5606 while ((i = cats.indexOf(TEMPL_DEF_TIME_CAT)) >= 0)
5607 {
5608 cats.removeAt(i);
5609 (flags += KAEventPrivate::TEMPL_AFTER_TIME_FLAG) += QLatin1String("0");
5610 }
5611 }
5612
5613 if (pre_1_3_1)
5614 {
5615 /*
5616 * It's a KAlarm pre-1.3.1 calendar file.
5617 * Convert simple XTERM category to LOG:xterm:
5618 */
5619 int i;
5620 while ((i = cats.indexOf(EXEC_IN_XTERM_CAT)) >= 0)
5621 {
5622 cats.removeAt(i);
5623 event->setCustomProperty(KACalendar::APPNAME, KAEventPrivate::LOG_PROPERTY, KAEventPrivate::xtermURL);
5624 }
5625 }
5626
5627 if (pre_1_9_0)
5628 {
5629 /*
5630 * It's a KAlarm pre-1.9 calendar file.
5631 * Add the X-KDE-KALARM-STATUS custom property.
5632 * Convert KAlarm categories to custom fields.
5633 */
5634 CalEvent::setStatus(event, CalEvent::status(event));
5635 for (int i = 0; i < cats.count(); )
5636 {
5637 const QString cat = cats.at(i);
5638 if (cat == DATE_ONLY_CATEGORY)
5639 flags += KAEventPrivate::DATE_ONLY_FLAG;
5640 else if (cat == CONFIRM_ACK_CATEGORY)
5641 flags += KAEventPrivate::CONFIRM_ACK_FLAG;
5642 else if (cat == EMAIL_BCC_CATEGORY)
5643 flags += KAEventPrivate::EMAIL_BCC_FLAG;
5644 else if (cat == KORGANIZER_CATEGORY)
5645 flags += KAEventPrivate::KORGANIZER_FLAG;
5646 else if (cat.startsWith(DEFER_CATEGORY))
5647 (flags += KAEventPrivate::DEFER_FLAG) += cat.mid(DEFER_CATEGORY.length());
5648 else if (cat.startsWith(TEMPL_AFTER_TIME_CATEGORY))
5649 (flags += KAEventPrivate::TEMPL_AFTER_TIME_FLAG) += cat.mid(TEMPL_AFTER_TIME_CATEGORY.length());
5650 else if (cat.startsWith(LATE_CANCEL_CATEGORY))
5651 (flags += KAEventPrivate::LATE_CANCEL_FLAG) += cat.mid(LATE_CANCEL_CATEGORY.length());
5652 else if (cat.startsWith(AUTO_CLOSE_CATEGORY))
5653 (flags += KAEventPrivate::AUTO_CLOSE_FLAG) += cat.mid(AUTO_CLOSE_CATEGORY.length());
5654 else if (cat.startsWith(KMAIL_SERNUM_CATEGORY))
5655 (flags += KAEventPrivate::KMAIL_SERNUM_FLAG) += cat.mid(KMAIL_SERNUM_CATEGORY.length());
5656 else if (cat == ARCHIVE_CATEGORY)
5657 event->setCustomProperty(KACalendar::APPNAME, ARCHIVE_PROPERTY, QLatin1String("0"));
5658 else if (cat.startsWith(ARCHIVE_CATEGORIES))
5659 event->setCustomProperty(KACalendar::APPNAME, ARCHIVE_PROPERTY, cat.mid(ARCHIVE_CATEGORIES.length()));
5660 else if (cat.startsWith(LOG_CATEGORY))
5661 event->setCustomProperty(KACalendar::APPNAME, KAEventPrivate::LOG_PROPERTY, cat.mid(LOG_CATEGORY.length()));
5662 else
5663 {
5664 ++i; // Not a KAlarm category, so leave it
5665 continue;
5666 }
5667 cats.removeAt(i);
5668 }
5669 }
5670
5671 if (pre_1_9_2)
5672 {
5673 /*
5674 * It's a KAlarm pre-1.9.2 calendar file.
5675 * Convert from clock time to the local system time zone.
5676 */
5677 event->shiftTimes(KDateTime::ClockTime, localZone);
5678 converted = true;
5679 }
5680
5681 if (addLateCancel)
5682 (flags += KAEventPrivate::LATE_CANCEL_FLAG) += QLatin1String("1");
5683 if (!flags.isEmpty())
5684 event->setCustomProperty(KACalendar::APPNAME, KAEventPrivate::FLAGS_PROPERTY, flags.join(KAEventPrivate::SC));
5685 event->setCategories(cats);
5686
5687 if ((pre_1_4_14 || (pre_1_9_7 && !pre_1_9_0))
5688 && event->recurrence() && event->recurrence()->recurs())
5689 {
5690 /*
5691 * It's a KAlarm pre-1.4.14 or KAlarm 1.9 series pre-1.9.7 calendar file.
5692 * For recurring events, convert the main alarm offset to an absolute
5693 * time in the X-KDE-KALARM-NEXTRECUR property, and set main alarm
5694 * offsets to zero, and convert deferral alarm offsets to be relative to
5695 * the next recurrence.
5696 */
5697 const QStringList flags = event->customProperty(KACalendar::APPNAME, KAEventPrivate::FLAGS_PROPERTY).split(KAEventPrivate::SC, QString::SkipEmptyParts);
5698 const bool dateOnly = flags.contains(KAEventPrivate::DATE_ONLY_FLAG);
5699 KDateTime startDateTime = event->dtStart();
5700 if (dateOnly)
5701 startDateTime.setDateOnly(true);
5702 // Convert the main alarm and get the next main trigger time from it
5703 KDateTime nextMainDateTime;
5704 bool mainExpired = true;
5705 for (int i = 0, alend = alarms.count(); i < alend; ++i)
5706 {
5707#ifndef KALARMCAL_USE_KRESOURCES
5708 Alarm::Ptr alarm = alarms[i];
5709#else
5710 Alarm* alarm = alarms[i];
5711#endif
5712 if (!alarm->hasStartOffset())
5713 continue;
5714 // Find whether the alarm triggers at the same time as the main
5715 // alarm, in which case its offset needs to be set to 0. The
5716 // following trigger with the main alarm:
5717 // - Additional audio alarm
5718 // - PRE_ACTION_TYPE
5719 // - POST_ACTION_TYPE
5720 // - DISPLAYING_TYPE
5721 bool mainAlarm = true;
5722 QString property = alarm->customProperty(KACalendar::APPNAME, KAEventPrivate::TYPE_PROPERTY);
5723 const QStringList types = property.split(QLatin1Char(','), QString::SkipEmptyParts);
5724 for (int t = 0; t < types.count(); ++t)
5725 {
5726 QString type = types[t];
5727 if (type == KAEventPrivate::AT_LOGIN_TYPE
5728 || type == KAEventPrivate::TIME_DEFERRAL_TYPE
5729 || type == KAEventPrivate::DATE_DEFERRAL_TYPE
5730 || type == KAEventPrivate::REMINDER_TYPE
5731 || type == REMINDER_ONCE_TYPE)
5732 {
5733 mainAlarm = false;
5734 break;
5735 }
5736 }
5737 if (mainAlarm)
5738 {
5739 if (mainExpired)
5740 {
5741 // All main alarms are supposed to be at the same time, so
5742 // don't readjust the event's time for subsequent main alarms.
5743 mainExpired = false;
5744 nextMainDateTime = alarm->time();
5745 nextMainDateTime.setDateOnly(dateOnly);
5746 nextMainDateTime = nextMainDateTime.toTimeSpec(startDateTime);
5747 if (nextMainDateTime != startDateTime)
5748 {
5749 QDateTime dt = nextMainDateTime.dateTime();
5750 event->setCustomProperty(KACalendar::APPNAME, KAEventPrivate::NEXT_RECUR_PROPERTY,
5751 dt.toString(dateOnly ? QLatin1String("yyyyMMdd") : QLatin1String("yyyyMMddThhmmss")));
5752 }
5753 }
5754 alarm->setStartOffset(0);
5755 converted = true;
5756 }
5757 }
5758 int adjustment;
5759 if (mainExpired)
5760 {
5761 // It's an expired recurrence.
5762 // Set the alarm offset relative to the first actual occurrence
5763 // (taking account of possible exceptions).
5764 KDateTime dt = event->recurrence()->getNextDateTime(startDateTime.addDays(-1));
5765 dt.setDateOnly(dateOnly);
5766 adjustment = startDateTime.secsTo(dt);
5767 }
5768 else
5769 adjustment = startDateTime.secsTo(nextMainDateTime);
5770 if (adjustment)
5771 {
5772 // Convert deferred alarms
5773 for (int i = 0, alend = alarms.count(); i < alend; ++i)
5774 {
5775#ifndef KALARMCAL_USE_KRESOURCES
5776 Alarm::Ptr alarm = alarms[i];
5777#else
5778 Alarm* alarm = alarms[i];
5779#endif
5780 if (!alarm->hasStartOffset())
5781 continue;
5782 const QString property = alarm->customProperty(KACalendar::APPNAME, KAEventPrivate::TYPE_PROPERTY);
5783 const QStringList types = property.split(QLatin1Char(','), QString::SkipEmptyParts);
5784 for (int t = 0; t < types.count(); ++t)
5785 {
5786 const QString type = types[t];
5787 if (type == KAEventPrivate::TIME_DEFERRAL_TYPE
5788 || type == KAEventPrivate::DATE_DEFERRAL_TYPE)
5789 {
5790 alarm->setStartOffset(alarm->startOffset().asSeconds() - adjustment);
5791 converted = true;
5792 break;
5793 }
5794 }
5795 }
5796 }
5797 }
5798
5799 if (pre_1_5_0 || (pre_1_9_9 && !pre_1_9_0))
5800 {
5801 /*
5802 * It's a KAlarm pre-1.5.0 or KAlarm 1.9 series pre-1.9.9 calendar file.
5803 * Convert email identity names to uoids.
5804 */
5805 for (int i = 0, alend = alarms.count(); i < alend; ++i)
5806 {
5807#ifndef KALARMCAL_USE_KRESOURCES
5808 Alarm::Ptr alarm = alarms[i];
5809#else
5810 Alarm* alarm = alarms[i];
5811#endif
5812 const QString name = alarm->customProperty(KACalendar::APPNAME, KMAIL_ID_PROPERTY);
5813 if (name.isEmpty())
5814 continue;
5815 const uint id = Identities::identityUoid(name);
5816 if (id)
5817 alarm->setCustomProperty(KACalendar::APPNAME, EMAIL_ID_PROPERTY, QString::number(id));
5818 alarm->removeCustomProperty(KACalendar::APPNAME, KMAIL_ID_PROPERTY);
5819 converted = true;
5820 }
5821 }
5822
5823 if (pre_1_9_10)
5824 {
5825 /*
5826 * It's a KAlarm pre-1.9.10 calendar file.
5827 * Convert simple repetitions without a recurrence, to a recurrence.
5828 */
5829 if (KAEventPrivate::convertRepetition(event))
5830 converted = true;
5831 }
5832
5833 if (pre_2_2_9 || (pre_2_3_2 && !pre_2_3_0))
5834 {
5835 /*
5836 * It's a KAlarm pre-2.2.9 or KAlarm 2.3 series pre-2.3.2 calendar file.
5837 * Set the time in the calendar for all date-only alarms to 00:00.
5838 */
5839 if (KAEventPrivate::convertStartOfDay(event))
5840 converted = true;
5841 }
5842
5843 if (pre_2_7_0)
5844 {
5845 /*
5846 * It's a KAlarm pre-2.7.0 calendar file.
5847 * Archive and at-login flags were stored in event's ARCHIVE property when the main alarm had expired.
5848 * Reminder parameters were stored in event's ARCHIVE property when no reminder was pending.
5849 * Negative reminder periods (i.e. alarm offset > 0) were invalid, so convert to 0.
5850 * Now store reminder information in FLAGS property, whether reminder is pending or not.
5851 * Move EMAILID, SPEAK, ERRCANCEL and ERRNOSHOW alarm properties into new FLAGS property.
5852 */
5853 bool flagsValid = false;
5854 QStringList flags;
5855 QString reminder;
5856 bool reminderOnce = false;
5857 const QString prop = event->customProperty(KACalendar::APPNAME, ARCHIVE_PROPERTY);
5858 if (!prop.isEmpty())
5859 {
5860 // Convert the event's ARCHIVE property to parameters in the FLAGS property
5861 flags = event->customProperty(KACalendar::APPNAME, KAEventPrivate::FLAGS_PROPERTY).split(KAEventPrivate::SC, QString::SkipEmptyParts);
5862 flags << KAEventPrivate::ARCHIVE_FLAG;
5863 flagsValid = true;
5864 if (prop != QLatin1String("0")) // "0" was a dummy parameter if no others were present
5865 {
5866 // It's the archive property containing a reminder time and/or repeat-at-login flag.
5867 // This was present when no reminder/at-login alarm was pending.
5868 const QStringList list = prop.split(KAEventPrivate::SC, QString::SkipEmptyParts);
5869 for (int i = 0; i < list.count(); ++i)
5870 {
5871 if (list[i] == KAEventPrivate::AT_LOGIN_TYPE)
5872 flags << KAEventPrivate::AT_LOGIN_TYPE;
5873 else if (list[i] == ARCHIVE_REMINDER_ONCE_TYPE)
5874 reminderOnce = true;
5875 else if (!list[i].isEmpty() && !list[i].startsWith(QChar::fromLatin1('-')))
5876 reminder = list[i];
5877 }
5878 }
5879 event->setCustomProperty(KACalendar::APPNAME, KAEventPrivate::FLAGS_PROPERTY, flags.join(KAEventPrivate::SC));
5880 event->removeCustomProperty(KACalendar::APPNAME, ARCHIVE_PROPERTY);
5881 }
5882
5883 for (int i = 0, alend = alarms.count(); i < alend; ++i)
5884 {
5885#ifndef KALARMCAL_USE_KRESOURCES
5886 Alarm::Ptr alarm = alarms[i];
5887#else
5888 Alarm* alarm = alarms[i];
5889#endif
5890 // Convert EMAILID, SPEAK, ERRCANCEL, ERRNOSHOW properties
5891 QStringList flags;
5892 QString property = alarm->customProperty(KACalendar::APPNAME, EMAIL_ID_PROPERTY);
5893 if (!property.isEmpty())
5894 {
5895 flags << KAEventPrivate::EMAIL_ID_FLAG << property;
5896 alarm->removeCustomProperty(KACalendar::APPNAME, EMAIL_ID_PROPERTY);
5897 }
5898 if (!alarm->customProperty(KACalendar::APPNAME, SPEAK_PROPERTY).isEmpty())
5899 {
5900 flags << KAEventPrivate::SPEAK_FLAG;
5901 alarm->removeCustomProperty(KACalendar::APPNAME, SPEAK_PROPERTY);
5902 }
5903 if (!alarm->customProperty(KACalendar::APPNAME, CANCEL_ON_ERROR_PROPERTY).isEmpty())
5904 {
5905 flags << KAEventPrivate::CANCEL_ON_ERROR_FLAG;
5906 alarm->removeCustomProperty(KACalendar::APPNAME, CANCEL_ON_ERROR_PROPERTY);
5907 }
5908 if (!alarm->customProperty(KACalendar::APPNAME, DONT_SHOW_ERROR_PROPERTY).isEmpty())
5909 {
5910 flags << KAEventPrivate::DONT_SHOW_ERROR_FLAG;
5911 alarm->removeCustomProperty(KACalendar::APPNAME, DONT_SHOW_ERROR_PROPERTY);
5912 }
5913 if (!flags.isEmpty())
5914 alarm->setCustomProperty(KACalendar::APPNAME, KAEventPrivate::FLAGS_PROPERTY, flags.join(KAEventPrivate::SC));
5915
5916 // Invalidate negative reminder periods in alarms
5917 if (!alarm->hasStartOffset())
5918 continue;
5919 property = alarm->customProperty(KACalendar::APPNAME, KAEventPrivate::TYPE_PROPERTY);
5920 QStringList types = property.split(QChar::fromLatin1(','), QString::SkipEmptyParts);
5921 const int r = types.indexOf(REMINDER_ONCE_TYPE);
5922 if (r >= 0)
5923 {
5924 // Move reminder-once indicator from the alarm to the event's FLAGS property
5925 types[r] = KAEventPrivate::REMINDER_TYPE;
5926 alarm->setCustomProperty(KACalendar::APPNAME, KAEventPrivate::TYPE_PROPERTY, types.join(QChar::fromLatin1(',')));
5927 reminderOnce = true;
5928 }
5929 if (r >= 0 || types.contains(KAEventPrivate::REMINDER_TYPE))
5930 {
5931 // The alarm is a reminder alarm
5932 const int offset = alarm->startOffset().asSeconds();
5933 if (offset > 0)
5934 {
5935 alarm->setStartOffset(0);
5936 converted = true;
5937 }
5938 else if (offset < 0)
5939 reminder = reminderToString(offset / 60);
5940 }
5941 }
5942 if (!reminder.isEmpty())
5943 {
5944 // Write reminder parameters into the event's FLAGS property
5945 if (!flagsValid)
5946 flags = event->customProperty(KACalendar::APPNAME, KAEventPrivate::FLAGS_PROPERTY).split(KAEventPrivate::SC, QString::SkipEmptyParts);
5947 if (flags.indexOf(KAEventPrivate::REMINDER_TYPE) < 0)
5948 {
5949 flags += KAEventPrivate::REMINDER_TYPE;
5950 if (reminderOnce)
5951 flags += KAEventPrivate::REMINDER_ONCE_FLAG;
5952 flags += reminder;
5953 }
5954 }
5955 }
5956
5957 if (readOnly)
5958 event->setReadOnly(true);
5959 event->endUpdates(); // finally issue an update notification
5960 }
5961 return converted;
5962}
5963
5964/******************************************************************************
5965* Set the time for a date-only event to 00:00.
5966* Reply = true if the event was updated.
5967*/
5968#ifndef KALARMCAL_USE_KRESOURCES
5969bool KAEventPrivate::convertStartOfDay(const Event::Ptr& event)
5970#else
5971bool KAEventPrivate::convertStartOfDay(Event* event)
5972#endif
5973{
5974 bool changed = false;
5975 const QTime midnight(0, 0);
5976 const QStringList flags = event->customProperty(KACalendar::APPNAME, KAEventPrivate::FLAGS_PROPERTY).split(KAEventPrivate::SC, QString::SkipEmptyParts);
5977 if (flags.indexOf(KAEventPrivate::DATE_ONLY_FLAG) >= 0)
5978 {
5979 // It's an untimed event, so fix it
5980 const KDateTime oldDt = event->dtStart();
5981 const int adjustment = oldDt.time().secsTo(midnight);
5982 if (adjustment)
5983 {
5984 event->setDtStart(KDateTime(oldDt.date(), midnight, oldDt.timeSpec()));
5985 int deferralOffset = 0;
5986 AlarmMap alarmMap;
5987 readAlarms(event, &alarmMap);
5988 for (AlarmMap::ConstIterator it = alarmMap.constBegin(); it != alarmMap.constEnd(); ++it)
5989 {
5990 const AlarmData& data = it.value();
5991 if (!data.alarm->hasStartOffset())
5992 continue;
5993 if (data.timedDeferral)
5994 {
5995 // Found a timed deferral alarm, so adjust the offset
5996 deferralOffset = data.alarm->startOffset().asSeconds();
5997#ifndef KALARMCAL_USE_KRESOURCES
5998 const_cast<Alarm*>(data.alarm.data())->setStartOffset(deferralOffset - adjustment);
5999#else
6000 const_cast<Alarm*>(data.alarm)->setStartOffset(deferralOffset - adjustment);
6001#endif
6002 }
6003 else if (data.type == AUDIO_ALARM
6004 && data.alarm->startOffset().asSeconds() == deferralOffset)
6005 {
6006 // Audio alarm is set for the same time as the above deferral alarm
6007#ifndef KALARMCAL_USE_KRESOURCES
6008 const_cast<Alarm*>(data.alarm.data())->setStartOffset(deferralOffset - adjustment);
6009#else
6010 const_cast<Alarm*>(data.alarm)->setStartOffset(deferralOffset - adjustment);
6011#endif
6012 }
6013 }
6014 changed = true;
6015 }
6016 }
6017 else
6018 {
6019 // It's a timed event. Fix any untimed alarms.
6020 bool foundDeferral = false;
6021 int deferralOffset = 0;
6022 int newDeferralOffset = 0;
6023 DateTime start;
6024 const KDateTime nextMainDateTime = readDateTime(event, false, start).kDateTime();
6025 AlarmMap alarmMap;
6026 readAlarms(event, &alarmMap);
6027 for (AlarmMap::ConstIterator it = alarmMap.constBegin(); it != alarmMap.constEnd(); ++it)
6028 {
6029 const AlarmData& data = it.value();
6030 if (!data.alarm->hasStartOffset())
6031 continue;
6032 if ((data.type & DEFERRED_ALARM) && !data.timedDeferral)
6033 {
6034 // Found a date-only deferral alarm, so adjust its time
6035 KDateTime altime = data.alarm->startOffset().end(nextMainDateTime);
6036 altime.setTime(midnight);
6037 deferralOffset = data.alarm->startOffset().asSeconds();
6038 newDeferralOffset = event->dtStart().secsTo(altime);
6039#ifndef KALARMCAL_USE_KRESOURCES
6040 const_cast<Alarm*>(data.alarm.data())->setStartOffset(newDeferralOffset);
6041#else
6042 const_cast<Alarm*>(data.alarm)->setStartOffset(newDeferralOffset);
6043#endif
6044 foundDeferral = true;
6045 changed = true;
6046 }
6047 else if (foundDeferral
6048 && data.type == AUDIO_ALARM
6049 && data.alarm->startOffset().asSeconds() == deferralOffset)
6050 {
6051 // Audio alarm is set for the same time as the above deferral alarm
6052#ifndef KALARMCAL_USE_KRESOURCES
6053 const_cast<Alarm*>(data.alarm.data())->setStartOffset(newDeferralOffset);
6054#else
6055 const_cast<Alarm*>(data.alarm)->setStartOffset(newDeferralOffset);
6056#endif
6057 changed = true;
6058 }
6059 }
6060 }
6061 return changed;
6062}
6063
6064/******************************************************************************
6065* Convert simple repetitions in an event without a recurrence, to a
6066* recurrence. Repetitions which are an exact multiple of 24 hours are converted
6067* to daily recurrences; else they are converted to minutely recurrences. Note
6068* that daily and minutely recurrences produce different results when they span
6069* a daylight saving time change.
6070* Reply = true if any conversions were done.
6071*/
6072#ifndef KALARMCAL_USE_KRESOURCES
6073bool KAEventPrivate::convertRepetition(const Event::Ptr& event)
6074#else
6075bool KAEventPrivate::convertRepetition(Event* event)
6076#endif
6077{
6078 const Alarm::List alarms = event->alarms();
6079 if (alarms.isEmpty())
6080 return false;
6081 Recurrence* recur = event->recurrence(); // guaranteed to return non-null
6082 if (recur->recurs())
6083 return false;
6084 bool converted = false;
6085 const bool readOnly = event->isReadOnly();
6086 for (int ai = 0, aend = alarms.count(); ai < aend; ++ai)
6087 {
6088#ifndef KALARMCAL_USE_KRESOURCES
6089 Alarm::Ptr alarm = alarms[ai];
6090#else
6091 Alarm* alarm = alarms[ai];
6092#endif
6093 if (alarm->repeatCount() > 0 && alarm->snoozeTime().value() > 0)
6094 {
6095 if (!converted)
6096 {
6097 event->startUpdates(); // prevent multiple update notifications
6098 if (readOnly)
6099 event->setReadOnly(false);
6100 if ((alarm->snoozeTime().asSeconds() % (24*3600)) != 0)
6101 recur->setMinutely(alarm->snoozeTime().asSeconds() / 60);
6102 else
6103 recur->setDaily(alarm->snoozeTime().asDays());
6104 recur->setDuration(alarm->repeatCount() + 1);
6105 converted = true;
6106 }
6107 alarm->setRepeatCount(0);
6108 alarm->setSnoozeTime(0);
6109 }
6110 }
6111 if (converted)
6112 {
6113 if (readOnly)
6114 event->setReadOnly(true);
6115 event->endUpdates(); // finally issue an update notification
6116 }
6117 return converted;
6118}
6119
6120/*=============================================================================
6121= Class KAAlarm
6122= Corresponds to a single KCal::Alarm instance.
6123=============================================================================*/
6124
6125KAAlarm::KAAlarm()
6126 : d(new Private)
6127{
6128}
6129
6130KAAlarm::Private::Private()
6131 : mType(INVALID_ALARM),
6132 mNextRepeat(0),
6133 mRepeatAtLogin(false),
6134 mDeferred(false)
6135{
6136}
6137
6138KAAlarm::KAAlarm(const KAAlarm& other)
6139 : d(new Private(*other.d))
6140{
6141}
6142
6143KAAlarm::~KAAlarm()
6144{
6145 delete d;
6146}
6147
6148KAAlarm& KAAlarm::operator=(const KAAlarm& other)
6149{
6150 if (&other != this)
6151 *d = *other.d;
6152 return *this;
6153}
6154
6155KAAlarm::Action KAAlarm::action() const
6156{
6157 return d->mActionType;
6158}
6159
6160bool KAAlarm::isValid() const
6161{
6162 return d->mType != INVALID_ALARM;
6163}
6164
6165KAAlarm::Type KAAlarm::type() const
6166{
6167 return d->mType;
6168}
6169
6170DateTime KAAlarm::dateTime(bool withRepeats) const
6171{
6172 return (withRepeats && d->mNextRepeat && d->mRepetition)
6173 ? d->mRepetition.duration(d->mNextRepeat).end(d->mNextMainDateTime.kDateTime())
6174 : d->mNextMainDateTime;
6175}
6176
6177QDate KAAlarm::date() const
6178{
6179 return d->mNextMainDateTime.date();
6180}
6181
6182QTime KAAlarm::time() const
6183{
6184 return d->mNextMainDateTime.effectiveTime();
6185}
6186
6187bool KAAlarm::repeatAtLogin() const
6188{
6189 return d->mRepeatAtLogin;
6190}
6191
6192bool KAAlarm::isReminder() const
6193{
6194 return d->mType == REMINDER_ALARM;
6195}
6196
6197bool KAAlarm::deferred() const
6198{
6199 return d->mDeferred;
6200}
6201
6202bool KAAlarm::timedDeferral() const
6203{
6204 return d->mDeferred && d->mTimedDeferral;
6205}
6206
6207void KAAlarm::setTime(const DateTime& dt)
6208{
6209 d->mNextMainDateTime = dt;
6210}
6211
6212void KAAlarm::setTime(const KDateTime& dt)
6213{
6214 d->mNextMainDateTime = dt;
6215}
6216
6217#ifdef KDE_NO_DEBUG_OUTPUT
6218const char* KAAlarm::debugType(Type) { return ""; }
6219#else
6220const char* KAAlarm::debugType(Type type)
6221{
6222 switch (type)
6223 {
6224 case MAIN_ALARM: return "MAIN";
6225 case REMINDER_ALARM: return "REMINDER";
6226 case DEFERRED_ALARM: return "DEFERRED";
6227 case DEFERRED_REMINDER_ALARM: return "DEFERRED_REMINDER";
6228 case AT_LOGIN_ALARM: return "LOGIN";
6229 case DISPLAYING_ALARM: return "DISPLAYING";
6230 default: return "INVALID";
6231 }
6232}
6233#endif
6234
6235/*=============================================================================
6236= Class EmailAddressList
6237=============================================================================*/
6238
6239/******************************************************************************
6240* Sets the list of email addresses, removing any empty addresses.
6241* Reply = false if empty addresses were found.
6242*/
6243#ifndef KALARMCAL_USE_KRESOURCES
6244EmailAddressList& EmailAddressList::operator=(const Person::List& addresses)
6245#else
6246EmailAddressList& EmailAddressList::operator=(const QList<Person>& addresses)
6247#endif
6248{
6249 clear();
6250 for (int p = 0, end = addresses.count(); p < end; ++p)
6251 {
6252#ifndef KALARMCAL_USE_KRESOURCES
6253 if (!addresses[p]->email().isEmpty())
6254#else
6255 if (!addresses[p].email().isEmpty())
6256#endif
6257 append(addresses[p]);
6258 }
6259 return *this;
6260}
6261
6262/******************************************************************************
6263* Return the email address list as a string list of email addresses.
6264*/
6265EmailAddressList::operator QStringList() const
6266{
6267 QStringList list;
6268 for (int p = 0, end = count(); p < end; ++p)
6269 list += address(p);
6270 return list;
6271}
6272
6273/******************************************************************************
6274* Return the email address list as a string, each address being delimited by
6275* the specified separator string.
6276*/
6277QString EmailAddressList::join(const QString& separator) const
6278{
6279 QString result;
6280 bool first = true;
6281 for (int p = 0, end = count(); p < end; ++p)
6282 {
6283 if (first)
6284 first = false;
6285 else
6286 result += separator;
6287 result += address(p);
6288 }
6289 return result;
6290}
6291
6292/******************************************************************************
6293* Convert one item into an email address, including name.
6294*/
6295QString EmailAddressList::address(int index) const
6296{
6297 if (index < 0 || index > count())
6298 return QString();
6299 QString result;
6300 bool quote = false;
6301#ifndef KALARMCAL_USE_KRESOURCES
6302 const Person::Ptr person = (*this)[index];
6303 const QString name = person->name();
6304#else
6305 const Person person = (*this)[index];
6306 const QString name = person.name();
6307#endif
6308 if (!name.isEmpty())
6309 {
6310 // Need to enclose the name in quotes if it has any special characters
6311 for (int i = 0, len = name.length(); i < len; ++i)
6312 {
6313 const QChar ch = name[i];
6314 if (!ch.isLetterOrNumber())
6315 {
6316 quote = true;
6317 result += QLatin1Char('\"');
6318 break;
6319 }
6320 }
6321#ifndef KALARMCAL_USE_KRESOURCES
6322 result += (*this)[index]->name();
6323#else
6324 result += (*this)[index].name();
6325#endif
6326 result += (quote ? QLatin1String("\" <") : QLatin1String(" <"));
6327 quote = true; // need angle brackets round email address
6328 }
6329
6330#ifndef KALARMCAL_USE_KRESOURCES
6331 result += person->email();
6332#else
6333 result += person.email();
6334#endif
6335 if (quote)
6336 result += QLatin1Char('>');
6337 return result;
6338}
6339
6340/******************************************************************************
6341* Return a list of the pure email addresses, excluding names.
6342*/
6343QStringList EmailAddressList::pureAddresses() const
6344{
6345 QStringList list;
6346 for (int p = 0, end = count(); p < end; ++p)
6347#ifndef KALARMCAL_USE_KRESOURCES
6348 list += at(p)->email();
6349#else
6350 list += at(p).email();
6351#endif
6352 return list;
6353}
6354
6355/******************************************************************************
6356* Return a list of the pure email addresses, excluding names, as a string.
6357*/
6358QString EmailAddressList::pureAddresses(const QString& separator) const
6359{
6360 QString result;
6361 bool first = true;
6362 for (int p = 0, end = count(); p < end; ++p)
6363 {
6364 if (first)
6365 first = false;
6366 else
6367 result += separator;
6368#ifndef KALARMCAL_USE_KRESOURCES
6369 result += at(p)->email();
6370#else
6371 result += at(p).email();
6372#endif
6373 }
6374 return result;
6375}
6376
6377/*=============================================================================
6378= Static functions
6379=============================================================================*/
6380
6381/******************************************************************************
6382* Set the specified alarm to be a procedure alarm with the given command line.
6383* The command line is first split into its program file and arguments before
6384* initialising the alarm.
6385*/
6386#ifndef KALARMCAL_USE_KRESOURCES
6387static void setProcedureAlarm(const Alarm::Ptr& alarm, const QString& commandLine)
6388#else
6389static void setProcedureAlarm(Alarm* alarm, const QString& commandLine)
6390#endif
6391{
6392 QString command;
6393 QString arguments;
6394 QChar quoteChar;
6395 bool quoted = false;
6396 const uint posMax = commandLine.length();
6397 uint pos;
6398 for (pos = 0; pos < posMax; ++pos)
6399 {
6400 const QChar ch = commandLine[pos];
6401 if (quoted)
6402 {
6403 if (ch == quoteChar)
6404 {
6405 ++pos; // omit the quote character
6406 break;
6407 }
6408 command += ch;
6409 }
6410 else
6411 {
6412 bool done = false;
6413 switch (ch.toLatin1())
6414 {
6415 case ' ':
6416 case ';':
6417 case '|':
6418 case '<':
6419 case '>':
6420 done = !command.isEmpty();
6421 break;
6422 case '\'':
6423 case '"':
6424 if (command.isEmpty())
6425 {
6426 // Start of a quoted string. Omit the quote character.
6427 quoted = true;
6428 quoteChar = ch;
6429 break;
6430 }
6431 // fall through to default
6432 default:
6433 command += ch;
6434 break;
6435 }
6436 if (done)
6437 break;
6438 }
6439 }
6440
6441 // Skip any spaces after the command
6442 for ( ; pos < posMax && commandLine[pos] == QLatin1Char(' '); ++pos) ;
6443 arguments = commandLine.mid(pos);
6444
6445 alarm->setProcedureAlarm(command, arguments);
6446}
6447
6448/******************************************************************************
6449* Converts a reminder interval into a parameter string for the
6450* X-KDE-KALARM-FLAGS property.
6451*/
6452QString reminderToString(int minutes)
6453{
6454 char unit = 'M';
6455 int count = abs(minutes);
6456 if (count % 1440 == 0)
6457 {
6458 unit = 'D';
6459 count /= 1440;
6460 }
6461 else if (count % 60 == 0)
6462 {
6463 unit = 'H';
6464 count /= 60;
6465 }
6466 if (minutes < 0)
6467 count = -count;
6468 return QString::fromLatin1("%1%2").arg(count).arg(unit);
6469}
6470
6471} // namespace KAlarmCal
6472
6473// vim: et sw=4:
Akonadi::Entity::Id
qint64 Id
KAlarmCal::AlarmText::fromCalendarText
static QString fromCalendarText(const QString &text, bool &email)
Translate an alarm calendar text to a display text.
Definition alarmtext.cpp:422
KAlarmCal::AlarmText::toCalendarText
static QString toCalendarText(const QString &text)
Return the text for an alarm message text, in alarm calendar format.
Definition alarmtext.cpp:462
KAlarmCal::DateTime
As KDateTime, but with a configurable start-of-day time for date-only values.
Definition datetime.h:43
KAlarmCal::DateTime::addMins
DateTime addMins(qint64 n) const
Returns a DateTime value mins minutes later than the value of this object.
Definition datetime.cpp:290
KAlarmCal::DateTime::kDateTime
KDateTime kDateTime() const
Returns the date and time of the value as a KDateTime.
Definition datetime.cpp:132
KAlarmCal::DateTime::toString
QString toString(Qt::DateFormat f=Qt::TextDate) const
Returns the value as a string.
Definition datetime.cpp:330
KAlarmCal::DateTime::startOfDay
static QTime startOfDay()
Returns the start-of-day time.
Definition datetime.cpp:361
KAlarmCal::DateTime::isDateOnly
bool isDateOnly() const
Returns true if it is date-only value.
Definition datetime.cpp:107
KAlarmCal::DateTime::isValid
bool isValid() const
Returns true if the date is valid and, if it is a date-time value, the time is also valid.
Definition datetime.cpp:102
KAlarmCal::DateTime::setDateOnly
void setDateOnly(bool d)
Sets the value to be either date-only or date-time.
Definition datetime.cpp:112
KAlarmCal::DateTime::setDate
void setDate(const QDate &d)
Sets the date component of the value.
Definition datetime.cpp:122
KAlarmCal::DateTime::effectiveKDateTime
KDateTime effectiveKDateTime() const
Returns the date and time of the value.
Definition datetime.cpp:163
KAlarmCal::DateTime::addSecs
DateTime addSecs(qint64 n) const
Returns a DateTime value secs seconds later than the value of this object.
Definition datetime.cpp:285
KAlarmCal::DateTime::setStartOfDay
static void setStartOfDay(const QTime &sod)
Sets the start-of-day time.
Definition datetime.cpp:351
KAlarmCal::DateTime::timeSpec
KDateTime::Spec timeSpec() const
Returns the time specification of the value.
Definition datetime.cpp:190
KAlarmCal::DateTime::date
QDate date() const
Returns the date part of the value.
Definition datetime.cpp:117
KAlarmCal::KAAlarm
KAAlarm represents individual alarms within a KAEvent.
Definition kaevent.h:78
KAlarmCal::KAAlarm::date
QDate date() const
Return the trigger date for the alarm.
Definition kaevent.cpp:6177
KAlarmCal::KAAlarm::KAAlarm
KAAlarm()
Default constructor, which creates an invalid instance.
Definition kaevent.cpp:6125
KAlarmCal::KAAlarm::setTime
void setTime(const DateTime &dt)
Set the alarm's trigger time.
Definition kaevent.cpp:6207
KAlarmCal::KAAlarm::action
Action action() const
Return the action type for the alarm.
Definition kaevent.cpp:6155
KAlarmCal::KAAlarm::debugType
static const char * debugType(Type)
Return an alarm type as a string.
Definition kaevent.cpp:6220
KAlarmCal::KAAlarm::dateTime
DateTime dateTime(bool withRepeats=false) const
Return the trigger time for the alarm.
Definition kaevent.cpp:6170
KAlarmCal::KAAlarm::timedDeferral
bool timedDeferral() const
Return whether in the case of a deferred alarm, it is timed (as opposed to date-only).
Definition kaevent.cpp:6202
KAlarmCal::KAAlarm::Action
Action
The basic KAAlarm action types.
Definition kaevent.h:82
KAlarmCal::KAAlarm::EMAIL
@ EMAIL
KCal::Alarm::Email type: send an email.
Definition kaevent.h:86
KAlarmCal::KAAlarm::MESSAGE
@ MESSAGE
KCal::Alarm::Display type: display a text message.
Definition kaevent.h:83
KAlarmCal::KAAlarm::FILE
@ FILE
KCal::Alarm::Display type: display a file (URL given by the alarm text)
Definition kaevent.h:84
KAlarmCal::KAAlarm::AUDIO
@ AUDIO
KCal::Alarm::Audio type: play a sound file.
Definition kaevent.h:87
KAlarmCal::KAAlarm::COMMAND
@ COMMAND
KCal::Alarm::Procedure type: execute a shell command.
Definition kaevent.h:85
KAlarmCal::KAAlarm::operator=
KAAlarm & operator=(const KAAlarm &other)
Assignment operator.
Definition kaevent.cpp:6148
KAlarmCal::KAAlarm::deferred
bool deferred() const
Return whether this is a deferred alarm.
Definition kaevent.cpp:6197
KAlarmCal::KAAlarm::isReminder
bool isReminder() const
Return whether this is a reminder alarm.
Definition kaevent.cpp:6192
KAlarmCal::KAAlarm::time
QTime time() const
Return the trigger time-of-day for the alarm.
Definition kaevent.cpp:6182
KAlarmCal::KAAlarm::type
Type type() const
Return the alarm's type (main, reminder, etc.).
Definition kaevent.cpp:6165
KAlarmCal::KAAlarm::~KAAlarm
~KAAlarm()
Destructor.
Definition kaevent.cpp:6143
KAlarmCal::KAAlarm::isValid
bool isValid() const
Return whether the alarm is valid, i.e.
Definition kaevent.cpp:6160
KAlarmCal::KAAlarm::repeatAtLogin
bool repeatAtLogin() const
Return whether this is a repeat-at-login alarm.
Definition kaevent.cpp:6187
KAlarmCal::KAAlarm::Type
Type
Alarm types.
Definition kaevent.h:95
KAlarmCal::KAAlarm::DEFERRED_ALARM
@ DEFERRED_ALARM
Deferred alarm.
Definition kaevent.h:99
KAlarmCal::KAAlarm::REMINDER_ALARM
@ REMINDER_ALARM
Reminder in advance of/after the main alarm.
Definition kaevent.h:98
KAlarmCal::KAAlarm::DEFERRED_REMINDER_ALARM
@ DEFERRED_REMINDER_ALARM
Deferred reminder alarm.
Definition kaevent.h:100
KAlarmCal::KAAlarm::INVALID_ALARM
@ INVALID_ALARM
Not an alarm.
Definition kaevent.h:96
KAlarmCal::KAAlarm::DISPLAYING_ALARM
@ DISPLAYING_ALARM
Copy of the alarm currently being displayed.
Definition kaevent.h:104
KAlarmCal::KAAlarm::MAIN_ALARM
@ MAIN_ALARM
THE real alarm. Must be the first in the enumeration.
Definition kaevent.h:97
KAlarmCal::KAAlarm::AT_LOGIN_ALARM
@ AT_LOGIN_ALARM
Additional repeat-at-login trigger.
Definition kaevent.h:103
KAlarmCal::KAEvent
KAEvent represents a KAlarm event.
Definition kaevent.h:211
KAlarmCal::KAEvent::reinstateFromDisplaying
void reinstateFromDisplaying(const KCalCore::Event::Ptr &event, Akonadi::Collection::Id &colId, bool &showEdit, bool &showDefer)
Reinstate the original event from the 'displaying' event.
Definition kaevent.cpp:3726
KAlarmCal::KAEvent::reminderMinutes
int reminderMinutes() const
Return the number of minutes BEFORE the main alarm when a reminder alarm is set.
Definition kaevent.cpp:2496
KAlarmCal::KAEvent::expired
bool expired() const
Return whether the event has expired.
Definition kaevent.cpp:1833
KAlarmCal::KAEvent::setDeferDefaultMinutes
void setDeferDefaultMinutes(int minutes, bool dateOnly=false)
Set defaults for the deferral dialog.
Definition kaevent.cpp:2671
KAlarmCal::KAEvent::OccurType
OccurType
What type of occurrence is due.
Definition kaevent.h:267
KAlarmCal::KAEvent::OCCURRENCE_REPEAT
@ OCCURRENCE_REPEAT
(bitmask for a sub-repetition of an occurrence)
Definition kaevent.h:273
KAlarmCal::KAEvent::RECURRENCE_DATE_TIME
@ RECURRENCE_DATE_TIME
a recurrence with a date and time
Definition kaevent.h:271
KAlarmCal::KAEvent::RECURRENCE_DATE
@ RECURRENCE_DATE
a recurrence with only a date, not a time
Definition kaevent.h:270
KAlarmCal::KAEvent::FIRST_OR_ONLY_OCCURRENCE
@ FIRST_OR_ONLY_OCCURRENCE
the first occurrence (takes precedence over LAST_RECURRENCE)
Definition kaevent.h:269
KAlarmCal::KAEvent::LAST_RECURRENCE
@ LAST_RECURRENCE
the last recurrence
Definition kaevent.h:272
KAlarmCal::KAEvent::NO_OCCURRENCE
@ NO_OCCURRENCE
no occurrence is due
Definition kaevent.h:268
KAlarmCal::KAEvent::repeatSoundPause
int repeatSoundPause() const
Return how many seconds to pause between repetitions of the sound file.
Definition kaevent.cpp:2337
KAlarmCal::KAEvent::setRepeatAtLogin
void setRepeatAtLogin(bool repeat)
Enable or disable repeat-at-login.
Definition kaevent.cpp:2840
KAlarmCal::KAEvent::deferDefaultDateOnly
bool deferDefaultDateOnly() const
Return the default date-only setting used in the deferral dialog.
Definition kaevent.cpp:2750
KAlarmCal::KAEvent::setRecurDaily
bool setRecurDaily(int freq, const QBitArray &days, int count, const QDate &end)
Set the recurrence to recur daily.
Definition kaevent.cpp:3025
KAlarmCal::KAEvent::setStartOfDay
static void setStartOfDay(const QTime &)
Set the start-of-day time used by all date-only alarms.
Definition kaevent.cpp:2784
KAlarmCal::KAEvent::setReminder
void setReminder(int minutes, bool onceOnly)
Set an additional reminder alarm.
Definition kaevent.cpp:2431
KAlarmCal::KAEvent::emailBcc
bool emailBcc() const
Return whether to send a blind copy of the email to the sender, for an email alarm.
Definition kaevent.cpp:2285
KAlarmCal::KAEvent::mainDateTime
DateTime mainDateTime(bool withRepeats=false) const
Return the next time the main alarm will trigger.
Definition kaevent.cpp:2766
KAlarmCal::KAEvent::audioFile
QString audioFile() const
Return the audio file path.
Definition kaevent.cpp:2312
KAlarmCal::KAEvent::autoClose
bool autoClose() const
Return whether auto-close is enabled, i.e.
Definition kaevent.cpp:2024
KAlarmCal::KAEvent::setCreatedDateTime
void setCreatedDateTime(const KDateTime &dt)
Set the date/time the event was created, or saved in the archive calendar.
Definition kaevent.cpp:2827
KAlarmCal::KAEvent::logFile
QString logFile() const
Return the log file which command alarm output should be written to.
Definition kaevent.cpp:2193
KAlarmCal::KAEvent::holidaysExcluded
bool holidaysExcluded() const
Return whether the alarm is disabled on holiday dates.
Definition kaevent.cpp:2883
KAlarmCal::KAEvent::previousOccurrence
OccurType previousOccurrence(const KDateTime &afterDateTime, DateTime &result, bool includeRepetitions=false) const
Get the date/time of the last previous occurrence of the event, before the specified date/time.
Definition kaevent.cpp:3603
KAlarmCal::KAEvent::emailSubject
QString emailSubject() const
Return the email subject line, for an email alarm.
Definition kaevent.cpp:2270
KAlarmCal::KAEvent::repeatSound
bool repeatSound() const
Return whether the sound file will be repeated indefinitely.
Definition kaevent.cpp:2332
KAlarmCal::KAEvent::mainExpired
bool mainExpired() const
Return whether the event's main alarm has expired.
Definition kaevent.cpp:1828
KAlarmCal::KAEvent::setActions
void setActions(const QString &pre, const QString &post, ExtraActionOptions options)
Set the pre-alarm and post-alarm actions, and their options.
Definition kaevent.cpp:2385
KAlarmCal::KAEvent::List
QVector< KAEvent * > List
A list of pointers to KAEvent objects.
Definition kaevent.h:214
KAlarmCal::KAEvent::recurrenceText
QString recurrenceText(bool brief=false) const
Return the recurrence interval as text suitable for display.
Definition kaevent.cpp:3291
KAlarmCal::KAEvent::setRecurMonthlyByDate
bool setRecurMonthlyByDate(int freq, const QVector< int > &days, int count, const QDate &end)
Set the recurrence to recur monthly, on the specified days within the month.
Definition kaevent.cpp:3074
KAlarmCal::KAEvent::recurInterval
int recurInterval() const
Return the recurrence interval in units of the recurrence period type (minutes, days,...
Definition kaevent.cpp:3214
KAlarmCal::KAEvent::SubAction
SubAction
The sub-action type for the event's main alarm.
Definition kaevent.h:257
KAlarmCal::KAEvent::FILE
@ FILE
display the contents of a file
Definition kaevent.h:259
KAlarmCal::KAEvent::COMMAND
@ COMMAND
execute a command
Definition kaevent.h:260
KAlarmCal::KAEvent::EMAIL
@ EMAIL
send an email
Definition kaevent.h:261
KAlarmCal::KAEvent::MESSAGE
@ MESSAGE
display a message text
Definition kaevent.h:258
KAlarmCal::KAEvent::AUDIO
@ AUDIO
play an audio file
Definition kaevent.h:262
KAlarmCal::KAEvent::setRecurrence
void setRecurrence(const KARecurrence &r)
Initialise the event's recurrence from a KARecurrence.
Definition kaevent.cpp:2973
KAlarmCal::KAEvent::setCollectionId_const
void setCollectionId_const(Akonadi::Collection::Id id) const
Set the ID of the Akonadi Collection which contains the event.
Definition kaevent.cpp:1916
KAlarmCal::KAEvent::setLateCancel
void setLateCancel(int minutes)
Set or clear the late-cancel option.
Definition kaevent.cpp:2005
KAlarmCal::KAEvent::commandXterm
bool commandXterm() const
Return whether to execute the command in a terminal window, for a command alarm.
Definition kaevent.cpp:2095
KAlarmCal::KAEvent::deferred
bool deferred() const
Return whether there is currently a deferred alarm pending.
Definition kaevent.cpp:2677
KAlarmCal::KAEvent::joinEmailAddresses
static QString joinEmailAddresses(const KCalCore::Person::List &addresses, const QString &sep)
Concatenate a list of email addresses into a string.
Definition kaevent.cpp:2252
KAlarmCal::KAEvent::commandDisplay
bool commandDisplay() const
Return whether the command output is to be displayed in an alarm message window.
Definition kaevent.cpp:2100
KAlarmCal::KAEvent::emailAddresses
QStringList emailAddresses() const
Return a list of the email addresses, including names, for an email alarm.
Definition kaevent.cpp:2241
KAlarmCal::KAEvent::compatibility
KACalendar::Compat compatibility() const
Return the event's storage format compatibility compared to the current KAlarm calendar format.
Definition kaevent.cpp:1965
KAlarmCal::KAEvent::collectionId
Akonadi::Collection::Id collectionId() const
Return the ID of the Akonadi Collection which contains the event.
Definition kaevent.cpp:1921
KAlarmCal::KAEvent::customProperties
QMap< QByteArray, QString > customProperties() const
Return the original KCalCore::Event's custom properties in the source calendar.
Definition kaevent.cpp:1970
KAlarmCal::KAEvent::repeatAtLogin
bool repeatAtLogin(bool includeArchived=false) const
Return whether the alarm repeats at login.
Definition kaevent.cpp:2871
KAlarmCal::KAEvent::setCommandError
void setCommandError(CmdErrType error) const
Set or clear the command execution error for the last time the alarm triggered.
Definition kaevent.cpp:2106
KAlarmCal::KAEvent::setExcludeHolidays
void setExcludeHolidays(bool exclude)
Enable or disable the alarm on holiday dates.
Definition kaevent.cpp:2876
KAlarmCal::KAEvent::fadeSeconds
int fadeSeconds() const
Return the fade period in seconds, or 0 if no fade is specified.
Definition kaevent.cpp:2327
KAlarmCal::KAEvent::deferDefaultMinutes
int deferDefaultMinutes() const
Return the default deferral interval used in the deferral dialog.
Definition kaevent.cpp:2745
KAlarmCal::KAEvent::command
QString command() const
Return the command or script to execute, for a command alarm.
Definition kaevent.cpp:2085
KAlarmCal::KAEvent::emailAttachments
QStringList emailAttachments() const
Return the list of file paths of the attachments, for an email alarm.
Definition kaevent.cpp:2275
KAlarmCal::KAEvent::displayMessage
QString displayMessage() const
Return the message text for a display alarm.
Definition kaevent.cpp:2050
KAlarmCal::KAEvent::mainEndRepeatTime
DateTime mainEndRepeatTime() const
Return the time at which the last sub-repetition of the main alarm will occur.
Definition kaevent.cpp:2776
KAlarmCal::KAEvent::convertDisplayingAlarm
KAAlarm convertDisplayingAlarm() const
Return the original alarm which the displaying alarm refers to.
Definition kaevent.cpp:3765
KAlarmCal::KAEvent::category
CalEvent::Type category() const
Return the alarm category (active/archived/template, or displaying).
Definition kaevent.cpp:1885
KAlarmCal::KAEvent::setReadOnly
void setReadOnly(bool ro)
Set the read-only status of the alarm.
Definition kaevent.cpp:1807
KAlarmCal::KAEvent::recurrence
KARecurrence * recurrence() const
Return the full recurrence data for the event.
Definition kaevent.cpp:3206
KAlarmCal::KAEvent::setCompatibility
void setCompatibility(KACalendar::Compat c)
Note the event's storage format compatibility compared to the current KAlarm calendar format.
Definition kaevent.cpp:1960
KAlarmCal::KAEvent::currentCalendarVersion
static int currentCalendarVersion()
Return the current KAlarm calendar storage format version.
Definition kaevent.cpp:446
KAlarmCal::KAEvent::firstAlarm
KAAlarm firstAlarm() const
Return the main alarm for the event.
Definition kaevent.cpp:3877
KAlarmCal::KAEvent::setFirstRecurrence
void setFirstRecurrence()
Adjust the event date/time to the first recurrence of the event, on or after the event start date/tim...
Definition kaevent.cpp:3245
KAlarmCal::KAEvent::bgColour
QColor bgColour() const
Return the message window background color, for a display alarm.
Definition kaevent.cpp:2060
KAlarmCal::KAEvent::startDateTime
DateTime startDateTime() const
Return the start time for the event.
Definition kaevent.cpp:2755
KAlarmCal::KAEvent::copyToKOrganizer
bool copyToKOrganizer() const
Return whether KOrganizer should hold a copy of the event.
Definition kaevent.cpp:2203
KAlarmCal::KAEvent::repetitionText
QString repetitionText(bool brief=false) const
Return the repetition interval as text suitable for display.
Definition kaevent.cpp:3383
KAlarmCal::KAEvent::incrementRevision
void incrementRevision()
Increment the revision number of the event (SEQUENCE property in iCalendar).
Definition kaevent.cpp:1900
KAlarmCal::KAEvent::currentCalendarVersionString
static QByteArray currentCalendarVersionString()
Return the current KAlarm calendar storage format version.
Definition kaevent.cpp:445
KAlarmCal::KAEvent::setTemplate
void setTemplate(const QString &name, int afterTime=-1)
Set the event to be an alarm template.
Definition kaevent.cpp:2357
KAlarmCal::KAEvent::setEventId
void setEventId(const QString &id)
Set the event's unique identifier.
Definition kaevent.cpp:1890
KAlarmCal::KAEvent::soundVolume
float soundVolume() const
Return the sound volume (the final volume if fade is specified).
Definition kaevent.cpp:2317
KAlarmCal::KAEvent::confirmAck
bool confirmAck() const
Return whether alarm acknowledgement must be confirmed by the user, for a display alarm.
Definition kaevent.cpp:2198
KAlarmCal::KAEvent::setCollectionId
void setCollectionId(Akonadi::Collection::Id id)
Set the ID of the Akonadi Collection which contains the event.
Definition kaevent.cpp:1911
KAlarmCal::KAEvent::toBeArchived
bool toBeArchived() const
Return whether the event should be archived when it expires or is deleted.
Definition kaevent.cpp:1823
KAlarmCal::KAEvent::message
QString message() const
Return the message text for a display alarm, or the email body for an email alarm.
Definition kaevent.cpp:2044
KAlarmCal::KAEvent::isWorkingTime
bool isWorkingTime(const KDateTime &dt) const
Check whether a date/time is during working hours and/or holidays, depending on the flags set for the...
Definition kaevent.cpp:2916
KAlarmCal::KAEvent::set
void set(const KCalCore::Event::Ptr &)
Initialise the instance from a KCalCore::Event.
Definition kaevent.cpp:757
KAlarmCal::KAEvent::nextAlarm
KAAlarm nextAlarm(const KAAlarm &previousAlarm) const
Return the next alarm for the event, after the specified alarm.
Definition kaevent.cpp:3898
KAlarmCal::KAEvent::itemId
Akonadi::Item::Id itemId() const
Return the ID of the Akonadi Item which contains the event.
Definition kaevent.cpp:1932
KAlarmCal::KAEvent::setTime
void setTime(const KDateTime &dt)
Set the next time to trigger the alarm (excluding sub-repetitions).
Definition kaevent.cpp:2760
KAlarmCal::KAEvent::createdDateTime
KDateTime createdDateTime() const
Return the date/time the event was created, or saved in the archive calendar.
Definition kaevent.cpp:2832
KAlarmCal::KAEvent::isReadOnly
bool isReadOnly() const
Return the read-only status of the alarm.
Definition kaevent.cpp:1812
KAlarmCal::KAEvent::usingDefaultTime
bool usingDefaultTime() const
Return whether the alarm template does not specify a time.
Definition kaevent.cpp:2375
KAlarmCal::KAEvent::setHolidays
static void setHolidays(const KHolidays::HolidayRegion &region)
Set the holiday region to be used by all KAEvent instances.
Definition kaevent.cpp:2895
KAlarmCal::KAEvent::id
QString id() const
Return the event's unique identifier.
Definition kaevent.cpp:1895
KAlarmCal::KAEvent::Actions
Actions
The basic action type(s) for the event's main alarm.
Definition kaevent.h:245
KAlarmCal::KAEvent::ACT_EMAIL
@ ACT_EMAIL
the alarm sends an email
Definition kaevent.h:249
KAlarmCal::KAEvent::ACT_DISPLAY
@ ACT_DISPLAY
the alarm displays something
Definition kaevent.h:247
KAlarmCal::KAEvent::ACT_NONE
@ ACT_NONE
invalid
Definition kaevent.h:246
KAlarmCal::KAEvent::ACT_DISPLAY_COMMAND
@ ACT_DISPLAY_COMMAND
the alarm displays command output
Definition kaevent.h:251
KAlarmCal::KAEvent::ACT_COMMAND
@ ACT_COMMAND
the alarm executes a command
Definition kaevent.h:248
KAlarmCal::KAEvent::ACT_AUDIO
@ ACT_AUDIO
the alarm plays an audio file (without any display)
Definition kaevent.h:250
KAlarmCal::KAEvent::nextRepetition
int nextRepetition() const
Return the count of the next sub-repetition which is due.
Definition kaevent.cpp:3375
KAlarmCal::KAEvent::revision
int revision() const
Return the revision number of the event (SEQUENCE property in iCalendar).
Definition kaevent.cpp:1905
KAlarmCal::KAEvent::setRecurMonthlyByPos
bool setRecurMonthlyByPos(int freq, const QVector< MonthPos > &pos, int count, const QDate &end)
Set the recurrence to recur monthly, on the specified weekdays in the specified weeks of the month.
Definition kaevent.cpp:3098
KAlarmCal::KAEvent::OccurOption
OccurOption
How to treat sub-repetitions in nextOccurrence().
Definition kaevent.h:282
KAlarmCal::KAEvent::RETURN_REPETITION
@ RETURN_REPETITION
return a sub-repetition if it's the next occurrence
Definition kaevent.h:284
KAlarmCal::KAEvent::IGNORE_REPETITION
@ IGNORE_REPETITION
check for recurrences only, ignore sub-repetitions
Definition kaevent.h:283
KAlarmCal::KAEvent::defer
void defer(const DateTime &dt, bool reminder, bool adjustRecurrence=false)
Defer the event to the specified time.
Definition kaevent.cpp:2522
KAlarmCal::KAEvent::dumpDebug
void dumpDebug() const
Output the event's data as debug output.
Definition kaevent.cpp:4044
KAlarmCal::KAEvent::reminderDeferral
bool reminderDeferral() const
Return whether there is currently a deferred reminder alarm pending.
Definition kaevent.cpp:2511
KAlarmCal::KAEvent::lateCancel
int lateCancel() const
Get the late cancellation period.
Definition kaevent.cpp:2014
KAlarmCal::KAEvent::setRecurAnnualByPos
bool setRecurAnnualByPos(int freq, const QVector< MonthPos > &pos, const QVector< int > &months, int count, const QDate &end)
Set the recurrence to recur annually, on the specified weekdays in the specified weeks of the specifi...
Definition kaevent.cpp:3151
KAlarmCal::KAEvent::font
QFont font() const
Return the font to use for alarm message texts.
Definition kaevent.cpp:2080
KAlarmCal::KAEvent::UidAction
UidAction
How to deal with the event UID in updateKCalEvent().
Definition kaevent.h:331
KAlarmCal::KAEvent::UID_SET
@ UID_SET
set the KCal::Event UID to the KAEvent ID
Definition kaevent.h:334
KAlarmCal::KAEvent::UID_CHECK
@ UID_CHECK
verify that the KCal::Event UID is already the same as the KAEvent ID, if the latter is non-empty
Definition kaevent.h:333
KAlarmCal::KAEvent::emailPureAddresses
QStringList emailPureAddresses() const
Return the list of email addressees, excluding names, for an email alarm.
Definition kaevent.cpp:2260
KAlarmCal::KAEvent::ANY_TIME
@ ANY_TIME
only a date is specified for the alarm, not a time
Definition kaevent.h:221
KAlarmCal::KAEvent::DISABLED
@ DISABLED
the alarm is currently disabled
Definition kaevent.h:226
KAlarmCal::KAEvent::REPEAT_AT_LOGIN
@ REPEAT_AT_LOGIN
repeat the alarm at every login
Definition kaevent.h:220
KAlarmCal::KAEvent::REPEAT_SOUND
@ REPEAT_SOUND
repeat the sound file while the alarm is displayed
Definition kaevent.h:225
KAlarmCal::KAEvent::EXCL_HOLIDAYS
@ EXCL_HOLIDAYS
don't trigger the alarm on holidays
Definition kaevent.h:232
KAlarmCal::KAEvent::REMINDER_ONCE
@ REMINDER_ONCE
only trigger the reminder on the first recurrence
Definition kaevent.h:235
KAlarmCal::KAEvent::SPEAK
@ SPEAK
speak the message when the alarm is displayed
Definition kaevent.h:230
KAlarmCal::KAEvent::COPY_KORGANIZER
@ COPY_KORGANIZER
KOrganizer should hold a copy of the event.
Definition kaevent.h:231
KAlarmCal::KAEvent::DEFAULT_FONT
@ DEFAULT_FONT
use the default alarm message font
Definition kaevent.h:224
KAlarmCal::KAEvent::WORK_TIME_ONLY
@ WORK_TIME_ONLY
trigger the alarm only during working hours
Definition kaevent.h:233
KAlarmCal::KAEvent::SCRIPT
@ SCRIPT
the command is a script, not a shell command line
Definition kaevent.h:228
KAlarmCal::KAEvent::BEEP
@ BEEP
sound an audible beep when the alarm is displayed
Definition kaevent.h:219
KAlarmCal::KAEvent::CONFIRM_ACK
@ CONFIRM_ACK
closing the alarm message window requires a confirmation prompt
Definition kaevent.h:222
KAlarmCal::KAEvent::EMAIL_BCC
@ EMAIL_BCC
blind copy the email to the user
Definition kaevent.h:223
KAlarmCal::KAEvent::EXEC_IN_XTERM
@ EXEC_IN_XTERM
execute the command in a terminal window
Definition kaevent.h:229
KAlarmCal::KAEvent::DISPLAY_COMMAND
@ DISPLAY_COMMAND
display command output in the alarm window
Definition kaevent.h:234
KAlarmCal::KAEvent::AUTO_CLOSE
@ AUTO_CLOSE
auto-close the alarm window after the late-cancel period
Definition kaevent.h:227
KAlarmCal::KAEvent::postAction
QString postAction() const
Return the shell command to execute after the display alarm is acknowledged.
Definition kaevent.cpp:2407
KAlarmCal::KAEvent::setRepetition
bool setRepetition(const Repetition &r)
Initialise the event's sub-repetition.
Definition kaevent.cpp:3332
KAlarmCal::KAEvent::setNextOccurrence
OccurType setNextOccurrence(const KDateTime &preDateTime)
Set the date/time of the event to the next scheduled occurrence after a specified date/time,...
Definition kaevent.cpp:3453
KAlarmCal::KAEvent::CmdErrType
CmdErrType
Command execution error type for last time the alarm was triggered.
Definition kaevent.h:310
KAlarmCal::KAEvent::CMD_ERROR_PRE
@ CMD_ERROR_PRE
pre-alarm command execution failed
Definition kaevent.h:313
KAlarmCal::KAEvent::CMD_ERROR
@ CMD_ERROR
command alarm execution failed
Definition kaevent.h:312
KAlarmCal::KAEvent::CMD_ERROR_POST
@ CMD_ERROR_POST
post-alarm command execution failed
Definition kaevent.h:314
KAlarmCal::KAEvent::CMD_NO_ERROR
@ CMD_NO_ERROR
no error
Definition kaevent.h:311
KAlarmCal::KAEvent::commandScript
bool commandScript() const
Return whether a command script is specified, for a command alarm.
Definition kaevent.cpp:2090
KAlarmCal::KAEvent::setDefaultFont
static void setDefaultFont(const QFont &font)
Set the global default font for alarm message texts.
Definition kaevent.cpp:2070
KAlarmCal::KAEvent::ptrList
static List ptrList(QVector< KAEvent > &events)
Return a list of pointers to a list of KAEvent objects.
Definition kaevent.cpp:4035
KAlarmCal::KAEvent::deferralLimit
DateTime deferralLimit(DeferLimitType *limitType=0) const
Return the latest time which the alarm can currently be deferred to.
Definition kaevent.cpp:2690
KAlarmCal::KAEvent::enabled
bool enabled() const
Return the enabled status of the alarm.
Definition kaevent.cpp:1801
KAlarmCal::KAEvent::fileName
QString fileName() const
Return the path of the file whose contents are to be shown, for a display alarm.
Definition kaevent.cpp:2055
KAlarmCal::KAEvent::setArchive
void setArchive()
Set the event to be archived when it expires or is deleted.
Definition kaevent.cpp:1818
KAlarmCal::KAEvent::nextTrigger
DateTime nextTrigger(TriggerType type) const
Return the next time the alarm will trigger.
Definition kaevent.cpp:2807
KAlarmCal::KAEvent::endChanges
void endChanges()
Call when a group of changes preceded by startChanges() is complete, to allow resultant updates to oc...
Definition kaevent.cpp:4020
KAlarmCal::KAEvent::nextOccurrence
OccurType nextOccurrence(const KDateTime &preDateTime, DateTime &result, OccurOption option=IGNORE_REPETITION) const
Get the date/time of the next occurrence of the event, after the specified date/time.
Definition kaevent.cpp:3527
KAlarmCal::KAEvent::setRecurMinutely
bool setRecurMinutely(int freq, int count, const KDateTime &end)
Set the recurrence to recur at a minutes interval.
Definition kaevent.cpp:3007
KAlarmCal::KAEvent::actionSubType
SubAction actionSubType() const
Return the action sub-type of the event's main alarm.
Definition kaevent.cpp:1987
KAlarmCal::KAEvent::setRecurAnnualByDate
bool setRecurAnnualByDate(int freq, const QVector< int > &months, int day, KARecurrence::Feb29Type, int count, const QDate &end)
Set the recurrence to recur annually, on the specified day in each of the specified months.
Definition kaevent.cpp:3124
KAlarmCal::KAEvent::setLogFile
void setLogFile(const QString &logfile)
Set the log file to write command alarm output to.
Definition kaevent.cpp:2186
KAlarmCal::KAEvent::reminderActive
bool reminderActive() const
Return whether a reminder is currently due (before the next, or after the last, main alarm/recurrence...
Definition kaevent.cpp:2501
KAlarmCal::KAEvent::setEmail
void setEmail(uint from, const KCalCore::Person::List &, const QString &subject, const QStringList &attachments)
Set the email related data for the event.
Definition kaevent.cpp:2209
KAlarmCal::KAEvent::longestRecurrenceInterval
KCalCore::Duration longestRecurrenceInterval() const
Return the longest interval which can occur between consecutive recurrences.
Definition kaevent.cpp:3235
KAlarmCal::KAEvent::deferDateTime
DateTime deferDateTime() const
Return the time at which the currently pending deferred alarm should trigger.
Definition kaevent.cpp:2682
KAlarmCal::KAEvent::templateAfterTime
int templateAfterTime() const
Return the number of minutes (>= 0) after the default alarm time which is specified in the alarm temp...
Definition kaevent.cpp:2380
KAlarmCal::KAEvent::setItemPayload
bool setItemPayload(Akonadi::Item &, const QStringList &collectionMimeTypes) const
Initialise an Akonadi::Item with the event's data.
Definition kaevent.cpp:1943
KAlarmCal::KAEvent::recurType
KARecurrence::Type recurType() const
Return the recurrence period type for the event.
Definition kaevent.cpp:3201
KAlarmCal::KAEvent::fadeVolume
float fadeVolume() const
Return the initial volume which will fade to the final volume.
Definition kaevent.cpp:2322
KAlarmCal::KAEvent::speak
bool speak() const
Return whether the displayed alarm text should be spoken.
Definition kaevent.cpp:2347
KAlarmCal::KAEvent::setRecurWeekly
bool setRecurWeekly(int freq, const QBitArray &days, int count, const QDate &end)
Set the recurrence to recur weekly, on the specified weekdays.
Definition kaevent.cpp:3054
KAlarmCal::KAEvent::displaying
bool displaying() const
Return whether the alarm is currently being displayed, i.e.
Definition kaevent.cpp:3788
KAlarmCal::KAEvent::adjustStartOfDay
static void adjustStartOfDay(const KAEvent::List &events)
Call when the user changes the start-of-day time, to adjust the data for each date-only event in a li...
Definition kaevent.cpp:2797
KAlarmCal::KAEvent::isValid
bool isValid() const
Return whether the instance represents a valid event.
Definition kaevent.cpp:1791
KAlarmCal::KAEvent::setItemId
void setItemId(Akonadi::Item::Id id)
Set the ID of the Akonadi Item which contains the event.
Definition kaevent.cpp:1927
KAlarmCal::KAEvent::extraActionOptions
ExtraActionOptions extraActionOptions() const
Return the pre- and post-alarm action options.
Definition kaevent.cpp:2412
KAlarmCal::KAEvent::updateKCalEvent
bool updateKCalEvent(const KCalCore::Event::Ptr &event, UidAction u, bool setCustomProperties=true) const
Update an existing KCalCore::Event with the KAEvent data.
Definition kaevent.cpp:1346
KAlarmCal::KAEvent::removeExpiredAlarm
void removeExpiredAlarm(KAAlarm::Type type)
Remove the alarm of the specified type from the event.
Definition kaevent.cpp:3951
KAlarmCal::KAEvent::flags
Flags flags() const
Return the OR of various Flag enum status values.
Definition kaevent.cpp:1838
KAlarmCal::KAEvent::DeferLimitType
DeferLimitType
What type of occurrence currently limits how long the alarm can be deferred.
Definition kaevent.h:290
KAlarmCal::KAEvent::LIMIT_REMINDER
@ LIMIT_REMINDER
a reminder
Definition kaevent.h:295
KAlarmCal::KAEvent::LIMIT_MAIN
@ LIMIT_MAIN
the main alarm
Definition kaevent.h:292
KAlarmCal::KAEvent::LIMIT_RECURRENCE
@ LIMIT_RECURRENCE
a recurrence
Definition kaevent.h:293
KAlarmCal::KAEvent::LIMIT_NONE
@ LIMIT_NONE
there is no limit
Definition kaevent.h:291
KAlarmCal::KAEvent::LIMIT_REPETITION
@ LIMIT_REPETITION
a sub-repetition
Definition kaevent.h:294
KAlarmCal::KAEvent::beep
bool beep() const
Return whether a beep should sound when the alarm is displayed.
Definition kaevent.cpp:2342
KAlarmCal::KAEvent::cleanText
QString cleanText() const
Return the alarm's text.
Definition kaevent.cpp:2039
KAlarmCal::KAEvent::DontShowPreActError
@ DontShowPreActError
do not notify pre-alarm action errors to user
Definition kaevent.h:324
KAlarmCal::KAEvent::ExecPreActOnDeferral
@ ExecPreActOnDeferral
execute pre-alarm action also for deferred alarms
Definition kaevent.h:325
KAlarmCal::KAEvent::CancelOnPreActError
@ CancelOnPreActError
cancel alarm on pre-alarm action error
Definition kaevent.h:323
KAlarmCal::KAEvent::alarm
KAAlarm alarm(KAAlarm::Type type) const
Return the alarm of a specified type.
Definition kaevent.cpp:3796
KAlarmCal::KAEvent::setWorkTime
static void setWorkTime(const QBitArray &days, const QTime &start, const QTime &end)
Set working days and times, to be used by all KAEvent instances.
Definition kaevent.cpp:2937
KAlarmCal::KAEvent::dontShowPreActionError
bool dontShowPreActionError() const
Return whether the user should not be notified if the pre-alarm action fails.
Definition kaevent.cpp:2422
KAlarmCal::KAEvent::recurs
bool recurs() const
Return whether the event recurs.
Definition kaevent.cpp:3196
KAlarmCal::KAEvent::actionTypes
Actions actionTypes() const
Return the OR of the basic action types of the event's main alarm (display, command,...
Definition kaevent.cpp:1992
KAlarmCal::KAEvent::isTemplate
bool isTemplate() const
Return whether the event is an alarm template.
Definition kaevent.cpp:2365
KAlarmCal::KAEvent::fgColour
QColor fgColour() const
Return the message window foreground color, for a display alarm.
Definition kaevent.cpp:2065
KAlarmCal::KAEvent::setAudioFile
void setAudioFile(const QString &filename, float volume, float fadeVolume, int fadeSeconds, int repeatPause=-1, bool allowEmptyFile=false)
Set the audio file related data for the event.
Definition kaevent.cpp:2290
KAlarmCal::KAEvent::TriggerType
TriggerType
Alarm trigger type.
Definition kaevent.h:300
KAlarmCal::KAEvent::MAIN_TRIGGER
@ MAIN_TRIGGER
next trigger, excluding reminders, ignoring working hours & holidays
Definition kaevent.h:302
KAlarmCal::KAEvent::WORK_TRIGGER
@ WORK_TRIGGER
next main working time trigger, excluding reminders
Definition kaevent.h:303
KAlarmCal::KAEvent::ALL_TRIGGER
@ ALL_TRIGGER
next trigger, including reminders, ignoring working hours & holidays
Definition kaevent.h:301
KAlarmCal::KAEvent::ALL_WORK_TRIGGER
@ ALL_WORK_TRIGGER
next actual working time trigger, including reminders
Definition kaevent.h:304
KAlarmCal::KAEvent::DISPLAY_TRIGGER
@ DISPLAY_TRIGGER
next trigger time for display purposes (i.e. excluding reminders)
Definition kaevent.h:305
KAlarmCal::KAEvent::useDefaultFont
bool useDefaultFont() const
Return whether to use the default font (as set by setDefaultFont()) for alarm message texts.
Definition kaevent.cpp:2075
KAlarmCal::KAEvent::mainTime
QTime mainTime() const
Return the time at which the main alarm will next trigger.
Definition kaevent.cpp:2771
KAlarmCal::KAEvent::emailFromId
uint emailFromId() const
Return the email identity to be used as the sender, for an email alarm.
Definition kaevent.cpp:2227
KAlarmCal::KAEvent::occursAfter
bool occursAfter(const KDateTime &preDateTime, bool includeRepetitions) const
Determine whether the event will occur after the specified date/time.
Definition kaevent.cpp:3410
KAlarmCal::KAEvent::cancelOnPreActionError
bool cancelOnPreActionError() const
Return whether the alarm is to be cancelled if the pre-alarm action fails.
Definition kaevent.cpp:2417
KAlarmCal::KAEvent::convertKCalEvents
static bool convertKCalEvents(const KCalCore::Calendar::Ptr &, int calendarVersion)
If a calendar was written by a previous version of KAlarm, do any necessary format conversions on the...
Definition kaevent.cpp:5240
KAlarmCal::KAEvent::startChanges
void startChanges()
Call before making a group of changes to the event, to avoid unnecessary calculation intensive recalc...
Definition kaevent.cpp:4011
KAlarmCal::KAEvent::templateName
QString templateName() const
Return the alarm template's name.
Definition kaevent.cpp:2370
KAlarmCal::KAEvent::setNoRecur
void setNoRecur()
Clear the event's recurrence and sub-repetition data.
Definition kaevent.cpp:2952
KAlarmCal::KAEvent::alarmCount
int alarmCount() const
Return the number of alarms in the event, i.e.
Definition kaevent.cpp:3941
KAlarmCal::KAEvent::activateReminderAfter
void activateReminderAfter(const DateTime &mainAlarmTime)
If there is a reminder which occurs AFTER the main alarm, activate the event's reminder which occurs ...
Definition kaevent.cpp:2458
KAlarmCal::KAEvent::preAction
QString preAction() const
Return the shell command to execute before the alarm is displayed.
Definition kaevent.cpp:2402
KAlarmCal::KAEvent::repetition
Repetition repetition() const
Return the event's sub-repetition data.
Definition kaevent.cpp:3370
KAlarmCal::KAEvent::emailMessage
QString emailMessage() const
Return the email message body, for an email alarm.
Definition kaevent.cpp:2222
KAlarmCal::KAEvent::KAEvent
KAEvent()
Default constructor which creates an invalid event.
KAlarmCal::KAEvent::workTimeOnly
bool workTimeOnly() const
Return whether the alarm is disabled on non-working days and outside working hours.
Definition kaevent.cpp:2907
KAlarmCal::KAEvent::commandError
CmdErrType commandError() const
Return the command execution error for the last time the alarm triggered.
Definition kaevent.cpp:2181
KAlarmCal::KAEvent::cancelDefer
void cancelDefer()
Cancel any deferral alarm which is pending.
Definition kaevent.cpp:2656
KAlarmCal::KAEvent::setCategory
void setCategory(CalEvent::Type type)
Set the alarm category (active/archived/template, or displaying).
Definition kaevent.cpp:1871
KAlarmCal::KAEvent::emailAddressees
KCalCore::Person::List emailAddressees() const
Return the list of email addressees, including names, for an email alarm.
Definition kaevent.cpp:2233
KAlarmCal::KAEvent::setDisplaying
bool setDisplaying(const KAEvent &event, KAAlarm::Type type, Akonadi::Collection::Id colId, const KDateTime &repeatAtLoginTime, bool showEdit, bool showDefer)
Set the event to be a copy of the specified event, making the specified alarm the 'displaying' alarm.
Definition kaevent.cpp:3667
KAlarmCal::KAEvent::setWorkTimeOnly
void setWorkTimeOnly(bool wto)
Enable or disable the alarm on non-working days and outside working hours.
Definition kaevent.cpp:2900
KAlarmCal::KAEvent::setEnabled
void setEnabled(bool enable)
Enable or disable the alarm.
Definition kaevent.cpp:1796
KAlarmCal::KAEvent::setAutoClose
void setAutoClose(bool autoclose)
Enable or disable auto-close for a display alarm, i.e.
Definition kaevent.cpp:2019
KAlarmCal::KAEvent::reminderOnceOnly
bool reminderOnceOnly() const
Return whether the reminder alarm is triggered only for the first recurrence.
Definition kaevent.cpp:2506
KAlarmCal::KARecurrence
Represents recurrences for KAlarm.
Definition karecurrence.h:62
KAlarmCal::KARecurrence::startDateTime
KDateTime startDateTime() const
Return the start date/time of the recurrence (Time for all-day recurrences will be 0:00).
Definition karecurrence.cpp:601
KAlarmCal::KARecurrence::set
bool set(const QString &icalRRULE)
Initialise the recurrence from an iCalendar RRULE string.
Definition karecurrence.cpp:275
KAlarmCal::KARecurrence::recurs
bool recurs() const
Returns whether the event recurs at all.
Definition karecurrence.cpp:725
KAlarmCal::KARecurrence::setFrequency
void setFrequency(int freq)
Sets the frequency of recurrence, in terms of the recurrence time period type.
Definition karecurrence.cpp:888
KAlarmCal::KARecurrence::endDateTime
KDateTime endDateTime() const
Return the date/time of the last recurrence.
Definition karecurrence.cpp:621
KAlarmCal::KARecurrence::Type
Type
The recurrence's period type.
Definition karecurrence.h:68
KAlarmCal::KARecurrence::MINUTELY
@ MINUTELY
at an hours/minutes interval
Definition karecurrence.h:70
KAlarmCal::KARecurrence::ANNUAL_DATE
@ ANNUAL_DATE
yearly, on a specified date in each of the specified months
Definition karecurrence.h:75
KAlarmCal::KARecurrence::DAILY
@ DAILY
daily
Definition karecurrence.h:71
KAlarmCal::KARecurrence::ANNUAL_POS
@ ANNUAL_POS
yearly, on specified weekdays in the specified weeks of the specified months
Definition karecurrence.h:76
KAlarmCal::KARecurrence::WEEKLY
@ WEEKLY
weekly, on specified weekdays
Definition karecurrence.h:72
KAlarmCal::KARecurrence::MONTHLY_DAY
@ MONTHLY_DAY
monthly, on a specified day of the month
Definition karecurrence.h:74
KAlarmCal::KARecurrence::MONTHLY_POS
@ MONTHLY_POS
monthly, on specified weekdays in a specified week of the month
Definition karecurrence.h:73
KAlarmCal::KARecurrence::NO_RECUR
@ NO_RECUR
does not recur
Definition karecurrence.h:69
KAlarmCal::KARecurrence::setStartDateTime
void setStartDateTime(const KDateTime &dt, bool dateOnly)
Set the recurrence start date/time, and optionally set it to all-day.
Definition karecurrence.cpp:611
KAlarmCal::KARecurrence::Feb29Type
Feb29Type
When annual February 29th recurrences should occur in non-leap years.
Definition karecurrence.h:80
KAlarmCal::KARecurrence::Feb29_None
@ Feb29_None
does not occur in non-leap years
Definition karecurrence.h:83
KAlarmCal::KARecurrence::getPreviousDateTime
KDateTime getPreviousDateTime(const KDateTime &afterDateTime) const
Get the previous time the recurrence occurred, strictly before a specified time.
Definition karecurrence.cpp:827
KAlarmCal::KARecurrence::recursOn
bool recursOn(const QDate &, const KDateTime::Spec &) const
Return whether the event will recur on the specified date.
Definition karecurrence.cpp:847
KAlarmCal::KARecurrence::getNextDateTime
KDateTime getNextDateTime(const KDateTime &preDateTime) const
Get the next time the recurrence occurs, strictly after a specified time.
Definition karecurrence.cpp:808
KAlarmCal::KARecurrence::type
Type type() const
Return the recurrence's period type.
Definition karecurrence.cpp:1237
KAlarmCal::KARecurrence::frequency
int frequency() const
Returns frequency of recurrence, in terms of the recurrence time period type.
Definition karecurrence.cpp:883
KAlarmCal::KARecurrence::init
bool init(KCalCore::RecurrenceRule::PeriodType t, int freq, int count, const KDateTime &start, const KDateTime &end)
Set up a KARecurrence from recurrence parameters.
Definition karecurrence.cpp:207
KAlarmCal::KARecurrence::longestInterval
KCalCore::Duration longestInterval() const
Return the longest interval between recurrences.
Definition karecurrence.cpp:992
KAlarmCal::KARecurrence::yearMonths
QList< int > yearMonths() const
Returns the months within a yearly recurrence.
Definition karecurrence.cpp:755
KAlarmCal::KARecurrence::regularInterval
KCalCore::Duration regularInterval() const
Return the interval between recurrences, if the interval between successive occurrences does not vary...
Definition karecurrence.cpp:1125
KAlarmCal::KARecurrence::duration
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
Definition karecurrence.cpp:893
KAlarmCal::Repetition
Represents a sub-repetition, defined by interval and repeat count.
Definition repetition.h:48
KAlarmCal::Repetition::set
void set(const KCalCore::Duration &interval, int count)
Initialises the instance with the specified interval and count.
Definition repetition.cpp:80
KAlarmCal::Repetition::nextRepeatCount
int nextRepeatCount(const KDateTime &from, const KDateTime &preDateTime) const
Find the repetition count for the next repetition after a specified time.
Definition repetition.cpp:154
KAlarmCal::Repetition::previousRepeatCount
int previousRepeatCount(const KDateTime &from, const KDateTime &afterDateTime) const
Find the repetition count for the last repetition before a specified time.
Definition repetition.cpp:161
KAlarmCal::Repetition::interval
KCalCore::Duration interval() const
Return the interval between repetitions.
Definition repetition.cpp:119
KAlarmCal::Repetition::duration
KCalCore::Duration duration() const
Return the overall duration of the repetition.
Definition repetition.cpp:124
KAlarmCal::Repetition::count
int count() const
Return the number of repetitions.
Definition repetition.cpp:114
KAlarmCal::Repetition::intervalDays
int intervalDays() const
Return the repetition interval in terms of days.
Definition repetition.cpp:139
KAlarmCal::Repetition::intervalSeconds
int intervalSeconds() const
Return the repetition interval in terms of seconds.
Definition repetition.cpp:149
KAlarmCal::Repetition::intervalMinutes
int intervalMinutes() const
Return the repetition interval in terms of minutes.
Definition repetition.cpp:144
KAlarmCal::Repetition::isDaily
bool isDaily() const
Check whether the repetition interval is in terms of days (as opposed to minutes).
Definition repetition.cpp:134
KCalCore::Alarm
KCalCore::Alarm::Ptr
QSharedPointer< Alarm > Ptr
KCalCore::Alarm::programFile
QString programFile() const
KCalCore::Alarm::snoozeTime
Duration snoozeTime() const
KCalCore::Alarm::setRepeatCount
void setRepeatCount(int alarmRepeatCount)
KCalCore::Alarm::setEnabled
void setEnabled(bool enable)
KCalCore::Alarm::setDisplayAlarm
void setDisplayAlarm(const QString &text=QString())
KCalCore::Alarm::Display
Display
KCalCore::Alarm::Email
Email
KCalCore::Alarm::Audio
Audio
KCalCore::Alarm::Procedure
Procedure
KCalCore::Alarm::Invalid
Invalid
KCalCore::Alarm::programArguments
QString programArguments() const
KCalCore::Alarm::setSnoozeTime
void setSnoozeTime(const Duration &alarmSnoozeTime)
KCalCore::Alarm::List
QVector< Ptr > List
KCalCore::Alarm::audioFile
QString audioFile() const
KCalCore::Alarm::setEmailAlarm
void setEmailAlarm(const QString &subject, const QString &text, const Person::List &addressees, const QStringList &attachments=QStringList())
KCalCore::Alarm::setAudioAlarm
void setAudioAlarm(const QString &audioFile=QString())
KCalCore::Alarm::text
QString text() const
KCalCore::Alarm::mailText
QString mailText() const
KCalCore::Alarm::setStartOffset
void setStartOffset(const Duration &offset)
KCalCore::Alarm::type
Type type() const
KCalCore::Alarm::repeatCount
int repeatCount() const
KCalCore::Alarm::setProcedureAlarm
void setProcedureAlarm(const QString &programFile, const QString &arguments=QString())
KCalCore::Calendar::Ptr
QSharedPointer< Calendar > Ptr
KCalCore::CustomProperties::setCustomProperty
void setCustomProperty(const QByteArray &app, const QByteArray &key, const QString &value)
KCalCore::CustomProperties::customProperty
QString customProperty(const QByteArray &app, const QByteArray &key) const
KCalCore::Duration
KCalCore::Duration::isDaily
bool isDaily() const
KCalCore::Duration::asDays
int asDays() const
KCalCore::Duration::value
int value() const
KCalCore::Duration::asSeconds
int asSeconds() const
KCalCore::Duration::Days
Days
KCalCore::Duration::Seconds
Seconds
KCalCore::Duration::end
KDateTime end(const KDateTime &start) const
KCalCore::Event
KCalCore::Event::Transparent
Transparent
KCalCore::Event::dtEnd
virtual KDateTime dtEnd() const
KCalCore::Event::Ptr
QSharedPointer< Event > Ptr
KCalCore::Event::List
QVector< Ptr > List
KCalCore::IncidenceBase::allDay
bool allDay() const
KCalCore::Incidence::customStatus
QString customStatus() const
KCalCore::Incidence::alarms
Alarm::List alarms() const
KCalCore::Incidence::recurrence
Recurrence * recurrence() const
KCalCore::Person
KCalCore::Person::List
QVector< Ptr > List
KCalCore::Person::email
QString email() const
KCalCore::Person::Ptr
QSharedPointer< Person > Ptr
KCalCore::Person::name
QString name() const
KCalCore::RecurrenceRule
KCalCore::RecurrenceRule::PeriodType
PeriodType
KCalCore::Recurrence
KCalCore::Recurrence::recurs
bool recurs() const
KCalCore::Recurrence::setMinutely
void setMinutely(int freq)
KCalCore::Recurrence::setDaily
void setDaily(int freq)
KCalCore::Recurrence::setDuration
void setDuration(int duration)
memorycalendar.h
KAlarmCal::CalEvent::type
Type type(const QString &mimeType)
Return the alarm Type for a mime type string.
Definition kacalendar.cpp:469
KAlarmCal::CalEvent::Type
Type
The category of an event, indicated by the middle part of its UID.
Definition kacalendar.h:156
KAlarmCal::CalEvent::DISPLAYING
@ DISPLAYING
the event is currently being displayed
Definition kacalendar.h:161
KAlarmCal::CalEvent::TEMPLATE
@ TEMPLATE
the event is an alarm template
Definition kacalendar.h:160
KAlarmCal::CalEvent::ACTIVE
@ ACTIVE
the event is currently active
Definition kacalendar.h:158
KAlarmCal::CalEvent::ARCHIVED
@ ARCHIVED
the event is archived
Definition kacalendar.h:159
KAlarmCal::CalEvent::EMPTY
@ EMPTY
the event has no alarms
Definition kacalendar.h:157
KAlarmCal::CalEvent::types
Types types(const QStringList &mimeTypes)
Return the alarm Types for a list of mime type strings.
Definition kacalendar.cpp:480
KAlarmCal::Identities::identityUoid
uint identityUoid(const QString &identityUoidOrName)
Fetch the uoid of an identity name or uoid string.
Definition identities.cpp:54
KAlarmCal::KACalendar::Current
@ Current
in current KAlarm format
Definition kacalendar.h:74
KAlarmCal::KACalendar::APPNAME
const QByteArray APPNAME
The application name ("KALARM") used in calendar properties.
KCalCore
KHolidays
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Wed Jan 24 2024 00:00:00 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KAlarm Library

Skip menu "KAlarm Library"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.14.10 API Reference

Skip menu "kdepimlibs-4.14.10 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal