00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kalarm.h"
00022 #include <unistd.h>
00023 #include <time.h>
00024
00025 #include <qfile.h>
00026 #include <qtextstream.h>
00027 #include <qregexp.h>
00028 #include <qtimer.h>
00029
00030 #include <klocale.h>
00031 #include <kmessagebox.h>
00032 #include <kstandarddirs.h>
00033 #include <kstaticdeleter.h>
00034 #include <kconfig.h>
00035 #include <kaboutdata.h>
00036 #include <kio/netaccess.h>
00037 #include <kfileitem.h>
00038 #include <ktempfile.h>
00039 #include <kfiledialog.h>
00040 #include <dcopclient.h>
00041 #include <kdebug.h>
00042
00043 extern "C" {
00044 #include <libical/ical.h>
00045 }
00046
00047 #include <libkcal/vcaldrag.h>
00048 #include <libkcal/vcalformat.h>
00049 #include <libkcal/icalformat.h>
00050
00051 #include "calendarcompat.h"
00052 #include "daemon.h"
00053 #include "functions.h"
00054 #include "kalarmapp.h"
00055 #include "mainwindow.h"
00056 #include "preferences.h"
00057 #include "startdaytimer.h"
00058 #include "alarmcalendar.moc"
00059
00060 using namespace KCal;
00061
00062 static const KAEvent::Status eventTypes[AlarmCalendar::NCALS] = {
00063 KAEvent::ACTIVE, KAEvent::EXPIRED, KAEvent::DISPLAYING, KAEvent::TEMPLATE
00064 };
00065 static const QString calendarNames[AlarmCalendar::NCALS] = {
00066 QString::fromLatin1("calendar.ics"),
00067 QString::fromLatin1("expired.ics"),
00068 QString::fromLatin1("displaying.ics"),
00069 QString::fromLatin1("template.ics")
00070 };
00071 static KStaticDeleter<AlarmCalendar> calendarDeleter[AlarmCalendar::NCALS];
00072
00073 AlarmCalendar* AlarmCalendar::mCalendars[NCALS] = { 0, 0, 0, 0 };
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 bool AlarmCalendar::initialiseCalendars()
00087 {
00088 KConfig* config = kapp->config();
00089 config->setGroup(QString::fromLatin1("General"));
00090 QString activeKey = QString::fromLatin1("Calendar");
00091 QString expiredKey = QString::fromLatin1("ExpiredCalendar");
00092 QString templateKey = QString::fromLatin1("TemplateCalendar");
00093 QString displayCal, activeCal, expiredCal, templateCal;
00094 calendarDeleter[ACTIVE].setObject(mCalendars[ACTIVE], createCalendar(ACTIVE, config, activeCal, activeKey));
00095 calendarDeleter[EXPIRED].setObject(mCalendars[EXPIRED], createCalendar(EXPIRED, config, expiredCal, expiredKey));
00096 calendarDeleter[DISPLAY].setObject(mCalendars[DISPLAY], createCalendar(DISPLAY, config, displayCal));
00097 calendarDeleter[TEMPLATE].setObject(mCalendars[TEMPLATE], createCalendar(TEMPLATE, config, templateCal, templateKey));
00098
00099 QString errorKey1, errorKey2;
00100 if (activeCal == displayCal)
00101 errorKey1 = activeKey;
00102 else if (expiredCal == displayCal)
00103 errorKey1 = expiredKey;
00104 else if (templateCal == displayCal)
00105 errorKey1 = templateKey;
00106 if (!errorKey1.isNull())
00107 {
00108 kdError(5950) << "AlarmCalendar::initialiseCalendars(): '" << errorKey1 << "' calendar name = display calendar name\n";
00109 QString file = config->readPathEntry(errorKey1);
00110 KAlarmApp::displayFatalError(i18n("%1: file name not permitted: %2").arg(errorKey1).arg(file));
00111 return false;
00112 }
00113 if (activeCal == expiredCal)
00114 {
00115 errorKey1 = activeKey;
00116 errorKey2 = expiredKey;
00117 }
00118 else if (activeCal == templateCal)
00119 {
00120 errorKey1 = activeKey;
00121 errorKey2 = templateKey;
00122 }
00123 else if (expiredCal == templateCal)
00124 {
00125 errorKey1 = expiredKey;
00126 errorKey2 = templateKey;
00127 }
00128 if (!errorKey1.isNull())
00129 {
00130 kdError(5950) << "AlarmCalendar::initialiseCalendars(): calendar names clash: " << errorKey1 << ", " << errorKey2 << endl;
00131 KAlarmApp::displayFatalError(i18n("%1, %2: file names must be different").arg(errorKey1).arg(errorKey2));
00132 return false;
00133 }
00134 if (!mCalendars[ACTIVE]->valid())
00135 {
00136 QString path = mCalendars[ACTIVE]->path();
00137 kdError(5950) << "AlarmCalendar::initialiseCalendars(): invalid name: " << path << endl;
00138 KAlarmApp::displayFatalError(i18n("Invalid calendar file name: %1").arg(path));
00139 return false;
00140 }
00141 return true;
00142 }
00143
00144
00145
00146
00147
00148 AlarmCalendar* AlarmCalendar::createCalendar(CalID type, KConfig* config, QString& writePath, const QString& configKey)
00149 {
00150 static QRegExp vcsRegExp(QString::fromLatin1("\\.vcs$"));
00151 static QString ical = QString::fromLatin1(".ics");
00152
00153 if (configKey.isNull())
00154 {
00155 writePath = locateLocal("appdata", calendarNames[type]);
00156 return new AlarmCalendar(writePath, type);
00157 }
00158 else
00159 {
00160 QString readPath = config->readPathEntry(configKey, locateLocal("appdata", calendarNames[type]));
00161 writePath = readPath;
00162 writePath.replace(vcsRegExp, ical);
00163 return new AlarmCalendar(readPath, type, writePath, configKey);
00164 }
00165 }
00166
00167
00168
00169
00170 void AlarmCalendar::terminateCalendars()
00171 {
00172 for (int i = 0; i < NCALS; ++i)
00173 {
00174 calendarDeleter[i].destructObject();
00175 mCalendars[i] = 0;
00176 }
00177 }
00178
00179
00180
00181
00182
00183
00184 AlarmCalendar* AlarmCalendar::calendarOpen(CalID id)
00185 {
00186 AlarmCalendar* cal = mCalendars[id];
00187 if (!cal->mPurgeDays)
00188 return 0;
00189 if (cal->open())
00190 return cal;
00191 kdError(5950) << "AlarmCalendar::calendarOpen(" << calendarNames[id] << "): open error\n";
00192 return 0;
00193 }
00194
00195
00196
00197
00198
00199 const KCal::Event* AlarmCalendar::getEvent(const QString& uniqueID)
00200 {
00201 if (uniqueID.isEmpty())
00202 return 0;
00203 CalID calID;
00204 switch (KAEvent::uidStatus(uniqueID))
00205 {
00206 case KAEvent::ACTIVE: calID = ACTIVE; break;
00207 case KAEvent::TEMPLATE: calID = TEMPLATE; break;
00208 case KAEvent::EXPIRED: calID = EXPIRED; break;
00209 case KAEvent::DISPLAYING: calID = DISPLAY; break;
00210 default:
00211 return 0;
00212 }
00213 AlarmCalendar* cal = calendarOpen(calID);
00214 if (!cal)
00215 return 0;
00216 return cal->event(uniqueID);
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226 AlarmCalendar::AlarmCalendar(const QString& path, CalID type, const QString& icalPath,
00227 const QString& configKey)
00228 : mCalendar(0),
00229 mConfigKey(icalPath.isNull() ? QString::null : configKey),
00230 mType(eventTypes[type]),
00231 mPurgeDays(-1),
00232 mOpen(false),
00233 mPurgeDaysQueued(-1),
00234 mUpdateCount(0),
00235 mUpdateSave(false)
00236 {
00237 mUrl.setPath(path);
00238 mICalUrl.setPath(icalPath.isNull() ? path : icalPath);
00239 mVCal = (icalPath.isNull() || path != icalPath);
00240 }
00241
00242 AlarmCalendar::~AlarmCalendar()
00243 {
00244 close();
00245 }
00246
00247
00248
00249
00250 bool AlarmCalendar::open()
00251 {
00252 if (mOpen)
00253 return true;
00254 if (!mUrl.isValid())
00255 return false;
00256
00257 kdDebug(5950) << "AlarmCalendar::open(" << mUrl.prettyURL() << ")\n";
00258 if (!mCalendar)
00259 mCalendar = new CalendarLocal(QString::fromLatin1("UTC"));
00260 mCalendar->setLocalTime();
00261
00262
00263
00264 if (!KIO::NetAccess::exists(mUrl, true, MainWindow::mainMainWindow()))
00265 {
00266
00267 if (create())
00268 load();
00269 }
00270 else
00271 {
00272
00273 if (load() == 0)
00274 {
00275 if (create())
00276 load();
00277 }
00278 }
00279 if (!mOpen)
00280 {
00281 delete mCalendar;
00282 mCalendar = 0;
00283 }
00284 return mOpen;
00285 }
00286
00287
00288
00289
00290
00291 bool AlarmCalendar::create()
00292 {
00293 if (mICalUrl.isLocalFile())
00294 return saveCal(mICalUrl.path());
00295 else
00296 {
00297 KTempFile tmpFile;
00298 return saveCal(tmpFile.name());
00299 }
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309 int AlarmCalendar::load()
00310 {
00311 if (!mCalendar)
00312 return -2;
00313
00314 kdDebug(5950) << "AlarmCalendar::load(): " << mUrl.prettyURL() << endl;
00315 QString tmpFile;
00316 if (!KIO::NetAccess::download(mUrl, tmpFile, MainWindow::mainMainWindow()))
00317 {
00318 kdError(5950) << "AlarmCalendar::load(): Load failure" << endl;
00319 KMessageBox::error(0, i18n("Cannot open calendar:\n%1").arg(mUrl.prettyURL()));
00320 return -1;
00321 }
00322 kdDebug(5950) << "AlarmCalendar::load(): --- Downloaded to " << tmpFile << endl;
00323 mCalendar->setTimeZoneId(QString::null);
00324 bool loaded = mCalendar->load(tmpFile);
00325 mCalendar->setLocalTime();
00326 if (!loaded)
00327 {
00328
00329 KIO::NetAccess::removeTempFile(tmpFile);
00330 KIO::UDSEntry uds;
00331 KIO::NetAccess::stat(mUrl, uds, MainWindow::mainMainWindow());
00332 KFileItem fi(uds, mUrl);
00333 if (!fi.size())
00334 return 0;
00335 kdError(5950) << "AlarmCalendar::load(): Error loading calendar file '" << tmpFile << "'" << endl;
00336 KMessageBox::error(0, i18n("Error loading calendar:\n%1\n\nPlease fix or delete the file.").arg(mUrl.prettyURL()));
00337
00338 mCalendar->close();
00339 delete mCalendar;
00340 mCalendar = 0;
00341 return -1;
00342 }
00343 if (!mLocalFile.isEmpty())
00344 KIO::NetAccess::removeTempFile(mLocalFile);
00345 mLocalFile = tmpFile;
00346
00347 CalendarCompat::fix(*mCalendar, mLocalFile);
00348 mOpen = true;
00349 return 1;
00350 }
00351
00352
00353
00354
00355 bool AlarmCalendar::reload()
00356 {
00357 if (!mCalendar)
00358 return false;
00359 kdDebug(5950) << "AlarmCalendar::reload(): " << mUrl.prettyURL() << endl;
00360 close();
00361 bool result = open();
00362 return result;
00363 }
00364
00365
00366
00367
00368
00369 bool AlarmCalendar::saveCal(const QString& newFile)
00370 {
00371 if (!mCalendar || !mOpen && newFile.isNull())
00372 return false;
00373
00374 kdDebug(5950) << "AlarmCalendar::saveCal(\"" << newFile << "\", " << mType << ")\n";
00375 QString saveFilename = newFile.isNull() ? mLocalFile : newFile;
00376 if (mVCal && newFile.isNull() && mUrl.isLocalFile())
00377 saveFilename = mICalUrl.path();
00378 if (!mCalendar->save(saveFilename, new ICalFormat))
00379 {
00380 kdError(5950) << "AlarmCalendar::saveCal(" << saveFilename << "): failed.\n";
00381 KMessageBox::error(0, i18n("Failed to save calendar to\n'%1'").arg(mICalUrl.prettyURL()));
00382 return false;
00383 }
00384
00385 if (!mICalUrl.isLocalFile())
00386 {
00387 if (!KIO::NetAccess::upload(saveFilename, mICalUrl, MainWindow::mainMainWindow()))
00388 {
00389 kdError(5950) << "AlarmCalendar::saveCal(" << saveFilename << "): upload failed.\n";
00390 KMessageBox::error(0, i18n("Cannot upload calendar to\n'%1'").arg(mICalUrl.prettyURL()));
00391 return false;
00392 }
00393 }
00394
00395 if (mVCal)
00396 {
00397
00398
00399 if (!mConfigKey.isNull())
00400 {
00401 KConfig* config = kapp->config();
00402 config->setGroup(QString::fromLatin1("General"));
00403 config->writePathEntry(mConfigKey, mICalUrl.path());
00404 config->sync();
00405 }
00406 mUrl = mICalUrl;
00407 mVCal = false;
00408 }
00409
00410 mUpdateSave = false;
00411 emit calendarSaved(this);
00412 return true;
00413 }
00414
00415
00416
00417
00418 void AlarmCalendar::close()
00419 {
00420 if (!mLocalFile.isEmpty())
00421 {
00422 KIO::NetAccess::removeTempFile(mLocalFile);
00423 mLocalFile = "";
00424 }
00425 if (mCalendar)
00426 {
00427 mCalendar->close();
00428 delete mCalendar;
00429 mCalendar = 0;
00430 }
00431 mOpen = false;
00432 }
00433
00434
00435
00436
00437
00438
00439
00440
00441 bool AlarmCalendar::importAlarms(QWidget* parent)
00442 {
00443 KURL url = KFileDialog::getOpenURL(QString::fromLatin1(":importalarms"),
00444 QString::fromLatin1("*.vcs *.ics|%1").arg(i18n("Calendar Files")), parent);
00445 if (url.isEmpty())
00446 {
00447 kdError(5950) << "AlarmCalendar::importAlarms(): Empty URL" << endl;
00448 return false;
00449 }
00450 if (!url.isValid())
00451 {
00452 kdDebug(5950) << "AlarmCalendar::importAlarms(): Invalid URL" << endl;
00453 return false;
00454 }
00455 kdDebug(5950) << "AlarmCalendar::importAlarms(" << url.prettyURL() << ")" << endl;
00456
00457 bool success = true;
00458 QString filename;
00459 bool local = url.isLocalFile();
00460 if (local)
00461 {
00462 filename = url.path();
00463 if (!KStandardDirs::exists(filename))
00464 {
00465 kdDebug(5950) << "AlarmCalendar::importAlarms(): File '" << url.prettyURL() << "' not found" << endl;
00466 KMessageBox::error(parent, i18n("Could not load calendar '%1'.").arg(url.prettyURL()));
00467 return false;
00468 }
00469 }
00470 else
00471 {
00472 if (!KIO::NetAccess::download(url, filename, MainWindow::mainMainWindow()))
00473 {
00474 kdError(5950) << "AlarmCalendar::importAlarms(): Download failure" << endl;
00475 KMessageBox::error(parent, i18n("Cannot download calendar:\n%1").arg(url.prettyURL()));
00476 return false;
00477 }
00478 kdDebug(5950) << "--- Downloaded to " << filename << endl;
00479 }
00480
00481
00482 CalendarLocal cal(QString::fromLatin1("UTC"));
00483 cal.setLocalTime();
00484 success = cal.load(filename);
00485 if (!success)
00486 {
00487 kdDebug(5950) << "AlarmCalendar::importAlarms(): error loading calendar '" << filename << "'" << endl;
00488 KMessageBox::error(parent, i18n("Could not load calendar '%1'.").arg(url.prettyURL()));
00489 }
00490 else
00491 {
00492 CalendarCompat::fix(cal, filename);
00493 bool saveActive = false;
00494 bool saveExpired = false;
00495 bool saveTemplate = false;
00496 AlarmCalendar* active = activeCalendar();
00497 AlarmCalendar* expired = expiredCalendar();
00498 AlarmCalendar* templat = 0;
00499 AlarmCalendar* acal;
00500 Event::List events = cal.rawEvents();
00501 for (Event::List::ConstIterator it = events.begin(); it != events.end(); ++it)
00502 {
00503 const Event* event = *it;
00504 if (event->alarms().isEmpty())
00505 continue;
00506 KAEvent::Status type = KAEvent::uidStatus(event->uid());
00507 switch (type)
00508 {
00509 case KAEvent::ACTIVE:
00510 acal = active;
00511 saveActive = true;
00512 break;
00513 case KAEvent::EXPIRED:
00514 acal = expired;
00515 saveExpired = true;
00516 break;
00517 case KAEvent::TEMPLATE:
00518 if (!templat)
00519 templat = templateCalendarOpen();
00520 acal = templat;
00521 saveTemplate = true;
00522 break;
00523 default:
00524 continue;
00525 }
00526 if (!acal)
00527 continue;
00528
00529 Event* newev = new Event(*event);
00530
00531
00532
00533 if (type == KAEvent::ACTIVE && !newev->summary().isEmpty())
00534 {
00535 const Alarm::List& alarms = newev->alarms();
00536 for (Alarm::List::ConstIterator ait = alarms.begin(); ait != alarms.end(); ++ait)
00537 {
00538 Alarm* alarm = *ait;
00539 if (alarm->type() == Alarm::Display && alarm->text().isEmpty())
00540 alarm->setText(newev->summary());
00541 }
00542 newev->setSummary(QString::null);
00543 }
00544
00545 newev->setUid(KAEvent::uid(CalFormat::createUniqueId(), type));
00546 if (!acal->mCalendar->addEvent(newev))
00547 success = false;
00548 }
00549
00550
00551 if (saveActive)
00552 active->saveCal();
00553 if (saveExpired)
00554 expired->saveCal();
00555 if (saveTemplate)
00556 templat->saveCal();
00557 }
00558 if (!local)
00559 KIO::NetAccess::removeTempFile(filename);
00560 return success;
00561 }
00562
00563
00564
00565
00566
00567 void AlarmCalendar::startUpdate()
00568 {
00569 ++mUpdateCount;
00570 }
00571
00572
00573
00574
00575
00576 void AlarmCalendar::endUpdate()
00577 {
00578 if (mUpdateCount > 0)
00579 --mUpdateCount;
00580 if (!mUpdateCount)
00581 {
00582 if (mUpdateSave)
00583 saveCal();
00584 }
00585 }
00586
00587
00588
00589
00590 void AlarmCalendar::save()
00591 {
00592 if (mUpdateCount)
00593 mUpdateSave = true;
00594 else
00595 saveCal();
00596 }
00597
00598 #if 0
00599
00600
00601
00602
00603 void AlarmCalendar::convertToICal()
00604 {
00605 if (mVCal)
00606 {
00607 if (!mConfigKey.isNull())
00608 {
00609 KConfig* config = kapp->config();
00610 config->setGroup(QString::fromLatin1("General"));
00611 config->writePathEntry(mConfigKey, mICalUrl.path());
00612 config->sync();
00613 }
00614 mUrl = mICalUrl;
00615 mVCal = false;
00616 }
00617 }
00618 #endif
00619
00620
00621
00622
00623
00624 void AlarmCalendar::setPurgeDays(int days)
00625 {
00626 if (days != mPurgeDays)
00627 {
00628 int oldDays = mPurgeDays;
00629 mPurgeDays = days;
00630 if (mPurgeDays <= 0)
00631 StartOfDayTimer::disconnect(this);
00632 if (oldDays < 0 || days >= 0 && days < oldDays)
00633 {
00634
00635 if (open())
00636 slotPurge();
00637 }
00638 else if (mPurgeDays > 0)
00639 startPurgeTimer();
00640 }
00641 }
00642
00643
00644
00645
00646
00647 void AlarmCalendar::slotPurge()
00648 {
00649 purge(mPurgeDays);
00650 startPurgeTimer();
00651 }
00652
00653
00654
00655
00656
00657 void AlarmCalendar::purge(int daysToKeep)
00658 {
00659 if (mPurgeDaysQueued < 0 || daysToKeep < mPurgeDaysQueued)
00660 mPurgeDaysQueued = daysToKeep;
00661
00662
00663 theApp()->processQueue();
00664 }
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674 void AlarmCalendar::purgeIfQueued()
00675 {
00676 if (mPurgeDaysQueued >= 0)
00677 {
00678 if (open())
00679 {
00680 kdDebug(5950) << "AlarmCalendar::purgeIfQueued(" << mPurgeDaysQueued << ")\n";
00681 bool changed = false;
00682 QDate cutoff = QDate::currentDate().addDays(-mPurgeDaysQueued);
00683 Event::List events = mCalendar->rawEvents();
00684 for (Event::List::ConstIterator it = events.begin(); it != events.end(); ++it)
00685 {
00686 Event* kcalEvent = *it;
00687 if (!mPurgeDaysQueued || kcalEvent->created().date() < cutoff)
00688 {
00689 mCalendar->deleteEvent(kcalEvent);
00690 changed = true;
00691 }
00692 }
00693 if (changed)
00694 {
00695 saveCal();
00696 emit purged();
00697 }
00698 mPurgeDaysQueued = -1;
00699 }
00700 }
00701 }
00702
00703
00704
00705
00706
00707
00708 void AlarmCalendar::startPurgeTimer()
00709 {
00710 if (mPurgeDays > 0)
00711 StartOfDayTimer::connect(this, SLOT(slotPurge()));
00712 }
00713
00714
00715
00716
00717
00718
00719
00720
00721 Event* AlarmCalendar::addEvent(KAEvent& event, bool useEventID)
00722 {
00723 if (!mOpen)
00724 return 0;
00725 QString id = event.id();
00726 Event* kcalEvent = new Event;
00727 if (mType == KAEvent::ACTIVE)
00728 {
00729 if (id.isEmpty())
00730 useEventID = false;
00731 if (!useEventID)
00732 event.setEventID(kcalEvent->uid());
00733 }
00734 else
00735 {
00736 if (id.isEmpty())
00737 id = kcalEvent->uid();
00738 useEventID = true;
00739 }
00740 if (useEventID)
00741 {
00742 id = KAEvent::uid(id, mType);
00743 event.setEventID(id);
00744 kcalEvent->setUid(id);
00745 }
00746 event.updateKCalEvent(*kcalEvent, false, (mType == KAEvent::EXPIRED), true);
00747 mCalendar->addEvent(kcalEvent);
00748 event.clearUpdated();
00749 return kcalEvent;
00750 }
00751
00752
00753
00754
00755
00756 void AlarmCalendar::updateEvent(const KAEvent& evnt)
00757 {
00758 if (mOpen)
00759 {
00760 Event* kcalEvent = event(evnt.id());
00761 if (kcalEvent)
00762 {
00763 evnt.updateKCalEvent(*kcalEvent);
00764 evnt.clearUpdated();
00765 if (mType == KAEvent::ACTIVE)
00766 Daemon::savingEvent(evnt.id());
00767 return;
00768 }
00769 }
00770 if (mType == KAEvent::ACTIVE)
00771 Daemon::eventHandled(evnt.id(), false);
00772 }
00773
00774
00775
00776
00777
00778 void AlarmCalendar::deleteEvent(const QString& eventID, bool saveit)
00779 {
00780 if (mOpen)
00781 {
00782 Event* kcalEvent = event(eventID);
00783 if (kcalEvent)
00784 {
00785 mCalendar->deleteEvent(kcalEvent);
00786 if (mType == KAEvent::ACTIVE)
00787 Daemon::savingEvent(eventID);
00788 if (saveit)
00789 save();
00790 return;
00791 }
00792 }
00793 if (mType == KAEvent::ACTIVE)
00794 Daemon::eventHandled(eventID, false);
00795 }
00796
00797
00798
00799
00800 void AlarmCalendar::emitEmptyStatus()
00801 {
00802 emit emptyStatus(events().isEmpty());
00803 }
00804
00805
00806
00807
00808 KCal::Event* AlarmCalendar::event(const QString& uniqueID)
00809 {
00810 return mCalendar ? mCalendar->event(uniqueID) : 0;
00811 }
00812
00813
00814
00815
00816 KCal::Event::List AlarmCalendar::events()
00817 {
00818 if (!mCalendar)
00819 return KCal::Event::List();
00820 KCal::Event::List list = mCalendar->rawEvents();
00821 KCal::Event::List::Iterator it = list.begin();
00822 while (it != list.end())
00823 {
00824 if ((*it)->alarms().isEmpty())
00825 it = list.remove(it);
00826 else
00827 ++it;
00828 }
00829 return list;
00830 }
00831
00832
00833
00834
00835 Event::List AlarmCalendar::eventsWithAlarms(const QDateTime& from, const QDateTime& to)
00836 {
00837 kdDebug(5950) << "AlarmCalendar::eventsWithAlarms(" << from.toString() << " - " << to.toString() << ")\n";
00838 Event::List evnts;
00839 if (!mCalendar)
00840 return evnts;
00841 QDateTime dt;
00842 Event::List allEvents = mCalendar->rawEvents();
00843 for (Event::List::ConstIterator it = allEvents.begin(); it != allEvents.end(); ++it)
00844 {
00845 Event* e = *it;
00846 bool recurs = e->doesRecur();
00847 int endOffset = 0;
00848 bool endOffsetValid = false;
00849 const Alarm::List& alarms = e->alarms();
00850 for (Alarm::List::ConstIterator ait = alarms.begin(); ait != alarms.end(); ++ait)
00851 {
00852 Alarm* alarm = *ait;
00853 if (alarm->enabled())
00854 {
00855 if (recurs)
00856 {
00857 if (alarm->hasTime())
00858 dt = alarm->time();
00859 else
00860 {
00861
00862
00863
00864 int offset = 0;
00865 if (alarm->hasStartOffset())
00866 offset = alarm->startOffset().asSeconds();
00867 else if (alarm->hasEndOffset())
00868 {
00869 if (!endOffsetValid)
00870 {
00871 endOffset = e->hasDuration() ? e->duration() : e->hasEndDate() ? e->dtStart().secsTo(e->dtEnd()) : 0;
00872 endOffsetValid = true;
00873 }
00874 offset = alarm->endOffset().asSeconds() + endOffset;
00875 }
00876
00877 QDateTime pre = from.addSecs(-offset - 1);
00878 if (e->doesFloat() && pre.time() < Preferences::startOfDay())
00879 pre = pre.addDays(-1);
00880 dt = e->recurrence()->getNextDateTime(pre);
00881 if (!dt.isValid())
00882 continue;
00883 dt = dt.addSecs(offset);
00884 }
00885 }
00886 else
00887 dt = alarm->time();
00888 if (dt >= from && dt <= to)
00889 {
00890 kdDebug(5950) << "AlarmCalendar::events() '" << e->summary()
00891 << "': " << dt.toString() << endl;
00892 evnts.append(e);
00893 break;
00894 }
00895 }
00896 }
00897 }
00898 return evnts;
00899 }