kalarm

alarmevent.cpp
1 /*
2  * alarmevent.cpp - represents calendar alarms and events
3  * Program: kalarm
4  * Copyright © 2001-2009 by David Jarvie <djarvie@kde.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 #include "kalarm.h"
22 
23 #include <stdlib.h>
24 #include <time.h>
25 #include <ctype.h>
26 #include <tqcolor.h>
27 #include <tqregexp.h>
28 
29 #include <tdelocale.h>
30 #include <kdebug.h>
31 
32 #include "alarmtext.h"
33 #include "functions.h"
34 #include "kalarmapp.h"
35 #include "kamail.h"
36 #include "preferences.h"
37 #include "alarmcalendar.h"
38 #include "alarmevent.h"
39 using namespace KCal;
40 
41 
42 const TQCString APPNAME("KALARM");
43 
44 // KAlarm version which first used the current calendar/event format.
45 // If this changes, KAEvent::convertKCalEvents() must be changed correspondingly.
46 // The string version is the KAlarm version string used in the calendar file.
47 TQString KAEvent::calVersionString() { return TQString::fromLatin1("1.5.0"); }
48 int KAEvent::calVersion() { return KAlarm::Version(1,5,0); }
49 
50 // Custom calendar properties.
51 // Note that all custom property names are prefixed with X-TDE-KALARM- in the calendar file.
52 // - Event properties
53 static const TQCString NEXT_RECUR_PROPERTY("NEXTRECUR"); // X-TDE-KALARM-NEXTRECUR property
54 static const TQCString REPEAT_PROPERTY("REPEAT"); // X-TDE-KALARM-REPEAT property
55 // - General alarm properties
56 static const TQCString TYPE_PROPERTY("TYPE"); // X-TDE-KALARM-TYPE property
57 static const TQString FILE_TYPE = TQString::fromLatin1("FILE");
58 static const TQString AT_LOGIN_TYPE = TQString::fromLatin1("LOGIN");
59 static const TQString REMINDER_TYPE = TQString::fromLatin1("REMINDER");
60 static const TQString REMINDER_ONCE_TYPE = TQString::fromLatin1("REMINDER_ONCE");
61 static const TQString ARCHIVE_REMINDER_ONCE_TYPE = TQString::fromLatin1("ONCE");
62 static const TQString TIME_DEFERRAL_TYPE = TQString::fromLatin1("DEFERRAL");
63 static const TQString DATE_DEFERRAL_TYPE = TQString::fromLatin1("DATE_DEFERRAL");
64 static const TQString DISPLAYING_TYPE = TQString::fromLatin1("DISPLAYING"); // used only in displaying calendar
65 static const TQString PRE_ACTION_TYPE = TQString::fromLatin1("PRE");
66 static const TQString POST_ACTION_TYPE = TQString::fromLatin1("POST");
67 static const TQCString NEXT_REPEAT_PROPERTY("NEXTREPEAT"); // X-TDE-KALARM-NEXTREPEAT property
68 // - Display alarm properties
69 static const TQCString FONT_COLOUR_PROPERTY("FONTCOLOR"); // X-TDE-KALARM-FONTCOLOR property
70 // - Email alarm properties
71 static const TQCString EMAIL_ID_PROPERTY("EMAILID"); // X-TDE-KALARM-EMAILID property
72 // - Audio alarm properties
73 static const TQCString VOLUME_PROPERTY("VOLUME"); // X-TDE-KALARM-VOLUME property
74 static const TQCString SPEAK_PROPERTY("SPEAK"); // X-TDE-KALARM-SPEAK property
75 
76 // Event categories
77 static const TQString DATE_ONLY_CATEGORY = TQString::fromLatin1("DATE");
78 static const TQString EMAIL_BCC_CATEGORY = TQString::fromLatin1("BCC");
79 static const TQString CONFIRM_ACK_CATEGORY = TQString::fromLatin1("ACKCONF");
80 static const TQString LATE_CANCEL_CATEGORY = TQString::fromLatin1("LATECANCEL;");
81 static const TQString AUTO_CLOSE_CATEGORY = TQString::fromLatin1("LATECLOSE;");
82 static const TQString TEMPL_AFTER_TIME_CATEGORY = TQString::fromLatin1("TMPLAFTTIME;");
83 static const TQString KMAIL_SERNUM_CATEGORY = TQString::fromLatin1("KMAIL:");
84 static const TQString KORGANIZER_CATEGORY = TQString::fromLatin1("KORG");
85 static const TQString DEFER_CATEGORY = TQString::fromLatin1("DEFER;");
86 static const TQString ARCHIVE_CATEGORY = TQString::fromLatin1("SAVE");
87 static const TQString ARCHIVE_CATEGORIES = TQString::fromLatin1("SAVE:");
88 static const TQString LOG_CATEGORY = TQString::fromLatin1("LOG:");
89 static const TQString xtermURL = TQString::fromLatin1("xterm:");
90 
91 // Event status strings
92 static const TQString DISABLED_STATUS = TQString::fromLatin1("DISABLED");
93 
94 static const TQString EXPIRED_UID = TQString::fromLatin1("-exp-");
95 static const TQString DISPLAYING_UID = TQString::fromLatin1("-disp-");
96 static const TQString TEMPLATE_UID = TQString::fromLatin1("-tmpl-");
97 static const TQString KORGANIZER_UID = TQString::fromLatin1("-korg-");
98 
99 struct AlarmData
100 {
101  const Alarm* alarm;
102  TQString cleanText; // text or audio file name
103  uint emailFromId;
104  EmailAddressList emailAddresses;
105  TQString emailSubject;
106  TQStringList emailAttachments;
107  TQFont font;
108  TQColor bgColour, fgColour;
109  float soundVolume;
110  float fadeVolume;
111  int fadeSeconds;
112  int startOffsetSecs;
113  bool speak;
114  KAAlarm::SubType type;
115  KAAlarmEventBase::Type action;
116  int displayingFlags;
117  bool defaultFont;
118  bool reminderOnceOnly;
119  bool isEmailText;
120  bool commandScript;
121  int repeatCount;
122  int repeatInterval;
123  int nextRepeat;
124 };
125 typedef TQMap<KAAlarm::SubType, AlarmData> AlarmMap;
126 
127 static void setProcedureAlarm(Alarm*, const TQString& commandLine);
128 
129 
130 /*=============================================================================
131 = Class KAEvent
132 = Corresponds to a KCal::Event instance.
133 =============================================================================*/
134 
135 inline void KAEvent::set_deferral(DeferType type)
136 {
137  if (type)
138  {
139  if (!mDeferral)
140  ++mAlarmCount;
141  }
142  else
143  {
144  if (mDeferral)
145  --mAlarmCount;
146  }
147  mDeferral = type;
148 }
149 
150 inline void KAEvent::set_reminder(int minutes)
151 {
152  if (minutes && !mReminderMinutes)
153  ++mAlarmCount;
154  else if (!minutes && mReminderMinutes)
155  --mAlarmCount;
156  mReminderMinutes = minutes;
157  mArchiveReminderMinutes = 0;
158 }
159 
160 inline void KAEvent::set_archiveReminder()
161 {
162  if (mReminderMinutes)
163  --mAlarmCount;
164  mArchiveReminderMinutes = mReminderMinutes;
165  mReminderMinutes = 0;
166 }
167 
168 
169 void KAEvent::copy(const KAEvent& event)
170 {
171  KAAlarmEventBase::copy(event);
172  mTemplateName = event.mTemplateName;
173  mAudioFile = event.mAudioFile;
174  mPreAction = event.mPreAction;
175  mPostAction = event.mPostAction;
176  mStartDateTime = event.mStartDateTime;
177  mSaveDateTime = event.mSaveDateTime;
178  mAtLoginDateTime = event.mAtLoginDateTime;
179  mDeferralTime = event.mDeferralTime;
180  mDisplayingTime = event.mDisplayingTime;
181  mDisplayingFlags = event.mDisplayingFlags;
182  mReminderMinutes = event.mReminderMinutes;
183  mArchiveReminderMinutes = event.mArchiveReminderMinutes;
184  mDeferDefaultMinutes = event.mDeferDefaultMinutes;
185  mRevision = event.mRevision;
186  mAlarmCount = event.mAlarmCount;
187  mDeferral = event.mDeferral;
188  mLogFile = event.mLogFile;
189  mCommandXterm = event.mCommandXterm;
190  mKMailSerialNumber = event.mKMailSerialNumber;
191  mCopyToKOrganizer = event.mCopyToKOrganizer;
192  mReminderOnceOnly = event.mReminderOnceOnly;
193  mMainExpired = event.mMainExpired;
194  mArchiveRepeatAtLogin = event.mArchiveRepeatAtLogin;
195  mArchive = event.mArchive;
196  mTemplateAfterTime = event.mTemplateAfterTime;
197  mEnabled = event.mEnabled;
198  mUpdated = event.mUpdated;
199  delete mRecurrence;
200  if (event.mRecurrence)
201  mRecurrence = new KARecurrence(*event.mRecurrence);
202  else
203  mRecurrence = 0;
204 }
205 
206 /******************************************************************************
207  * Initialise the KAEvent from a KCal::Event.
208  */
209 void KAEvent::set(const Event& event)
210 {
211  // Extract status from the event
212  mEventID = event.uid();
213  mRevision = event.revision();
214  mTemplateName = TQString();
215  mLogFile = TQString();
216  mTemplateAfterTime = -1;
217  mBeep = false;
218  mSpeak = false;
219  mEmailBcc = false;
220  mCommandXterm = false;
221  mCopyToKOrganizer = false;
222  mConfirmAck = false;
223  mArchive = false;
224  mReminderOnceOnly = false;
225  mAutoClose = false;
226  mArchiveRepeatAtLogin = false;
227  mArchiveReminderMinutes = 0;
228  mDeferDefaultMinutes = 0;
229  mLateCancel = 0;
230  mKMailSerialNumber = 0;
231  mBgColour = TQColor(255, 255, 255); // missing/invalid colour - return white background
232  mFgColour = TQColor(0, 0, 0); // and black foreground
233  mDefaultFont = true;
234  mEnabled = true;
235  clearRecur();
236  bool ok;
237  bool dateOnly = false;
238  const TQStringList cats = event.categories();
239  for (unsigned int i = 0; i < cats.count(); ++i)
240  {
241  if (cats[i] == DATE_ONLY_CATEGORY)
242  dateOnly = true;
243  else if (cats[i] == CONFIRM_ACK_CATEGORY)
244  mConfirmAck = true;
245  else if (cats[i] == EMAIL_BCC_CATEGORY)
246  mEmailBcc = true;
247  else if (cats[i] == ARCHIVE_CATEGORY)
248  mArchive = true;
249  else if (cats[i] == KORGANIZER_CATEGORY)
250  mCopyToKOrganizer = true;
251  else if (cats[i].startsWith(KMAIL_SERNUM_CATEGORY))
252  mKMailSerialNumber = cats[i].mid(KMAIL_SERNUM_CATEGORY.length()).toULong();
253  else if (cats[i].startsWith(LOG_CATEGORY))
254  {
255  TQString logUrl = cats[i].mid(LOG_CATEGORY.length());
256  if (logUrl == xtermURL)
257  mCommandXterm = true;
258  else
259  mLogFile = logUrl;
260  }
261  else if (cats[i].startsWith(ARCHIVE_CATEGORIES))
262  {
263  // It's the archive flag plus a reminder time and/or repeat-at-login flag
264  mArchive = true;
265  TQStringList list = TQStringList::split(';', cats[i].mid(ARCHIVE_CATEGORIES.length()));
266  for (unsigned int j = 0; j < list.count(); ++j)
267  {
268  if (list[j] == AT_LOGIN_TYPE)
269  mArchiveRepeatAtLogin = true;
270  else if (list[j] == ARCHIVE_REMINDER_ONCE_TYPE)
271  mReminderOnceOnly = true;
272  else
273  {
274  char ch;
275  const char* cat = list[j].latin1();
276  while ((ch = *cat) != 0 && (ch < '0' || ch > '9'))
277  ++cat;
278  if (ch)
279  {
280  mArchiveReminderMinutes = ch - '0';
281  while ((ch = *++cat) >= '0' && ch <= '9')
282  mArchiveReminderMinutes = mArchiveReminderMinutes * 10 + ch - '0';
283  switch (ch)
284  {
285  case 'M': break;
286  case 'H': mArchiveReminderMinutes *= 60; break;
287  case 'D': mArchiveReminderMinutes *= 1440; break;
288  }
289  }
290  }
291  }
292  }
293  else if (cats[i].startsWith(DEFER_CATEGORY))
294  {
295  mDeferDefaultMinutes = static_cast<int>(cats[i].mid(DEFER_CATEGORY.length()).toUInt(&ok));
296  if (!ok)
297  mDeferDefaultMinutes = 0; // invalid parameter
298  }
299  else if (cats[i].startsWith(TEMPL_AFTER_TIME_CATEGORY))
300  {
301  mTemplateAfterTime = static_cast<int>(cats[i].mid(TEMPL_AFTER_TIME_CATEGORY.length()).toUInt(&ok));
302  if (!ok)
303  mTemplateAfterTime = -1; // invalid parameter
304  }
305  else if (cats[i].startsWith(LATE_CANCEL_CATEGORY))
306  {
307  mLateCancel = static_cast<int>(cats[i].mid(LATE_CANCEL_CATEGORY.length()).toUInt(&ok));
308  if (!ok || !mLateCancel)
309  mLateCancel = 1; // invalid parameter defaults to 1 minute
310  }
311  else if (cats[i].startsWith(AUTO_CLOSE_CATEGORY))
312  {
313  mLateCancel = static_cast<int>(cats[i].mid(AUTO_CLOSE_CATEGORY.length()).toUInt(&ok));
314  if (!ok || !mLateCancel)
315  mLateCancel = 1; // invalid parameter defaults to 1 minute
316  mAutoClose = true;
317  }
318  }
319  TQString prop = event.customProperty(APPNAME, REPEAT_PROPERTY);
320  if (!prop.isEmpty())
321  {
322  // This property is used when the main alarm has expired
323  TQStringList list = TQStringList::split(':', prop);
324  if (list.count() >= 2)
325  {
326  int interval = static_cast<int>(list[0].toUInt());
327  int count = static_cast<int>(list[1].toUInt());
328  if (interval && count)
329  {
330  mRepeatInterval = interval;
331  mRepeatCount = count;
332  }
333  }
334  }
335  mNextMainDateTime = readDateTime(event, dateOnly, mStartDateTime);
336  mSaveDateTime = event.created();
337  if (uidStatus() == TEMPLATE)
338  mTemplateName = event.summary();
339  if (event.statusStr() == DISABLED_STATUS)
340  mEnabled = false;
341 
342  // Extract status from the event's alarms.
343  // First set up defaults.
344  mActionType = T_MESSAGE;
345  mMainExpired = true;
346  mRepeatAtLogin = false;
347  mDisplaying = false;
348  mRepeatSound = false;
349  mCommandScript = false;
350  mDeferral = NO_DEFERRAL;
351  mSoundVolume = -1;
352  mFadeVolume = -1;
353  mFadeSeconds = 0;
354  mReminderMinutes = 0;
355  mEmailFromIdentity = 0;
356  mText = "";
357  mAudioFile = "";
358  mPreAction = "";
359  mPostAction = "";
360  mEmailSubject = "";
361  mEmailAddresses.clear();
362  mEmailAttachments.clear();
363 
364  // Extract data from all the event's alarms and index the alarms by sequence number
365  AlarmMap alarmMap;
366  readAlarms(event, &alarmMap);
367 
368  // Incorporate the alarms' details into the overall event
369  mAlarmCount = 0; // initialise as invalid
370  DateTime alTime;
371  bool set = false;
372  bool isEmailText = false;
373  bool setDeferralTime = false;
374  Duration deferralOffset;
375  for (AlarmMap::ConstIterator it = alarmMap.begin(); it != alarmMap.end(); ++it)
376  {
377  const AlarmData& data = it.data();
378  DateTime dateTime = data.alarm->hasStartOffset() ? mNextMainDateTime.addSecs(data.alarm->startOffset().asSeconds()) : data.alarm->time();
379  switch (data.type)
380  {
381  case KAAlarm::MAIN__ALARM:
382  mMainExpired = false;
383  alTime = dateTime;
384  alTime.setDateOnly(mStartDateTime.isDateOnly());
385  if (data.repeatCount && data.repeatInterval)
386  {
387  mRepeatInterval = data.repeatInterval; // values may be adjusted in setRecurrence()
388  mRepeatCount = data.repeatCount;
389  mNextRepeat = data.nextRepeat;
390  }
391  break;
392  case KAAlarm::AT_LOGIN__ALARM:
393  mRepeatAtLogin = true;
394  mAtLoginDateTime = dateTime.rawDateTime();
395  alTime = mAtLoginDateTime;
396  break;
397  case KAAlarm::REMINDER__ALARM:
398  mReminderMinutes = -(data.startOffsetSecs / 60);
399  if (mReminderMinutes)
400  mArchiveReminderMinutes = 0;
401  break;
402  case KAAlarm::DEFERRED_REMINDER_DATE__ALARM:
403  case KAAlarm::DEFERRED_DATE__ALARM:
404  mDeferral = (data.type == KAAlarm::DEFERRED_REMINDER_DATE__ALARM) ? REMINDER_DEFERRAL : NORMAL_DEFERRAL;
405  mDeferralTime = dateTime;
406  mDeferralTime.setDateOnly(true);
407  if (data.alarm->hasStartOffset())
408  deferralOffset = data.alarm->startOffset();
409  break;
410  case KAAlarm::DEFERRED_REMINDER_TIME__ALARM:
411  case KAAlarm::DEFERRED_TIME__ALARM:
412  mDeferral = (data.type == KAAlarm::DEFERRED_REMINDER_TIME__ALARM) ? REMINDER_DEFERRAL : NORMAL_DEFERRAL;
413  mDeferralTime = dateTime;
414  if (data.alarm->hasStartOffset())
415  deferralOffset = data.alarm->startOffset();
416  break;
417  case KAAlarm::DISPLAYING__ALARM:
418  {
419  mDisplaying = true;
420  mDisplayingFlags = data.displayingFlags;
421  bool dateOnly = (mDisplayingFlags & DEFERRAL) ? !(mDisplayingFlags & TIMED_FLAG)
422  : mStartDateTime.isDateOnly();
423  mDisplayingTime = dateTime;
424  mDisplayingTime.setDateOnly(dateOnly);
425  alTime = mDisplayingTime;
426  break;
427  }
428  case KAAlarm::AUDIO__ALARM:
429  mAudioFile = data.cleanText;
430  mSpeak = data.speak && mAudioFile.isEmpty();
431  mBeep = !mSpeak && mAudioFile.isEmpty();
432  mSoundVolume = (!mBeep && !mSpeak) ? data.soundVolume : -1;
433  mFadeVolume = (mSoundVolume >= 0 && data.fadeSeconds > 0) ? data.fadeVolume : -1;
434  mFadeSeconds = (mFadeVolume >= 0) ? data.fadeSeconds : 0;
435  mRepeatSound = (!mBeep && !mSpeak) && (data.repeatCount < 0);
436  break;
437  case KAAlarm::PRE_ACTION__ALARM:
438  mPreAction = data.cleanText;
439  break;
440  case KAAlarm::POST_ACTION__ALARM:
441  mPostAction = data.cleanText;
442  break;
443  case KAAlarm::INVALID__ALARM:
444  default:
445  break;
446  }
447 
448  if (data.reminderOnceOnly)
449  mReminderOnceOnly = true;
450  bool noSetNextTime = false;
451  switch (data.type)
452  {
453  case KAAlarm::DEFERRED_REMINDER_DATE__ALARM:
454  case KAAlarm::DEFERRED_DATE__ALARM:
455  case KAAlarm::DEFERRED_REMINDER_TIME__ALARM:
456  case KAAlarm::DEFERRED_TIME__ALARM:
457  if (!set)
458  {
459  // The recurrence has to be evaluated before we can
460  // calculate the time of a deferral alarm.
461  setDeferralTime = true;
462  noSetNextTime = true;
463  }
464  // fall through to AT_LOGIN__ALARM etc.
465  case KAAlarm::AT_LOGIN__ALARM:
466  case KAAlarm::REMINDER__ALARM:
467  case KAAlarm::DISPLAYING__ALARM:
468  if (!set && !noSetNextTime)
469  mNextMainDateTime = alTime;
470  // fall through to MAIN__ALARM
471  case KAAlarm::MAIN__ALARM:
472  // Ensure that the basic fields are set up even if there is no main
473  // alarm in the event (if it has expired and then been deferred)
474  if (!set)
475  {
476  mActionType = data.action;
477  mText = (mActionType == T_COMMAND) ? data.cleanText.stripWhiteSpace() : data.cleanText;
478  switch (data.action)
479  {
480  case T_MESSAGE:
481  mFont = data.font;
482  mDefaultFont = data.defaultFont;
483  if (data.isEmailText)
484  isEmailText = true;
485  // fall through to T_FILE
486  case T_FILE:
487  mBgColour = data.bgColour;
488  mFgColour = data.fgColour;
489  break;
490  case T_COMMAND:
491  mCommandScript = data.commandScript;
492  break;
493  case T_EMAIL:
494  mEmailFromIdentity = data.emailFromId;
495  mEmailAddresses = data.emailAddresses;
496  mEmailSubject = data.emailSubject;
497  mEmailAttachments = data.emailAttachments;
498  break;
499  default:
500  break;
501  }
502  set = true;
503  }
504  if (data.action == T_FILE && mActionType == T_MESSAGE)
505  mActionType = T_FILE;
506  ++mAlarmCount;
507  break;
508  case KAAlarm::AUDIO__ALARM:
509  case KAAlarm::PRE_ACTION__ALARM:
510  case KAAlarm::POST_ACTION__ALARM:
511  case KAAlarm::INVALID__ALARM:
512  default:
513  break;
514  }
515  }
516  if (!isEmailText)
517  mKMailSerialNumber = 0;
518  if (mRepeatAtLogin)
519  mArchiveRepeatAtLogin = false;
520 
521  Recurrence* recur = event.recurrence();
522  if (recur && recur->doesRecur())
523  {
524  int nextRepeat = mNextRepeat; // setRecurrence() clears mNextRepeat
525  setRecurrence(*recur);
526  if (nextRepeat <= mRepeatCount)
527  mNextRepeat = nextRepeat;
528  }
529  else
530  checkRepetition();
531 
532  if (mMainExpired && deferralOffset.asSeconds() && checkRecur() != KARecurrence::NO_RECUR)
533  {
534  // Adjust the deferral time for an expired recurrence, since the
535  // offset is relative to the first actual occurrence.
536  DateTime dt = mRecurrence->getNextDateTime(mStartDateTime.dateTime().addDays(-1));
537  dt.setDateOnly(mStartDateTime.isDateOnly());
538  if (mDeferralTime.isDateOnly())
539  {
540  mDeferralTime = dt.addSecs(deferralOffset.asSeconds());
541  mDeferralTime.setDateOnly(true);
542  }
543  else
544  mDeferralTime = deferralOffset.end(dt.dateTime());
545  }
546  if (mDeferral)
547  {
548  if (mNextMainDateTime == mDeferralTime)
549  mDeferral = CANCEL_DEFERRAL; // it's a cancelled deferral
550  if (setDeferralTime)
551  mNextMainDateTime = mDeferralTime;
552  }
553 
554  mUpdated = false;
555 }
556 
557 /******************************************************************************
558 * Fetch the start and next date/time for a KCal::Event.
559 * Reply = next main date/time.
560 */
561 DateTime KAEvent::readDateTime(const Event& event, bool dateOnly, DateTime& start)
562 {
563  start.set(event.dtStart(), dateOnly);
564  DateTime next = start;
565  TQString prop = event.customProperty(APPNAME, NEXT_RECUR_PROPERTY);
566  if (prop.length() >= 8)
567  {
568  // The next due recurrence time is specified
569  TQDate d(prop.left(4).toInt(), prop.mid(4,2).toInt(), prop.mid(6,2).toInt());
570  if (d.isValid())
571  {
572  if (dateOnly && prop.length() == 8)
573  next = d;
574  else if (!dateOnly && prop.length() == 15 && prop[8] == TQChar('T'))
575  {
576  TQTime t(prop.mid(9,2).toInt(), prop.mid(11,2).toInt(), prop.mid(13,2).toInt());
577  if (t.isValid())
578  next = TQDateTime(d, t);
579  }
580  }
581  }
582  return next;
583 }
584 
585 /******************************************************************************
586  * Parse the alarms for a KCal::Event.
587  * Reply = map of alarm data, indexed by KAAlarm::Type
588  */
589 void KAEvent::readAlarms(const Event& event, void* almap)
590 {
591  AlarmMap* alarmMap = (AlarmMap*)almap;
592  Alarm::List alarms = event.alarms();
593  for (Alarm::List::ConstIterator it = alarms.begin(); it != alarms.end(); ++it)
594  {
595  // Parse the next alarm's text
596  AlarmData data;
597  readAlarm(**it, data);
598  if (data.type != KAAlarm::INVALID__ALARM)
599  alarmMap->insert(data.type, data);
600  }
601 }
602 
603 /******************************************************************************
604  * Parse a KCal::Alarm.
605  * Reply = alarm ID (sequence number)
606  */
607 void KAEvent::readAlarm(const Alarm& alarm, AlarmData& data)
608 {
609  // Parse the next alarm's text
610  data.alarm = &alarm;
611  data.startOffsetSecs = alarm.startOffset().asSeconds(); // can have start offset but no valid date/time (e.g. reminder in template)
612  data.displayingFlags = 0;
613  data.isEmailText = false;
614  data.nextRepeat = 0;
615  data.repeatInterval = alarm.snoozeTime();
616  data.repeatCount = alarm.repeatCount();
617  if (data.repeatCount)
618  {
619  bool ok;
620  TQString property = alarm.customProperty(APPNAME, NEXT_REPEAT_PROPERTY);
621  int n = static_cast<int>(property.toUInt(&ok));
622  if (ok)
623  data.nextRepeat = n;
624  }
625  switch (alarm.type())
626  {
627  case Alarm::Procedure:
628  data.action = T_COMMAND;
629  data.cleanText = alarm.programFile();
630  data.commandScript = data.cleanText.isEmpty(); // blank command indicates a script
631  if (!alarm.programArguments().isEmpty())
632  {
633  if (!data.commandScript)
634  data.cleanText += ' ';
635  data.cleanText += alarm.programArguments();
636  }
637  break;
638  case Alarm::Email:
639  data.action = T_EMAIL;
640  data.emailFromId = alarm.customProperty(APPNAME, EMAIL_ID_PROPERTY).toUInt();
641  data.emailAddresses = alarm.mailAddresses();
642  data.emailSubject = alarm.mailSubject();
643  data.emailAttachments = alarm.mailAttachments();
644  data.cleanText = alarm.mailText();
645  break;
646  case Alarm::Display:
647  {
648  data.action = T_MESSAGE;
649  data.cleanText = AlarmText::fromCalendarText(alarm.text(), data.isEmailText);
650  TQString property = alarm.customProperty(APPNAME, FONT_COLOUR_PROPERTY);
651  TQStringList list = TQStringList::split(TQChar(';'), property, true);
652  data.bgColour = TQColor(255, 255, 255); // white
653  data.fgColour = TQColor(0, 0, 0); // black
654  int n = list.count();
655  if (n > 0)
656  {
657  if (!list[0].isEmpty())
658  {
659  TQColor c(list[0]);
660  if (c.isValid())
661  data.bgColour = c;
662  }
663  if (n > 1 && !list[1].isEmpty())
664  {
665  TQColor c(list[1]);
666  if (c.isValid())
667  data.fgColour = c;
668  }
669  }
670  data.defaultFont = (n <= 2 || list[2].isEmpty());
671  if (!data.defaultFont)
672  data.font.fromString(list[2]);
673  break;
674  }
675  case Alarm::Audio:
676  {
677  data.action = T_AUDIO;
678  data.cleanText = alarm.audioFile();
679  data.type = KAAlarm::AUDIO__ALARM;
680  data.soundVolume = -1;
681  data.fadeVolume = -1;
682  data.fadeSeconds = 0;
683  data.speak = !alarm.customProperty(APPNAME, SPEAK_PROPERTY).isNull();
684  TQString property = alarm.customProperty(APPNAME, VOLUME_PROPERTY);
685  if (!property.isEmpty())
686  {
687  bool ok;
688  float fadeVolume;
689  int fadeSecs = 0;
690  TQStringList list = TQStringList::split(TQChar(';'), property, true);
691  data.soundVolume = list[0].toFloat(&ok);
692  if (!ok)
693  data.soundVolume = -1;
694  if (data.soundVolume >= 0 && list.count() >= 3)
695  {
696  fadeVolume = list[1].toFloat(&ok);
697  if (ok)
698  fadeSecs = static_cast<int>(list[2].toUInt(&ok));
699  if (ok && fadeVolume >= 0 && fadeSecs > 0)
700  {
701  data.fadeVolume = fadeVolume;
702  data.fadeSeconds = fadeSecs;
703  }
704  }
705  }
706  return;
707  }
708  case Alarm::Invalid:
709  data.type = KAAlarm::INVALID__ALARM;
710  return;
711  }
712 
713  bool atLogin = false;
714  bool reminder = false;
715  bool deferral = false;
716  bool dateDeferral = false;
717  data.reminderOnceOnly = false;
718  data.type = KAAlarm::MAIN__ALARM;
719  TQString property = alarm.customProperty(APPNAME, TYPE_PROPERTY);
720  TQStringList types = TQStringList::split(TQChar(','), property);
721  for (unsigned int i = 0; i < types.count(); ++i)
722  {
723  TQString type = types[i];
724  if (type == AT_LOGIN_TYPE)
725  atLogin = true;
726  else if (type == FILE_TYPE && data.action == T_MESSAGE)
727  data.action = T_FILE;
728  else if (type == REMINDER_TYPE)
729  reminder = true;
730  else if (type == REMINDER_ONCE_TYPE)
731  reminder = data.reminderOnceOnly = true;
732  else if (type == TIME_DEFERRAL_TYPE)
733  deferral = true;
734  else if (type == DATE_DEFERRAL_TYPE)
735  dateDeferral = deferral = true;
736  else if (type == DISPLAYING_TYPE)
737  data.type = KAAlarm::DISPLAYING__ALARM;
738  else if (type == PRE_ACTION_TYPE && data.action == T_COMMAND)
739  data.type = KAAlarm::PRE_ACTION__ALARM;
740  else if (type == POST_ACTION_TYPE && data.action == T_COMMAND)
741  data.type = KAAlarm::POST_ACTION__ALARM;
742  }
743 
744  if (reminder)
745  {
746  if (data.type == KAAlarm::MAIN__ALARM)
747  data.type = dateDeferral ? KAAlarm::DEFERRED_REMINDER_DATE__ALARM
748  : deferral ? KAAlarm::DEFERRED_REMINDER_TIME__ALARM : KAAlarm::REMINDER__ALARM;
749  else if (data.type == KAAlarm::DISPLAYING__ALARM)
750  data.displayingFlags = dateDeferral ? REMINDER | DATE_DEFERRAL
751  : deferral ? REMINDER | TIME_DEFERRAL : REMINDER;
752  }
753  else if (deferral)
754  {
755  if (data.type == KAAlarm::MAIN__ALARM)
756  data.type = dateDeferral ? KAAlarm::DEFERRED_DATE__ALARM : KAAlarm::DEFERRED_TIME__ALARM;
757  else if (data.type == KAAlarm::DISPLAYING__ALARM)
758  data.displayingFlags = dateDeferral ? DATE_DEFERRAL : TIME_DEFERRAL;
759  }
760  if (atLogin)
761  {
762  if (data.type == KAAlarm::MAIN__ALARM)
763  data.type = KAAlarm::AT_LOGIN__ALARM;
764  else if (data.type == KAAlarm::DISPLAYING__ALARM)
765  data.displayingFlags = REPEAT_AT_LOGIN;
766  }
767 //kdDebug(5950)<<"ReadAlarm(): text="<<alarm.text()<<", time="<<alarm.time().toString()<<", valid time="<<alarm.time().isValid()<<endl;
768 }
769 
770 /******************************************************************************
771  * Initialise the KAEvent with the specified parameters.
772  */
773 void KAEvent::set(const TQDateTime& dateTime, const TQString& text, const TQColor& bg, const TQColor& fg,
774  const TQFont& font, Action action, int lateCancel, int flags)
775 {
776  clearRecur();
777  mStartDateTime.set(dateTime, flags & ANY_TIME);
778  mNextMainDateTime = mStartDateTime;
779  switch (action)
780  {
781  case MESSAGE:
782  case FILE:
783  case COMMAND:
784  case EMAIL:
785  mActionType = (KAAlarmEventBase::Type)action;
786  break;
787  default:
788  mActionType = T_MESSAGE;
789  break;
790  }
791  mText = (mActionType == T_COMMAND) ? text.stripWhiteSpace() : text;
792  mEventID = TQString();
793  mTemplateName = TQString();
794  mPreAction = TQString();
795  mPostAction = TQString();
796  mAudioFile = "";
797  mSoundVolume = -1;
798  mFadeVolume = -1;
799  mTemplateAfterTime = -1;
800  mFadeSeconds = 0;
801  mBgColour = bg;
802  mFgColour = fg;
803  mFont = font;
804  mAlarmCount = 1;
805  mLateCancel = lateCancel; // do this before setting flags
806  mDeferral = NO_DEFERRAL; // do this before setting flags
807 
808  KAAlarmEventBase::set(flags & ~READ_ONLY_FLAGS);
809  mStartDateTime.setDateOnly(flags & ANY_TIME);
810  set_deferral((flags & DEFERRAL) ? NORMAL_DEFERRAL : NO_DEFERRAL);
811  mCommandXterm = flags & EXEC_IN_XTERM;
812  mCopyToKOrganizer = flags & COPY_KORGANIZER;
813  mEnabled = !(flags & DISABLED);
814 
815  mKMailSerialNumber = 0;
816  mReminderMinutes = 0;
817  mArchiveReminderMinutes = 0;
818  mDeferDefaultMinutes = 0;
819  mArchiveRepeatAtLogin = false;
820  mReminderOnceOnly = false;
821  mDisplaying = false;
822  mMainExpired = false;
823  mArchive = false;
824  mUpdated = false;
825 }
826 
827 void KAEvent::setLogFile(const TQString& logfile)
828 {
829  mLogFile = logfile;
830  if (!logfile.isEmpty())
831  mCommandXterm = false;
832 }
833 
834 void KAEvent::setEmail(uint from, const EmailAddressList& addresses, const TQString& subject, const TQStringList& attachments)
835 {
836  mEmailFromIdentity = from;
837  mEmailAddresses = addresses;
838  mEmailSubject = subject;
839  mEmailAttachments = attachments;
840 }
841 
842 void KAEvent::setAudioFile(const TQString& filename, float volume, float fadeVolume, int fadeSeconds)
843 {
844  mAudioFile = filename;
845  mSoundVolume = filename.isEmpty() ? -1 : volume;
846  if (mSoundVolume >= 0)
847  {
848  mFadeVolume = (fadeSeconds > 0) ? fadeVolume : -1;
849  mFadeSeconds = (mFadeVolume >= 0) ? fadeSeconds : 0;
850  }
851  else
852  {
853  mFadeVolume = -1;
854  mFadeSeconds = 0;
855  }
856  mUpdated = true;
857 }
858 
859 void KAEvent::setReminder(int minutes, bool onceOnly)
860 {
861  if (minutes != mReminderMinutes)
862  {
863  set_reminder(minutes);
864  mReminderOnceOnly = onceOnly;
865  mUpdated = true;
866  }
867 }
868 
869 /******************************************************************************
870  * Return the time of the next scheduled occurrence of the event.
871  * Reminders and deferred reminders can optionally be ignored.
872  */
873 DateTime KAEvent::displayDateTime() const
874 {
875  DateTime dt = mainDateTime(true);
876  if (mDeferral > 0 && mDeferral != REMINDER_DEFERRAL)
877  {
878  if (mMainExpired)
879  return mDeferralTime;
880  return TQMIN(mDeferralTime, dt);
881  }
882  return dt;
883 }
884 
885 /******************************************************************************
886  * Convert a unique ID to indicate that the event is in a specified calendar file.
887  */
888 TQString KAEvent::uid(const TQString& id, Status status)
889 {
890  TQString result = id;
891  Status oldStatus;
892  int i, len;
893  if ((i = result.find(EXPIRED_UID)) > 0)
894  {
895  oldStatus = EXPIRED;
896  len = EXPIRED_UID.length();
897  }
898  else if ((i = result.find(DISPLAYING_UID)) > 0)
899  {
900  oldStatus = DISPLAYING;
901  len = DISPLAYING_UID.length();
902  }
903  else if ((i = result.find(TEMPLATE_UID)) > 0)
904  {
905  oldStatus = TEMPLATE;
906  len = TEMPLATE_UID.length();
907  }
908  else if ((i = result.find(KORGANIZER_UID)) > 0)
909  {
910  oldStatus = KORGANIZER;
911  len = KORGANIZER_UID.length();
912  }
913  else
914  {
915  oldStatus = ACTIVE;
916  i = result.findRev('-');
917  len = 1;
918  }
919  if (status != oldStatus && i > 0)
920  {
921  TQString part;
922  switch (status)
923  {
924  case ACTIVE: part = "-"; break;
925  case EXPIRED: part = EXPIRED_UID; break;
926  case DISPLAYING: part = DISPLAYING_UID; break;
927  case TEMPLATE: part = TEMPLATE_UID; break;
928  case KORGANIZER: part = KORGANIZER_UID; break;
929  }
930  result.replace(i, len, part);
931  }
932  return result;
933 }
934 
935 /******************************************************************************
936  * Get the calendar type for a unique ID.
937  */
938 KAEvent::Status KAEvent::uidStatus(const TQString& uid)
939 {
940  if (uid.find(EXPIRED_UID) > 0)
941  return EXPIRED;
942  if (uid.find(DISPLAYING_UID) > 0)
943  return DISPLAYING;
944  if (uid.find(TEMPLATE_UID) > 0)
945  return TEMPLATE;
946  if (uid.find(KORGANIZER_UID) > 0)
947  return KORGANIZER;
948  return ACTIVE;
949 }
950 
951 int KAEvent::flags() const
952 {
953  return KAAlarmEventBase::flags()
954  | (mStartDateTime.isDateOnly() ? ANY_TIME : 0)
955  | (mDeferral > 0 ? DEFERRAL : 0)
956  | (mCommandXterm ? EXEC_IN_XTERM : 0)
957  | (mCopyToKOrganizer ? COPY_KORGANIZER : 0)
958  | (mEnabled ? 0 : DISABLED);
959 }
960 
961 /******************************************************************************
962  * Create a new Event from the KAEvent data.
963  */
964 Event* KAEvent::event() const
965 {
966  KCal::Event* ev = new KCal::Event;
967  ev->setUid(mEventID);
968  updateKCalEvent(*ev, false);
969  return ev;
970 }
971 
972 /******************************************************************************
973  * Update an existing KCal::Event with the KAEvent data.
974  * If 'original' is true, the event start date/time is adjusted to its original
975  * value instead of its next occurrence, and the expired main alarm is
976  * reinstated.
977  */
978 bool KAEvent::updateKCalEvent(Event& ev, bool checkUid, bool original, bool cancelCancelledDefer) const
979 {
980  if ((checkUid && !mEventID.isEmpty() && mEventID != ev.uid())
981  || (!mAlarmCount && (!original || !mMainExpired)))
982  return false;
983 
984  checkRecur(); // ensure recurrence/repetition data is consistent
985  bool readOnly = ev.isReadOnly();
986  ev.setReadOnly(false);
987  ev.setTransparency(Event::Transparent);
988 
989  // Set up event-specific data
990 
991  // Set up custom properties.
992  ev.removeCustomProperty(APPNAME, NEXT_RECUR_PROPERTY);
993  ev.removeCustomProperty(APPNAME, REPEAT_PROPERTY);
994 
995  TQStringList cats;
996  if (mStartDateTime.isDateOnly())
997  cats.append(DATE_ONLY_CATEGORY);
998  if (mConfirmAck)
999  cats.append(CONFIRM_ACK_CATEGORY);
1000  if (mEmailBcc)
1001  cats.append(EMAIL_BCC_CATEGORY);
1002  if (mKMailSerialNumber)
1003  cats.append(TQString("%1%2").arg(KMAIL_SERNUM_CATEGORY).arg(mKMailSerialNumber));
1004  if (mCopyToKOrganizer)
1005  cats.append(KORGANIZER_CATEGORY);
1006  if (mCommandXterm)
1007  cats.append(LOG_CATEGORY + xtermURL);
1008  else if (!mLogFile.isEmpty())
1009  cats.append(LOG_CATEGORY + mLogFile);
1010  if (mLateCancel)
1011  cats.append(TQString("%1%2").arg(mAutoClose ? AUTO_CLOSE_CATEGORY : LATE_CANCEL_CATEGORY).arg(mLateCancel));
1012  if (mDeferDefaultMinutes)
1013  cats.append(TQString("%1%2").arg(DEFER_CATEGORY).arg(mDeferDefaultMinutes));
1014  if (!mTemplateName.isEmpty() && mTemplateAfterTime >= 0)
1015  cats.append(TQString("%1%2").arg(TEMPL_AFTER_TIME_CATEGORY).arg(mTemplateAfterTime));
1016  if (mArchive && !original)
1017  {
1018  TQStringList params;
1019  if (mArchiveReminderMinutes)
1020  {
1021  if (mReminderOnceOnly)
1022  params += ARCHIVE_REMINDER_ONCE_TYPE;
1023  char unit = 'M';
1024  int count = mArchiveReminderMinutes;
1025  if (count % 1440 == 0)
1026  {
1027  unit = 'D';
1028  count /= 1440;
1029  }
1030  else if (count % 60 == 0)
1031  {
1032  unit = 'H';
1033  count /= 60;
1034  }
1035  params += TQString("%1%2").arg(count).arg(unit);
1036  }
1037  if (mArchiveRepeatAtLogin)
1038  params += AT_LOGIN_TYPE;
1039  if (params.count() > 0)
1040  {
1041  TQString cat = ARCHIVE_CATEGORIES;
1042  cat += params.join(TQString::fromLatin1(";"));
1043  cats.append(cat);
1044  }
1045  else
1046  cats.append(ARCHIVE_CATEGORY);
1047  }
1048  ev.setCategories(cats);
1049  ev.setCustomStatus(mEnabled ? TQString() : DISABLED_STATUS);
1050  ev.setRevision(mRevision);
1051  ev.clearAlarms();
1052 
1053  // Always set DTSTART as date/time, since alarm times can only be specified
1054  // in local time (instead of UTC) if they are relative to a DTSTART or DTEND
1055  // which is also specified in local time. Instead of calling setFloats() to
1056  // indicate a date-only event, the category "DATE" is included.
1057  ev.setDtStart(mStartDateTime.dateTime());
1058  ev.setFloats(false);
1059  ev.setHasEndDate(false);
1060 
1061  DateTime dtMain = original ? mStartDateTime : mNextMainDateTime;
1062  int ancillaryType = 0; // 0 = invalid, 1 = time, 2 = offset
1063  DateTime ancillaryTime; // time for ancillary alarms (audio, pre-action, etc)
1064  int ancillaryOffset = 0; // start offset for ancillary alarms
1065  if (!mMainExpired || original)
1066  {
1067  /* The alarm offset must always be zero for the main alarm. To determine
1068  * which recurrence is due, the property X-TDE-KALARM_NEXTRECUR is used.
1069  * If the alarm offset was non-zero, exception dates and rules would not
1070  * work since they apply to the event time, not the alarm time.
1071  */
1072  if (!original && checkRecur() != KARecurrence::NO_RECUR)
1073  {
1074  TQDateTime dt = mNextMainDateTime.dateTime();
1075  ev.setCustomProperty(APPNAME, NEXT_RECUR_PROPERTY,
1076  dt.toString(mNextMainDateTime.isDateOnly() ? "yyyyMMdd" : "yyyyMMddThhmmss"));
1077  }
1078  // Add the main alarm
1079  initKCalAlarm(ev, 0, TQStringList(), KAAlarm::MAIN_ALARM);
1080  ancillaryOffset = 0;
1081  ancillaryType = dtMain.isValid() ? 2 : 0;
1082  }
1083  else if (mRepeatCount && mRepeatInterval)
1084  {
1085  // Alarm repetition is normally held in the main alarm, but since
1086  // the main alarm has expired, store in a custom property.
1087  TQString param = TQString("%1:%2").arg(mRepeatInterval).arg(mRepeatCount);
1088  ev.setCustomProperty(APPNAME, REPEAT_PROPERTY, param);
1089  }
1090 
1091  // Add subsidiary alarms
1092  if (mRepeatAtLogin || (mArchiveRepeatAtLogin && original))
1093  {
1094  DateTime dtl;
1095  if (mArchiveRepeatAtLogin)
1096  dtl = mStartDateTime.dateTime().addDays(-1);
1097  else if (mAtLoginDateTime.isValid())
1098  dtl = mAtLoginDateTime;
1099  else if (mStartDateTime.isDateOnly())
1100  dtl = TQDate::currentDate().addDays(-1);
1101  else
1102  dtl = TQDateTime::currentDateTime();
1103  initKCalAlarm(ev, dtl, AT_LOGIN_TYPE);
1104  if (!ancillaryType && dtl.isValid())
1105  {
1106  ancillaryTime = dtl;
1107  ancillaryType = 1;
1108  }
1109  }
1110  if (mReminderMinutes || (mArchiveReminderMinutes && original))
1111  {
1112  int minutes = mReminderMinutes ? mReminderMinutes : mArchiveReminderMinutes;
1113  initKCalAlarm(ev, -minutes * 60, TQStringList(mReminderOnceOnly ? REMINDER_ONCE_TYPE : REMINDER_TYPE));
1114  if (!ancillaryType)
1115  {
1116  ancillaryOffset = -minutes * 60;
1117  ancillaryType = 2;
1118  }
1119  }
1120  if (mDeferral > 0 || (mDeferral == CANCEL_DEFERRAL && !cancelCancelledDefer))
1121  {
1122  DateTime nextDateTime = mNextMainDateTime;
1123  if (mMainExpired)
1124  {
1125  if (checkRecur() == KARecurrence::NO_RECUR)
1126  nextDateTime = mStartDateTime;
1127  else if (!original)
1128  {
1129  // It's a deferral of an expired recurrence.
1130  // Need to ensure that the alarm offset is to an occurrence
1131  // which isn't excluded by an exception - otherwise, it will
1132  // never be triggered. So choose the first recurrence which
1133  // isn't an exception.
1134  nextDateTime = mRecurrence->getNextDateTime(mStartDateTime.dateTime().addDays(-1));
1135  nextDateTime.setDateOnly(mStartDateTime.isDateOnly());
1136  }
1137  }
1138  int startOffset;
1139  TQStringList list;
1140  if (mDeferralTime.isDateOnly())
1141  {
1142  startOffset = nextDateTime.secsTo(mDeferralTime.dateTime());
1143  list += DATE_DEFERRAL_TYPE;
1144  }
1145  else
1146  {
1147  startOffset = nextDateTime.dateTime().secsTo(mDeferralTime.dateTime());
1148  list += TIME_DEFERRAL_TYPE;
1149  }
1150  if (mDeferral == REMINDER_DEFERRAL)
1151  list += mReminderOnceOnly ? REMINDER_ONCE_TYPE : REMINDER_TYPE;
1152  initKCalAlarm(ev, startOffset, list);
1153  if (!ancillaryType && mDeferralTime.isValid())
1154  {
1155  ancillaryOffset = startOffset;
1156  ancillaryType = 2;
1157  }
1158  }
1159  if (!mTemplateName.isEmpty())
1160  ev.setSummary(mTemplateName);
1161  else if (mDisplaying)
1162  {
1163  TQStringList list(DISPLAYING_TYPE);
1164  if (mDisplayingFlags & REPEAT_AT_LOGIN)
1165  list += AT_LOGIN_TYPE;
1166  else if (mDisplayingFlags & DEFERRAL)
1167  {
1168  if (mDisplayingFlags & TIMED_FLAG)
1169  list += TIME_DEFERRAL_TYPE;
1170  else
1171  list += DATE_DEFERRAL_TYPE;
1172  }
1173  if (mDisplayingFlags & REMINDER)
1174  list += mReminderOnceOnly ? REMINDER_ONCE_TYPE : REMINDER_TYPE;
1175  initKCalAlarm(ev, mDisplayingTime, list);
1176  if (!ancillaryType && mDisplayingTime.isValid())
1177  {
1178  ancillaryTime = mDisplayingTime;
1179  ancillaryType = 1;
1180  }
1181  }
1182  if (mBeep || mSpeak || !mAudioFile.isEmpty())
1183  {
1184  // A sound is specified
1185  if (ancillaryType == 2)
1186  initKCalAlarm(ev, ancillaryOffset, TQStringList(), KAAlarm::AUDIO_ALARM);
1187  else
1188  initKCalAlarm(ev, ancillaryTime, TQStringList(), KAAlarm::AUDIO_ALARM);
1189  }
1190  if (!mPreAction.isEmpty())
1191  {
1192  // A pre-display action is specified
1193  if (ancillaryType == 2)
1194  initKCalAlarm(ev, ancillaryOffset, TQStringList(PRE_ACTION_TYPE), KAAlarm::PRE_ACTION_ALARM);
1195  else
1196  initKCalAlarm(ev, ancillaryTime, TQStringList(PRE_ACTION_TYPE), KAAlarm::PRE_ACTION_ALARM);
1197  }
1198  if (!mPostAction.isEmpty())
1199  {
1200  // A post-display action is specified
1201  if (ancillaryType == 2)
1202  initKCalAlarm(ev, ancillaryOffset, TQStringList(POST_ACTION_TYPE), KAAlarm::POST_ACTION_ALARM);
1203  else
1204  initKCalAlarm(ev, ancillaryTime, TQStringList(POST_ACTION_TYPE), KAAlarm::POST_ACTION_ALARM);
1205  }
1206 
1207  if (mRecurrence)
1208  mRecurrence->writeRecurrence(*ev.recurrence());
1209  else
1210  ev.clearRecurrence();
1211  if (mSaveDateTime.isValid())
1212  ev.setCreated(mSaveDateTime);
1213  ev.setReadOnly(readOnly);
1214  return true;
1215 }
1216 
1217 /******************************************************************************
1218  * Create a new alarm for a libkcal event, and initialise it according to the
1219  * alarm action. If 'types' is non-null, it is appended to the X-TDE-KALARM-TYPE
1220  * property value list.
1221  */
1222 Alarm* KAEvent::initKCalAlarm(Event& event, const DateTime& dt, const TQStringList& types, KAAlarm::Type type) const
1223 {
1224  int startOffset = dt.isDateOnly() ? mStartDateTime.secsTo(dt)
1225  : mStartDateTime.dateTime().secsTo(dt.dateTime());
1226  return initKCalAlarm(event, startOffset, types, type);
1227 }
1228 
1229 Alarm* KAEvent::initKCalAlarm(Event& event, int startOffsetSecs, const TQStringList& types, KAAlarm::Type type) const
1230 {
1231  TQStringList alltypes;
1232  Alarm* alarm = event.newAlarm();
1233  alarm->setEnabled(true);
1234  if (type != KAAlarm::MAIN_ALARM)
1235  {
1236  // RFC2445 specifies that absolute alarm times must be stored as UTC.
1237  // So, in order to store local times, set the alarm time as an offset to DTSTART.
1238  alarm->setStartOffset(startOffsetSecs);
1239  }
1240 
1241  switch (type)
1242  {
1243  case KAAlarm::AUDIO_ALARM:
1244  alarm->setAudioAlarm(mAudioFile); // empty for a beep or for speaking
1245  if (mSpeak)
1246  alarm->setCustomProperty(APPNAME, SPEAK_PROPERTY, TQString::fromLatin1("Y"));
1247  if (mRepeatSound)
1248  {
1249  alarm->setRepeatCount(-1);
1250  alarm->setSnoozeTime(0);
1251  }
1252  if (!mAudioFile.isEmpty() && mSoundVolume >= 0)
1253  alarm->setCustomProperty(APPNAME, VOLUME_PROPERTY,
1254  TQString::fromLatin1("%1;%2;%3").arg(TQString::number(mSoundVolume, 'f', 2))
1255  .arg(TQString::number(mFadeVolume, 'f', 2))
1256  .arg(mFadeSeconds));
1257  break;
1258  case KAAlarm::PRE_ACTION_ALARM:
1259  setProcedureAlarm(alarm, mPreAction);
1260  break;
1261  case KAAlarm::POST_ACTION_ALARM:
1262  setProcedureAlarm(alarm, mPostAction);
1263  break;
1264  case KAAlarm::MAIN_ALARM:
1265  alarm->setSnoozeTime(mRepeatInterval);
1266  alarm->setRepeatCount(mRepeatCount);
1267  if (mRepeatCount)
1268  alarm->setCustomProperty(APPNAME, NEXT_REPEAT_PROPERTY,
1269  TQString::number(mNextRepeat));
1270  // fall through to INVALID_ALARM
1271  case KAAlarm::INVALID_ALARM:
1272  switch (mActionType)
1273  {
1274  case T_FILE:
1275  alltypes += FILE_TYPE;
1276  // fall through to T_MESSAGE
1277  case T_MESSAGE:
1278  alarm->setDisplayAlarm(AlarmText::toCalendarText(mText));
1279  alarm->setCustomProperty(APPNAME, FONT_COLOUR_PROPERTY,
1280  TQString::fromLatin1("%1;%2;%3").arg(mBgColour.name())
1281  .arg(mFgColour.name())
1282  .arg(mDefaultFont ? TQString() : mFont.toString()));
1283  break;
1284  case T_COMMAND:
1285  if (mCommandScript)
1286  alarm->setProcedureAlarm("", mText);
1287  else
1288  setProcedureAlarm(alarm, mText);
1289  break;
1290  case T_EMAIL:
1291  alarm->setEmailAlarm(mEmailSubject, mText, mEmailAddresses, mEmailAttachments);
1292  if (mEmailFromIdentity)
1293  alarm->setCustomProperty(APPNAME, EMAIL_ID_PROPERTY, TQString::number(mEmailFromIdentity));
1294  break;
1295  case T_AUDIO:
1296  break;
1297  }
1298  break;
1299  case KAAlarm::REMINDER_ALARM:
1300  case KAAlarm::DEFERRED_ALARM:
1301  case KAAlarm::DEFERRED_REMINDER_ALARM:
1302  case KAAlarm::AT_LOGIN_ALARM:
1303  case KAAlarm::DISPLAYING_ALARM:
1304  break;
1305  }
1306  alltypes += types;
1307  if (alltypes.count() > 0)
1308  alarm->setCustomProperty(APPNAME, TYPE_PROPERTY, alltypes.join(","));
1309  return alarm;
1310 }
1311 
1312 /******************************************************************************
1313  * Return the alarm of the specified type.
1314  */
1315 KAAlarm KAEvent::alarm(KAAlarm::Type type) const
1316 {
1317  checkRecur(); // ensure recurrence/repetition data is consistent
1318  KAAlarm al; // this sets type to INVALID_ALARM
1319  if (mAlarmCount)
1320  {
1321  al.mEventID = mEventID;
1322  al.mActionType = mActionType;
1323  al.mText = mText;
1324  al.mBgColour = mBgColour;
1325  al.mFgColour = mFgColour;
1326  al.mFont = mFont;
1327  al.mDefaultFont = mDefaultFont;
1328  al.mBeep = mBeep;
1329  al.mSpeak = mSpeak;
1330  al.mSoundVolume = mSoundVolume;
1331  al.mFadeVolume = mFadeVolume;
1332  al.mFadeSeconds = mFadeSeconds;
1333  al.mRepeatSound = mRepeatSound;
1334  al.mConfirmAck = mConfirmAck;
1335  al.mRepeatCount = 0;
1336  al.mRepeatInterval = 0;
1337  al.mRepeatAtLogin = false;
1338  al.mDeferred = false;
1339  al.mLateCancel = mLateCancel;
1340  al.mAutoClose = mAutoClose;
1341  al.mEmailBcc = mEmailBcc;
1342  al.mCommandScript = mCommandScript;
1343  if (mActionType == T_EMAIL)
1344  {
1345  al.mEmailFromIdentity = mEmailFromIdentity;
1346  al.mEmailAddresses = mEmailAddresses;
1347  al.mEmailSubject = mEmailSubject;
1348  al.mEmailAttachments = mEmailAttachments;
1349  }
1350  switch (type)
1351  {
1352  case KAAlarm::MAIN_ALARM:
1353  if (!mMainExpired)
1354  {
1355  al.mType = KAAlarm::MAIN__ALARM;
1356  al.mNextMainDateTime = mNextMainDateTime;
1357  al.mRepeatCount = mRepeatCount;
1358  al.mRepeatInterval = mRepeatInterval;
1359  al.mNextRepeat = mNextRepeat;
1360  }
1361  break;
1362  case KAAlarm::REMINDER_ALARM:
1363  if (mReminderMinutes)
1364  {
1365  al.mType = KAAlarm::REMINDER__ALARM;
1366  if (mReminderOnceOnly)
1367  al.mNextMainDateTime = mStartDateTime.addMins(-mReminderMinutes);
1368  else
1369  al.mNextMainDateTime = mNextMainDateTime.addMins(-mReminderMinutes);
1370  }
1371  break;
1372  case KAAlarm::DEFERRED_REMINDER_ALARM:
1373  if (mDeferral != REMINDER_DEFERRAL)
1374  break;
1375  // fall through to DEFERRED_ALARM
1376  case KAAlarm::DEFERRED_ALARM:
1377  if (mDeferral > 0)
1378  {
1379  al.mType = static_cast<KAAlarm::SubType>((mDeferral == REMINDER_DEFERRAL ? KAAlarm::DEFERRED_REMINDER_ALARM : KAAlarm::DEFERRED_ALARM)
1380  | (mDeferralTime.isDateOnly() ? 0 : KAAlarm::TIMED_DEFERRAL_FLAG));
1381  al.mNextMainDateTime = mDeferralTime;
1382  al.mDeferred = true;
1383  }
1384  break;
1385  case KAAlarm::AT_LOGIN_ALARM:
1386  if (mRepeatAtLogin)
1387  {
1388  al.mType = KAAlarm::AT_LOGIN__ALARM;
1389  al.mNextMainDateTime = mAtLoginDateTime;
1390  al.mRepeatAtLogin = true;
1391  al.mLateCancel = 0;
1392  al.mAutoClose = false;
1393  }
1394  break;
1395  case KAAlarm::DISPLAYING_ALARM:
1396  if (mDisplaying)
1397  {
1398  al.mType = KAAlarm::DISPLAYING__ALARM;
1399  al.mNextMainDateTime = mDisplayingTime;
1400  al.mDisplaying = true;
1401  }
1402  break;
1403  case KAAlarm::AUDIO_ALARM:
1404  case KAAlarm::PRE_ACTION_ALARM:
1405  case KAAlarm::POST_ACTION_ALARM:
1406  case KAAlarm::INVALID_ALARM:
1407  default:
1408  break;
1409  }
1410  }
1411  return al;
1412 }
1413 
1414 /******************************************************************************
1415  * Return the main alarm for the event.
1416  * If the main alarm does not exist, one of the subsidiary ones is returned if
1417  * possible.
1418  * N.B. a repeat-at-login alarm can only be returned if it has been read from/
1419  * written to the calendar file.
1420  */
1421 KAAlarm KAEvent::firstAlarm() const
1422 {
1423  if (mAlarmCount)
1424  {
1425  if (!mMainExpired)
1426  return alarm(KAAlarm::MAIN_ALARM);
1427  return nextAlarm(KAAlarm::MAIN_ALARM);
1428  }
1429  return KAAlarm();
1430 }
1431 
1432 /******************************************************************************
1433  * Return the next alarm for the event, after the specified alarm.
1434  * N.B. a repeat-at-login alarm can only be returned if it has been read from/
1435  * written to the calendar file.
1436  */
1437 KAAlarm KAEvent::nextAlarm(KAAlarm::Type prevType) const
1438 {
1439  switch (prevType)
1440  {
1441  case KAAlarm::MAIN_ALARM:
1442  if (mReminderMinutes)
1443  return alarm(KAAlarm::REMINDER_ALARM);
1444  // fall through to REMINDER_ALARM
1445  case KAAlarm::REMINDER_ALARM:
1446  // There can only be one deferral alarm
1447  if (mDeferral == REMINDER_DEFERRAL)
1448  return alarm(KAAlarm::DEFERRED_REMINDER_ALARM);
1449  if (mDeferral == NORMAL_DEFERRAL)
1450  return alarm(KAAlarm::DEFERRED_ALARM);
1451  // fall through to DEFERRED_ALARM
1452  case KAAlarm::DEFERRED_REMINDER_ALARM:
1453  case KAAlarm::DEFERRED_ALARM:
1454  if (mRepeatAtLogin)
1455  return alarm(KAAlarm::AT_LOGIN_ALARM);
1456  // fall through to AT_LOGIN_ALARM
1457  case KAAlarm::AT_LOGIN_ALARM:
1458  if (mDisplaying)
1459  return alarm(KAAlarm::DISPLAYING_ALARM);
1460  // fall through to DISPLAYING_ALARM
1461  case KAAlarm::DISPLAYING_ALARM:
1462  // fall through to default
1463  case KAAlarm::AUDIO_ALARM:
1464  case KAAlarm::PRE_ACTION_ALARM:
1465  case KAAlarm::POST_ACTION_ALARM:
1466  case KAAlarm::INVALID_ALARM:
1467  default:
1468  break;
1469  }
1470  return KAAlarm();
1471 }
1472 
1473 /******************************************************************************
1474  * Remove the alarm of the specified type from the event.
1475  * This must only be called to remove an alarm which has expired, not to
1476  * reconfigure the event.
1477  */
1478 void KAEvent::removeExpiredAlarm(KAAlarm::Type type)
1479 {
1480  int count = mAlarmCount;
1481  switch (type)
1482  {
1483  case KAAlarm::MAIN_ALARM:
1484  mAlarmCount = 0; // removing main alarm - also remove subsidiary alarms
1485  break;
1486  case KAAlarm::AT_LOGIN_ALARM:
1487  if (mRepeatAtLogin)
1488  {
1489  // Remove the at-login alarm, but keep a note of it for archiving purposes
1490  mArchiveRepeatAtLogin = true;
1491  mRepeatAtLogin = false;
1492  --mAlarmCount;
1493  }
1494  break;
1495  case KAAlarm::REMINDER_ALARM:
1496  // Remove any reminder alarm, but keep a note of it for archiving purposes
1497  set_archiveReminder();
1498  break;
1499  case KAAlarm::DEFERRED_REMINDER_ALARM:
1500  case KAAlarm::DEFERRED_ALARM:
1501  set_deferral(NO_DEFERRAL);
1502  break;
1503  case KAAlarm::DISPLAYING_ALARM:
1504  if (mDisplaying)
1505  {
1506  mDisplaying = false;
1507  --mAlarmCount;
1508  }
1509  break;
1510  case KAAlarm::AUDIO_ALARM:
1511  case KAAlarm::PRE_ACTION_ALARM:
1512  case KAAlarm::POST_ACTION_ALARM:
1513  case KAAlarm::INVALID_ALARM:
1514  default:
1515  break;
1516  }
1517  if (mAlarmCount != count)
1518  mUpdated = true;
1519 }
1520 
1521 /******************************************************************************
1522  * Defer the event to the specified time.
1523  * If the main alarm time has passed, the main alarm is marked as expired.
1524  * If 'adjustRecurrence' is true, ensure that the next scheduled recurrence is
1525  * after the current time.
1526  * Reply = true if a repetition has been deferred.
1527  */
1528 bool KAEvent::defer(const DateTime& dateTime, bool reminder, bool adjustRecurrence)
1529 {
1530  bool result = false;
1531  bool setNextRepetition = false;
1532  bool checkRepetition = false;
1533  cancelCancelledDeferral();
1534  if (checkRecur() == KARecurrence::NO_RECUR)
1535  {
1536  if (mReminderMinutes || mDeferral == REMINDER_DEFERRAL || mArchiveReminderMinutes)
1537  {
1538  if (dateTime < mNextMainDateTime.dateTime())
1539  {
1540  set_deferral(REMINDER_DEFERRAL); // defer reminder alarm
1541  mDeferralTime = dateTime;
1542  }
1543  else
1544  {
1545  // Deferring past the main alarm time, so adjust any existing deferral
1546  if (mReminderMinutes || mDeferral == REMINDER_DEFERRAL)
1547  set_deferral(NO_DEFERRAL);
1548  }
1549  // Remove any reminder alarm, but keep a note of it for archiving purposes
1550  if (mReminderMinutes)
1551  set_archiveReminder();
1552  }
1553  if (mDeferral != REMINDER_DEFERRAL)
1554  {
1555  // We're deferring the main alarm, not a reminder
1556  if (mRepeatCount && mRepeatInterval && dateTime < mainEndRepeatTime())
1557  {
1558  // The alarm is repeated, and we're deferring to a time before the last repetition
1559  set_deferral(NORMAL_DEFERRAL);
1560  mDeferralTime = dateTime;
1561  result = true;
1562  setNextRepetition = true;
1563  }
1564  else
1565  {
1566  // Main alarm has now expired
1567  mNextMainDateTime = mDeferralTime = dateTime;
1568  set_deferral(NORMAL_DEFERRAL);
1569  if (!mMainExpired)
1570  {
1571  // Mark the alarm as expired now
1572  mMainExpired = true;
1573  --mAlarmCount;
1574  if (mRepeatAtLogin)
1575  {
1576  // Remove the repeat-at-login alarm, but keep a note of it for archiving purposes
1577  mArchiveRepeatAtLogin = true;
1578  mRepeatAtLogin = false;
1579  --mAlarmCount;
1580  }
1581  }
1582  }
1583  }
1584  }
1585  else if (reminder)
1586  {
1587  // Deferring a reminder for a recurring alarm
1588  if (dateTime >= mNextMainDateTime.dateTime())
1589  set_deferral(NO_DEFERRAL); // (error)
1590  else
1591  {
1592  set_deferral(REMINDER_DEFERRAL);
1593  mDeferralTime = dateTime;
1594  checkRepetition = true;
1595  }
1596  }
1597  else
1598  {
1599  mDeferralTime = dateTime;
1600  if (mDeferral <= 0)
1601  set_deferral(NORMAL_DEFERRAL);
1602  if (adjustRecurrence)
1603  {
1604  TQDateTime now = TQDateTime::currentDateTime();
1605  if (mainEndRepeatTime() < now)
1606  {
1607  // The last repetition (if any) of the current recurrence has already passed.
1608  // Adjust to the next scheduled recurrence after now.
1609  if (!mMainExpired && setNextOccurrence(now) == NO_OCCURRENCE)
1610  {
1611  mMainExpired = true;
1612  --mAlarmCount;
1613  }
1614  }
1615  else
1616  setNextRepetition = (mRepeatCount && mRepeatInterval);
1617  }
1618  else
1619  checkRepetition = true;
1620  }
1621  if (checkRepetition)
1622  setNextRepetition = (mRepeatCount && mRepeatInterval && mDeferralTime < mainEndRepeatTime());
1623  if (setNextRepetition)
1624  {
1625  // The alarm is repeated, and we're deferring to a time before the last repetition.
1626  // Set the next scheduled repetition to the one after the deferral.
1627  mNextRepeat = (mNextMainDateTime < mDeferralTime)
1628  ? mNextMainDateTime.secsTo(mDeferralTime) / (mRepeatInterval * 60) + 1 : 0;
1629  }
1630  mUpdated = true;
1631  return result;
1632 }
1633 
1634 /******************************************************************************
1635  * Cancel any deferral alarm.
1636  */
1637 void KAEvent::cancelDefer()
1638 {
1639  if (mDeferral > 0)
1640  {
1641  // Set the deferral time to be the same as the next recurrence/repetition.
1642  // This prevents an immediate retriggering of the alarm.
1643  if (mMainExpired
1644  || nextOccurrence(TQDateTime::currentDateTime(), mDeferralTime, RETURN_REPETITION) == NO_OCCURRENCE)
1645  {
1646  // The main alarm has expired, so simply delete the deferral
1647  mDeferralTime = DateTime();
1648  set_deferral(NO_DEFERRAL);
1649  }
1650  else
1651  set_deferral(CANCEL_DEFERRAL);
1652  mUpdated = true;
1653  }
1654 }
1655 
1656 /******************************************************************************
1657  * Cancel any cancelled deferral alarm.
1658  */
1659 void KAEvent::cancelCancelledDeferral()
1660 {
1661  if (mDeferral == CANCEL_DEFERRAL)
1662  {
1663  mDeferralTime = DateTime();
1664  set_deferral(NO_DEFERRAL);
1665  }
1666 }
1667 
1668 /******************************************************************************
1669 * Find the latest time which the alarm can currently be deferred to.
1670 */
1671 DateTime KAEvent::deferralLimit(KAEvent::DeferLimitType* limitType) const
1672 {
1673  DeferLimitType ltype;
1674  DateTime endTime;
1675  bool recurs = (checkRecur() != KARecurrence::NO_RECUR);
1676  if (recurs || mRepeatCount)
1677  {
1678  // It's a repeated alarm. Don't allow it to be deferred past its
1679  // next occurrence or repetition.
1680  DateTime reminderTime;
1681  TQDateTime now = TQDateTime::currentDateTime();
1682  OccurType type = nextOccurrence(now, endTime, RETURN_REPETITION);
1683  if (type & OCCURRENCE_REPEAT)
1684  ltype = LIMIT_REPETITION;
1685  else if (type == NO_OCCURRENCE)
1686  ltype = LIMIT_NONE;
1687  else if (mReminderMinutes && (now < (reminderTime = endTime.addMins(-mReminderMinutes))))
1688  {
1689  endTime = reminderTime;
1690  ltype = LIMIT_REMINDER;
1691  }
1692  else if (type == FIRST_OR_ONLY_OCCURRENCE && !recurs)
1693  ltype = LIMIT_REPETITION;
1694  else
1695  ltype = LIMIT_RECURRENCE;
1696  }
1697  else if ((mReminderMinutes || mDeferral == REMINDER_DEFERRAL || mArchiveReminderMinutes)
1698  && TQDateTime::currentDateTime() < mNextMainDateTime.dateTime())
1699  {
1700  // It's an reminder alarm. Don't allow it to be deferred past its main alarm time.
1701  endTime = mNextMainDateTime;
1702  ltype = LIMIT_REMINDER;
1703  }
1704  else
1705  ltype = LIMIT_NONE;
1706  if (ltype != LIMIT_NONE)
1707  endTime = endTime.addMins(-1);
1708  if (limitType)
1709  *limitType = ltype;
1710  return endTime;
1711 }
1712 
1713 /******************************************************************************
1714  * Set the event to be a copy of the specified event, making the specified
1715  * alarm the 'displaying' alarm.
1716  * The purpose of setting up a 'displaying' alarm is to be able to reinstate
1717  * the alarm message in case of a crash, or to reinstate it should the user
1718  * choose to defer the alarm. Note that even repeat-at-login alarms need to be
1719  * saved in case their end time expires before the next login.
1720  * Reply = true if successful, false if alarm was not copied.
1721  */
1722 bool KAEvent::setDisplaying(const KAEvent& event, KAAlarm::Type alarmType, const TQDateTime& repeatAtLoginTime)
1723 {
1724  if (!mDisplaying
1725  && (alarmType == KAAlarm::MAIN_ALARM
1726  || alarmType == KAAlarm::REMINDER_ALARM
1727  || alarmType == KAAlarm::DEFERRED_REMINDER_ALARM
1728  || alarmType == KAAlarm::DEFERRED_ALARM
1729  || alarmType == KAAlarm::AT_LOGIN_ALARM))
1730  {
1731 //kdDebug(5950)<<"KAEvent::setDisplaying("<<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()<<endl;
1732  KAAlarm al = event.alarm(alarmType);
1733  if (al.valid())
1734  {
1735  *this = event;
1736  setUid(DISPLAYING);
1737  mDisplaying = true;
1738  mDisplayingTime = (alarmType == KAAlarm::AT_LOGIN_ALARM) ? repeatAtLoginTime : al.dateTime();
1739  switch (al.subType())
1740  {
1741  case KAAlarm::AT_LOGIN__ALARM: mDisplayingFlags = REPEAT_AT_LOGIN; break;
1742  case KAAlarm::REMINDER__ALARM: mDisplayingFlags = REMINDER; break;
1743  case KAAlarm::DEFERRED_REMINDER_TIME__ALARM: mDisplayingFlags = REMINDER | TIME_DEFERRAL; break;
1744  case KAAlarm::DEFERRED_REMINDER_DATE__ALARM: mDisplayingFlags = REMINDER | DATE_DEFERRAL; break;
1745  case KAAlarm::DEFERRED_TIME__ALARM: mDisplayingFlags = TIME_DEFERRAL; break;
1746  case KAAlarm::DEFERRED_DATE__ALARM: mDisplayingFlags = DATE_DEFERRAL; break;
1747  default: mDisplayingFlags = 0; break;
1748  }
1749  ++mAlarmCount;
1750  mUpdated = true;
1751  return true;
1752  }
1753  }
1754  return false;
1755 }
1756 
1757 /******************************************************************************
1758  * Return the original alarm which the displaying alarm refers to.
1759  */
1760 KAAlarm KAEvent::convertDisplayingAlarm() const
1761 {
1762  KAAlarm al;
1763  if (mDisplaying)
1764  {
1765  al = alarm(KAAlarm::DISPLAYING_ALARM);
1766  if (mDisplayingFlags & REPEAT_AT_LOGIN)
1767  {
1768  al.mRepeatAtLogin = true;
1769  al.mType = KAAlarm::AT_LOGIN__ALARM;
1770  }
1771  else if (mDisplayingFlags & DEFERRAL)
1772  {
1773  al.mDeferred = true;
1774  al.mType = (mDisplayingFlags == (REMINDER | DATE_DEFERRAL)) ? KAAlarm::DEFERRED_REMINDER_DATE__ALARM
1775  : (mDisplayingFlags == (REMINDER | TIME_DEFERRAL)) ? KAAlarm::DEFERRED_REMINDER_TIME__ALARM
1776  : (mDisplayingFlags == DATE_DEFERRAL) ? KAAlarm::DEFERRED_DATE__ALARM
1777  : KAAlarm::DEFERRED_TIME__ALARM;
1778  }
1779  else if (mDisplayingFlags & REMINDER)
1780  al.mType = KAAlarm::REMINDER__ALARM;
1781  else
1782  al.mType = KAAlarm::MAIN__ALARM;
1783  }
1784  return al;
1785 }
1786 
1787 /******************************************************************************
1788  * Reinstate the original event from the 'displaying' event.
1789  */
1790 void KAEvent::reinstateFromDisplaying(const KAEvent& dispEvent)
1791 {
1792  if (dispEvent.mDisplaying)
1793  {
1794  *this = dispEvent;
1795  setUid(ACTIVE);
1796  mDisplaying = false;
1797  --mAlarmCount;
1798  mUpdated = true;
1799  }
1800 }
1801 
1802 /******************************************************************************
1803  * Determine whether the event will occur after the specified date/time.
1804  * If 'includeRepetitions' is true and the alarm has a sub-repetition, it
1805  * returns true if any repetitions occur after the specified date/time.
1806  */
1807 bool KAEvent::occursAfter(const TQDateTime& preDateTime, bool includeRepetitions) const
1808 {
1809  TQDateTime dt;
1810  if (checkRecur() != KARecurrence::NO_RECUR)
1811  {
1812  if (mRecurrence->duration() < 0)
1813  return true; // infinite recurrence
1814  dt = mRecurrence->endDateTime();
1815  }
1816  else
1817  dt = mNextMainDateTime.dateTime();
1818  if (mStartDateTime.isDateOnly())
1819  {
1820  TQDate pre = preDateTime.date();
1821  if (preDateTime.time() < Preferences::startOfDay())
1822  pre = pre.addDays(-1); // today's recurrence (if today recurs) is still to come
1823  if (pre < dt.date())
1824  return true;
1825  }
1826  else if (preDateTime < dt)
1827  return true;
1828 
1829  if (includeRepetitions && mRepeatCount)
1830  {
1831  if (preDateTime < dt.addSecs(mRepeatCount * mRepeatInterval * 60))
1832  return true;
1833  }
1834  return false;
1835 }
1836 
1837 /******************************************************************************
1838  * Get the date/time of the next occurrence of the event, after the specified
1839  * date/time.
1840  * 'result' = date/time of next occurrence, or invalid date/time if none.
1841  */
1842 KAEvent::OccurType KAEvent::nextOccurrence(const TQDateTime& preDateTime, DateTime& result,
1843  KAEvent::OccurOption includeRepetitions) const
1844 {
1845  int repeatSecs = 0;
1846  TQDateTime pre = preDateTime;
1847  if (includeRepetitions != IGNORE_REPETITION)
1848  {
1849  if (!mRepeatCount || !mRepeatInterval)
1850  includeRepetitions = IGNORE_REPETITION;
1851  else
1852  {
1853  repeatSecs = mRepeatInterval * 60;
1854  pre = preDateTime.addSecs(-mRepeatCount * repeatSecs);
1855  }
1856  }
1857 
1858  OccurType type;
1859  bool recurs = (checkRecur() != KARecurrence::NO_RECUR);
1860  if (recurs)
1861  type = nextRecurrence(pre, result);
1862  else if (pre < mNextMainDateTime.dateTime())
1863  {
1864  result = mNextMainDateTime;
1865  type = FIRST_OR_ONLY_OCCURRENCE;
1866  }
1867  else
1868  {
1869  result = DateTime();
1870  type = NO_OCCURRENCE;
1871  }
1872 
1873  if (type != NO_OCCURRENCE && result <= preDateTime && includeRepetitions != IGNORE_REPETITION)
1874  {
1875  // The next occurrence is a sub-repetition
1876  int repetition = result.secsTo(preDateTime) / repeatSecs + 1;
1877  DateTime repeatDT = result.addSecs(repetition * repeatSecs);
1878  if (recurs)
1879  {
1880  // We've found a recurrence before the specified date/time, which has
1881  // a sub-repetition after the date/time.
1882  // However, if the intervals between recurrences vary, we could possibly
1883  // have missed a later recurrence, which fits the criterion, so check again.
1884  DateTime dt;
1885  OccurType newType = previousOccurrence(repeatDT.dateTime(), dt, false);
1886  if (dt > result)
1887  {
1888  type = newType;
1889  result = dt;
1890  if (includeRepetitions == RETURN_REPETITION && result <= preDateTime)
1891  {
1892  // The next occurrence is a sub-repetition
1893  int repetition = result.secsTo(preDateTime) / repeatSecs + 1;
1894  result = result.addSecs(repetition * repeatSecs);
1895  type = static_cast<OccurType>(type | OCCURRENCE_REPEAT);
1896  }
1897  return type;
1898  }
1899  }
1900  if (includeRepetitions == RETURN_REPETITION)
1901  {
1902  // The next occurrence is a sub-repetition
1903  result = repeatDT;
1904  type = static_cast<OccurType>(type | OCCURRENCE_REPEAT);
1905  }
1906  }
1907  return type;
1908 }
1909 
1910 /******************************************************************************
1911  * Get the date/time of the last previous occurrence of the event, before the
1912  * specified date/time.
1913  * If 'includeRepetitions' is true and the alarm has a sub-repetition, the
1914  * last previous repetition is returned if appropriate.
1915  * 'result' = date/time of previous occurrence, or invalid date/time if none.
1916  */
1917 KAEvent::OccurType KAEvent::previousOccurrence(const TQDateTime& afterDateTime, DateTime& result, bool includeRepetitions) const
1918 {
1919  if (mStartDateTime >= afterDateTime)
1920  {
1921  result = TQDateTime();
1922  return NO_OCCURRENCE; // the event starts after the specified date/time
1923  }
1924 
1925  // Find the latest recurrence of the event
1926  OccurType type;
1927  if (checkRecur() == KARecurrence::NO_RECUR)
1928  {
1929  result = mStartDateTime;
1930  type = FIRST_OR_ONLY_OCCURRENCE;
1931  }
1932  else
1933  {
1934  TQDateTime recurStart = mRecurrence->startDateTime();
1935  TQDateTime after = afterDateTime;
1936  if (mStartDateTime.isDateOnly() && afterDateTime.time() > Preferences::startOfDay())
1937  after = after.addDays(1); // today's recurrence (if today recurs) has passed
1938  TQDateTime dt = mRecurrence->getPreviousDateTime(after);
1939  result.set(dt, mStartDateTime.isDateOnly());
1940  if (!dt.isValid())
1941  return NO_OCCURRENCE;
1942  if (dt == recurStart)
1943  type = FIRST_OR_ONLY_OCCURRENCE;
1944  else if (mRecurrence->getNextDateTime(dt).isValid())
1945  type = result.isDateOnly() ? RECURRENCE_DATE : RECURRENCE_DATE_TIME;
1946  else
1947  type = LAST_RECURRENCE;
1948  }
1949 
1950  if (includeRepetitions && mRepeatCount)
1951  {
1952  // Find the latest repetition which is before the specified time.
1953  // N.B. This is coded to avoid 32-bit integer overflow which occurs
1954  // in TQDateTime::secsTo() for large enough time differences.
1955  int repeatSecs = mRepeatInterval * 60;
1956  DateTime lastRepetition = result.addSecs(mRepeatCount * repeatSecs);
1957  if (lastRepetition < afterDateTime)
1958  {
1959  result = lastRepetition;
1960  return static_cast<OccurType>(type | OCCURRENCE_REPEAT);
1961  }
1962  int repetition = (result.dateTime().secsTo(afterDateTime) - 1) / repeatSecs;
1963  if (repetition > 0)
1964  {
1965  result = result.addSecs(repetition * repeatSecs);
1966  return static_cast<OccurType>(type | OCCURRENCE_REPEAT);
1967  }
1968  }
1969  return type;
1970 }
1971 
1972 /******************************************************************************
1973  * Set the date/time of the event to the next scheduled occurrence after the
1974  * specified date/time, provided that this is later than its current date/time.
1975  * Any reminder alarm is adjusted accordingly.
1976  * If the alarm has a sub-repetition, and a repetition of a previous
1977  * recurrence occurs after the specified date/time, that repetition is set as
1978  * the next occurrence.
1979  */
1980 KAEvent::OccurType KAEvent::setNextOccurrence(const TQDateTime& preDateTime)
1981 {
1982  if (preDateTime < mNextMainDateTime.dateTime())
1983  return FIRST_OR_ONLY_OCCURRENCE; // it might not be the first recurrence - tant pis
1984  TQDateTime pre = preDateTime;
1985  // If there are repetitions, adjust the comparison date/time so that
1986  // we find the earliest recurrence which has a repetition falling after
1987  // the specified preDateTime.
1988  if (mRepeatCount && mRepeatInterval)
1989  pre = preDateTime.addSecs(-mRepeatCount * mRepeatInterval * 60);
1990 
1991  DateTime dt;
1992  OccurType type;
1993  if (pre < mNextMainDateTime.dateTime())
1994  {
1995  dt = mNextMainDateTime;
1996  type = FIRST_OR_ONLY_OCCURRENCE; // may not actually be the first occurrence
1997  }
1998  else if (checkRecur() != KARecurrence::NO_RECUR)
1999  {
2000  type = nextRecurrence(pre, dt);
2001  if (type == NO_OCCURRENCE)
2002  return NO_OCCURRENCE;
2003  if (type != FIRST_OR_ONLY_OCCURRENCE && dt != mNextMainDateTime)
2004  {
2005  // Need to reschedule the next trigger date/time
2006  mNextMainDateTime = dt;
2007  // Reinstate the reminder (if any) for the rescheduled recurrence
2008  if (mDeferral == REMINDER_DEFERRAL || mArchiveReminderMinutes)
2009  {
2010  if (mReminderOnceOnly)
2011  {
2012  if (mReminderMinutes)
2013  set_archiveReminder();
2014  }
2015  else
2016  set_reminder(mArchiveReminderMinutes);
2017  }
2018  if (mDeferral == REMINDER_DEFERRAL)
2019  set_deferral(NO_DEFERRAL);
2020  mUpdated = true;
2021  }
2022  }
2023  else
2024  return NO_OCCURRENCE;
2025 
2026  if (mRepeatCount && mRepeatInterval)
2027  {
2028  int secs = dt.dateTime().secsTo(preDateTime);
2029  if (secs >= 0)
2030  {
2031  // The next occurrence is a sub-repetition.
2032  type = static_cast<OccurType>(type | OCCURRENCE_REPEAT);
2033  mNextRepeat = (secs / (60 * mRepeatInterval)) + 1;
2034  // Repetitions can't have a reminder, so remove any.
2035  if (mReminderMinutes)
2036  set_archiveReminder();
2037  if (mDeferral == REMINDER_DEFERRAL)
2038  set_deferral(NO_DEFERRAL);
2039  mUpdated = true;
2040  }
2041  else if (mNextRepeat)
2042  {
2043  // The next occurrence is the main occurrence, not a repetition
2044  mNextRepeat = 0;
2045  mUpdated = true;
2046  }
2047  }
2048  return type;
2049 }
2050 
2051 /******************************************************************************
2052  * Get the date/time of the next recurrence of the event, after the specified
2053  * date/time.
2054  * 'result' = date/time of next occurrence, or invalid date/time if none.
2055  */
2056 KAEvent::OccurType KAEvent::nextRecurrence(const TQDateTime& preDateTime, DateTime& result) const
2057 {
2058  TQDateTime recurStart = mRecurrence->startDateTime();
2059  TQDateTime pre = preDateTime;
2060  if (mStartDateTime.isDateOnly() && preDateTime.time() < Preferences::startOfDay())
2061  {
2062  pre = pre.addDays(-1); // today's recurrence (if today recurs) is still to come
2063  pre.setTime(Preferences::startOfDay());
2064  }
2065  TQDateTime dt = mRecurrence->getNextDateTime(pre);
2066  result.set(dt, mStartDateTime.isDateOnly());
2067  if (!dt.isValid())
2068  return NO_OCCURRENCE;
2069  if (dt == recurStart)
2070  return FIRST_OR_ONLY_OCCURRENCE;
2071  if (mRecurrence->duration() >= 0 && dt == mRecurrence->endDateTime())
2072  return LAST_RECURRENCE;
2073  return result.isDateOnly() ? RECURRENCE_DATE : RECURRENCE_DATE_TIME;
2074 }
2075 
2076 /******************************************************************************
2077  * Return the recurrence interval as text suitable for display.
2078  */
2079 TQString KAEvent::recurrenceText(bool brief) const
2080 {
2081  if (mRepeatAtLogin)
2082  return brief ? i18n("Brief form of 'At Login'", "Login") : i18n("At login");
2083  if (mRecurrence)
2084  {
2085  int frequency = mRecurrence->frequency();
2086  switch (mRecurrence->defaultRRuleConst()->recurrenceType())
2087  {
2088  case RecurrenceRule::rMinutely:
2089  if (frequency < 60)
2090  return i18n("1 Minute", "%n Minutes", frequency);
2091  else if (frequency % 60 == 0)
2092  return i18n("1 Hour", "%n Hours", frequency/60);
2093  else
2094  {
2095  TQString mins;
2096  return i18n("Hours and Minutes", "%1H %2M").arg(TQString::number(frequency/60)).arg(mins.sprintf("%02d", frequency%60));
2097  }
2098  case RecurrenceRule::rDaily:
2099  return i18n("1 Day", "%n Days", frequency);
2100  case RecurrenceRule::rWeekly:
2101  return i18n("1 Week", "%n Weeks", frequency);
2102  case RecurrenceRule::rMonthly:
2103  return i18n("1 Month", "%n Months", frequency);
2104  case RecurrenceRule::rYearly:
2105  return i18n("1 Year", "%n Years", frequency);
2106  case RecurrenceRule::rNone:
2107  default:
2108  break;
2109  }
2110  }
2111  return brief ? TQString() : i18n("None");
2112 }
2113 
2114 /******************************************************************************
2115  * Return the repetition interval as text suitable for display.
2116  */
2117 TQString KAEvent::repetitionText(bool brief) const
2118 {
2119  if (mRepeatCount)
2120  {
2121  if (mRepeatInterval % 1440)
2122  {
2123  if (mRepeatInterval < 60)
2124  return i18n("1 Minute", "%n Minutes", mRepeatInterval);
2125  if (mRepeatInterval % 60 == 0)
2126  return i18n("1 Hour", "%n Hours", mRepeatInterval/60);
2127  TQString mins;
2128  return i18n("Hours and Minutes", "%1H %2M").arg(TQString::number(mRepeatInterval/60)).arg(mins.sprintf("%02d", mRepeatInterval%60));
2129  }
2130  if (mRepeatInterval % (7*1440))
2131  return i18n("1 Day", "%n Days", mRepeatInterval/1440);
2132  return i18n("1 Week", "%n Weeks", mRepeatInterval/(7*1440));
2133  }
2134  return brief ? TQString() : i18n("None");
2135 }
2136 
2137 /******************************************************************************
2138  * Adjust the event date/time to the first recurrence of the event, on or after
2139  * start date/time. The event start date may not be a recurrence date, in which
2140  * case a later date will be set.
2141  */
2142 void KAEvent::setFirstRecurrence()
2143 {
2144  switch (checkRecur())
2145  {
2146  case KARecurrence::NO_RECUR:
2147  case KARecurrence::MINUTELY:
2148  return;
2149  case KARecurrence::ANNUAL_DATE:
2150  case KARecurrence::ANNUAL_POS:
2151  if (mRecurrence->yearMonths().isEmpty())
2152  return; // (presumably it's a template)
2153  break;
2154  case KARecurrence::DAILY:
2155  case KARecurrence::WEEKLY:
2156  case KARecurrence::MONTHLY_POS:
2157  case KARecurrence::MONTHLY_DAY:
2158  break;
2159  }
2160  TQDateTime recurStart = mRecurrence->startDateTime();
2161  if (mRecurrence->recursOn(recurStart.date()))
2162  return; // it already recurs on the start date
2163 
2164  // Set the frequency to 1 to find the first possible occurrence
2165  int frequency = mRecurrence->frequency();
2166  mRecurrence->setFrequency(1);
2167  DateTime next;
2168  nextRecurrence(mNextMainDateTime.dateTime(), next);
2169  if (!next.isValid())
2170  mRecurrence->setStartDateTime(recurStart); // reinstate the old value
2171  else
2172  {
2173  mRecurrence->setStartDateTime(next.dateTime());
2174  mStartDateTime = mNextMainDateTime = next;
2175  mUpdated = true;
2176  }
2177  mRecurrence->setFrequency(frequency); // restore the frequency
2178 }
2179 
2180 /******************************************************************************
2181 * Initialise the event's recurrence from a KCal::Recurrence.
2182 * The event's start date/time is not changed.
2183 */
2184 void KAEvent::setRecurrence(const KARecurrence& recurrence)
2185 {
2186  mUpdated = true;
2187  delete mRecurrence;
2188  if (recurrence.doesRecur())
2189  {
2190  mRecurrence = new KARecurrence(recurrence);
2191  mRecurrence->setStartDateTime(mStartDateTime.dateTime());
2192  mRecurrence->setFloats(mStartDateTime.isDateOnly());
2193  }
2194  else
2195  mRecurrence = 0;
2196 
2197  // Adjust sub-repetition values to fit the recurrence
2198  setRepetition(mRepeatInterval, mRepeatCount);
2199 }
2200 
2201 /******************************************************************************
2202 * Initialise the event's sub-repetition.
2203 * The repetition length is adjusted if necessary to fit any recurrence interval.
2204 * Reply = false if a non-daily interval was specified for a date-only recurrence.
2205 */
2206 bool KAEvent::setRepetition(int interval, int count)
2207 {
2208  mUpdated = true;
2209  mRepeatInterval = 0;
2210  mRepeatCount = 0;
2211  mNextRepeat = 0;
2212  if (interval > 0 && count > 0 && !mRepeatAtLogin)
2213  {
2214  Q_ASSERT(checkRecur() != KARecurrence::NO_RECUR);
2215  if (interval % 1440 && mStartDateTime.isDateOnly())
2216  return false; // interval must be in units of days for date-only alarms
2217  if (checkRecur() != KARecurrence::NO_RECUR)
2218  {
2219  int longestInterval = mRecurrence->longestInterval() - 1;
2220  if (interval * count > longestInterval)
2221  count = longestInterval / interval;
2222  }
2223  mRepeatInterval = interval;
2224  mRepeatCount = count;
2225  }
2226  return true;
2227 }
2228 
2229 /******************************************************************************
2230  * Set the recurrence to recur at a minutes interval.
2231  * Parameters:
2232  * freq = how many minutes between recurrences.
2233  * count = number of occurrences, including first and last.
2234  * = -1 to recur indefinitely.
2235  * = 0 to use 'end' instead.
2236  * end = end date/time (invalid to use 'count' instead).
2237  * Reply = false if no recurrence was set up.
2238  */
2239 bool KAEvent::setRecurMinutely(int freq, int count, const TQDateTime& end)
2240 {
2241  return setRecur(RecurrenceRule::rMinutely, freq, count, end);
2242 }
2243 
2244 /******************************************************************************
2245  * Set the recurrence to recur daily.
2246  * Parameters:
2247  * freq = how many days between recurrences.
2248  * days = which days of the week alarms are allowed to occur on.
2249  * count = number of occurrences, including first and last.
2250  * = -1 to recur indefinitely.
2251  * = 0 to use 'end' instead.
2252  * end = end date (invalid to use 'count' instead).
2253  * Reply = false if no recurrence was set up.
2254  */
2255 bool KAEvent::setRecurDaily(int freq, const TQBitArray& days, int count, const TQDate& end)
2256 {
2257  if (!setRecur(RecurrenceRule::rDaily, freq, count, end))
2258  return false;
2259  int n = 0;
2260  for (int i = 0; i < 7; ++i)
2261  {
2262  if (days.testBit(i))
2263  ++n;
2264  }
2265  if (n < 7)
2266  mRecurrence->addWeeklyDays(days);
2267  return true;
2268 }
2269 
2270 /******************************************************************************
2271  * Set the recurrence to recur weekly, on the specified weekdays.
2272  * Parameters:
2273  * freq = how many weeks between recurrences.
2274  * days = which days of the week alarms should occur on.
2275  * count = number of occurrences, including first and last.
2276  * = -1 to recur indefinitely.
2277  * = 0 to use 'end' instead.
2278  * end = end date (invalid to use 'count' instead).
2279  * Reply = false if no recurrence was set up.
2280  */
2281 bool KAEvent::setRecurWeekly(int freq, const TQBitArray& days, int count, const TQDate& end)
2282 {
2283  if (!setRecur(RecurrenceRule::rWeekly, freq, count, end))
2284  return false;
2285  mRecurrence->addWeeklyDays(days);
2286  return true;
2287 }
2288 
2289 /******************************************************************************
2290  * Set the recurrence to recur monthly, on the specified days within the month.
2291  * Parameters:
2292  * freq = how many months between recurrences.
2293  * days = which days of the month alarms should occur on.
2294  * count = number of occurrences, including first and last.
2295  * = -1 to recur indefinitely.
2296  * = 0 to use 'end' instead.
2297  * end = end date (invalid to use 'count' instead).
2298  * Reply = false if no recurrence was set up.
2299  */
2300 bool KAEvent::setRecurMonthlyByDate(int freq, const TQValueList<int>& days, int count, const TQDate& end)
2301 {
2302  if (!setRecur(RecurrenceRule::rMonthly, freq, count, end))
2303  return false;
2304  for (TQValueListConstIterator<int> it = days.begin(); it != days.end(); ++it)
2305  mRecurrence->addMonthlyDate(*it);
2306  return true;
2307 }
2308 
2309 /******************************************************************************
2310  * Set the recurrence to recur monthly, on the specified weekdays in the
2311  * specified weeks of the month.
2312  * Parameters:
2313  * freq = how many months between recurrences.
2314  * posns = which days of the week/weeks of the month alarms should occur on.
2315  * count = number of occurrences, including first and last.
2316  * = -1 to recur indefinitely.
2317  * = 0 to use 'end' instead.
2318  * end = end date (invalid to use 'count' instead).
2319  * Reply = false if no recurrence was set up.
2320  */
2321 bool KAEvent::setRecurMonthlyByPos(int freq, const TQValueList<MonthPos>& posns, int count, const TQDate& end)
2322 {
2323  if (!setRecur(RecurrenceRule::rMonthly, freq, count, end))
2324  return false;
2325  for (TQValueListConstIterator<MonthPos> it = posns.begin(); it != posns.end(); ++it)
2326  mRecurrence->addMonthlyPos((*it).weeknum, (*it).days);
2327  return true;
2328 }
2329 
2330 /******************************************************************************
2331  * Set the recurrence to recur annually, on the specified start date in each
2332  * of the specified months.
2333  * Parameters:
2334  * freq = how many years between recurrences.
2335  * months = which months of the year alarms should occur on.
2336  * day = day of month, or 0 to use start date
2337  * feb29 = when February 29th should recur in non-leap years.
2338  * count = number of occurrences, including first and last.
2339  * = -1 to recur indefinitely.
2340  * = 0 to use 'end' instead.
2341  * end = end date (invalid to use 'count' instead).
2342  * Reply = false if no recurrence was set up.
2343  */
2344 bool KAEvent::setRecurAnnualByDate(int freq, const TQValueList<int>& months, int day, KARecurrence::Feb29Type feb29, int count, const TQDate& end)
2345 {
2346  if (!setRecur(RecurrenceRule::rYearly, freq, count, end, feb29))
2347  return false;
2348  for (TQValueListConstIterator<int> it = months.begin(); it != months.end(); ++it)
2349  mRecurrence->addYearlyMonth(*it);
2350  if (day)
2351  mRecurrence->addMonthlyDate(day);
2352  return true;
2353 }
2354 
2355 /******************************************************************************
2356  * Set the recurrence to recur annually, on the specified weekdays in the
2357  * specified weeks of the specified months.
2358  * Parameters:
2359  * freq = how many years between recurrences.
2360  * posns = which days of the week/weeks of the month alarms should occur on.
2361  * months = which months of the year alarms should occur on.
2362  * count = number of occurrences, including first and last.
2363  * = -1 to recur indefinitely.
2364  * = 0 to use 'end' instead.
2365  * end = end date (invalid to use 'count' instead).
2366  * Reply = false if no recurrence was set up.
2367  */
2368 bool KAEvent::setRecurAnnualByPos(int freq, const TQValueList<MonthPos>& posns, const TQValueList<int>& months, int count, const TQDate& end)
2369 {
2370  if (!setRecur(RecurrenceRule::rYearly, freq, count, end))
2371  return false;
2372  for (TQValueListConstIterator<int> it = months.begin(); it != months.end(); ++it)
2373  mRecurrence->addYearlyMonth(*it);
2374  for (TQValueListConstIterator<MonthPos> it = posns.begin(); it != posns.end(); ++it)
2375  mRecurrence->addYearlyPos((*it).weeknum, (*it).days);
2376  return true;
2377 }
2378 
2379 /******************************************************************************
2380  * Initialise the event's recurrence data.
2381  * Parameters:
2382  * freq = how many intervals between recurrences.
2383  * count = number of occurrences, including first and last.
2384  * = -1 to recur indefinitely.
2385  * = 0 to use 'end' instead.
2386  * end = end date/time (invalid to use 'count' instead).
2387  * Reply = false if no recurrence was set up.
2388  */
2389 bool KAEvent::setRecur(RecurrenceRule::PeriodType recurType, int freq, int count, const TQDateTime& end, KARecurrence::Feb29Type feb29)
2390 {
2391  if (count >= -1 && (count || end.date().isValid()))
2392  {
2393  if (!mRecurrence)
2394  mRecurrence = new KARecurrence;
2395  if (mRecurrence->init(recurType, freq, count, mNextMainDateTime, end, feb29))
2396  {
2397  mUpdated = true;
2398  return true;
2399  }
2400  }
2401  clearRecur();
2402  return false;
2403 }
2404 
2405 /******************************************************************************
2406  * Clear the event's recurrence and alarm repetition data.
2407  */
2408 void KAEvent::clearRecur()
2409 {
2410  delete mRecurrence;
2411  mRecurrence = 0;
2412  mRepeatInterval = 0;
2413  mRepeatCount = 0;
2414  mNextRepeat = 0;
2415  mUpdated = true;
2416 }
2417 
2418 /******************************************************************************
2419 * Validate the event's recurrence data, correcting any inconsistencies (which
2420 * should never occur!).
2421 * Reply = true if a recurrence (as opposed to a login repetition) exists.
2422 */
2423 KARecurrence::Type KAEvent::checkRecur() const
2424 {
2425  if (mRecurrence)
2426  {
2427  KARecurrence::Type type = mRecurrence->type();
2428  switch (type)
2429  {
2430  case KARecurrence::MINUTELY: // hourly
2431  case KARecurrence::DAILY: // daily
2432  case KARecurrence::WEEKLY: // weekly on multiple days of week
2433  case KARecurrence::MONTHLY_DAY: // monthly on multiple dates in month
2434  case KARecurrence::MONTHLY_POS: // monthly on multiple nth day of week
2435  case KARecurrence::ANNUAL_DATE: // annually on multiple months (day of month = start date)
2436  case KARecurrence::ANNUAL_POS: // annually on multiple nth day of week in multiple months
2437  return type;
2438  default:
2439  if (mRecurrence)
2440  const_cast<KAEvent*>(this)->clearRecur(); // recurrence shouldn't exist!!
2441  break;
2442  }
2443  }
2444  return KARecurrence::NO_RECUR;
2445 }
2446 
2447 
2448 /******************************************************************************
2449  * Return the recurrence interval in units of the recurrence period type.
2450  */
2451 int KAEvent::recurInterval() const
2452 {
2453  if (mRecurrence)
2454  {
2455  switch (mRecurrence->type())
2456  {
2457  case KARecurrence::MINUTELY:
2458  case KARecurrence::DAILY:
2459  case KARecurrence::WEEKLY:
2460  case KARecurrence::MONTHLY_DAY:
2461  case KARecurrence::MONTHLY_POS:
2462  case KARecurrence::ANNUAL_DATE:
2463  case KARecurrence::ANNUAL_POS:
2464  return mRecurrence->frequency();
2465  default:
2466  break;
2467  }
2468  }
2469  return 0;
2470 }
2471 
2472 /******************************************************************************
2473 * Validate the event's alarm sub-repetition data, correcting any
2474 * inconsistencies (which should never occur!).
2475 */
2476 void KAEvent::checkRepetition() const
2477 {
2478  if (mRepeatCount && !mRepeatInterval)
2479  const_cast<KAEvent*>(this)->mRepeatCount = 0;
2480  if (!mRepeatCount && mRepeatInterval)
2481  const_cast<KAEvent*>(this)->mRepeatInterval = 0;
2482 }
2483 
2484 #if 0
2485 /******************************************************************************
2486  * Convert a TQValueList<WDayPos> to TQValueList<MonthPos>.
2487  */
2488 TQValueList<KAEvent::MonthPos> KAEvent::convRecurPos(const TQValueList<KCal::RecurrenceRule::WDayPos>& wdaypos)
2489 {
2490  TQValueList<MonthPos> mposns;
2491  for (TQValueList<KCal::RecurrenceRule::WDayPos>::ConstIterator it = wdaypos.begin(); it != wdaypos.end(); ++it)
2492  {
2493  int daybit = (*it).day() - 1;
2494  int weeknum = (*it).pos();
2495  bool found = false;
2496  for (TQValueList<MonthPos>::Iterator mit = mposns.begin(); mit != mposns.end(); ++mit)
2497  {
2498  if ((*mit).weeknum == weeknum)
2499  {
2500  (*mit).days.setBit(daybit);
2501  found = true;
2502  break;
2503  }
2504  }
2505  if (!found)
2506  {
2507  MonthPos mpos;
2508  mpos.days.fill(false);
2509  mpos.days.setBit(daybit);
2510  mpos.weeknum = weeknum;
2511  mposns.append(mpos);
2512  }
2513  }
2514  return mposns;
2515 }
2516 #endif
2517 
2518 /******************************************************************************
2519  * Find the alarm template with the specified name.
2520  * Reply = invalid event if not found.
2521  */
2522 KAEvent KAEvent::findTemplateName(AlarmCalendar& calendar, const TQString& name)
2523 {
2524  KAEvent event;
2525  Event::List events = calendar.events();
2526  for (Event::List::ConstIterator evit = events.begin(); evit != events.end(); ++evit)
2527  {
2528  Event* ev = *evit;
2529  if (ev->summary() == name)
2530  {
2531  event.set(*ev);
2532  if (!event.isTemplate())
2533  return KAEvent(); // this shouldn't ever happen
2534  break;
2535  }
2536  }
2537  return event;
2538 }
2539 
2540 /******************************************************************************
2541  * Adjust the time at which date-only events will occur for each of the events
2542  * in a list. Events for which both date and time are specified are left
2543  * unchanged.
2544  * Reply = true if any events have been updated.
2545  */
2546 bool KAEvent::adjustStartOfDay(const Event::List& events)
2547 {
2548  bool changed = false;
2549  TQTime startOfDay = Preferences::startOfDay();
2550  for (Event::List::ConstIterator evit = events.begin(); evit != events.end(); ++evit)
2551  {
2552  Event* event = *evit;
2553  const TQStringList cats = event->categories();
2554  if (cats.find(DATE_ONLY_CATEGORY) != cats.end())
2555  {
2556  // It's an untimed event, so fix it
2557  TQTime oldTime = event->dtStart().time();
2558  int adjustment = oldTime.secsTo(startOfDay);
2559  if (adjustment)
2560  {
2561  event->setDtStart(TQDateTime(event->dtStart().date(), startOfDay));
2562  Alarm::List alarms = event->alarms();
2563  int deferralOffset = 0;
2564  for (Alarm::List::ConstIterator alit = alarms.begin(); alit != alarms.end(); ++alit)
2565  {
2566  // Parse the next alarm's text
2567  Alarm& alarm = **alit;
2568  AlarmData data;
2569  readAlarm(alarm, data);
2570  if (data.type & KAAlarm::TIMED_DEFERRAL_FLAG)
2571  {
2572  // Timed deferral alarm, so adjust the offset
2573  deferralOffset = alarm.startOffset().asSeconds();
2574  alarm.setStartOffset(deferralOffset - adjustment);
2575  }
2576  else if (data.type == KAAlarm::AUDIO__ALARM
2577  && alarm.startOffset().asSeconds() == deferralOffset)
2578  {
2579  // Audio alarm is set for the same time as the deferral alarm
2580  alarm.setStartOffset(deferralOffset - adjustment);
2581  }
2582  }
2583  changed = true;
2584  }
2585  }
2586  else
2587  {
2588  // It's a timed event. Fix any untimed alarms.
2589  int deferralOffset = 0;
2590  int newDeferralOffset = 0;
2591  DateTime start;
2592  TQDateTime nextMainDateTime = readDateTime(*event, false, start).rawDateTime();
2593  AlarmMap alarmMap;
2594  readAlarms(*event, &alarmMap);
2595  for (AlarmMap::Iterator it = alarmMap.begin(); it != alarmMap.end(); ++it)
2596  {
2597  const AlarmData& data = it.data();
2598  if (!data.alarm->hasStartOffset())
2599  continue;
2600  if ((data.type & KAAlarm::DEFERRED_ALARM)
2601  && !(data.type & KAAlarm::TIMED_DEFERRAL_FLAG))
2602  {
2603  // Date-only deferral alarm, so adjust its time
2604  TQDateTime altime = nextMainDateTime.addSecs(data.alarm->startOffset().asSeconds());
2605  altime.setTime(startOfDay);
2606  deferralOffset = data.alarm->startOffset().asSeconds();
2607  newDeferralOffset = event->dtStart().secsTo(altime);
2608  const_cast<Alarm*>(data.alarm)->setStartOffset(newDeferralOffset);
2609  changed = true;
2610  }
2611  else if (data.type == KAAlarm::AUDIO__ALARM
2612  && data.alarm->startOffset().asSeconds() == deferralOffset)
2613  {
2614  // Audio alarm is set for the same time as the deferral alarm
2615  const_cast<Alarm*>(data.alarm)->setStartOffset(newDeferralOffset);
2616  changed = true;
2617  }
2618  }
2619  }
2620  }
2621  return changed;
2622 }
2623 
2624 /******************************************************************************
2625  * If the calendar was written by a previous version of KAlarm, do any
2626  * necessary format conversions on the events to ensure that when the calendar
2627  * is saved, no information is lost or corrupted.
2628  */
2629 void KAEvent::convertKCalEvents(KCal::Calendar& calendar, int version, bool adjustSummerTime)
2630 {
2631  // KAlarm pre-0.9 codes held in the alarm's DESCRIPTION property
2632  static const TQChar SEPARATOR = ';';
2633  static const TQChar LATE_CANCEL_CODE = 'C';
2634  static const TQChar AT_LOGIN_CODE = 'L'; // subsidiary alarm at every login
2635  static const TQChar DEFERRAL_CODE = 'D'; // extra deferred alarm
2636  static const TQString TEXT_PREFIX = TQString::fromLatin1("TEXT:");
2637  static const TQString FILE_PREFIX = TQString::fromLatin1("FILE:");
2638  static const TQString COMMAND_PREFIX = TQString::fromLatin1("CMD:");
2639 
2640  // KAlarm pre-0.9.2 codes held in the event's CATEGORY property
2641  static const TQString BEEP_CATEGORY = TQString::fromLatin1("BEEP");
2642 
2643  // KAlarm pre-1.1.1 LATECANCEL category with no parameter
2644  static const TQString LATE_CANCEL_CAT = TQString::fromLatin1("LATECANCEL");
2645 
2646  // KAlarm pre-1.3.0 TMPLDEFTIME category with no parameter
2647  static const TQString TEMPL_DEF_TIME_CAT = TQString::fromLatin1("TMPLDEFTIME");
2648 
2649  // KAlarm pre-1.3.1 XTERM category
2650  static const TQString EXEC_IN_XTERM_CAT = TQString::fromLatin1("XTERM");
2651 
2652  // KAlarm pre-1.4.22 properties
2653  static const TQCString KMAIL_ID_PROPERTY("KMAILID"); // X-TDE-KALARM-KMAILID property
2654 
2655  if (version >= calVersion())
2656  return;
2657 
2658  kdDebug(5950) << "KAEvent::convertKCalEvents(): adjusting version " << version << endl;
2659  bool pre_0_7 = (version < KAlarm::Version(0,7,0));
2660  bool pre_0_9 = (version < KAlarm::Version(0,9,0));
2661  bool pre_0_9_2 = (version < KAlarm::Version(0,9,2));
2662  bool pre_1_1_1 = (version < KAlarm::Version(1,1,1));
2663  bool pre_1_2_1 = (version < KAlarm::Version(1,2,1));
2664  bool pre_1_3_0 = (version < KAlarm::Version(1,3,0));
2665  bool pre_1_3_1 = (version < KAlarm::Version(1,3,1));
2666  bool pre_1_4_14 = (version < KAlarm::Version(1,4,14));
2667  bool pre_1_5_0 = (version < KAlarm::Version(1,5,0));
2668  Q_ASSERT(calVersion() == KAlarm::Version(1,5,0));
2669 
2670  TQDateTime dt0(TQDate(1970,1,1), TQTime(0,0,0));
2671  TQTime startOfDay = Preferences::startOfDay();
2672 
2673  Event::List events = calendar.rawEvents();
2674  for (Event::List::ConstIterator evit = events.begin(); evit != events.end(); ++evit)
2675  {
2676  Event* event = *evit;
2677  Alarm::List alarms = event->alarms();
2678  if (alarms.isEmpty())
2679  continue; // KAlarm isn't interested in events without alarms
2680  TQStringList cats = event->categories();
2681  bool addLateCancel = false;
2682 
2683  if (pre_0_7 && event->doesFloat())
2684  {
2685  // It's a KAlarm pre-0.7 calendar file.
2686  // Ensure that when the calendar is saved, the alarm time isn't lost.
2687  event->setFloats(false);
2688  }
2689 
2690  if (pre_0_9)
2691  {
2692  /*
2693  * It's a KAlarm pre-0.9 calendar file.
2694  * All alarms were of type DISPLAY. Instead of the X-TDE-KALARM-TYPE
2695  * alarm property, characteristics were stored as a prefix to the
2696  * alarm DESCRIPTION property, as follows:
2697  * SEQNO;[FLAGS];TYPE:TEXT
2698  * where
2699  * SEQNO = sequence number of alarm within the event
2700  * FLAGS = C for late-cancel, L for repeat-at-login, D for deferral
2701  * TYPE = TEXT or FILE or CMD
2702  * TEXT = message text, file name/URL or command
2703  */
2704  for (Alarm::List::ConstIterator alit = alarms.begin(); alit != alarms.end(); ++alit)
2705  {
2706  Alarm* alarm = *alit;
2707  bool atLogin = false;
2708  bool deferral = false;
2709  bool lateCancel = false;
2710  KAAlarmEventBase::Type action = T_MESSAGE;
2711  TQString txt = alarm->text();
2712  int length = txt.length();
2713  int i = 0;
2714  if (txt[0].isDigit())
2715  {
2716  while (++i < length && txt[i].isDigit()) ;
2717  if (i < length && txt[i++] == SEPARATOR)
2718  {
2719  while (i < length)
2720  {
2721  TQChar ch = txt[i++];
2722  if (ch == SEPARATOR)
2723  break;
2724  if (ch == LATE_CANCEL_CODE)
2725  lateCancel = true;
2726  else if (ch == AT_LOGIN_CODE)
2727  atLogin = true;
2728  else if (ch == DEFERRAL_CODE)
2729  deferral = true;
2730  }
2731  }
2732  else
2733  i = 0; // invalid prefix
2734  }
2735  if (txt.find(TEXT_PREFIX, i) == i)
2736  i += TEXT_PREFIX.length();
2737  else if (txt.find(FILE_PREFIX, i) == i)
2738  {
2739  action = T_FILE;
2740  i += FILE_PREFIX.length();
2741  }
2742  else if (txt.find(COMMAND_PREFIX, i) == i)
2743  {
2744  action = T_COMMAND;
2745  i += COMMAND_PREFIX.length();
2746  }
2747  else
2748  i = 0;
2749  txt = txt.mid(i);
2750 
2751  TQStringList types;
2752  switch (action)
2753  {
2754  case T_FILE:
2755  types += FILE_TYPE;
2756  // fall through to T_MESSAGE
2757  case T_MESSAGE:
2758  alarm->setDisplayAlarm(txt);
2759  break;
2760  case T_COMMAND:
2761  setProcedureAlarm(alarm, txt);
2762  break;
2763  case T_EMAIL: // email alarms were introduced in KAlarm 0.9
2764  case T_AUDIO: // never occurs in this context
2765  break;
2766  }
2767  if (atLogin)
2768  {
2769  types += AT_LOGIN_TYPE;
2770  lateCancel = false;
2771  }
2772  else if (deferral)
2773  types += TIME_DEFERRAL_TYPE;
2774  if (lateCancel)
2775  addLateCancel = true;
2776  if (types.count() > 0)
2777  alarm->setCustomProperty(APPNAME, TYPE_PROPERTY, types.join(","));
2778 
2779  if (pre_0_7 && alarm->repeatCount() > 0 && alarm->snoozeTime().value() > 0)
2780  {
2781  // It's a KAlarm pre-0.7 calendar file.
2782  // Minutely recurrences were stored differently.
2783  Recurrence* recur = event->recurrence();
2784  if (recur && recur->doesRecur())
2785  {
2786  recur->setMinutely(alarm->snoozeTime());
2787  recur->setDuration(alarm->repeatCount() + 1);
2788  alarm->setRepeatCount(0);
2789  alarm->setSnoozeTime(0);
2790  }
2791  }
2792 
2793  if (adjustSummerTime)
2794  {
2795  // The calendar file was written by the KDE 3.0.0 version of KAlarm 0.5.7.
2796  // Summer time was ignored when converting to UTC.
2797  TQDateTime dt = alarm->time();
2798  time_t t = dt0.secsTo(dt);
2799  struct tm* dtm = localtime(&t);
2800  if (dtm->tm_isdst)
2801  {
2802  dt = dt.addSecs(-3600);
2803  alarm->setTime(dt);
2804  }
2805  }
2806  }
2807  }
2808 
2809  if (pre_0_9_2)
2810  {
2811  /*
2812  * It's a KAlarm pre-0.9.2 calendar file.
2813  * For the expired calendar, set the CREATED time to the DTEND value.
2814  * Convert date-only DTSTART to date/time, and add category "DATE".
2815  * Set the DTEND time to the DTSTART time.
2816  * Convert all alarm times to DTSTART offsets.
2817  * For display alarms, convert the first unlabelled category to an
2818  * X-TDE-KALARM-FONTCOLOUR property.
2819  * Convert BEEP category into an audio alarm with no audio file.
2820  */
2821  if (uidStatus(event->uid()) == EXPIRED)
2822  event->setCreated(event->dtEnd());
2823  TQDateTime start = event->dtStart();
2824  if (event->doesFloat())
2825  {
2826  event->setFloats(false);
2827  start.setTime(startOfDay);
2828  cats.append(DATE_ONLY_CATEGORY);
2829  }
2830  event->setHasEndDate(false);
2831 
2832  Alarm::List::ConstIterator alit;
2833  for (alit = alarms.begin(); alit != alarms.end(); ++alit)
2834  {
2835  Alarm* alarm = *alit;
2836  TQDateTime dt = alarm->time();
2837  alarm->setStartOffset(start.secsTo(dt));
2838  }
2839 
2840  if (cats.count() > 0)
2841  {
2842  for (alit = alarms.begin(); alit != alarms.end(); ++alit)
2843  {
2844  Alarm* alarm = *alit;
2845  if (alarm->type() == Alarm::Display)
2846  alarm->setCustomProperty(APPNAME, FONT_COLOUR_PROPERTY,
2847  TQString::fromLatin1("%1;;").arg(cats[0]));
2848  }
2849  cats.remove(cats.begin());
2850  }
2851 
2852  for (TQStringList::Iterator it = cats.begin(); it != cats.end(); ++it)
2853  {
2854  if (*it == BEEP_CATEGORY)
2855  {
2856  cats.remove(it);
2857 
2858  Alarm* alarm = event->newAlarm();
2859  alarm->setEnabled(true);
2860  alarm->setAudioAlarm();
2861  TQDateTime dt = event->dtStart(); // default
2862 
2863  // Parse and order the alarms to know which one's date/time to use
2864  AlarmMap alarmMap;
2865  readAlarms(*event, &alarmMap);
2866  AlarmMap::ConstIterator it = alarmMap.begin();
2867  if (it != alarmMap.end())
2868  {
2869  dt = it.data().alarm->time();
2870  break;
2871  }
2872  alarm->setStartOffset(start.secsTo(dt));
2873  break;
2874  }
2875  }
2876  }
2877 
2878  if (pre_1_1_1)
2879  {
2880  /*
2881  * It's a KAlarm pre-1.1.1 calendar file.
2882  * Convert simple LATECANCEL category to LATECANCEL:n where n = minutes late.
2883  */
2884  TQStringList::Iterator it;
2885  while ((it = cats.find(LATE_CANCEL_CAT)) != cats.end())
2886  {
2887  cats.remove(it);
2888  addLateCancel = true;
2889  }
2890  }
2891 
2892  if (pre_1_2_1)
2893  {
2894  /*
2895  * It's a KAlarm pre-1.2.1 calendar file.
2896  * Convert email display alarms from translated to untranslated header prefixes.
2897  */
2898  for (Alarm::List::ConstIterator alit = alarms.begin(); alit != alarms.end(); ++alit)
2899  {
2900  Alarm* alarm = *alit;
2901  if (alarm->type() == Alarm::Display)
2902  {
2903  TQString oldtext = alarm->text();
2904  TQString newtext = AlarmText::toCalendarText(oldtext);
2905  if (oldtext != newtext)
2906  alarm->setDisplayAlarm(newtext);
2907  }
2908  }
2909  }
2910 
2911  if (pre_1_3_0)
2912  {
2913  /*
2914  * It's a KAlarm pre-1.3.0 calendar file.
2915  * Convert simple TMPLDEFTIME category to TMPLAFTTIME:n where n = minutes after.
2916  */
2917  TQStringList::Iterator it;
2918  while ((it = cats.find(TEMPL_DEF_TIME_CAT)) != cats.end())
2919  {
2920  cats.remove(it);
2921  cats.append(TQString("%1%2").arg(TEMPL_AFTER_TIME_CATEGORY).arg(0));
2922  }
2923  }
2924 
2925  if (pre_1_3_1)
2926  {
2927  /*
2928  * It's a KAlarm pre-1.3.1 calendar file.
2929  * Convert simple XTERM category to LOG:xterm:
2930  */
2931  TQStringList::Iterator it;
2932  while ((it = cats.find(EXEC_IN_XTERM_CAT)) != cats.end())
2933  {
2934  cats.remove(it);
2935  cats.append(LOG_CATEGORY + xtermURL);
2936  }
2937  }
2938 
2939  if (addLateCancel)
2940  cats.append(TQString("%1%2").arg(LATE_CANCEL_CATEGORY).arg(1));
2941 
2942  event->setCategories(cats);
2943 
2944 
2945  if (pre_1_4_14
2946  && event->recurrence() && event->recurrence()->doesRecur())
2947  {
2948  /*
2949  * It's a KAlarm pre-1.4.14 calendar file.
2950  * For recurring events, convert the main alarm offset to an absolute
2951  * time in the X-TDE-KALARM-NEXTRECUR property, and convert main
2952  * alarm offsets to zero and deferral alarm offsets to be relative to
2953  * the next recurrence.
2954  */
2955  bool dateOnly = (cats.find(DATE_ONLY_CATEGORY) != cats.end());
2956  DateTime startDateTime(event->dtStart(), dateOnly);
2957  // Convert the main alarm and get the next main trigger time from it
2958  DateTime nextMainDateTime;
2959  bool mainExpired = true;
2960  Alarm::List::ConstIterator alit;
2961  for (alit = alarms.begin(); alit != alarms.end(); ++alit)
2962  {
2963  Alarm* alarm = *alit;
2964  if (!alarm->hasStartOffset())
2965  continue;
2966  bool mainAlarm = true;
2967  TQString property = alarm->customProperty(APPNAME, TYPE_PROPERTY);
2968  TQStringList types = TQStringList::split(TQChar(','), property);
2969  for (unsigned int i = 0; i < types.count(); ++i)
2970  {
2971  TQString type = types[i];
2972  if (type == AT_LOGIN_TYPE
2973  || type == TIME_DEFERRAL_TYPE
2974  || type == DATE_DEFERRAL_TYPE
2975  || type == REMINDER_TYPE
2976  || type == REMINDER_ONCE_TYPE
2977  || type == DISPLAYING_TYPE
2978  || type == PRE_ACTION_TYPE
2979  || type == POST_ACTION_TYPE)
2980  mainAlarm = false;
2981  }
2982  if (mainAlarm)
2983  {
2984  mainExpired = false;
2985  nextMainDateTime = alarm->time();
2986  nextMainDateTime.setDateOnly(dateOnly);
2987  if (nextMainDateTime != startDateTime)
2988  {
2989  TQDateTime dt = nextMainDateTime.dateTime();
2990  event->setCustomProperty(APPNAME, NEXT_RECUR_PROPERTY,
2991  dt.toString(dateOnly ? "yyyyMMdd" : "yyyyMMddThhmmss"));
2992  }
2993  alarm->setStartOffset(0);
2994  }
2995  }
2996  int adjustment;
2997  if (mainExpired)
2998  {
2999  // It's an expired recurrence.
3000  // Set the alarm offset relative to the first actual occurrence
3001  // (taking account of possible exceptions).
3002  DateTime dt = event->recurrence()->getNextDateTime(startDateTime.dateTime().addDays(-1));
3003  dt.setDateOnly(dateOnly);
3004  adjustment = startDateTime.secsTo(dt);
3005  }
3006  else
3007  adjustment = startDateTime.secsTo(nextMainDateTime);
3008  if (adjustment)
3009  {
3010  // Convert deferred alarms
3011  for (alit = alarms.begin(); alit != alarms.end(); ++alit)
3012  {
3013  Alarm* alarm = *alit;
3014  if (!alarm->hasStartOffset())
3015  continue;
3016  TQString property = alarm->customProperty(APPNAME, TYPE_PROPERTY);
3017  TQStringList types = TQStringList::split(TQChar(','), property);
3018  for (unsigned int i = 0; i < types.count(); ++i)
3019  {
3020  TQString type = types[i];
3021  if (type == TIME_DEFERRAL_TYPE
3022  || type == DATE_DEFERRAL_TYPE)
3023  {
3024  alarm->setStartOffset(alarm->startOffset().asSeconds() - adjustment);
3025  break;
3026  }
3027  }
3028  }
3029  }
3030  }
3031 
3032  if (pre_1_5_0)
3033  {
3034  /*
3035  * It's a KAlarm pre-1.5.0 calendar file.
3036  * Convert email identity names to uoids.
3037  * Convert simple repetitions without a recurrence, to a recurrence.
3038  */
3039  for (Alarm::List::ConstIterator alit = alarms.begin(); alit != alarms.end(); ++alit)
3040  {
3041  Alarm* alarm = *alit;
3042  TQString name = alarm->customProperty(APPNAME, KMAIL_ID_PROPERTY);
3043  if (name.isEmpty())
3044  continue;
3045  uint id = KAMail::identityUoid(name);
3046  if (id)
3047  alarm->setCustomProperty(APPNAME, EMAIL_ID_PROPERTY, TQString::number(id));
3048  alarm->removeCustomProperty(APPNAME, KMAIL_ID_PROPERTY);
3049  }
3050  convertRepetition(event);
3051  }
3052  }
3053 }
3054 
3055 /******************************************************************************
3056 * If the calendar was written by a pre-1.4.22 version of KAlarm, or another
3057 * program, convert simple repetitions in events without a recurrence, to a
3058 * recurrence.
3059 * Reply = true if any conversions were done.
3060 */
3061 void KAEvent::convertRepetitions(KCal::CalendarLocal& calendar)
3062 {
3063 
3064  Event::List events = calendar.rawEvents();
3065  for (Event::List::ConstIterator ev = events.begin(); ev != events.end(); ++ev)
3066  convertRepetition(*ev);
3067 }
3068 
3069 /******************************************************************************
3070 * Convert simple repetitions in an event without a recurrence, to a
3071 * recurrence. Repetitions which are an exact multiple of 24 hours are converted
3072 * to daily recurrences; else they are converted to minutely recurrences. Note
3073 * that daily and minutely recurrences produce different results when they span
3074 * a daylight saving time change.
3075 * Reply = true if any conversions were done.
3076 */
3077 bool KAEvent::convertRepetition(KCal::Event* event)
3078 {
3079  Alarm::List alarms = event->alarms();
3080  if (alarms.isEmpty())
3081  return false;
3082  Recurrence* recur = event->recurrence(); // guaranteed to return non-null
3083  if (!recur->doesRecur())
3084  return false;
3085  bool converted = false;
3086  bool readOnly = event->isReadOnly();
3087  for (Alarm::List::ConstIterator alit = alarms.begin(); alit != alarms.end(); ++alit)
3088  {
3089  Alarm* alarm = *alit;
3090  if (alarm->repeatCount() > 0 && alarm->snoozeTime().value() > 0)
3091  {
3092  if (!converted)
3093  {
3094  if (readOnly)
3095  event->setReadOnly(false);
3096  if (alarm->snoozeTime() % (24*3600))
3097  recur->setMinutely(alarm->snoozeTime());
3098  else
3099  recur->setDaily(alarm->snoozeTime() / (24*3600));
3100  recur->setDuration(alarm->repeatCount() + 1);
3101  converted = true;
3102  }
3103  alarm->setRepeatCount(0);
3104  alarm->setSnoozeTime(0);
3105  }
3106  }
3107  if (converted)
3108  {
3109  if (readOnly)
3110  event->setReadOnly(true);
3111  }
3112  return converted;
3113 }
3114 
3115 #ifndef NDEBUG
3116 void KAEvent::dumpDebug() const
3117 {
3118  kdDebug(5950) << "KAEvent dump:\n";
3119  KAAlarmEventBase::dumpDebug();
3120  if (!mTemplateName.isEmpty())
3121  {
3122  kdDebug(5950) << "-- mTemplateName:" << mTemplateName << ":\n";
3123  kdDebug(5950) << "-- mTemplateAfterTime:" << mTemplateAfterTime << ":\n";
3124  }
3125  if (mActionType == T_MESSAGE || mActionType == T_FILE)
3126  {
3127  kdDebug(5950) << "-- mAudioFile:" << mAudioFile << ":\n";
3128  kdDebug(5950) << "-- mPreAction:" << mPreAction << ":\n";
3129  kdDebug(5950) << "-- mPostAction:" << mPostAction << ":\n";
3130  }
3131  else if (mActionType == T_COMMAND)
3132  {
3133  kdDebug(5950) << "-- mCommandXterm:" << (mCommandXterm ? "true" : "false") << ":\n";
3134  kdDebug(5950) << "-- mLogFile:" << mLogFile << ":\n";
3135  }
3136  kdDebug(5950) << "-- mKMailSerialNumber:" << mKMailSerialNumber << ":\n";
3137  kdDebug(5950) << "-- mCopyToKOrganizer:" << (mCopyToKOrganizer ? "true" : "false") << ":\n";
3138  kdDebug(5950) << "-- mStartDateTime:" << mStartDateTime.toString() << ":\n";
3139  kdDebug(5950) << "-- mSaveDateTime:" << mSaveDateTime.toString() << ":\n";
3140  if (mRepeatAtLogin)
3141  kdDebug(5950) << "-- mAtLoginDateTime:" << mAtLoginDateTime.toString() << ":\n";
3142  kdDebug(5950) << "-- mArchiveRepeatAtLogin:" << (mArchiveRepeatAtLogin ? "true" : "false") << ":\n";
3143  kdDebug(5950) << "-- mEnabled:" << (mEnabled ? "true" : "false") << ":\n";
3144  if (mReminderMinutes)
3145  kdDebug(5950) << "-- mReminderMinutes:" << mReminderMinutes << ":\n";
3146  if (mArchiveReminderMinutes)
3147  kdDebug(5950) << "-- mArchiveReminderMinutes:" << mArchiveReminderMinutes << ":\n";
3148  if (mReminderMinutes || mArchiveReminderMinutes)
3149  kdDebug(5950) << "-- mReminderOnceOnly:" << mReminderOnceOnly << ":\n";
3150  else if (mDeferral > 0)
3151  {
3152  kdDebug(5950) << "-- mDeferral:" << (mDeferral == NORMAL_DEFERRAL ? "normal" : "reminder") << ":\n";
3153  kdDebug(5950) << "-- mDeferralTime:" << mDeferralTime.toString() << ":\n";
3154  }
3155  else if (mDeferral == CANCEL_DEFERRAL)
3156  kdDebug(5950) << "-- mDeferral:cancel:\n";
3157  kdDebug(5950) << "-- mDeferDefaultMinutes:" << mDeferDefaultMinutes << ":\n";
3158  if (mDisplaying)
3159  {
3160  kdDebug(5950) << "-- mDisplayingTime:" << mDisplayingTime.toString() << ":\n";
3161  kdDebug(5950) << "-- mDisplayingFlags:" << mDisplayingFlags << ":\n";
3162  }
3163  kdDebug(5950) << "-- mRevision:" << mRevision << ":\n";
3164  kdDebug(5950) << "-- mRecurrence:" << (mRecurrence ? "true" : "false") << ":\n";
3165  kdDebug(5950) << "-- mAlarmCount:" << mAlarmCount << ":\n";
3166  kdDebug(5950) << "-- mMainExpired:" << (mMainExpired ? "true" : "false") << ":\n";
3167  kdDebug(5950) << "KAEvent dump end\n";
3168 }
3169 #endif
3170 
3171 
3172 /*=============================================================================
3173 = Class KAAlarm
3174 = Corresponds to a single KCal::Alarm instance.
3175 =============================================================================*/
3176 
3177 KAAlarm::KAAlarm(const KAAlarm& alarm)
3178  : KAAlarmEventBase(alarm),
3179  mType(alarm.mType),
3180  mRecurs(alarm.mRecurs),
3181  mDeferred(alarm.mDeferred)
3182 { }
3183 
3184 
3185 int KAAlarm::flags() const
3186 {
3187  return KAAlarmEventBase::flags()
3188  | (mDeferred ? KAEvent::DEFERRAL : 0);
3189 
3190 }
3191 
3192 #ifndef NDEBUG
3193 void KAAlarm::dumpDebug() const
3194 {
3195  kdDebug(5950) << "KAAlarm dump:\n";
3196  KAAlarmEventBase::dumpDebug();
3197  const char* altype = 0;
3198  switch (mType)
3199  {
3200  case MAIN__ALARM: altype = "MAIN"; break;
3201  case REMINDER__ALARM: altype = "REMINDER"; break;
3202  case DEFERRED_DATE__ALARM: altype = "DEFERRED(DATE)"; break;
3203  case DEFERRED_TIME__ALARM: altype = "DEFERRED(TIME)"; break;
3204  case DEFERRED_REMINDER_DATE__ALARM: altype = "DEFERRED_REMINDER(DATE)"; break;
3205  case DEFERRED_REMINDER_TIME__ALARM: altype = "DEFERRED_REMINDER(TIME)"; break;
3206  case AT_LOGIN__ALARM: altype = "LOGIN"; break;
3207  case DISPLAYING__ALARM: altype = "DISPLAYING"; break;
3208  case AUDIO__ALARM: altype = "AUDIO"; break;
3209  case PRE_ACTION__ALARM: altype = "PRE_ACTION"; break;
3210  case POST_ACTION__ALARM: altype = "POST_ACTION"; break;
3211  default: altype = "INVALID"; break;
3212  }
3213  kdDebug(5950) << "-- mType:" << altype << ":\n";
3214  kdDebug(5950) << "-- mRecurs:" << (mRecurs ? "true" : "false") << ":\n";
3215  kdDebug(5950) << "-- mDeferred:" << (mDeferred ? "true" : "false") << ":\n";
3216  kdDebug(5950) << "KAAlarm dump end\n";
3217 }
3218 
3219 const char* KAAlarm::debugType(Type type)
3220 {
3221  switch (type)
3222  {
3223  case MAIN_ALARM: return "MAIN";
3224  case REMINDER_ALARM: return "REMINDER";
3225  case DEFERRED_ALARM: return "DEFERRED";
3226  case DEFERRED_REMINDER_ALARM: return "DEFERRED_REMINDER";
3227  case AT_LOGIN_ALARM: return "LOGIN";
3228  case DISPLAYING_ALARM: return "DISPLAYING";
3229  case AUDIO_ALARM: return "AUDIO";
3230  case PRE_ACTION_ALARM: return "PRE_ACTION";
3231  case POST_ACTION_ALARM: return "POST_ACTION";
3232  default: return "INVALID";
3233  }
3234 }
3235 #endif
3236 
3237 
3238 /*=============================================================================
3239 = Class KAAlarmEventBase
3240 =============================================================================*/
3241 
3242 void KAAlarmEventBase::copy(const KAAlarmEventBase& rhs)
3243 {
3244  mEventID = rhs.mEventID;
3245  mText = rhs.mText;
3246  mNextMainDateTime = rhs.mNextMainDateTime;
3247  mBgColour = rhs.mBgColour;
3248  mFgColour = rhs.mFgColour;
3249  mFont = rhs.mFont;
3250  mEmailFromIdentity = rhs.mEmailFromIdentity;
3251  mEmailAddresses = rhs.mEmailAddresses;
3252  mEmailSubject = rhs.mEmailSubject;
3253  mEmailAttachments = rhs.mEmailAttachments;
3254  mSoundVolume = rhs.mSoundVolume;
3255  mFadeVolume = rhs.mFadeVolume;
3256  mFadeSeconds = rhs.mFadeSeconds;
3257  mActionType = rhs.mActionType;
3258  mCommandScript = rhs.mCommandScript;
3259  mRepeatCount = rhs.mRepeatCount;
3260  mRepeatInterval = rhs.mRepeatInterval;
3261  mNextRepeat = rhs.mNextRepeat;
3262  mBeep = rhs.mBeep;
3263  mSpeak = rhs.mSpeak;
3264  mRepeatSound = rhs.mRepeatSound;
3265  mRepeatAtLogin = rhs.mRepeatAtLogin;
3266  mDisplaying = rhs.mDisplaying;
3267  mLateCancel = rhs.mLateCancel;
3268  mAutoClose = rhs.mAutoClose;
3269  mEmailBcc = rhs.mEmailBcc;
3270  mConfirmAck = rhs.mConfirmAck;
3271  mDefaultFont = rhs.mDefaultFont;
3272 }
3273 
3274 void KAAlarmEventBase::set(int flags)
3275 {
3276  mSpeak = flags & KAEvent::SPEAK;
3277  mBeep = (flags & KAEvent::BEEP) && !mSpeak;
3278  mRepeatSound = flags & KAEvent::REPEAT_SOUND;
3279  mRepeatAtLogin = flags & KAEvent::REPEAT_AT_LOGIN;
3280  mAutoClose = (flags & KAEvent::AUTO_CLOSE) && mLateCancel;
3281  mEmailBcc = flags & KAEvent::EMAIL_BCC;
3282  mConfirmAck = flags & KAEvent::CONFIRM_ACK;
3283  mDisplaying = flags & KAEvent::DISPLAYING_;
3284  mDefaultFont = flags & KAEvent::DEFAULT_FONT;
3285  mCommandScript = flags & KAEvent::SCRIPT;
3286 }
3287 
3288 int KAAlarmEventBase::flags() const
3289 {
3290  return (mBeep && !mSpeak ? KAEvent::BEEP : 0)
3291  | (mSpeak ? KAEvent::SPEAK : 0)
3292  | (mRepeatSound ? KAEvent::REPEAT_SOUND : 0)
3293  | (mRepeatAtLogin ? KAEvent::REPEAT_AT_LOGIN : 0)
3294  | (mAutoClose ? KAEvent::AUTO_CLOSE : 0)
3295  | (mEmailBcc ? KAEvent::EMAIL_BCC : 0)
3296  | (mConfirmAck ? KAEvent::CONFIRM_ACK : 0)
3297  | (mDisplaying ? KAEvent::DISPLAYING_ : 0)
3298  | (mDefaultFont ? KAEvent::DEFAULT_FONT : 0)
3299  | (mCommandScript ? KAEvent::SCRIPT : 0);
3300 }
3301 
3302 const TQFont& KAAlarmEventBase::font() const
3303 {
3304  return mDefaultFont ? Preferences::messageFont() : mFont;
3305 }
3306 
3307 #ifndef NDEBUG
3308 void KAAlarmEventBase::dumpDebug() const
3309 {
3310  kdDebug(5950) << "-- mEventID:" << mEventID << ":\n";
3311  kdDebug(5950) << "-- mActionType:" << (mActionType == T_MESSAGE ? "MESSAGE" : mActionType == T_FILE ? "FILE" : mActionType == T_COMMAND ? "COMMAND" : mActionType == T_EMAIL ? "EMAIL" : mActionType == T_AUDIO ? "AUDIO" : "??") << ":\n";
3312  kdDebug(5950) << "-- mText:" << mText << ":\n";
3313  if (mActionType == T_COMMAND)
3314  kdDebug(5950) << "-- mCommandScript:" << (mCommandScript ? "true" : "false") << ":\n";
3315  kdDebug(5950) << "-- mNextMainDateTime:" << mNextMainDateTime.toString() << ":\n";
3316  if (mActionType == T_EMAIL)
3317  {
3318  kdDebug(5950) << "-- mEmail: FromKMail:" << mEmailFromIdentity << ":\n";
3319  kdDebug(5950) << "-- Addresses:" << mEmailAddresses.join(", ") << ":\n";
3320  kdDebug(5950) << "-- Subject:" << mEmailSubject << ":\n";
3321  kdDebug(5950) << "-- Attachments:" << mEmailAttachments.join(", ") << ":\n";
3322  kdDebug(5950) << "-- Bcc:" << (mEmailBcc ? "true" : "false") << ":\n";
3323  }
3324  kdDebug(5950) << "-- mBgColour:" << TQString(mBgColour.name()) << ":\n";
3325  kdDebug(5950) << "-- mFgColour:" << TQString(mFgColour.name()) << ":\n";
3326  kdDebug(5950) << "-- mDefaultFont:" << (mDefaultFont ? "true" : "false") << ":\n";
3327  if (!mDefaultFont)
3328  kdDebug(5950) << "-- mFont:" << TQString(mFont.toString()) << ":\n";
3329  kdDebug(5950) << "-- mBeep:" << (mBeep ? "true" : "false") << ":\n";
3330  kdDebug(5950) << "-- mSpeak:" << (mSpeak ? "true" : "false") << ":\n";
3331  if (mActionType == T_AUDIO)
3332  {
3333  if (mSoundVolume >= 0)
3334  {
3335  kdDebug(5950) << "-- mSoundVolume:" << mSoundVolume << ":\n";
3336  if (mFadeVolume >= 0)
3337  {
3338  kdDebug(5950) << "-- mFadeVolume:" << mFadeVolume << ":\n";
3339  kdDebug(5950) << "-- mFadeSeconds:" << mFadeSeconds << ":\n";
3340  }
3341  else
3342  kdDebug(5950) << "-- mFadeVolume:-:\n";
3343  }
3344  else
3345  kdDebug(5950) << "-- mSoundVolume:-:\n";
3346  kdDebug(5950) << "-- mRepeatSound:" << (mRepeatSound ? "true" : "false") << ":\n";
3347  }
3348  kdDebug(5950) << "-- mConfirmAck:" << (mConfirmAck ? "true" : "false") << ":\n";
3349  kdDebug(5950) << "-- mRepeatAtLogin:" << (mRepeatAtLogin ? "true" : "false") << ":\n";
3350  kdDebug(5950) << "-- mRepeatCount:" << mRepeatCount << ":\n";
3351  kdDebug(5950) << "-- mRepeatInterval:" << mRepeatInterval << ":\n";
3352  kdDebug(5950) << "-- mNextRepeat:" << mNextRepeat << ":\n";
3353  kdDebug(5950) << "-- mDisplaying:" << (mDisplaying ? "true" : "false") << ":\n";
3354  kdDebug(5950) << "-- mLateCancel:" << mLateCancel << ":\n";
3355  kdDebug(5950) << "-- mAutoClose:" << (mAutoClose ? "true" : "false") << ":\n";
3356 }
3357 #endif
3358 
3359 
3360 /*=============================================================================
3361 = Class EmailAddressList
3362 =============================================================================*/
3363 
3364 /******************************************************************************
3365  * Sets the list of email addresses, removing any empty addresses.
3366  * Reply = false if empty addresses were found.
3367  */
3368 EmailAddressList& EmailAddressList::operator=(const TQValueList<Person>& addresses)
3369 {
3370  clear();
3371  for (TQValueList<Person>::ConstIterator it = addresses.begin(); it != addresses.end(); ++it)
3372  {
3373  if (!(*it).email().isEmpty())
3374  append(*it);
3375  }
3376  return *this;
3377 }
3378 
3379 /******************************************************************************
3380  * Return the email address list as a string, each address being delimited by
3381  * the specified separator string.
3382  */
3383 TQString EmailAddressList::join(const TQString& separator) const
3384 {
3385  TQString result;
3386  bool first = true;
3387  for (TQValueList<Person>::ConstIterator it = begin(); it != end(); ++it)
3388  {
3389  if (first)
3390  first = false;
3391  else
3392  result += separator;
3393 
3394  bool quote = false;
3395  TQString name = (*it).name();
3396  if (!name.isEmpty())
3397  {
3398  // Need to enclose the name in quotes if it has any special characters
3399  int len = name.length();
3400  for (int i = 0; i < len; ++i)
3401  {
3402  TQChar ch = name[i];
3403  if (!ch.isLetterOrNumber())
3404  {
3405  quote = true;
3406  result += '\"';
3407  break;
3408  }
3409  }
3410  result += (*it).name();
3411  result += (quote ? "\" <" : " <");
3412  quote = true; // need angle brackets round email address
3413  }
3414 
3415  result += (*it).email();
3416  if (quote)
3417  result += '>';
3418  }
3419  return result;
3420 }
3421 
3422 
3423 /*=============================================================================
3424 = Static functions
3425 =============================================================================*/
3426 
3427 /******************************************************************************
3428  * Set the specified alarm to be a procedure alarm with the given command line.
3429  * The command line is first split into its program file and arguments before
3430  * initialising the alarm.
3431  */
3432 static void setProcedureAlarm(Alarm* alarm, const TQString& commandLine)
3433 {
3434  TQString command = TQString();
3435  TQString arguments = TQString();
3436  TQChar quoteChar;
3437  bool quoted = false;
3438  uint posMax = commandLine.length();
3439  uint pos;
3440  for (pos = 0; pos < posMax; ++pos)
3441  {
3442  TQChar ch = commandLine[pos];
3443  if (quoted)
3444  {
3445  if (ch == quoteChar)
3446  {
3447  ++pos; // omit the quote character
3448  break;
3449  }
3450  command += ch;
3451  }
3452  else
3453  {
3454  bool done = false;
3455  switch (ch)
3456  {
3457  case ' ':
3458  case ';':
3459  case '|':
3460  case '<':
3461  case '>':
3462  done = !command.isEmpty();
3463  break;
3464  case '\'':
3465  case '"':
3466  if (command.isEmpty())
3467  {
3468  // Start of a quoted string. Omit the quote character.
3469  quoted = true;
3470  quoteChar = ch;
3471  break;
3472  }
3473  // fall through to default
3474  default:
3475  command += ch;
3476  break;
3477  }
3478  if (done)
3479  break;
3480  }
3481  }
3482 
3483  // Skip any spaces after the command
3484  for ( ; pos < posMax && commandLine[pos] == ' '; ++pos) ;
3485  arguments = commandLine.mid(pos);
3486 
3487  alarm->setProcedureAlarm(command, arguments);
3488 }
represents calendar alarms and events
Provides read and write access to calendar files.
Definition: alarmcalendar.h:37
KAEvent corresponds to a KCal::Event instance.
Definition: alarmevent.h:232
Status
The category of an event, indicated by the middle part of its UID.
Definition: alarmevent.h:270
void setAudioAlarm(const TQString &audioFile=TQString())
bool hasStartOffset() const
TQString audioFile() const
Duration snoozeTime() const
TQString programFile() const
void setRepeatCount(int alarmRepeatCount)
TQString mailSubject() const
TQDateTime time() const
TQString text() const
void setEnabled(bool enable)
void setDisplayAlarm(const TQString &text=TQString())
Duration startOffset() const
void setSnoozeTime(const Duration &alarmSnoozeTime)
TQString programArguments() const
void setEmailAlarm(const TQString &subject, const TQString &text, const TQValueList< Person > &addressees, const TQStringList &attachments=TQStringList())
TQString mailText() const
void setStartOffset(const Duration &)
TQValueList< Person > mailAddresses() const
void setTime(const TQDateTime &alarmTime)
Type type() const
void setProcedureAlarm(const TQString &programFile, const TQString &arguments=TQString())
int repeatCount() const
TQStringList mailAttachments() const
Event::List rawEvents(EventSortField sortField=EventSortUnsorted, SortDirection sortDirection=SortDirectionAscending)
virtual Event::List rawEvents(EventSortField sortField=EventSortUnsorted, SortDirection sortDirection=SortDirectionAscending)=0
void setCustomProperty(const TQCString &app, const TQCString &key, const TQString &value)
TQString customProperty(const TQCString &app, const TQCString &key) const
void removeCustomProperty(const TQCString &app, const TQCString &key)
TQDateTime end(const TQDateTime &start) const
int value() const
int asSeconds() const
void setHasEndDate(bool)
void setTransparency(Transparency transparency)
TQString uid() const
void setUid(const TQString &)
virtual TQDateTime dtStart() const
bool isReadOnly() const
TQString statusStr() const
void setReadOnly(bool readonly)
const Alarm::List & alarms() const
void setSummary(const TQString &summary)
void setCustomStatus(const TQString &status)
TQStringList categories() const
void setFloats(bool f)
virtual void setDtStart(const TQDateTime &dtStart)
void setCategories(const TQStringList &categories)
void clearRecurrence()
TQString summary() const
Recurrence * recurrence() const
void setRevision(int rev)
void setCreated(const TQDateTime &)
void setMinutely(int freq)
void setDaily(int freq)
bool doesRecur() const
void setDuration(int duration)
miscellaneous functions
the KAlarm application object