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

KAlarm Library

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

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kldap
  • kmbox
  • kmime
  • kpimidentities
  • kpimtextedit
  • kresources
  • ktnef
  • kxmlrpcclient
  • microblog

Search



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