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

Skip menu "kdepimlibs-4.11.3 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