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

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