summaryrefslogtreecommitdiffabout
path: root/libkcal/calendarlocal.cpp
Unidiff
Diffstat (limited to 'libkcal/calendarlocal.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libkcal/calendarlocal.cpp655
1 files changed, 655 insertions, 0 deletions
diff --git a/libkcal/calendarlocal.cpp b/libkcal/calendarlocal.cpp
new file mode 100644
index 0000000..8ff8b14
--- a/dev/null
+++ b/libkcal/calendarlocal.cpp
@@ -0,0 +1,655 @@
1/*
2 This file is part of libkcal.
3
4 Copyright (c) 1998 Preston Brown
5 Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
21*/
22
23#include <qdatetime.h>
24#include <qstring.h>
25#include <qptrlist.h>
26
27#include <kdebug.h>
28#include <kconfig.h>
29#include <kglobal.h>
30#include <klocale.h>
31
32#include "vcaldrag.h"
33#include "vcalformat.h"
34#include "icalformat.h"
35#include "exceptions.h"
36#include "incidence.h"
37#include "journal.h"
38#include "filestorage.h"
39#include "calfilter.h"
40
41#include "calendarlocal.h"
42
43// #ifndef DESKTOP_VERSION
44// #include <qtopia/alarmserver.h>
45// #endif
46using namespace KCal;
47
48CalendarLocal::CalendarLocal()
49 : Calendar()
50{
51 init();
52}
53
54CalendarLocal::CalendarLocal(const QString &timeZoneId)
55 : Calendar(timeZoneId)
56{
57 init();
58}
59
60void CalendarLocal::init()
61{
62 mNextAlarmIncidence = 0;
63}
64
65
66CalendarLocal::~CalendarLocal()
67{
68 close();
69}
70
71bool CalendarLocal::load( const QString &fileName )
72{
73 FileStorage storage( this, fileName );
74 return storage.load();
75}
76
77bool CalendarLocal::save( const QString &fileName, CalFormat *format )
78{
79 FileStorage storage( this, fileName, format );
80 return storage.save();
81}
82
83void CalendarLocal::close()
84{
85 mEventList.setAutoDelete( true );
86 mTodoList.setAutoDelete( true );
87 mJournalList.setAutoDelete( false );
88
89 mEventList.clear();
90 mTodoList.clear();
91 mJournalList.clear();
92
93 mEventList.setAutoDelete( false );
94 mTodoList.setAutoDelete( false );
95 mJournalList.setAutoDelete( false );
96
97 setModified( false );
98}
99bool CalendarLocal::addEventNoDup( Event *event )
100{
101 Event * eve;
102 for ( eve = mEventList.first(); eve ; eve = mEventList.next() ) {
103 if ( *eve == *event ) {
104 //qDebug("CalendarLocal::Duplicate event found! Not inserted! ");
105 return false;
106 }
107 }
108 return addEvent( event );
109}
110
111bool CalendarLocal::addEvent( Event *event )
112{
113 insertEvent( event );
114
115 event->registerObserver( this );
116
117 setModified( true );
118
119 return true;
120}
121
122void CalendarLocal::deleteEvent( Event *event )
123{
124
125
126 if ( mEventList.removeRef( event ) ) {
127 setModified( true );
128 }
129}
130
131
132Event *CalendarLocal::event( const QString &uid )
133{
134
135 Event *event;
136
137 for ( event = mEventList.first(); event; event = mEventList.next() ) {
138 if ( event->uid() == uid ) {
139 return event;
140 }
141 }
142
143 return 0;
144}
145bool CalendarLocal::addTodoNoDup( Todo *todo )
146{
147 Todo * eve;
148 for ( eve = mTodoList.first(); eve ; eve = mTodoList.next() ) {
149 if ( *eve == *todo ) {
150 //qDebug("duplicate todo found! not inserted! ");
151 return false;
152 }
153 }
154 return addTodo( todo );
155}
156bool CalendarLocal::addTodo( Todo *todo )
157{
158 mTodoList.append( todo );
159
160 todo->registerObserver( this );
161
162 // Set up subtask relations
163 setupRelations( todo );
164
165 setModified( true );
166
167 return true;
168}
169
170void CalendarLocal::deleteTodo( Todo *todo )
171{
172 // Handle orphaned children
173 removeRelations( todo );
174
175 if ( mTodoList.removeRef( todo ) ) {
176 setModified( true );
177 }
178}
179
180QPtrList<Todo> CalendarLocal::rawTodos()
181{
182 return mTodoList;
183}
184Todo *CalendarLocal::todo( int id )
185{
186 Todo *todo;
187 for ( todo = mTodoList.first(); todo; todo = mTodoList.next() ) {
188 if ( todo->zaurusId() == id ) return todo;
189 }
190
191 return 0;
192}
193
194Event *CalendarLocal::event( int id )
195{
196 Event *todo;
197 for ( todo = mEventList.first(); todo; todo = mEventList.next() ) {
198 if ( todo->zaurusId() == id ) return todo;
199 }
200
201 return 0;
202}
203Todo *CalendarLocal::todo( const QString &uid )
204{
205 Todo *todo;
206 for ( todo = mTodoList.first(); todo; todo = mTodoList.next() ) {
207 if ( todo->uid() == uid ) return todo;
208 }
209
210 return 0;
211}
212QString CalendarLocal::nextSummary() const
213{
214 return mNextSummary;
215}
216QDateTime CalendarLocal::nextAlarmEventDateTime() const
217{
218 return mNextAlarmEventDateTime;
219}
220void CalendarLocal::checkAlarmForIncidence( Incidence * incidence, bool deleted)
221{
222 //mNextAlarmIncidence
223 //mNextAlarmDateTime
224 //return mNextSummary;
225 //return mNextAlarmEventDateTime;
226 bool newNextAlarm = false;
227 bool computeNextAlarm = false;
228 bool ok;
229 int offset;
230 QDateTime nextA;
231 // QString nextSum;
232 //QDateTime nextEvent;
233 if ( mNextAlarmIncidence == 0 || incidence == 0 ) {
234 computeNextAlarm = true;
235 } else {
236 if ( ! deleted ) {
237 nextA = incidence->getNextAlarmDateTime(& ok, &offset ) ;
238 if ( ok ) {
239 if ( nextA < mNextAlarmDateTime ) {
240 deRegisterAlarm();
241 mNextAlarmDateTime = nextA;
242 mNextSummary = incidence->summary();
243 mNextAlarmEventDateTime = nextA.addSecs(offset ) ;
244 mNextAlarmEventDateTimeString = KGlobal::locale()->formatDateTime(mNextAlarmEventDateTime);
245 newNextAlarm = true;
246 mNextAlarmIncidence = incidence;
247 } else {
248 if ( incidence == mNextAlarmIncidence ) {
249 computeNextAlarm = true;
250 }
251 }
252 } else {
253 if ( mNextAlarmIncidence == incidence ) {
254 computeNextAlarm = true;
255 }
256 }
257 } else { // deleted
258 if ( incidence == mNextAlarmIncidence ) {
259 computeNextAlarm = true;
260 }
261 }
262 }
263 if ( computeNextAlarm ) {
264 deRegisterAlarm();
265 nextA = nextAlarm( 1000 );
266 if (! mNextAlarmIncidence ) {
267 return;
268 }
269 newNextAlarm = true;
270 }
271 if ( newNextAlarm )
272 registerAlarm();
273}
274QString CalendarLocal:: getAlarmNotification()
275{
276 QString ret;
277 // this should not happen
278 if (! mNextAlarmIncidence )
279 return "cal_alarm"+ mNextSummary.left( 25 )+"\n"+mNextAlarmEventDateTimeString;
280 Alarm* alarm = mNextAlarmIncidence->alarms().first();
281 if ( alarm->type() == Alarm::Procedure ) {
282 ret = "proc_alarm" + alarm->programFile()+"+++";
283 } else {
284 ret = "audio_alarm" +alarm->audioFile() +"+++";
285 }
286 ret += "cal_alarm"+ mNextSummary.left( 25 );
287 if ( mNextSummary.length() > 25 )
288 ret += "\n" + mNextSummary.mid(25, 25 );
289 ret+= "\n"+mNextAlarmEventDateTimeString;
290 return ret;
291}
292
293void CalendarLocal::registerAlarm()
294{
295 mLastAlarmNotificationString = getAlarmNotification();
296 // qDebug("++ register Alarm %s %s",mNextAlarmDateTime.toString().latin1(), mLastAlarmNotificationString.latin1() );
297 emit addAlarm ( mNextAlarmDateTime, mLastAlarmNotificationString );
298// #ifndef DESKTOP_VERSION
299// AlarmServer::addAlarm ( mNextAlarmDateTime,"koalarm", mLastAlarmNotificationString.latin1() );
300// #endif
301}
302void CalendarLocal::deRegisterAlarm()
303{
304 if ( mLastAlarmNotificationString.isNull() )
305 return;
306 //qDebug("-- deregister Alarm %s ", mLastAlarmNotificationString.latin1() );
307
308 emit removeAlarm ( mNextAlarmDateTime, mLastAlarmNotificationString );
309// #ifndef DESKTOP_VERSION
310// AlarmServer::deleteAlarm (mNextAlarmDateTime ,"koalarm" ,mLastAlarmNotificationString.latin1() );
311// #endif
312}
313
314QPtrList<Todo> CalendarLocal::todos( const QDate &date )
315{
316 QPtrList<Todo> todos;
317
318 Todo *todo;
319 for ( todo = mTodoList.first(); todo; todo = mTodoList.next() ) {
320 if ( todo->hasDueDate() && todo->dtDue().date() == date ) {
321 todos.append( todo );
322 }
323 }
324
325 filter()->apply( &todos );
326 return todos;
327}
328void CalendarLocal::reInitAlarmSettings()
329{
330 if ( !mNextAlarmIncidence ) {
331 nextAlarm( 1000 );
332 }
333 deRegisterAlarm();
334 mNextAlarmIncidence = 0;
335 checkAlarmForIncidence( 0, false );
336
337}
338
339
340
341QDateTime CalendarLocal::nextAlarm( int daysTo )
342{
343 QDateTime nextA = QDateTime::currentDateTime().addDays( daysTo );
344 QDateTime start = QDateTime::currentDateTime().addSecs( 30 );
345 QDateTime next;
346 Event *e;
347 bool ok;
348 bool found = false;
349 int offset;
350 mNextAlarmIncidence = 0;
351 for( e = mEventList.first(); e; e = mEventList.next() ) {
352 next = e->getNextAlarmDateTime(& ok, &offset ) ;
353 if ( ok ) {
354 if ( next < nextA ) {
355 nextA = next;
356 found = true;
357 mNextSummary = e->summary();
358 mNextAlarmEventDateTime = next.addSecs(offset ) ;
359 mNextAlarmIncidence = (Incidence *) e;
360 }
361 }
362 }
363 Todo *t;
364 for( t = mTodoList.first(); t; t = mTodoList.next() ) {
365 next = t->getNextAlarmDateTime(& ok, &offset ) ;
366 if ( ok ) {
367 if ( next < nextA ) {
368 nextA = next;
369 found = true;
370 mNextSummary = t->summary();
371 mNextAlarmEventDateTime = next.addSecs(offset );
372 mNextAlarmIncidence = (Incidence *) t;
373 }
374 }
375 }
376 if ( mNextAlarmIncidence ) {
377 mNextAlarmEventDateTimeString = KGlobal::locale()->formatDateTime(mNextAlarmEventDateTime);
378 mNextAlarmDateTime = nextA;
379 }
380 return nextA;
381}
382Alarm::List CalendarLocal::alarmsTo( const QDateTime &to )
383{
384 return alarms( QDateTime( QDate( 1900, 1, 1 ) ), to );
385}
386
387Alarm::List CalendarLocal::alarms( const QDateTime &from, const QDateTime &to )
388{
389 kdDebug(5800) << "CalendarLocal::alarms(" << from.toString() << " - "
390 << to.toString() << ")\n";
391
392 Alarm::List alarms;
393
394 Event *e;
395
396 for( e = mEventList.first(); e; e = mEventList.next() ) {
397 if ( e->doesRecur() ) appendRecurringAlarms( alarms, e, from, to );
398 else appendAlarms( alarms, e, from, to );
399 }
400
401 Todo *t;
402 for( t = mTodoList.first(); t; t = mTodoList.next() ) {
403 appendAlarms( alarms, t, from, to );
404 }
405
406 return alarms;
407}
408
409void CalendarLocal::appendAlarms( Alarm::List &alarms, Incidence *incidence,
410 const QDateTime &from, const QDateTime &to )
411{
412 QPtrList<Alarm> alarmList = incidence->alarms();
413 Alarm *alarm;
414 for( alarm = alarmList.first(); alarm; alarm = alarmList.next() ) {
415// kdDebug(5800) << "CalendarLocal::appendAlarms() '" << alarm->text()
416// << "': " << alarm->time().toString() << " - " << alarm->enabled() << endl;
417 if ( alarm->enabled() ) {
418 if ( alarm->time() >= from && alarm->time() <= to ) {
419 kdDebug(5800) << "CalendarLocal::appendAlarms() '" << incidence->summary()
420 << "': " << alarm->time().toString() << endl;
421 alarms.append( alarm );
422 }
423 }
424 }
425}
426
427void CalendarLocal::appendRecurringAlarms( Alarm::List &alarms,
428 Incidence *incidence,
429 const QDateTime &from,
430 const QDateTime &to )
431{
432
433 QPtrList<Alarm> alarmList = incidence->alarms();
434 Alarm *alarm;
435 QDateTime qdt;
436 for( alarm = alarmList.first(); alarm; alarm = alarmList.next() ) {
437 if (incidence->recursOn(from.date())) {
438 qdt.setTime(alarm->time().time());
439 qdt.setDate(from.date());
440 }
441 else qdt = alarm->time();
442 // qDebug("1 %s %s %s", qdt.toString().latin1(), from.toString().latin1(), to.toString().latin1());
443 if ( alarm->enabled() ) {
444 if ( qdt >= from && qdt <= to ) {
445 alarms.append( alarm );
446 }
447 }
448 }
449}
450
451
452/****************************** PROTECTED METHODS ****************************/
453
454// after changes are made to an event, this should be called.
455void CalendarLocal::update( IncidenceBase *incidence )
456{
457 incidence->setSyncStatus( Event::SYNCMOD );
458 incidence->setLastModified( QDateTime::currentDateTime() );
459 // we should probably update the revision number here,
460 // or internally in the Event itself when certain things change.
461 // need to verify with ical documentation.
462
463 setModified( true );
464}
465
466void CalendarLocal::insertEvent( Event *event )
467{
468 if ( mEventList.findRef( event ) < 0 ) mEventList.append( event );
469}
470
471
472QPtrList<Event> CalendarLocal::rawEventsForDate( const QDate &qd, bool sorted )
473{
474 QPtrList<Event> eventList;
475
476 Event *event;
477 for( event = mEventList.first(); event; event = mEventList.next() ) {
478 if ( event->doesRecur() ) {
479 if ( event->isMultiDay() ) {
480 int extraDays = event->dtStart().date().daysTo( event->dtEnd().date() );
481 int i;
482 for ( i = 0; i <= extraDays; i++ ) {
483 if ( event->recursOn( qd.addDays( -i ) ) ) {
484 eventList.append( event );
485 break;
486 }
487 }
488 } else {
489 if ( event->recursOn( qd ) )
490 eventList.append( event );
491 }
492 } else {
493 if ( event->dtStart().date() <= qd && event->dtEnd().date() >= qd ) {
494 eventList.append( event );
495 }
496 }
497 }
498
499 if ( !sorted ) {
500 return eventList;
501 }
502
503 // kdDebug(5800) << "Sorting events for date\n" << endl;
504 // now, we have to sort it based on dtStart.time()
505 QPtrList<Event> eventListSorted;
506 Event *sortEvent;
507 for ( event = eventList.first(); event; event = eventList.next() ) {
508 sortEvent = eventListSorted.first();
509 int i = 0;
510 while ( sortEvent && event->dtStart().time()>=sortEvent->dtStart().time() )
511 {
512 i++;
513 sortEvent = eventListSorted.next();
514 }
515 eventListSorted.insert( i, event );
516 }
517 return eventListSorted;
518}
519
520
521QPtrList<Event> CalendarLocal::rawEvents( const QDate &start, const QDate &end,
522 bool inclusive )
523{
524 Event *event = 0;
525
526 QPtrList<Event> eventList;
527
528 // Get non-recurring events
529 for( event = mEventList.first(); event; event = mEventList.next() ) {
530 if ( event->doesRecur() ) {
531 QDate rStart = event->dtStart().date();
532 bool found = false;
533 if ( inclusive ) {
534 if ( rStart >= start && rStart <= end ) {
535 // Start date of event is in range. Now check for end date.
536 // if duration is negative, event recurs forever, so do not include it.
537 if ( event->recurrence()->duration() == 0 ) { // End date set
538 QDate rEnd = event->recurrence()->endDate();
539 if ( rEnd >= start && rEnd <= end ) { // End date within range
540 found = true;
541 }
542 } else if ( event->recurrence()->duration() > 0 ) { // Duration set
543 // TODO: Calculate end date from duration. Should be done in Event
544 // For now exclude all events with a duration.
545 }
546 }
547 } else {
548 bool founOne;
549 QDate next = event->getNextOccurence( start, &founOne ).date();
550 if ( founOne ) {
551 if ( next <= end ) {
552 found = true;
553 }
554 }
555
556 /*
557 // crap !!!
558 if ( rStart <= end ) { // Start date not after range
559 if ( rStart >= start ) { // Start date within range
560 found = true;
561 } else if ( event->recurrence()->duration() == -1 ) { // Recurs forever
562 found = true;
563 } else if ( event->recurrence()->duration() == 0 ) { // End date set
564 QDate rEnd = event->recurrence()->endDate();
565 if ( rEnd >= start && rEnd <= end ) { // End date within range
566 found = true;
567 }
568 } else { // Duration set
569 // TODO: Calculate end date from duration. Should be done in Event
570 // For now include all events with a duration.
571 found = true;
572 }
573 }
574 */
575
576 }
577
578 if ( found ) eventList.append( event );
579 } else {
580 QDate s = event->dtStart().date();
581 QDate e = event->dtEnd().date();
582
583 if ( inclusive ) {
584 if ( s >= start && e <= end ) {
585 eventList.append( event );
586 }
587 } else {
588 if ( ( s >= start && s <= end ) || ( e >= start && e <= end ) ) {
589 eventList.append( event );
590 }
591 }
592 }
593 }
594
595 return eventList;
596}
597
598QPtrList<Event> CalendarLocal::rawEventsForDate( const QDateTime &qdt )
599{
600 return rawEventsForDate( qdt.date() );
601}
602
603QPtrList<Event> CalendarLocal::rawEvents()
604{
605 return mEventList;
606}
607
608bool CalendarLocal::addJournal(Journal *journal)
609{
610 if ( journal->dtStart().isValid())
611 kdDebug(5800) << "Adding Journal on " << journal->dtStart().toString() << endl;
612 else
613 kdDebug(5800) << "Adding Journal without a DTSTART" << endl;
614
615 mJournalList.append(journal);
616
617 journal->registerObserver( this );
618
619 setModified( true );
620
621 return true;
622}
623
624void CalendarLocal::deleteJournal( Journal *journal )
625{
626 if ( mJournalList.removeRef(journal) ) {
627 setModified( true );
628 }
629}
630
631Journal *CalendarLocal::journal( const QDate &date )
632{
633// kdDebug(5800) << "CalendarLocal::journal() " << date.toString() << endl;
634
635 for ( Journal *it = mJournalList.first(); it; it = mJournalList.next() )
636 if ( it->dtStart().date() == date )
637 return it;
638
639 return 0;
640}
641
642Journal *CalendarLocal::journal( const QString &uid )
643{
644 for ( Journal *it = mJournalList.first(); it; it = mJournalList.next() )
645 if ( it->uid() == uid )
646 return it;
647
648 return 0;
649}
650
651QPtrList<Journal> CalendarLocal::journals()
652{
653 return mJournalList;
654}
655