00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdlib.h>
00022 #include <time.h>
00023 #include <ctype.h>
00024 #include <qcolor.h>
00025 #include <qregexp.h>
00026 #include <kdebug.h>
00027
00028 #include "kalarm.h"
00029 #include "kalarmapp.h"
00030 #include "prefsettings.h"
00031 #include "alarmcalendar.h"
00032 #include "msgevent.h"
00033 using namespace KCal;
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 static const QChar SEPARATOR = QChar(';');
00046 static const QString TEXT_PREFIX = QString::fromLatin1("TEXT:");
00047 static const QString FILE_PREFIX = QString::fromLatin1("FILE:");
00048 static const QString COMMAND_PREFIX = QString::fromLatin1("CMD:");
00049 static const QString LATE_CANCEL_CODE = QString::fromLatin1("C");
00050 static const QString AT_LOGIN_CODE = QString::fromLatin1("L");
00051 static const QString DEFERRAL_CODE = QString::fromLatin1("D");
00052 static const QString BEEP_CATEGORY = QString::fromLatin1("BEEP");
00053 static const QString CONFIRM_ACK_CATEGORY = QString::fromLatin1("ACKCONF");
00054
00055 struct AlarmData
00056 {
00057 QString cleanText;
00058 QDateTime dateTime;
00059 int repeatCount;
00060 int repeatMinutes;
00061 KAlarmAlarm::Type type;
00062 bool lateCancel;
00063 bool repeatAtLogin;
00064 bool deferral;
00065 };
00066 typedef QMap<int, AlarmData> AlarmMap;
00067
00068
00069
00070
00071
00072
00073
00074 const int KAlarmEvent::MAIN_ALARM_ID = 1;
00075 const int KAlarmEvent::REPEAT_AT_LOGIN_OFFSET = 1;
00076 const int KAlarmEvent::DEFERRAL_OFFSET = 2;
00077 const int KAlarmEvent::AUDIO_ALARM_ID = 100;
00078
00079
00080 void KAlarmEvent::copy(const KAlarmEvent& event)
00081 {
00082 mEventID = event.mEventID;
00083 mCleanText = event.mCleanText;
00084 mAudioFile = event.mAudioFile;
00085 mDateTime = event.mDateTime;
00086 mRepeatAtLoginDateTime = event.mRepeatAtLoginDateTime;
00087 mDeferralTime = event.mDeferralTime;
00088 mColour = event.mColour;
00089 mType = event.mType;
00090 mRevision = event.mRevision;
00091 mRepeatDuration = event.mRepeatDuration;
00092 mAlarmCount = event.mAlarmCount;
00093 mMainAlarmID = event.mMainAlarmID;
00094 mRepeatAtLoginAlarmID = event.mRepeatAtLoginAlarmID;
00095 mDeferralAlarmID = event.mDeferralAlarmID;
00096 mRecursFeb29 = event.mRecursFeb29;
00097 mAnyTime = event.mAnyTime;
00098 mBeep = event.mBeep;
00099 mRepeatAtLogin = event.mRepeatAtLogin;
00100 mDeferral = event.mDeferral;
00101 mLateCancel = event.mLateCancel;
00102 mConfirmAck = event.mConfirmAck;
00103 mUpdated = event.mUpdated;
00104 delete mRecurrence;
00105 if (event.mRecurrence)
00106 mRecurrence = new Recurrence(*event.mRecurrence, 0L);
00107 else
00108 mRecurrence = 0L;
00109 }
00110
00111
00112
00113
00114 void KAlarmEvent::set(const Event& event)
00115 {
00116
00117 mEventID = event.uid();
00118 mRevision = event.revision();
00119 const QStringList& cats = event.categories();
00120 mBeep = false;
00121 mConfirmAck = false;
00122 mColour = QColor(255, 255, 255);
00123 if (cats.count() > 0)
00124 {
00125 QColor colour(cats[0]);
00126 if (colour.isValid())
00127 mColour = colour;
00128
00129 for (unsigned int i = 1; i < cats.count(); ++i)
00130 if (cats[i] == BEEP_CATEGORY)
00131 mBeep = true;
00132 else if (cats[i] == CONFIRM_ACK_CATEGORY)
00133 mConfirmAck = true;
00134 }
00135
00136
00137
00138 mType = KAlarmAlarm::MESSAGE;
00139 mRecursFeb29 = false;
00140 mLateCancel = false;
00141 mRepeatAtLogin = false;
00142 mDeferral = false;
00143 mCleanText = "";
00144 mAudioFile = "";
00145 mDateTime = event.dtStart();
00146 mAnyTime = event.doesFloat();
00147 initRecur(false);
00148
00149
00150 AlarmMap alarmMap;
00151 QPtrList<Alarm> alarms = event.alarms();
00152 for (QPtrListIterator<Alarm> ia(alarms); ia.current(); ++ia)
00153 {
00154
00155 AlarmData data;
00156 int sequence = readAlarm(*ia.current(), data);
00157 alarmMap.insert(sequence, data);
00158 }
00159
00160
00161 AlarmMap::ConstIterator it = alarmMap.begin();
00162 mMainAlarmID = -1;
00163 mAlarmCount = 0;
00164 int repeatCount = 0;
00165 int repeatMinutes = 0;
00166 bool set = false;
00167 for ( ; it != alarmMap.end(); ++it)
00168 {
00169 bool main = false;
00170 const AlarmData& data = it.data();
00171 if (data.type == KAlarmAlarm::AUDIO)
00172 mAudioFile = data.cleanText;
00173 else if (data.repeatAtLogin)
00174 {
00175 mRepeatAtLogin = true;
00176 mRepeatAtLoginDateTime = data.dateTime;
00177 mRepeatAtLoginAlarmID = it.key();
00178 }
00179 else if (data.deferral)
00180 {
00181 mDeferral = true;
00182 mDeferralTime = data.dateTime;
00183 mDeferralAlarmID = it.key();
00184 }
00185 else
00186 {
00187 mMainAlarmID = it.key();
00188 main = true;
00189 }
00190
00191
00192
00193 if (main || !set)
00194 {
00195 if (data.type != KAlarmAlarm::AUDIO)
00196 {
00197 mType = data.type;
00198 mCleanText = (mType == KAlarmAlarm::COMMAND) ? data.cleanText.stripWhiteSpace() : data.cleanText;
00199 }
00200 mDateTime = data.dateTime;
00201 if (data.repeatCount && data.repeatMinutes)
00202 {
00203
00204 repeatCount = data.repeatCount;
00205 repeatMinutes = data.repeatMinutes;
00206 }
00207 if (mAnyTime)
00208 mDateTime.setTime(QTime());
00209 mLateCancel = data.lateCancel;
00210 set = true;
00211 }
00212 ++mAlarmCount;
00213 }
00214
00215 Recurrence* recur = event.recurrence();
00216 if (recur && recur->doesRecur() != Recurrence::rNone)
00217 {
00218
00219 QDateTime savedDT = mDateTime;
00220 switch (recur->doesRecur())
00221 {
00222 case Recurrence::rYearlyMonth:
00223 {
00224 QDate start = recur->recurStart().date();
00225 mRecursFeb29 = (start.day() == 29 && start.month() == 2);
00226
00227 }
00228 case Recurrence::rMinutely:
00229 case Recurrence::rHourly:
00230 case Recurrence::rDaily:
00231 case Recurrence::rWeekly:
00232 case Recurrence::rMonthlyDay:
00233 case Recurrence::rMonthlyPos:
00234 case Recurrence::rYearlyPos:
00235 case Recurrence::rYearlyDay:
00236 delete mRecurrence;
00237 mRecurrence = new Recurrence(*recur, 0L);
00238 mRepeatDuration = recur->duration();
00239 if (mRepeatDuration > 0)
00240 mRepeatDuration -= recur->durationTo(savedDT) - 1;
00241 break;
00242 default:
00243 mDateTime = savedDT;
00244 break;
00245 }
00246 }
00247 else if (repeatCount > 0 && repeatMinutes > 0)
00248 {
00249
00250 delete mRecurrence;
00251 mRecurrence = new Recurrence(0L);
00252 mRepeatDuration = repeatCount + 1;
00253 mRecurrence->setMinutely(repeatMinutes, mRepeatDuration);
00254 }
00255
00256 mUpdated = false;
00257 }
00258
00259
00260
00261
00262
00263 int KAlarmEvent::readAlarm(const Alarm& alarm, AlarmData& data)
00264 {
00265
00266 int sequence;
00267 data.lateCancel = false;
00268 data.repeatAtLogin = false;
00269 data.deferral = false;
00270 if (!alarm.audioFile().isEmpty())
00271 {
00272 data.type = KAlarmAlarm::AUDIO;
00273 data.cleanText = alarm.audioFile();
00274 sequence = AUDIO_ALARM_ID;
00275 }
00276 else
00277 {
00278
00279 data.type = KAlarmAlarm::MESSAGE;
00280 sequence = MAIN_ALARM_ID;
00281 const QString& txt = alarm.text();
00282 int length = txt.length();
00283 int i = 0;
00284 if (txt[0].isDigit())
00285 {
00286 sequence = txt[0].digitValue();
00287 for (i = 1; i < length; ++i)
00288 if (txt[i].isDigit())
00289 sequence = sequence * 10 + txt[i].digitValue();
00290 else
00291 {
00292 if (txt[i++] == SEPARATOR)
00293 {
00294 while (i < length)
00295 {
00296 QChar ch = txt[i++];
00297 if (ch == SEPARATOR)
00298 break;
00299 if (ch == LATE_CANCEL_CODE)
00300 data.lateCancel = true;
00301 else if (ch == AT_LOGIN_CODE)
00302 data.repeatAtLogin = true;
00303 else if (ch == DEFERRAL_CODE)
00304 data.deferral = true;
00305 }
00306 }
00307 else
00308 {
00309 i = 0;
00310 sequence = MAIN_ALARM_ID;
00311 }
00312 break;
00313 }
00314 }
00315 if (txt.find(TEXT_PREFIX, i) == i)
00316 i += TEXT_PREFIX.length();
00317 else if (txt.find(FILE_PREFIX, i) == i)
00318 {
00319 data.type = KAlarmAlarm::FILE;
00320 i += FILE_PREFIX.length();
00321 }
00322 else if (txt.find(COMMAND_PREFIX, i) == i)
00323 {
00324 data.type = KAlarmAlarm::COMMAND;
00325 i += COMMAND_PREFIX.length();
00326 }
00327 else
00328 i = 0;
00329
00330 data.cleanText = txt.mid(i);
00331 }
00332 data.dateTime = alarm.time();
00333 data.repeatCount = alarm.repeatCount();
00334 data.repeatMinutes = alarm.snoozeTime();
00335 return sequence;
00336 }
00337
00338
00339
00340
00341 void KAlarmEvent::set(const QDateTime& dateTime, const QString& text, const QColor& colour, KAlarmAlarm::Type type, int flags)
00342 {
00343 initRecur(false);
00344 mMainAlarmID = MAIN_ALARM_ID;
00345 mDateTime = dateTime;
00346 mCleanText = (type == KAlarmAlarm::COMMAND) ? text.stripWhiteSpace() : text;
00347 mAudioFile = "";
00348 mType = type;
00349 mColour = colour;
00350 set(flags);
00351 mDeferral = false;
00352 mUpdated = false;
00353 }
00354
00355 void KAlarmEvent::set(int flags)
00356 {
00357 mBeep = flags & BEEP;
00358 mRepeatAtLogin = flags & REPEAT_AT_LOGIN;
00359 mLateCancel = flags & LATE_CANCEL;
00360 mConfirmAck = flags & CONFIRM_ACK;
00361 mAnyTime = flags & ANY_TIME;
00362 }
00363
00364 int KAlarmEvent::flags() const
00365 {
00366 return (mBeep ? BEEP : 0)
00367 | (mRepeatAtLogin ? REPEAT_AT_LOGIN : 0)
00368 | (mLateCancel ? LATE_CANCEL : 0)
00369 | (mConfirmAck ? CONFIRM_ACK : 0)
00370 | (mAnyTime ? ANY_TIME : 0)
00371 | (mDeferral ? DEFERRAL : 0);
00372 }
00373
00374
00375
00376
00377 Event* KAlarmEvent::event() const
00378 {
00379 Event* ev = new KCal::Event;
00380 updateEvent(*ev);
00381 return ev;
00382 }
00383
00384
00385
00386
00387 bool KAlarmEvent::updateEvent(Event& ev) const
00388 {
00389 if (!mEventID.isEmpty() && mEventID != ev.uid())
00390 return false;
00391 checkRecur();
00392 bool readOnly = ev.isReadOnly();
00393 ev.setReadOnly(false);
00394
00395
00396 QStringList cats;
00397 cats.append(mColour.name());
00398 if (mBeep)
00399 cats.append(BEEP_CATEGORY);
00400 if (mConfirmAck)
00401 cats.append(CONFIRM_ACK_CATEGORY);
00402 ev.setCategories(cats);
00403 ev.setRevision(mRevision);
00404
00405
00406 ev.clearAlarms();
00407 Alarm* al = ev.newAlarm();
00408 al->setEnabled(true);
00409 QString suffix;
00410 if (mLateCancel)
00411 suffix = LATE_CANCEL_CODE;
00412 suffix += SEPARATOR;
00413 switch (mType)
00414 {
00415 case KAlarmAlarm::MESSAGE: suffix += TEXT_PREFIX; break;
00416 case KAlarmAlarm::FILE: suffix += FILE_PREFIX; break;
00417 case KAlarmAlarm::COMMAND: suffix += COMMAND_PREFIX; break;
00418 case KAlarmAlarm::AUDIO: break;
00419 }
00420 suffix += mCleanText;
00421 al->setText(QString::number(MAIN_ALARM_ID) + SEPARATOR + suffix);
00422 QDateTime aldt = mDateTime;
00423 if (mAnyTime)
00424 aldt.setTime(theApp()->settings()->startOfDay());
00425 al->setTime(aldt);
00426 QDateTime dt = mDateTime;
00427
00428
00429 if (mRepeatAtLogin)
00430 {
00431 al = ev.newAlarm();
00432 al->setEnabled(true);
00433 al->setText(QString::number(MAIN_ALARM_ID + REPEAT_AT_LOGIN_OFFSET)
00434 + SEPARATOR + AT_LOGIN_CODE + suffix);
00435 QDateTime dtl = mRepeatAtLoginDateTime.isValid() ? mRepeatAtLoginDateTime
00436 : QDateTime::currentDateTime();
00437 al->setTime(dtl);
00438 if (dtl < dt)
00439 dt = dtl;
00440 }
00441 if (mDeferral)
00442 {
00443 al = ev.newAlarm();
00444 al->setEnabled(true);
00445 al->setText(QString::number(MAIN_ALARM_ID + DEFERRAL_OFFSET)
00446 + SEPARATOR + DEFERRAL_CODE + suffix);
00447 al->setTime(mDeferralTime);
00448 if (mDeferralTime < dt)
00449 dt = mDeferralTime;
00450 }
00451 if (!mAudioFile.isEmpty())
00452 {
00453 al = ev.newAlarm();
00454 al->setEnabled(true);
00455 al->setAudioFile(mAudioFile);
00456 al->setTime(aldt);
00457 }
00458
00459
00460 if (mRecurrence)
00461 {
00462 Recurrence* recur = ev.recurrence();
00463 int frequency = mRecurrence->frequency();
00464 int duration = mRecurrence->duration();
00465 const QDateTime& endDateTime = mRecurrence->endDateTime();
00466 dt = mRecurrence->recurStart();
00467 recur->setRecurStart(dt);
00468 ushort rectype = mRecurrence->doesRecur();
00469 switch (rectype)
00470 {
00471 case Recurrence::rHourly:
00472 frequency *= 60;
00473
00474 case Recurrence::rMinutely:
00475 if (duration)
00476 recur->setMinutely(frequency, duration);
00477 else
00478 recur->setMinutely(frequency, endDateTime);
00479 break;
00480 case Recurrence::rDaily:
00481 if (duration)
00482 recur->setDaily(frequency, duration);
00483 else
00484 recur->setDaily(frequency, endDateTime.date());
00485 break;
00486 case Recurrence::rWeekly:
00487 if (duration)
00488 recur->setWeekly(frequency, mRecurrence->days(), duration);
00489 else
00490 recur->setWeekly(frequency, mRecurrence->days(), endDateTime.date());
00491 break;
00492 case Recurrence::rMonthlyDay:
00493 {
00494 if (duration)
00495 recur->setMonthly(Recurrence::rMonthlyDay, frequency, duration);
00496 else
00497 recur->setMonthly(Recurrence::rMonthlyDay, frequency, endDateTime.date());
00498 const QPtrList<int>& mdays = mRecurrence->monthDays();
00499 for (QPtrListIterator<int> it(mdays); it.current(); ++it)
00500 recur->addMonthlyDay(*it.current());
00501 break;
00502 }
00503 case Recurrence::rMonthlyPos:
00504 {
00505 if (duration)
00506 recur->setMonthly(Recurrence::rMonthlyPos, frequency, duration);
00507 else
00508 recur->setMonthly(Recurrence::rMonthlyPos, frequency, endDateTime.date());
00509 const QPtrList<Recurrence::rMonthPos>& mpos = mRecurrence->monthPositions();
00510 for (QPtrListIterator<Recurrence::rMonthPos> it(mpos); it.current(); ++it)
00511 {
00512 short weekno = it.current()->rPos;
00513 if (it.current()->negative)
00514 weekno = -weekno;
00515 recur->addMonthlyPos(weekno, it.current()->rDays);
00516 }
00517 break;
00518 }
00519 case Recurrence::rYearlyMonth:
00520 case Recurrence::rYearlyPos:
00521 case Recurrence::rYearlyDay:
00522 {
00523 if (duration)
00524 recur->setYearly(rectype, frequency, duration);
00525 else
00526 recur->setYearly(rectype, frequency, endDateTime.date());
00527 const QPtrList<int>& ynums = mRecurrence->yearNums();
00528 for (QPtrListIterator<int> it(ynums); it.current(); ++it)
00529 recur->addYearlyNum(*it.current());
00530 if (rectype == Recurrence::rYearlyPos)
00531 {
00532 const QPtrList<Recurrence::rMonthPos>& mpos = mRecurrence->yearMonthPositions();
00533 for (QPtrListIterator<Recurrence::rMonthPos> it(mpos); it.current(); ++it)
00534 {
00535 short weekno = it.current()->rPos;
00536 if (it.current()->negative)
00537 weekno = -weekno;
00538 recur->addYearlyMonthPos(weekno, it.current()->rDays);
00539 }
00540 }
00541 break;
00542 }
00543 default:
00544 break;
00545 }
00546 }
00547
00548 ev.setDtStart(dt);
00549 ev.setDtEnd(dt);
00550 ev.setFloats(mAnyTime);
00551 ev.setReadOnly(readOnly);
00552 return true;
00553 }
00554
00555
00556
00557
00558 KAlarmAlarm KAlarmEvent::alarm(int alarmID) const
00559 {
00560 checkRecur();
00561 KAlarmAlarm al;
00562 al.mEventID = mEventID;
00563 if (alarmID == AUDIO_ALARM_ID)
00564 {
00565 al.mType = KAlarmAlarm::AUDIO;
00566 al.mAlarmSeq = AUDIO_ALARM_ID;
00567 al.mDateTime = mDateTime;
00568 al.mCleanText = mAudioFile;
00569 }
00570 else
00571 {
00572 al.mType = mType;
00573 al.mCleanText = mCleanText;
00574 al.mColour = mColour;
00575 al.mBeep = mBeep;
00576 al.mConfirmAck = mConfirmAck;
00577 if (mMainAlarmID >= 0 && alarmID == mMainAlarmID)
00578 {
00579 al.mAlarmSeq = mMainAlarmID;
00580 al.mDateTime = mDateTime;
00581 al.mLateCancel = mLateCancel;
00582 }
00583 else if (mRepeatAtLogin && alarmID == mRepeatAtLoginAlarmID)
00584 {
00585 al.mAlarmSeq = mRepeatAtLoginAlarmID;
00586 al.mDateTime = mRepeatAtLoginDateTime;
00587 al.mRepeatAtLogin = true;
00588 }
00589 else if (mDeferral && alarmID == mDeferralAlarmID)
00590 {
00591 al.mAlarmSeq = mDeferralAlarmID;
00592 al.mDateTime = mDeferralTime;
00593 al.mDeferral = true;
00594 }
00595 }
00596 return al;
00597 }
00598
00599
00600
00601
00602
00603
00604
00605
00606 KAlarmAlarm KAlarmEvent::firstAlarm() const
00607 {
00608 if (mMainAlarmID > 0)
00609 return alarm(mMainAlarmID);
00610 if (mDeferral)
00611 return alarm(mDeferralAlarmID);
00612 if (mRepeatAtLogin)
00613 return alarm(mRepeatAtLoginAlarmID);
00614 if (!mAudioFile.isEmpty())
00615 return alarm(AUDIO_ALARM_ID);
00616 return KAlarmAlarm();
00617 }
00618
00619
00620
00621
00622
00623
00624 KAlarmAlarm KAlarmEvent::nextAlarm(const KAlarmAlarm& alrm) const
00625 {
00626 int next;
00627 if (alrm.id() == mMainAlarmID) next = 1;
00628 else if (mDeferral && alrm.id() == mDeferralAlarmID) next = 2;
00629 else if (mRepeatAtLogin && alrm.id() == mRepeatAtLoginAlarmID) next = 3;
00630 else next = -1;
00631 switch (next)
00632 {
00633 case 1:
00634 if (mDeferral)
00635 return alarm(mDeferralAlarmID);
00636
00637 case 2:
00638 if (mRepeatAtLogin)
00639 return alarm(mRepeatAtLoginAlarmID);
00640
00641 case 3:
00642 if (!mAudioFile.isEmpty())
00643 return alarm(AUDIO_ALARM_ID);
00644
00645 default:
00646 break;
00647 }
00648 return KAlarmAlarm();
00649 }
00650
00651
00652
00653
00654 void KAlarmEvent::removeAlarm(int alarmID)
00655 {
00656 if (alarmID == mMainAlarmID)
00657 mAlarmCount = 0;
00658 else if (mRepeatAtLogin && alarmID == mRepeatAtLoginAlarmID)
00659 {
00660 mRepeatAtLogin = false;
00661 --mAlarmCount;
00662 }
00663 else if (mDeferral && alarmID == mDeferralAlarmID)
00664 {
00665 mDeferral = false;
00666 --mAlarmCount;
00667 }
00668 else if (alarmID == AUDIO_ALARM_ID)
00669 {
00670 mAudioFile = "";
00671 --mAlarmCount;
00672 }
00673 }
00674
00675
00676
00677
00678 void KAlarmEvent::defer(const QDateTime& dateTime)
00679 {
00680 mDeferralTime = dateTime;
00681 mDeferralAlarmID = MAIN_ALARM_ID + DEFERRAL_OFFSET;
00682 mDeferral = true;
00683 }
00684
00685
00686
00687
00688 void KAlarmEvent::cancelDefer()
00689 {
00690 mDeferralTime = QDateTime();
00691 mDeferral = false;
00692 }
00693
00694
00695
00696
00697
00698 KAlarmEvent::RecurType KAlarmEvent::recurs() const
00699 {
00700 RecurType type = checkRecur();
00701 if (type == NO_RECUR && mRepeatDuration)
00702 return MINUTELY;
00703 return type;
00704 }
00705
00706
00707
00708
00709
00710
00711 KAlarmEvent::OccurType KAlarmEvent::nextOccurrence(const QDateTime& preDateTime, QDateTime& result) const
00712 {
00713 if (checkRecur() != NO_RECUR)
00714 {
00715 int remainingCount;
00716 return nextRecurrence(preDateTime, result, remainingCount);
00717 }
00718 if (preDateTime < mDateTime)
00719 {
00720 result = mDateTime;
00721 return FIRST_OCCURRENCE;
00722 }
00723 result = QDateTime();
00724 return NO_OCCURRENCE;
00725 }
00726
00727
00728
00729
00730
00731
00732 KAlarmEvent::OccurType KAlarmEvent::previousOccurrence(const QDateTime& afterDateTime, QDateTime& result) const
00733 {
00734 if (checkRecur() == NO_RECUR)
00735 {
00736 result = QDateTime();
00737 return NO_OCCURRENCE;
00738 }
00739 QDateTime recurStart = mRecurrence->recurStart();
00740 QDateTime after = afterDateTime;
00741 if (mAnyTime && afterDateTime.time() > theApp()->settings()->startOfDay())
00742 after = after.addDays(1);
00743 bool last;
00744 result = mRecurrence->getPreviousDateTime(after, &last);
00745 if (!result.isValid())
00746 return NO_OCCURRENCE;
00747 if (result == recurStart)
00748 return FIRST_OCCURRENCE;
00749 if (last)
00750 return LAST_OCCURRENCE;
00751 return mAnyTime ? RECURRENCE_DATE : RECURRENCE_DATE_TIME;
00752 }
00753
00754
00755
00756
00757
00758 KAlarmEvent::OccurType KAlarmEvent::setNextOccurrence(const QDateTime& preDateTime)
00759 {
00760 if (preDateTime < mDateTime)
00761 return FIRST_OCCURRENCE;
00762 OccurType type;
00763 if (checkRecur() != NO_RECUR)
00764 {
00765 int remainingCount;
00766 QDateTime newTime;
00767 type = nextRecurrence(preDateTime, newTime, remainingCount);
00768 if (type != FIRST_OCCURRENCE && type != NO_OCCURRENCE)
00769 {
00770 mDateTime = newTime;
00771 if (mRecurrence->duration() > 0)
00772 mRepeatDuration = remainingCount;
00773 mUpdated = true;
00774 }
00775 }
00776 else
00777 return NO_OCCURRENCE;
00778 return type;
00779 }
00780
00781
00782
00783
00784
00785
00786
00787 KAlarmEvent::OccurType KAlarmEvent::nextRecurrence(const QDateTime& preDateTime, QDateTime& result, int& remainingCount) const
00788 {
00789 QDateTime recurStart = mRecurrence->recurStart();
00790 QDateTime pre = preDateTime;
00791 if (mAnyTime && preDateTime.time() < theApp()->settings()->startOfDay())
00792 pre = pre.addDays(-1);
00793 remainingCount = 0;
00794 bool last;
00795 result = mRecurrence->getNextDateTime(pre, &last);
00796 if (!result.isValid())
00797 return NO_OCCURRENCE;
00798 if (result == recurStart)
00799 {
00800 remainingCount = mRecurrence->duration();
00801 return FIRST_OCCURRENCE;
00802 }
00803 if (last)
00804 {
00805 remainingCount = 1;
00806 return LAST_OCCURRENCE;
00807 }
00808 remainingCount = mRecurrence->duration() - mRecurrence->durationTo(result) + 1;
00809 return mAnyTime ? RECURRENCE_DATE : RECURRENCE_DATE_TIME;
00810 }
00811
00812
00813
00814
00815
00816
00817 void KAlarmEvent::setFirstRecurrence()
00818 {
00819 if (checkRecur() != NO_RECUR)
00820 {
00821 int remainingCount;
00822 QDateTime next;
00823 QDateTime pre = mDateTime.addDays(-1);
00824 mRecurrence->setRecurStart(pre);
00825 nextRecurrence(pre, next, remainingCount);
00826 if (next.isValid())
00827 {
00828 mRecurrence->setRecurStart(next);
00829 mDateTime = next;
00830 }
00831 }
00832 }
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842 void KAlarmEvent::setRecurMinutely(int freq, int count, const QDateTime& end)
00843 {
00844 if (initRecur(end.isValid(), count))
00845 {
00846 if (count)
00847 mRecurrence->setMinutely(freq, count);
00848 else
00849 mRecurrence->setMinutely(freq, end);
00850 }
00851 }
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861 void KAlarmEvent::setRecurDaily(int freq, int count, const QDate& end)
00862 {
00863 if (initRecur(end.isValid(), count))
00864 {
00865 if (count)
00866 mRecurrence->setDaily(freq, count);
00867 else
00868 mRecurrence->setDaily(freq, end);
00869 }
00870 }
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881 void KAlarmEvent::setRecurWeekly(int freq, const QBitArray& days, int count, const QDate& end)
00882 {
00883 if (initRecur(end.isValid(), count))
00884 {
00885 if (count)
00886 mRecurrence->setWeekly(freq, days, count);
00887 else
00888 mRecurrence->setWeekly(freq, days, end);
00889 }
00890 }
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901 void KAlarmEvent::setRecurMonthlyByDate(int freq, const QValueList<int>& days, int count, const QDate& end)
00902 {
00903 if (initRecur(end.isValid(), count))
00904 {
00905 if (count)
00906 mRecurrence->setMonthly(Recurrence::rMonthlyDay, freq, count);
00907 else
00908 mRecurrence->setMonthly(Recurrence::rMonthlyDay, freq, end);
00909 for (QValueListConstIterator<int> it = days.begin(); it != days.end(); ++it)
00910 mRecurrence->addMonthlyDay(*it);
00911 }
00912 }
00913
00914 void KAlarmEvent::setRecurMonthlyByDate(int freq, const QPtrList<int>& days, int count, const QDate& end)
00915 {
00916 if (initRecur(end.isValid(), count))
00917 {
00918 if (count)
00919 mRecurrence->setMonthly(Recurrence::rMonthlyDay, freq, count);
00920 else
00921 mRecurrence->setMonthly(Recurrence::rMonthlyDay, freq, end);
00922 for (QPtrListIterator<int> it(days); it.current(); ++it)
00923 mRecurrence->addMonthlyDay(*it.current());
00924 }
00925 }
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937 void KAlarmEvent::setRecurMonthlyByPos(int freq, const QValueList<MonthPos>& posns, int count, const QDate& end)
00938 {
00939 if (initRecur(end.isValid(), count))
00940 {
00941 if (count)
00942 mRecurrence->setMonthly(Recurrence::rMonthlyPos, freq, count);
00943 else
00944 mRecurrence->setMonthly(Recurrence::rMonthlyPos, freq, end);
00945 for (QValueListConstIterator<MonthPos> it = posns.begin(); it != posns.end(); ++it)
00946 mRecurrence->addMonthlyPos((*it).weeknum, (*it).days);
00947 }
00948 }
00949
00950 void KAlarmEvent::setRecurMonthlyByPos(int freq, const QPtrList<Recurrence::rMonthPos>& posns, int count, const QDate& end)
00951 {
00952 if (initRecur(end.isValid(), count))
00953 {
00954 if (count)
00955 mRecurrence->setMonthly(Recurrence::rMonthlyPos, freq, count);
00956 else
00957 mRecurrence->setMonthly(Recurrence::rMonthlyPos, freq, end);
00958 for (QPtrListIterator<Recurrence::rMonthPos> it(posns); it.current(); ++it)
00959 {
00960 short weekno = it.current()->rPos;
00961 if (it.current()->negative)
00962 weekno = -weekno;
00963 mRecurrence->addMonthlyPos(weekno, it.current()->rDays);
00964 }
00965 }
00966 }
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979 void KAlarmEvent::setRecurAnnualByDate(int freq, const QValueList<int>& months, bool feb29, int count, const QDate& end)
00980 {
00981 if (initRecur(end.isValid(), count, feb29))
00982 {
00983 if (count)
00984 mRecurrence->setYearly(Recurrence::rYearlyMonth, freq, count);
00985 else
00986 mRecurrence->setYearly(Recurrence::rYearlyMonth, freq, end);
00987 for (QValueListConstIterator<int> it = months.begin(); it != months.end(); ++it)
00988 mRecurrence->addYearlyNum(*it);
00989 }
00990 }
00991
00992 void KAlarmEvent::setRecurAnnualByDate(int freq, const QPtrList<int>& months, bool feb29, int count, const QDate& end)
00993 {
00994 if (initRecur(end.isValid(), count, feb29))
00995 {
00996 if (count)
00997 mRecurrence->setYearly(Recurrence::rYearlyMonth, freq, count);
00998 else
00999 mRecurrence->setYearly(Recurrence::rYearlyMonth, freq, end);
01000 for (QPtrListIterator<int> it(months); it.current(); ++it)
01001 mRecurrence->addYearlyNum(*it.current());
01002 }
01003 }
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016 void KAlarmEvent::setRecurAnnualByPos(int freq, const QValueList<MonthPos>& posns, const QValueList<int>& months, int count, const QDate& end)
01017 {
01018 if (initRecur(end.isValid(), count))
01019 {
01020 if (count)
01021 mRecurrence->setYearly(Recurrence::rYearlyPos, freq, count);
01022 else
01023 mRecurrence->setYearly(Recurrence::rYearlyPos, freq, end);
01024 for (QValueListConstIterator<int> it = months.begin(); it != months.end(); ++it)
01025 mRecurrence->addYearlyNum(*it);
01026 for (QValueListConstIterator<MonthPos> it = posns.begin(); it != posns.end(); ++it)
01027 mRecurrence->addYearlyMonthPos((*it).weeknum, (*it).days);
01028 }
01029 }
01030
01031 void KAlarmEvent::setRecurAnnualByPos(int freq, const QPtrList<Recurrence::rMonthPos>& posns, const QPtrList<int>& months, int count, const QDate& end)
01032 {
01033 if (initRecur(end.isValid(), count))
01034 {
01035 if (count)
01036 mRecurrence->setYearly(Recurrence::rYearlyPos, freq, count);
01037 else
01038 mRecurrence->setYearly(Recurrence::rYearlyPos, freq, end);
01039 for (QPtrListIterator<int> it(months); it.current(); ++it)
01040 mRecurrence->addYearlyNum(*it.current());
01041 for (QPtrListIterator<Recurrence::rMonthPos> it(posns); it.current(); ++it)
01042 {
01043 short weekno = it.current()->rPos;
01044 if (it.current()->negative)
01045 weekno = -weekno;
01046 mRecurrence->addYearlyMonthPos(weekno, it.current()->rDays);
01047 }
01048 }
01049 }
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060 void KAlarmEvent::setRecurAnnualByDay(int freq, const QValueList<int>& days, int count, const QDate& end)
01061 {
01062 if (initRecur(end.isValid(), count))
01063 {
01064 if (count)
01065 mRecurrence->setYearly(Recurrence::rYearlyDay, freq, count);
01066 else
01067 mRecurrence->setYearly(Recurrence::rYearlyDay, freq, end);
01068 for (QValueListConstIterator<int> it = days.begin(); it != days.end(); ++it)
01069 mRecurrence->addYearlyNum(*it);
01070 }
01071 }
01072
01073 void KAlarmEvent::setRecurAnnualByDay(int freq, const QPtrList<int>& days, int count, const QDate& end)
01074 {
01075 if (initRecur(end.isValid(), count))
01076 {
01077 if (count)
01078 mRecurrence->setYearly(Recurrence::rYearlyDay, freq, count);
01079 else
01080 mRecurrence->setYearly(Recurrence::rYearlyDay, freq, end);
01081 for (QPtrListIterator<int> it(days); it.current(); ++it)
01082 mRecurrence->addYearlyNum(*it.current());
01083 }
01084 }
01085
01086
01087
01088
01089
01090 bool KAlarmEvent::initRecur(bool endDate, int count, bool feb29)
01091 {
01092 mUpdated = true;
01093 mRecursFeb29 = false;
01094 if (endDate || count)
01095 {
01096 if (!mRecurrence)
01097 mRecurrence = new Recurrence(0);
01098 mRecurrence->setRecurStart(mDateTime);
01099 mRepeatDuration = count;
01100 int year = mDateTime.date().year();
01101 if (feb29 && !QDate::leapYear(year)
01102 && mDateTime.date().month() == 3 && mDateTime.date().day() == 1)
01103 {
01104
01105
01106 while (!QDate::leapYear(--year)) ;
01107 mRecurrence->setRecurStart(QDateTime(QDate(year, 2, 29), mDateTime.time()));
01108 mRecursFeb29 = true;
01109 }
01110 return true;
01111 }
01112 else
01113 {
01114 delete mRecurrence;
01115 mRecurrence = 0;
01116 mRepeatDuration = 0;
01117 return false;
01118 }
01119 }
01120
01121
01122
01123
01124
01125
01126 KAlarmEvent::RecurType KAlarmEvent::checkRecur() const
01127 {
01128 if (mRecurrence)
01129 {
01130 RecurType type = static_cast<RecurType>(mRecurrence->doesRecur());
01131 switch (type)
01132 {
01133 case Recurrence::rMinutely:
01134 case Recurrence::rDaily:
01135 case Recurrence::rWeekly:
01136 case Recurrence::rMonthlyDay:
01137 case Recurrence::rMonthlyPos:
01138 case Recurrence::rYearlyMonth:
01139 case Recurrence::rYearlyPos:
01140 case Recurrence::rYearlyDay:
01141 return type;
01142 case Recurrence::rHourly:
01143 return MINUTELY;
01144 case Recurrence::rNone:
01145 default:
01146 if (mRecurrence)
01147 {
01148 delete mRecurrence;
01149 const_cast<KAlarmEvent*>(this)->mRecurrence = 0L;
01150 }
01151 break;
01152 }
01153 }
01154 return NO_RECUR;
01155 }
01156
01157
01158
01159
01160 int KAlarmEvent::recurInterval() const
01161 {
01162 if (mRecurrence)
01163 {
01164 switch (mRecurrence->doesRecur())
01165 {
01166 case Recurrence::rMinutely:
01167 case Recurrence::rDaily:
01168 case Recurrence::rWeekly:
01169 case Recurrence::rMonthlyDay:
01170 case Recurrence::rMonthlyPos:
01171 case Recurrence::rYearlyMonth:
01172 case Recurrence::rYearlyPos:
01173 case Recurrence::rYearlyDay:
01174 return mRecurrence->frequency();
01175 case Recurrence::rHourly:
01176 return mRecurrence->frequency() * 60;
01177 case Recurrence::rNone:
01178 default:
01179 break;
01180 }
01181 }
01182 return 0;
01183 }
01184
01185
01186
01187
01188
01189
01190
01191 bool KAlarmEvent::adjustStartOfDay(const QPtrList<Event>& events)
01192 {
01193 bool changed = false;
01194 QTime startOfDay = theApp()->settings()->startOfDay();
01195 for (QPtrListIterator<Event> it(events); it.current(); ++it)
01196 {
01197 Event* event = it.current();
01198 if (event->doesFloat())
01199 {
01200
01201 QPtrList<Alarm> alarms = event->alarms();
01202 for (QPtrListIterator<Alarm> it(alarms); it.current(); ++it)
01203 {
01204
01205 Alarm& alarm = *it.current();
01206 AlarmData data;
01207 if (readAlarm(alarm, data) == MAIN_ALARM_ID)
01208 {
01209 alarm.setTime(QDateTime(alarm.time().date(), startOfDay));
01210 changed = true;
01211 break;
01212 }
01213 }
01214 }
01215 }
01216 return changed;
01217 }
01218
01219
01220
01221
01222
01223
01224 void KAlarmEvent::convertKCalEvents()
01225 {
01226 if (theApp()->getCalendar().KAlarmVersion() < AlarmCalendar::KAlarmVersion(0,7,0))
01227 {
01228 kdDebug()<<"KAlarmEvent::convertKCalEvents(): adjusting\n";
01229 bool adjustSummerTime = theApp()->getCalendar().KAlarmVersion057_UTC();
01230 QDateTime dt0(QDate(1970,1,1), QTime(0,0,0));
01231
01232 QPtrList<Event> events = theApp()->getCalendar().events();
01233 for (Event* event = events.first(); event; event = events.next())
01234 {
01235 if (event->doesFloat())
01236 {
01237
01238
01239 event->setFloats(false);
01240 }
01241 if (adjustSummerTime)
01242 {
01243
01244
01245 QPtrList<Alarm> alarms = event->alarms();
01246 for (QPtrListIterator<Alarm> ia(alarms); ia.current(); ++ia)
01247 {
01248 Alarm* alarm = ia.current();
01249 QDateTime dt = alarm->time();
01250 time_t t = dt0.secsTo(dt);
01251 struct tm* dtm = localtime(&t);
01252 if (dtm->tm_isdst)
01253 {
01254 dt = dt.addSecs(-3600);
01255 alarm->setTime(dt);
01256 }
01257 }
01258 }
01259 }
01260 }
01261 }
01262
01263 #ifndef NDEBUG
01264 void KAlarmEvent::dumpDebug() const
01265 {
01266 kdDebug(5950) << "KAlarmEvent dump:\n";
01267 kdDebug(5950) << "-- mEventID:" << mEventID << ":\n";
01268 kdDebug(5950) << "-- mCleanText:" << mCleanText << ":\n";
01269 kdDebug(5950) << "-- mAudioFile:" << mAudioFile << ":\n";
01270 kdDebug(5950) << "-- mDateTime:" << mDateTime.toString() << ":\n";
01271 kdDebug(5950) << "-- mRepeatAtLoginDateTime:" << mRepeatAtLoginDateTime.toString() << ":\n";
01272 kdDebug(5950) << "-- mDeferralTime:" << mDeferralTime.toString() << ":\n";
01273 kdDebug(5950) << "-- mColour:" << mColour.name() << ":\n";
01274 kdDebug(5950) << "-- mRevision:" << mRevision << ":\n";
01275 kdDebug(5950) << "-- mMainAlarmID:" << mMainAlarmID << ":\n";
01276 kdDebug(5950) << "-- mRepeatAtLoginAlarmID:" << mRepeatAtLoginAlarmID << ":\n";
01277 kdDebug(5950) << "-- mRecurrence:" << (mRecurrence ? "true" : "false") << ":\n";
01278 if (mRecurrence)
01279 kdDebug(5950) << "-- mRecursFeb29:" << (mRecursFeb29 ? "true" : "false") << ":\n";
01280 kdDebug(5950) << "-- mRepeatDuration:" << mRepeatDuration << ":\n";
01281 kdDebug(5950) << "-- mBeep:" << (mBeep ? "true" : "false") << ":\n";
01282 kdDebug(5950) << "-- mConfirmAck:" << (mConfirmAck ? "true" : "false") << ":\n";
01283 kdDebug(5950) << "-- mType:" << mType << ":\n";
01284 kdDebug(5950) << "-- mRepeatAtLogin:" << (mRepeatAtLogin ? "true" : "false") << ":\n";
01285 kdDebug(5950) << "-- mDeferral:" << (mDeferral ? "true" : "false") << ":\n";
01286 kdDebug(5950) << "-- mLateCancel:" << (mLateCancel ? "true" : "false") << ":\n";
01287 kdDebug(5950) << "KAlarmEvent dump end\n";
01288 }
01289 #endif
01290
01291
01292
01293
01294
01295
01296
01297 void KAlarmAlarm::set(int flags)
01298 {
01299 mBeep = flags & KAlarmEvent::BEEP;
01300 mRepeatAtLogin = flags & KAlarmEvent::REPEAT_AT_LOGIN;
01301 mLateCancel = flags & KAlarmEvent::LATE_CANCEL;
01302 mConfirmAck = flags & KAlarmEvent::CONFIRM_ACK;
01303 mDeferral = flags & KAlarmEvent::DEFERRAL;
01304 }
01305
01306 int KAlarmAlarm::flags() const
01307 {
01308 return (mBeep ? KAlarmEvent::BEEP : 0)
01309 | (mRepeatAtLogin ? KAlarmEvent::REPEAT_AT_LOGIN : 0)
01310 | (mLateCancel ? KAlarmEvent::LATE_CANCEL : 0)
01311 | (mConfirmAck ? KAlarmEvent::CONFIRM_ACK : 0)
01312 | (mDeferral ? KAlarmEvent::DEFERRAL : 0);
01313 }
01314
01315
01316 void KAlarmAlarm::commandArgs(QStringList& list) const
01317 {
01318 list.clear();
01319 if (mType != COMMAND)
01320 return;
01321 int imax = mCleanText.length();
01322 for (int i = 0; i < imax; )
01323 {
01324
01325 if ((i = mCleanText.find(QRegExp("[^\\s]"), i)) < 0)
01326 break;
01327
01328
01329
01330 int j, jmax;
01331 QChar quote = mCleanText[i];
01332 if (quote == QChar('\'') || quote == QChar('"'))
01333 {
01334 for (j = i + 1; j < imax; )
01335 {
01336 QChar ch = mCleanText[j++];
01337 if (ch == quote)
01338 break;
01339 if (ch == QChar('\\') && j < imax)
01340 ++j;
01341 }
01342 jmax = j;
01343 }
01344 else
01345 {
01346 for (j = i; j < imax; ++j)
01347 {
01348 QChar ch = mCleanText[j];
01349 if (ch.isSpace())
01350 break;
01351 if (ch == QChar('\\') && j < imax - 1)
01352 ++j;
01353 }
01354 jmax = j;
01355 }
01356 list.append(mCleanText.mid(i, jmax - i));
01357 i = j;
01358 }
01359 }
01360
01361
01362 QString KAlarmAlarm::commandFromArgs(const QStringList& list)
01363 {
01364 if (list.isEmpty())
01365 return QString("");
01366 QString cmd;
01367 QStringList::ConstIterator it = list.begin();
01368 for ( ; it != list.end(); ++it)
01369 {
01370 QString value = *it;
01371 if (value.find(QRegExp("\\s")) >= 0)
01372 {
01373
01374
01375 const QChar quote('"');
01376 cmd += quote;
01377 for (unsigned i = 0; i < value.length(); ++i)
01378 {
01379 if (value[i] == quote || value[i] == QChar('\\'))
01380 cmd += QChar('\\');
01381 cmd += value[i];
01382 }
01383 cmd += quote;
01384 }
01385 else
01386 {
01387
01388 for (unsigned i = 0; i < value.length(); ++i)
01389 {
01390 if (value[i] == QChar('\\'))
01391 cmd += QChar('\\');
01392 cmd += value[i];
01393 }
01394 }
01395 cmd += QChar(' ');
01396 }
01397 cmd.truncate(cmd.length() - 1);
01398 return cmd;
01399 }
01400
01401 #ifndef NDEBUG
01402 void KAlarmAlarm::dumpDebug() const
01403 {
01404 kdDebug(5950) << "KAlarmAlarm dump:\n";
01405 kdDebug(5950) << "-- mEventID:" << mEventID << ":\n";
01406 kdDebug(5950) << "-- mCleanText:" << mCleanText << ":\n";
01407 kdDebug(5950) << "-- mDateTime:" << mDateTime.toString() << ":\n";
01408 kdDebug(5950) << "-- mColour:" << mColour.name() << ":\n";
01409 kdDebug(5950) << "-- mAlarmSeq:" << mAlarmSeq << ":\n";
01410 kdDebug(5950) << "-- mBeep:" << (mBeep ? "true" : "false") << ":\n";
01411 kdDebug(5950) << "-- mConfirmAck:" << (mConfirmAck ? "true" : "false") << ":\n";
01412 kdDebug(5950) << "-- mType:" << mType << ":\n";
01413 kdDebug(5950) << "-- mRepeatAtLogin:" << (mRepeatAtLogin ? "true" : "false") << ":\n";
01414 kdDebug(5950) << "-- mDeferral:" << (mDeferral ? "true" : "false") << ":\n";
01415 kdDebug(5950) << "-- mLateCancel:" << (mLateCancel ? "true" : "false") << ":\n";
01416 kdDebug(5950) << "KAlarmAlarm dump end\n";
01417 }
01418 #endif