00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdlib.h>
00023
00024 #include <qdatetime.h>
00025 #include <qstring.h>
00026 #include <qptrlist.h>
00027
00028 #include <kdebug.h>
00029
00030 #include "vcaldrag.h"
00031 #include "vcalformat.h"
00032 #include "icalformat.h"
00033 #include "exceptions.h"
00034 #include "incidence.h"
00035 #include "journal.h"
00036 #include "filestorage.h"
00037
00038 #include "calendarlocal.h"
00039
00040 using namespace KCal;
00041
00042 CalendarLocal::CalendarLocal()
00043 : Calendar()
00044 {
00045 init();
00046 }
00047
00048 CalendarLocal::CalendarLocal(const QString &timeZoneId)
00049 : Calendar(timeZoneId)
00050 {
00051 init();
00052 }
00053
00054 void CalendarLocal::init()
00055 {
00056 mOldestDate = 0L;
00057 mNewestDate = 0L;
00058
00059 mRecursList.setAutoDelete(true);
00060
00061 mTodoList.setAutoDelete(true);
00062
00063 mCalDict = new QIntDict<QPtrList<Event> > (BIGPRIME);
00064 mCalDict->setAutoDelete(true);
00065
00066 mJournalList.setAutoDelete(true);
00067 }
00068
00069
00070 CalendarLocal::~CalendarLocal()
00071 {
00072 close();
00073 delete mCalDict;
00074 delete mNewestDate;
00075 delete mOldestDate;
00076 }
00077
00078 bool CalendarLocal::load( const QString &fileName )
00079 {
00080 FileStorage storage( this, fileName );
00081 return storage.load();
00082 }
00083
00084 bool CalendarLocal::save( const QString &fileName, CalFormat *format )
00085 {
00086 FileStorage storage( this, fileName, format );
00087 return storage.save();
00088 }
00089
00090 void CalendarLocal::close()
00091 {
00092 QIntDictIterator<QPtrList<Event> > qdi(*mCalDict);
00093 QPtrList<Event> *tmpList;
00094
00095
00096 qdi.toFirst();
00097 while (qdi.current()) {
00098 tmpList = qdi.current();
00099 QDate keyDate = keyToDate(qdi.currentKey());
00100 Event *ev;
00101 for(ev = tmpList->first();ev;ev = tmpList->next()) {
00102
00103
00104 bool del = false;
00105 if (ev->isMultiDay()) {
00106 if (ev->dtStart().date() == keyDate) {
00107 del = true;
00108 }
00109 } else {
00110 del = true;
00111 }
00112 if (del) {
00113
00114 delete ev;
00115 }
00116 }
00117 ++qdi;
00118 }
00119
00120 mCalDict->clear();
00121 mRecursList.clear();
00122 mTodoList.clear();
00123
00124
00125 delete mOldestDate;
00126 mOldestDate = 0L;
00127 delete mNewestDate;
00128 mNewestDate = 0L;
00129
00130 setModified( false );
00131 }
00132
00133
00134 void CalendarLocal::addEvent(Event *anEvent)
00135 {
00136 insertEvent(anEvent);
00137 if (anEvent->organizer() != getEmail()) {
00138 kdDebug(5800) << "Event " << anEvent->summary() << " Organizer: " << anEvent->organizer()
00139 << " Email: " << getEmail() << endl;
00140
00141 }
00142
00143 anEvent->registerObserver( this );
00144
00145 setModified( true );
00146 }
00147
00148
00149 void CalendarLocal::deleteEvent(Event *event)
00150 {
00151 kdDebug(5800) << "CalendarLocal::deleteEvent" << endl;
00152
00153 QDate date(event->dtStart().date());
00154
00155 QPtrList<Event> *tmpList;
00156 Event *anEvent;
00157 int extraDays, dayOffset;
00158 QDate startDate, tmpDate;
00159
00160 tmpList = mCalDict->find(makeKey(date));
00161
00162
00163 if (tmpList) {
00164 for (anEvent = tmpList->first(); anEvent;
00165 anEvent = tmpList->next()) {
00166 if (anEvent == event) {
00167 if (!anEvent->isMultiDay()) {
00168 tmpList->setAutoDelete(FALSE);
00169 tmpList->remove();
00170 goto FINISH;
00171 } else {
00172
00173
00174 startDate = anEvent->dtStart().date();
00175 extraDays = startDate.daysTo(anEvent->dtEnd().date());
00176 for (dayOffset = 0; dayOffset <= extraDays; dayOffset++) {
00177 tmpDate = startDate.addDays(dayOffset);
00178 tmpList = mCalDict->find(makeKey(tmpDate));
00179 if (tmpList) {
00180 for (anEvent = tmpList->first(); anEvent;
00181 anEvent = tmpList->next()) {
00182 if (anEvent == event)
00183 tmpList->remove();
00184 }
00185 }
00186 }
00187
00188 delete anEvent;
00189 goto FINISH;
00190 }
00191 }
00192 }
00193 }
00194 for (anEvent = mRecursList.first(); anEvent;
00195 anEvent = mRecursList.next()) {
00196 if (anEvent == event) {
00197 mRecursList.remove();
00198 }
00199 }
00200
00201
00202 FINISH:
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 if (date == (*mOldestDate)) {
00216 for (; !mCalDict->find(makeKey((*mOldestDate))) &&
00217 (*mOldestDate != *mNewestDate);
00218 (*mOldestDate) = mOldestDate->addDays(1));
00219 mRecursList.first();
00220 while ((anEvent = mRecursList.current())) {
00221 if (anEvent->dtStart().date() < (*mOldestDate)) {
00222 (*mOldestDate) = anEvent->dtStart().date();
00223 mRecursList.first();
00224 }
00225 anEvent = mRecursList.next();
00226 }
00227 }
00228
00229 if (date == (*mNewestDate)) {
00230 for (; !mCalDict->find(makeKey((*mNewestDate))) &&
00231 (*mNewestDate != *mOldestDate);
00232 (*mNewestDate) = mNewestDate->addDays(-1));
00233 mRecursList.first();
00234 while ((anEvent = mRecursList.current())) {
00235 if (anEvent->dtStart().date() > (*mNewestDate)) {
00236 (*mNewestDate) = anEvent->dtStart().date();
00237 mRecursList.first();
00238 }
00239 anEvent = mRecursList.next();
00240 }
00241 }
00242
00243 setModified( true );
00244 }
00245
00246
00247 Event *CalendarLocal::event( const QString &uid )
00248 {
00249 kdDebug(5800) << "CalendarLocal::event(): " << uid << endl;
00250
00251 QPtrList<Event> *eventList;
00252 QIntDictIterator<QPtrList<Event> > dictIt(*mCalDict);
00253 Event *anEvent;
00254
00255 while (dictIt.current()) {
00256 eventList = dictIt.current();
00257 for (anEvent = eventList->first(); anEvent;
00258 anEvent = eventList->next()) {
00259 if (anEvent->uid() == uid) {
00260 return anEvent;
00261 }
00262 }
00263 ++dictIt;
00264 }
00265 for (anEvent = mRecursList.first(); anEvent;
00266 anEvent = mRecursList.next()) {
00267 if (anEvent->uid() == uid) {
00268 return anEvent;
00269 }
00270 }
00271
00272 return (Event *) 0L;
00273 }
00274
00275 void CalendarLocal::addTodo(Todo *todo)
00276 {
00277 mTodoList.append(todo);
00278
00279 todo->registerObserver( this );
00280
00281 setModified( true );
00282 }
00283
00284 void CalendarLocal::deleteTodo(Todo *todo)
00285 {
00286 mTodoList.findRef(todo);
00287 mTodoList.remove();
00288
00289 setModified( true );
00290 }
00291
00292 QPtrList<Todo> CalendarLocal::rawTodos() const
00293 {
00294 return mTodoList;
00295 }
00296
00297 Todo *CalendarLocal::todo( const QString &uid )
00298 {
00299 Todo *aTodo;
00300 for (aTodo = mTodoList.first(); aTodo;
00301 aTodo = mTodoList.next())
00302 if (aTodo->uid() == uid)
00303 return aTodo;
00304
00305 return 0;
00306 }
00307
00308 QPtrList<Todo> CalendarLocal::todos( const QDate &date )
00309 {
00310 QPtrList<Todo> todos;
00311
00312 Todo *aTodo;
00313 for (aTodo = mTodoList.first();aTodo;aTodo = mTodoList.next()) {
00314 if (aTodo->hasDueDate() && aTodo->dtDue().date() == date) {
00315 todos.append(aTodo);
00316 }
00317 }
00318
00319 return todos;
00320 }
00321
00322 int CalendarLocal::numEvents(const QDate &qd)
00323 {
00324 QPtrList<Event> *tmpList;
00325 Event *anEvent;
00326 int count = 0;
00327 int extraDays, i;
00328
00329
00330 tmpList = mCalDict->find(makeKey(qd));
00331 if (tmpList)
00332 count += tmpList->count();
00333
00334
00335 for (anEvent = mRecursList.first(); anEvent; anEvent = mRecursList.next()) {
00336 if (anEvent->isMultiDay()) {
00337 extraDays = anEvent->dtStart().date().daysTo(anEvent->dtEnd().date());
00338
00339 for (i = 0; i <= extraDays; i++) {
00340 if (anEvent->recursOn(qd.addDays(i))) {
00341 ++count;
00342 break;
00343 }
00344 }
00345 } else {
00346 if (anEvent->recursOn(qd))
00347 ++count;
00348 }
00349 }
00350 return count;
00351 }
00352
00353
00354 Alarm::List CalendarLocal::alarmsTo( const QDateTime &to )
00355 {
00356 if( mOldestDate )
00357 return alarms( *mOldestDate, to );
00358 else
00359 return alarms( QDateTime( QDate( 1900, 1, 1 ) ), to );
00360 }
00361
00362 Alarm::List CalendarLocal::alarms( const QDateTime &from, const QDateTime &to )
00363 {
00364 kdDebug(5800) << "CalendarLocal::alarms(" << from.toString() << " - " << to.toString() << ")\n";
00365 Alarm::List alarms;
00366
00367
00368 QIntDictIterator<QPtrList<Event> > it( *mCalDict );
00369 for( ; it.current(); ++it ) {
00370 QPtrList<Event> *events = it.current();
00371 Event *e;
00372 for( e = events->first(); e; e = events->next() ) {
00373 appendAlarms( alarms, e, from, to );
00374 }
00375 }
00376
00377
00378 Event *e;
00379 for( e = mRecursList.first(); e; e = mRecursList.next() ) {
00380 appendRecurringAlarms( alarms, e, from, to );
00381 }
00382
00383
00384 Todo *t;
00385 for( t = mTodoList.first(); t; t = mTodoList.next() ) {
00386 appendAlarms( alarms, t, from, to );
00387 }
00388
00389 return alarms;
00390 }
00391
00392 void CalendarLocal::appendAlarms( Alarm::List &alarms, Incidence *incidence,
00393 const QDateTime &from, const QDateTime &to )
00394 {
00395 QPtrList<Alarm> alarmList = incidence->alarms();
00396 Alarm *alarm;
00397 for( alarm = alarmList.first(); alarm; alarm = alarmList.next() ) {
00398
00399
00400 if ( alarm->enabled() ) {
00401 if ( alarm->time() >= from && alarm->time() <= to ) {
00402 kdDebug(5800) << "CalendarLocal::appendAlarms() '" << incidence->summary()
00403 << "': " << alarm->time().toString() << endl;
00404 alarms.append( alarm );
00405 }
00406 }
00407 }
00408 }
00409
00410 void CalendarLocal::appendRecurringAlarms( Alarm::List &alarms, Incidence *incidence,
00411 const QDateTime &from, const QDateTime &to )
00412 {
00413 QPtrList<Alarm> alarmList = incidence->alarms();
00414 Alarm *alarm;
00415 QDateTime qdt;
00416 for( alarm = alarmList.first(); alarm; alarm = alarmList.next() ) {
00417 if (incidence->recursOn(from.date())) {
00418 qdt.setTime(alarm->time().time());
00419 qdt.setDate(from.date());
00420 }
00421 else qdt = alarm->time();
00422 kdDebug(5800) << "CalendarLocal::appendAlarms() '" << incidence->summary()
00423 << "': " << qdt.toString() << " - " << alarm->enabled() << endl;
00424 if ( alarm->enabled() ) {
00425
00426
00427 if ( qdt >= from && qdt <= to ) {
00428 alarms.append( alarm );
00429 }
00430 }
00431 }
00432 }
00433
00434
00435
00436
00437
00438 void CalendarLocal::update(IncidenceBase *incidence)
00439 {
00440 incidence->setSyncStatus(Event::SYNCMOD);
00441 incidence->setLastModified(QDateTime::currentDateTime());
00442
00443
00444
00445
00446 if ( incidence->type() == "Event" ) {
00447 Event *anEvent = static_cast<Event *>(incidence);
00448
00449 QIntDictIterator<QPtrList<Event> > qdi(*mCalDict);
00450 QPtrList<Event> *tmpList;
00451
00452
00453
00454
00455 qdi.toFirst();
00456 while ((tmpList = qdi.current()) != 0L) {
00457 ++qdi;
00458 tmpList->removeRef(anEvent);
00459 }
00460
00461 if (mRecursList.findRef(anEvent) != -1)
00462 mRecursList.take();
00463
00464
00465 insertEvent(anEvent);
00466 }
00467
00468 setModified( true );
00469 }
00470
00471
00472
00473
00474 void CalendarLocal::insertEvent(const Event *anEvent)
00475 {
00476 long tmpKey;
00477 QString tmpDateStr;
00478 QPtrList<Event> *eventList;
00479 int extraDays, dayCount;
00480
00481
00482 if (!mOldestDate) {
00483 mOldestDate = new QDate();
00484 (*mOldestDate) = anEvent->dtStart().date();
00485 }
00486 if (!mNewestDate) {
00487 mNewestDate = new QDate();
00488 (*mNewestDate) = anEvent->dtStart().date();
00489 }
00490
00491
00492 if (anEvent->dtStart().date() < (*mOldestDate))
00493 (*mOldestDate) = anEvent->dtStart().date();
00494 if (anEvent->dtStart().date() > (*mNewestDate))
00495 (*mNewestDate) = anEvent->dtStart().date();
00496
00497 if (anEvent->recurrence()->doesRecur()) {
00498 mRecursList.append(anEvent);
00499 } else {
00500
00501 extraDays = anEvent->dtStart().date().daysTo(anEvent->dtEnd().date());
00502 for (dayCount = 0; dayCount <= extraDays; dayCount++) {
00503 tmpKey = makeKey(anEvent->dtStart().addDays(dayCount));
00504
00505 if ((eventList = mCalDict->find(tmpKey)) != 0) {
00506 eventList->append(anEvent);
00507 } else {
00508
00509 eventList = new QPtrList<Event>;
00510 eventList->append(anEvent);
00511 mCalDict->insert(tmpKey, eventList);
00512 }
00513 }
00514 }
00515 }
00516
00517
00518 long int CalendarLocal::makeKey(const QDateTime &dt)
00519 {
00520 QDate tmpD;
00521 QString tmpStr;
00522
00523 tmpD = dt.date();
00524 tmpStr.sprintf("%d%.2d%.2d",tmpD.year(), tmpD.month(), tmpD.day());
00525
00526 return tmpStr.toLong();
00527 }
00528
00529
00530 long int CalendarLocal::makeKey(const QDate &d)
00531 {
00532 QString tmpStr;
00533
00534 tmpStr.sprintf("%d%.2d%.2d",d.year(), d.month(), d.day());
00535 return tmpStr.toLong();
00536 }
00537
00538 QDate CalendarLocal::keyToDate(long int key)
00539 {
00540 QString dateStr = QString::number(key);
00541
00542 QDate date(dateStr.mid(0,4).toInt(),dateStr.mid(4,2).toInt(),
00543 dateStr.mid(6,2).toInt());
00544
00545
00546
00547 return date;
00548 }
00549
00550
00551
00552
00553 QPtrList<Event> CalendarLocal::rawEventsForDate(const QDate &qd, bool sorted)
00554 {
00555
00556 QPtrList<Event> eventList;
00557 QPtrList<Event> *tmpList;
00558 Event *anEvent;
00559 tmpList = mCalDict->find(makeKey(qd));
00560 if (tmpList) {
00561 for (anEvent = tmpList->first(); anEvent;
00562 anEvent = tmpList->next())
00563 eventList.append(anEvent);
00564 }
00565
00566
00567 int extraDays, i;
00568 for (anEvent = mRecursList.first(); anEvent; anEvent = mRecursList.next()) {
00569 if (anEvent->isMultiDay()) {
00570 extraDays = anEvent->dtStart().date().daysTo(anEvent->dtEnd().date());
00571 for (i = 0; i <= extraDays; i++) {
00572 if (anEvent->recursOn(qd.addDays(-i))) {
00573 eventList.append(anEvent);
00574 break;
00575 }
00576 }
00577 } else {
00578 if (anEvent->recursOn(qd))
00579 eventList.append(anEvent);
00580 }
00581 }
00582
00583 if (!sorted) {
00584 return eventList;
00585 }
00586
00587
00588
00589 QPtrList<Event> eventListSorted;
00590 Event *sortEvent, *event;
00591 for ( event = eventList.first(); event; event = eventList.next() ) {
00592 sortEvent = eventListSorted.first();
00593 int i = 0;
00594 while ( sortEvent && event->dtStart().time()>=sortEvent->dtStart().time() )
00595 {
00596 i++;
00597 sortEvent = eventListSorted.next();
00598 }
00599 eventListSorted.insert( i, event );
00600 }
00601
00602 return eventListSorted;
00603 }
00604
00605
00606 QPtrList<Event> CalendarLocal::rawEvents( const QDate &start, const QDate &end,
00607 bool inclusive )
00608 {
00609 QIntDictIterator<QPtrList<Event> > qdi(*mCalDict);
00610 QPtrList<Event> matchList, *tmpList, tmpList2;
00611 Event *ev = 0;
00612
00613 qdi.toFirst();
00614
00615
00616 while (qdi.current()) {
00617 QDate keyDate = keyToDate(qdi.currentKey());
00618 if (keyDate >= start && keyDate <= end) {
00619 tmpList = qdi.current();
00620 for(ev = tmpList->first();ev;ev = tmpList->next()) {
00621 bool found = false;
00622 if (ev->isMultiDay()) {
00623 QDate mStart = ev->dtStart().date();
00624 QDate mEnd = ev->dtEnd().date();
00625
00626
00627
00628 if ((mStart >= start && mStart == keyDate) ||
00629 (mStart < start && start == keyDate)) {
00630 if (inclusive) {
00631 if (mStart >= start && mEnd <= end) {
00632
00633 found = true;
00634 }
00635 } else {
00636
00637 found = true;
00638 }
00639 }
00640 } else {
00641 found = true;
00642 }
00643 if (found) matchList.append(ev);
00644 }
00645 }
00646 ++qdi;
00647 }
00648
00649
00650 for(ev = mRecursList.first();ev;ev = mRecursList.next()) {
00651 QDate rStart = ev->dtStart().date();
00652 bool found = false;
00653 if (inclusive) {
00654 if (rStart >= start && rStart <= end) {
00655
00656
00657 if (ev->recurrence()->duration() == 0) {
00658 QDate rEnd = ev->recurrence()->endDate();
00659 if (rEnd >= start && rEnd <= end) {
00660 found = true;
00661 }
00662 } else if (ev->recurrence()->duration() > 0) {
00663
00664
00665 }
00666 }
00667 } else {
00668 if (rStart <= end) {
00669 if (rStart >= start) {
00670 found = true;
00671 } else if (ev->recurrence()->duration() == -1) {
00672 found = true;
00673 } else if (ev->recurrence()->duration() == 0) {
00674 QDate rEnd = ev->recurrence()->endDate();
00675 if (rEnd >= start && rEnd <= end) {
00676 found = true;
00677 }
00678 } else {
00679
00680
00681 found = true;
00682 }
00683 }
00684 }
00685
00686 if (found) matchList.append(ev);
00687 }
00688
00689 return matchList;
00690 }
00691
00692 QPtrList<Event> CalendarLocal::rawEventsForDate(const QDateTime &qdt)
00693 {
00694 return rawEventsForDate( qdt.date() );
00695 }
00696
00697 QPtrList<Event> CalendarLocal::rawEvents()
00698 {
00699 QPtrList<Event> eventList;
00700
00701 if( mOldestDate && mNewestDate )
00702 eventList = rawEvents(*mOldestDate,*mNewestDate);
00703
00704 return eventList;
00705 }
00706
00707 void CalendarLocal::addJournal(Journal *journal)
00708 {
00709 if (journal->dtStart().isValid())
00710 kdDebug(5800) << "Adding Journal on " << journal->dtStart().toString() << endl;
00711 else
00712 kdDebug(5800) << "Adding Journal without a DTSTART" << endl;
00713
00714 mJournalList.append(journal);
00715
00716 journal->registerObserver( this );
00717
00718 setModified( true );
00719 }
00720
00721 void CalendarLocal::deleteJournal(Journal *journal)
00722 {
00723 mJournalList.findRef(journal);
00724 mJournalList.remove();
00725
00726 setModified( true );
00727 }
00728
00729 Journal *CalendarLocal::journal(const QDate &date)
00730 {
00731
00732
00733 for (Journal *it = mJournalList.first(); it; it = mJournalList.next())
00734 if (it->dtStart().date() == date)
00735 return it;
00736
00737 return 0;
00738 }
00739
00740 Journal *CalendarLocal::journal(const QString &uid)
00741 {
00742 for (Journal *it = mJournalList.first(); it; it = mJournalList.next())
00743 if (it->uid() == uid)
00744 return it;
00745
00746 return 0;
00747 }
00748
00749 QPtrList<Journal> CalendarLocal::journals()
00750 {
00751 return mJournalList;
00752 }