kalarm Library API Documentation

msgevent.cpp

00001 /*
00002  *  msgevent.cpp  -  the event object for messages
00003  *  Program:  kalarm
00004  *  (C) 2001, 2002 by David Jarvie  software@astrojar.org.uk
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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  * Each alarm DESCRIPTION field contains the following:
00038  *   SEQNO;[FLAGS];TYPE:TEXT
00039  * where
00040  *   SEQNO = sequence number of alarm within the event
00041  *   FLAGS = C for late-cancel, L for repeat-at-login, D for deferral
00042  *   TYPE = TEXT or FILE or CMD
00043  *   TEXT = message text, file name/URL or command
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");   // subsidiary alarm at every login
00051 static const QString DEFERRAL_CODE        = QString::fromLatin1("D");   // extra deferred alarm
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;       // text or audio file name
00058         QDateTime         dateTime;
00059         int               repeatCount;     // backwards compatibility with KAlarm pre-0.7 calendar files
00060         int               repeatMinutes;   // backwards compatibility with KAlarm pre-0.7 calendar files
00061         KAlarmAlarm::Type type;
00062         bool              lateCancel;
00063         bool              repeatAtLogin;
00064         bool              deferral;
00065 };
00066 typedef QMap<int, AlarmData> AlarmMap;
00067 
00068 
00069 /*=============================================================================
00070 = Class KAlarmEvent
00071 = Corresponds to a KCal::Event instance.
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;   // not actually stored in the alarm
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  * Initialise the KAlarmEvent from a KCal::Event.
00113  */
00114 void KAlarmEvent::set(const Event& event)
00115 {
00116         // Extract status from the event
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);    // missing/invalid colour - return white
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         // Extract status from the event's alarms.
00137         // First set up defaults.
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         // Extract data from all the event's alarms and index the alarms by sequence number
00150         AlarmMap alarmMap;
00151         QPtrList<Alarm> alarms = event.alarms();
00152         for (QPtrListIterator<Alarm> ia(alarms);  ia.current();  ++ia)
00153         {
00154                 // Parse the next alarm's text
00155                 AlarmData data;
00156                 int sequence = readAlarm(*ia.current(), data);
00157                 alarmMap.insert(sequence, data);
00158         }
00159 
00160         // Incorporate the alarms' details into the overall event
00161         AlarmMap::ConstIterator it = alarmMap.begin();
00162         mMainAlarmID = -1;    // initialise as invalid
00163         mAlarmCount = 0;
00164         int repeatCount   = 0;    // backwards compatibility with KAlarm pre-0.7 calendar files
00165         int repeatMinutes = 0;    // backwards compatibility with KAlarm pre-0.7 calendar files
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                 // Ensure that the basic fields are set up even if there is no main
00192                 // alarm in the event (which shouldn't ever happen!)
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                                 // Backwards compatibility with KAlarm pre-0.7 calendar files
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                 // Copy the recurrence details.
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                                 // fall through to rMinutely
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                 // Backwards compatibility with KAlarm pre-0.7 calendar files
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  * Parse a KCal::Alarm.
00261  * Reply = alarm ID (sequence number)
00262  */
00263 int KAlarmEvent::readAlarm(const Alarm& alarm, AlarmData& data)
00264 {
00265         // Parse the next alarm's text
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                 // It's a text message/file/command
00279                 data.type = KAlarmAlarm::MESSAGE;
00280                 sequence = MAIN_ALARM_ID;      // default 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;     // invalid sequence number - use default
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();  // backwards compatibility with KAlarm pre-0.7 calendar files
00334         data.repeatMinutes = alarm.snoozeTime();   // backwards compatibility with KAlarm pre-0.7 calendar files
00335         return sequence;
00336 }
00337 
00338 /******************************************************************************
00339  * Initialise the KAlarmEvent with the specified parameters.
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  * Create a new Event from the KAlarmEvent data.
00376  */
00377 Event* KAlarmEvent::event() const
00378 {
00379         Event* ev = new KCal::Event;
00380         updateEvent(*ev);
00381         return ev;
00382 }
00383 
00384 /******************************************************************************
00385  * Update an existing KCal::Event with the KAlarmEvent data.
00386  */
00387 bool KAlarmEvent::updateEvent(Event& ev) const
00388 {
00389         if (!mEventID.isEmpty()  &&  mEventID != ev.uid())
00390                 return false;
00391         checkRecur();     // ensure recurrence/repetition data is consistent
00392         bool readOnly = ev.isReadOnly();
00393         ev.setReadOnly(false);
00394 
00395         // Set up event-specific data
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         // Add the main alarm
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;   // never occurs in this context
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         // Add subsidiary alarms
00429         if (mRepeatAtLogin)
00430         {
00431                 al = ev.newAlarm();
00432                 al->setEnabled(true);        // enable the alarm
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);        // enable the alarm
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);        // enable the alarm
00455                 al->setAudioFile(mAudioFile);
00456                 al->setTime(aldt);           // set it for the main alarm time
00457         }
00458 
00459         // Add recurrence data
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                                 // fall through to Recurrence::rMinutely
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  * Return the alarm with the specified ID.
00557  */
00558 KAlarmAlarm KAlarmEvent::alarm(int alarmID) const
00559 {
00560         checkRecur();     // ensure recurrence/repetition data is consistent
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  * Return the main alarm for the event.
00601  * If for some strange reason the main alarm does not exist, one of the
00602  * subsidiary ones is returned if possible.
00603  * N.B. a repeat-at-login alarm can only be returned if it has been read from/
00604  * written to the calendar file.
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  * Return the next alarm for the event, after the specified alarm.
00621  * N.B. a repeat-at-login alarm can only be returned if it has been read from/
00622  * written to the calendar file.
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                         // fall through to REPEAT
00637                 case 2:
00638                         if (mRepeatAtLogin)
00639                                 return alarm(mRepeatAtLoginAlarmID);
00640                         // fall through to LOGIN
00641                 case 3:
00642                         if (!mAudioFile.isEmpty())
00643                                 return alarm(AUDIO_ALARM_ID);
00644                         // fall through to default
00645                 default:
00646                         break;
00647         }
00648         return KAlarmAlarm();
00649 }
00650 
00651 /******************************************************************************
00652  * Remove the alarm with the specified ID from the event.
00653  */
00654 void KAlarmEvent::removeAlarm(int alarmID)
00655 {
00656         if (alarmID == mMainAlarmID)
00657                 mAlarmCount = 0;    // removing main alarm - also remove subsidiary alarms
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  * Add a deferral alarm with the specified trigger time.
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  * Cancel any deferral alarm.
00687  */
00688 void KAlarmEvent::cancelDefer()
00689 {
00690         mDeferralTime = QDateTime();
00691         mDeferral     = false;
00692 }
00693 
00694 /******************************************************************************
00695  * Check whether the event regularly repeats - with a recurrence specification
00696  * and/or an alarm repetition.
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  * Get the date/time of the next occurrence of the event, after the specified
00708  * date/time.
00709  * 'result' = date/time of next occurrence, or invalid date/time if none.
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  * Get the date/time of the last previous occurrence of the event, before the
00729  * specified date/time.
00730  * 'result' = date/time of previous occurrence, or invalid date/time if none.
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);    // today's recurrence (if today recurs) has passed
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  * Set the date/time of the event to the next scheduled occurrence after the
00756  * specified date/time.
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  * Get the date/time of the next recurrence of the event, after the specified
00783  * date/time.
00784  * 'result' = date/time of next occurrence, or invalid date/time if none.
00785  * 'remainingCount' = number of repetitions due, including the next occurrence.
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);    // today's recurrence (if today recurs) is still to come
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  * Adjust the event date/time to the first recurrence of the event, on or after
00814  * start date/time. The event start date may not be a recurrence date, in which
00815  * case a later date will be set.
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  * Set the event to recur at a minutes interval.
00836  * Parameters:
00837  *    freq  = how many minutes between recurrences.
00838  *    count = number of occurrences, including first and last.
00839  *          = 0 to use 'end' instead.
00840  *    end   = end date/time (invalid to use 'count' instead).
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  * Set the event to recur daily.
00855  * Parameters:
00856  *    freq  = how many days between recurrences.
00857  *    count = number of occurrences, including first and last.
00858  *          = 0 to use 'end' instead.
00859  *    end   = end date (invalid to use 'count' instead).
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  * Set the event to recur weekly, on the specified weekdays.
00874  * Parameters:
00875  *    freq  = how many weeks between recurrences.
00876  *    days  = which days of the week alarms should occur on.
00877  *    count = number of occurrences, including first and last.
00878  *          = 0 to use 'end' instead.
00879  *    end   = end date (invalid to use 'count' instead).
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  * Set the event to recur monthly, on the specified days within the month.
00894  * Parameters:
00895  *    freq  = how many months between recurrences.
00896  *    days  = which days of the month alarms should occur on.
00897  *    count = number of occurrences, including first and last.
00898  *          = 0 to use 'end' instead.
00899  *    end   = end date (invalid to use 'count' instead).
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  * Set the event to recur monthly, on the specified weekdays in the specified
00929  * weeks of the month.
00930  * Parameters:
00931  *    freq  = how many months between recurrences.
00932  *    posns = which days of the week/weeks of the month alarms should occur on.
00933  *    count = number of occurrences, including first and last.
00934  *          = 0 to use 'end' instead.
00935  *    end   = end date (invalid to use 'count' instead).
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  * Set the event to recur annually, on the specified start date in each of the
00970  * specified months.
00971  * Parameters:
00972  *    freq   = how many years between recurrences.
00973  *    months = which months of the year alarms should occur on.
00974  *    feb29  = if start date is March 1st, recur on February 29th; otherwise ignored
00975  *    count  = number of occurrences, including first and last.
00976  *           = 0 to use 'end' instead.
00977  *    end    = end date (invalid to use 'count' instead).
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  * Set the event to recur annually, on the specified weekdays in the specified
01007  * weeks of the specified month.
01008  * Parameters:
01009  *    freq   = how many years between recurrences.
01010  *    posns  = which days of the week/weeks of the month alarms should occur on.
01011  *    months = which months of the year alarms should occur on.
01012  *    count  = number of occurrences, including first and last.
01013  *           = 0 to use 'end' instead.
01014  *    end    = end date (invalid to use 'count' instead).
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  * Set the event to recur annually, on the specified day numbers.
01053  * Parameters:
01054  *    freq  = how many years between recurrences.
01055  *    days  = which days of the year alarms should occur on.
01056  *    count = number of occurrences, including first and last.
01057  *          = 0 to use 'end' instead.
01058  *    end   = end date (invalid to use 'count' instead).
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  * Initialise the event's recurrence and alarm repetition data, and set the
01088  * recurrence start date and repetition count if applicable.
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                         // The event start date is March 1st, but it is a recurrence
01105                         // on February 29th (recurring on March 1st in non-leap years)
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  * Validate the event's recurrence and alarm repetition data, correcting any
01123  * inconsistencies (which should never occur!).
01124  * Reply = true if a recurrence (as opposed to a repetition) exists.
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:        // minutely
01134                         case Recurrence::rDaily:           // daily
01135                         case Recurrence::rWeekly:          // weekly on multiple days of week
01136                         case Recurrence::rMonthlyDay:      // monthly on multiple dates in month
01137                         case Recurrence::rMonthlyPos:      // monthly on multiple nth day of week
01138                         case Recurrence::rYearlyMonth:     // annually on multiple months (day of month = start date)
01139                         case Recurrence::rYearlyPos:       // annually on multiple nth day of week in multiple months
01140                         case Recurrence::rYearlyDay:       // annually on multiple day numbers in year
01141                                 return type;
01142                         case Recurrence::rHourly:          // hourly
01143                                 return MINUTELY;
01144                         case Recurrence::rNone:
01145                         default:
01146                                 if (mRecurrence)
01147                                 {
01148                                         delete mRecurrence;     // this shouldn't exist!!
01149                                         const_cast<KAlarmEvent*>(this)->mRecurrence = 0L;
01150                                 }
01151                                 break;
01152                 }
01153         }
01154         return NO_RECUR;
01155 }
01156 
01157 /******************************************************************************
01158  * Return the recurrence interval in units of the recurrence period type.
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  * Adjust the time at which date-only events will occur for each of the events
01187  * in a list. Events for which both date and time are specified are left
01188  * unchanged.
01189  * Reply = true if any events have been updated.
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                         // It's an untimed event, so fix it
01201                         QPtrList<Alarm> alarms = event->alarms();
01202                         for (QPtrListIterator<Alarm> it(alarms);  it.current();  ++it)
01203                         {
01204                                 // Parse the next alarm's text
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  * If the calendar was written by a previous version of KAlarm, do any
01221  * necessary format conversions on the events to ensure that when the calendar
01222  * is saved, no information is lost or corrupted.
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                                 // Backwards compatibility with KAlarm pre-0.7 calendar files.
01238                                 // Ensure that when the calendar is saved, the alarm time isn't lost.
01239                                 event->setFloats(false);
01240                         }
01241                         if (adjustSummerTime)
01242                         {
01243                                 // Backwards compatibility with the KDE 3.0.0 version of KAlarm 0.5.7.
01244                                 // Summer time was ignored when converting to UTC.
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 = Class KAlarmAlarm
01294 = Corresponds to a single KCal::Alarm instance.
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 // Convert a string to command arguments
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                 // Find the first non-space
01325                 if ((i = mCleanText.find(QRegExp("[^\\s]"), i)) < 0)
01326                         break;
01327 
01328                 // Find the end of the next parameter.
01329                 // Allow for quoted parameters, and also for escaped characters.
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 // Convert a command with arguments to a string
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                         // Argument has spaces in it, so enclose it in quotes and
01374                         // escape any quotes within it.
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                         // Argument has no spaces in it
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);      // remove the trailing space
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
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 15 11:41:03 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2001