-rw-r--r-- | libkcal/incidence.cpp | 594 |
1 files changed, 594 insertions, 0 deletions
diff --git a/libkcal/incidence.cpp b/libkcal/incidence.cpp new file mode 100644 index 0000000..d9bda64 --- a/dev/null +++ b/libkcal/incidence.cpp | |||
@@ -0,0 +1,594 @@ | |||
1 | /* | ||
2 | This file is part of libkcal. | ||
3 | Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to | ||
17 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <kglobal.h> | ||
22 | #include <klocale.h> | ||
23 | #include <kdebug.h> | ||
24 | |||
25 | #include "calformat.h" | ||
26 | |||
27 | #include "incidence.h" | ||
28 | #include "todo.h" | ||
29 | |||
30 | using namespace KCal; | ||
31 | |||
32 | Incidence::Incidence() : | ||
33 | IncidenceBase(), | ||
34 | mRelatedTo(0), mSecrecy(SecrecyPublic), mPriority(3) | ||
35 | { | ||
36 | mRecurrence = new Recurrence(this); | ||
37 | mCancelled = false; | ||
38 | recreate(); | ||
39 | mHasStartDate = true; | ||
40 | mAlarms.setAutoDelete(true); | ||
41 | mAttachments.setAutoDelete(true); | ||
42 | } | ||
43 | |||
44 | Incidence::Incidence( const Incidence &i ) : IncidenceBase( i ) | ||
45 | { | ||
46 | // TODO: reenable attributes currently commented out. | ||
47 | mRevision = i.mRevision; | ||
48 | mCreated = i.mCreated; | ||
49 | mDescription = i.mDescription; | ||
50 | mSummary = i.mSummary; | ||
51 | mCategories = i.mCategories; | ||
52 | // Incidence *mRelatedTo; Incidence *mRelatedTo; | ||
53 | mRelatedTo = 0; | ||
54 | mRelatedToUid = i.mRelatedToUid; | ||
55 | // QPtrList<Incidence> mRelations; QPtrList<Incidence> mRelations; | ||
56 | mExDates = i.mExDates; | ||
57 | mAttachments = i.mAttachments; | ||
58 | mResources = i.mResources; | ||
59 | mSecrecy = i.mSecrecy; | ||
60 | mPriority = i.mPriority; | ||
61 | mLocation = i.mLocation; | ||
62 | mCancelled = i.mCancelled; | ||
63 | mHasStartDate = i.mHasStartDate; | ||
64 | QPtrListIterator<Alarm> it( i.mAlarms ); | ||
65 | const Alarm *a; | ||
66 | while( (a = it.current()) ) { | ||
67 | Alarm *b = new Alarm( *a ); | ||
68 | b->setParent( this ); | ||
69 | mAlarms.append( b ); | ||
70 | |||
71 | ++it; | ||
72 | } | ||
73 | mAlarms.setAutoDelete(true); | ||
74 | |||
75 | mRecurrence = new Recurrence( *(i.mRecurrence), this ); | ||
76 | } | ||
77 | |||
78 | Incidence::~Incidence() | ||
79 | { | ||
80 | |||
81 | Incidence *ev; | ||
82 | QPtrList<Incidence> Relations = relations(); | ||
83 | for (ev=Relations.first();ev;ev=Relations.next()) { | ||
84 | if (ev->relatedTo() == this) ev->setRelatedTo(0); | ||
85 | } | ||
86 | if (relatedTo()) relatedTo()->removeRelation(this); | ||
87 | delete mRecurrence; | ||
88 | |||
89 | } | ||
90 | |||
91 | bool Incidence::cancelled() const | ||
92 | { | ||
93 | return mCancelled; | ||
94 | } | ||
95 | void Incidence::setCancelled( bool b ) | ||
96 | { | ||
97 | mCancelled = b; | ||
98 | updated(); | ||
99 | } | ||
100 | bool Incidence::hasStartDate() const | ||
101 | { | ||
102 | return mHasStartDate; | ||
103 | } | ||
104 | |||
105 | void Incidence::setHasStartDate(bool f) | ||
106 | { | ||
107 | if (mReadOnly) return; | ||
108 | mHasStartDate = f; | ||
109 | updated(); | ||
110 | } | ||
111 | |||
112 | // A string comparison that considers that null and empty are the same | ||
113 | static bool stringCompare( const QString& s1, const QString& s2 ) | ||
114 | { | ||
115 | if ( s1.isEmpty() && s2.isEmpty() ) | ||
116 | return true; | ||
117 | return s1 == s2; | ||
118 | } | ||
119 | |||
120 | bool KCal::operator==( const Incidence& i1, const Incidence& i2 ) | ||
121 | { | ||
122 | |||
123 | if( i1.alarms().count() != i2.alarms().count() ) { | ||
124 | return false; // no need to check further | ||
125 | } | ||
126 | if ( i1.alarms().count() > 0 ) { | ||
127 | if ( !( *(i1.alarms().first()) == *(i2.alarms().first())) ) | ||
128 | { | ||
129 | qDebug("alarm not equal "); | ||
130 | return false; | ||
131 | } | ||
132 | } | ||
133 | #if 0 | ||
134 | QPtrListIterator<Alarm> a1( i1.alarms() ); | ||
135 | QPtrListIterator<Alarm> a2( i2.alarms() ); | ||
136 | for( ; a1.current() && a2.current(); ++a1, ++a2 ) { | ||
137 | if( *a1.current() == *a2.current() ) { | ||
138 | continue; | ||
139 | } | ||
140 | else { | ||
141 | return false; | ||
142 | } | ||
143 | } | ||
144 | #endif | ||
145 | |||
146 | if ( ! operator==( (const IncidenceBase&)i1, (const IncidenceBase&)i2 ) ) | ||
147 | return false; | ||
148 | if ( i1.hasStartDate() == i2.hasStartDate() ) { | ||
149 | if ( i1.hasStartDate() ) { | ||
150 | if ( i1.dtStart() != i2.dtStart() ) | ||
151 | return false; | ||
152 | } | ||
153 | } else { | ||
154 | return false; | ||
155 | } | ||
156 | if (!( *i1.recurrence() == *i2.recurrence()) ) { | ||
157 | qDebug("recurrence is NOT equal "); | ||
158 | return false; | ||
159 | } | ||
160 | return | ||
161 | // i1.created() == i2.created() && | ||
162 | stringCompare( i1.description(), i2.description() ) && | ||
163 | stringCompare( i1.summary(), i2.summary() ) && | ||
164 | i1.categories() == i2.categories() && | ||
165 | // no need to compare mRelatedTo | ||
166 | stringCompare( i1.relatedToUid(), i2.relatedToUid() ) && | ||
167 | // i1.relations() == i2.relations() && | ||
168 | i1.exDates() == i2.exDates() && | ||
169 | i1.attachments() == i2.attachments() && | ||
170 | i1.resources() == i2.resources() && | ||
171 | i1.secrecy() == i2.secrecy() && | ||
172 | i1.priority() == i2.priority() && | ||
173 | stringCompare( i1.location(), i2.location() ); | ||
174 | } | ||
175 | |||
176 | |||
177 | void Incidence::recreate() | ||
178 | { | ||
179 | setCreated(QDateTime::currentDateTime()); | ||
180 | |||
181 | setUid(CalFormat::createUniqueId()); | ||
182 | |||
183 | setRevision(0); | ||
184 | |||
185 | setLastModified(QDateTime::currentDateTime()); | ||
186 | } | ||
187 | |||
188 | void Incidence::setReadOnly( bool readOnly ) | ||
189 | { | ||
190 | IncidenceBase::setReadOnly( readOnly ); | ||
191 | recurrence()->setRecurReadOnly( readOnly); | ||
192 | } | ||
193 | |||
194 | void Incidence::setCreated(QDateTime created) | ||
195 | { | ||
196 | if (mReadOnly) return; | ||
197 | mCreated = getEvenTime(created); | ||
198 | } | ||
199 | |||
200 | QDateTime Incidence::created() const | ||
201 | { | ||
202 | return mCreated; | ||
203 | } | ||
204 | |||
205 | void Incidence::setRevision(int rev) | ||
206 | { | ||
207 | if (mReadOnly) return; | ||
208 | mRevision = rev; | ||
209 | |||
210 | updated(); | ||
211 | } | ||
212 | |||
213 | int Incidence::revision() const | ||
214 | { | ||
215 | return mRevision; | ||
216 | } | ||
217 | |||
218 | void Incidence::setDtStart(const QDateTime &dtStart) | ||
219 | { | ||
220 | |||
221 | QDateTime dt = getEvenTime(dtStart); | ||
222 | recurrence()->setRecurStart( dt); | ||
223 | IncidenceBase::setDtStart( dt ); | ||
224 | } | ||
225 | |||
226 | void Incidence::setDescription(const QString &description) | ||
227 | { | ||
228 | if (mReadOnly) return; | ||
229 | mDescription = description; | ||
230 | updated(); | ||
231 | } | ||
232 | |||
233 | QString Incidence::description() const | ||
234 | { | ||
235 | return mDescription; | ||
236 | } | ||
237 | |||
238 | |||
239 | void Incidence::setSummary(const QString &summary) | ||
240 | { | ||
241 | if (mReadOnly) return; | ||
242 | mSummary = summary; | ||
243 | updated(); | ||
244 | } | ||
245 | |||
246 | QString Incidence::summary() const | ||
247 | { | ||
248 | return mSummary; | ||
249 | } | ||
250 | |||
251 | void Incidence::setCategories(const QStringList &categories) | ||
252 | { | ||
253 | if (mReadOnly) return; | ||
254 | mCategories = categories; | ||
255 | updated(); | ||
256 | } | ||
257 | |||
258 | // TODO: remove setCategories(QString) function | ||
259 | void Incidence::setCategories(const QString &catStr) | ||
260 | { | ||
261 | if (mReadOnly) return; | ||
262 | mCategories.clear(); | ||
263 | |||
264 | if (catStr.isEmpty()) return; | ||
265 | |||
266 | mCategories = QStringList::split(",",catStr); | ||
267 | |||
268 | QStringList::Iterator it; | ||
269 | for(it = mCategories.begin();it != mCategories.end(); ++it) { | ||
270 | *it = (*it).stripWhiteSpace(); | ||
271 | } | ||
272 | |||
273 | updated(); | ||
274 | } | ||
275 | |||
276 | QStringList Incidence::categories() const | ||
277 | { | ||
278 | return mCategories; | ||
279 | } | ||
280 | |||
281 | QString Incidence::categoriesStr() | ||
282 | { | ||
283 | return mCategories.join(","); | ||
284 | } | ||
285 | |||
286 | void Incidence::setRelatedToUid(const QString &relatedToUid) | ||
287 | { | ||
288 | if (mReadOnly) return; | ||
289 | mRelatedToUid = relatedToUid; | ||
290 | } | ||
291 | |||
292 | QString Incidence::relatedToUid() const | ||
293 | { | ||
294 | return mRelatedToUid; | ||
295 | } | ||
296 | |||
297 | void Incidence::setRelatedTo(Incidence *relatedTo) | ||
298 | { | ||
299 | //qDebug("Incidence::setRelatedTo %d ", relatedTo); | ||
300 | //qDebug("setRelatedTo(Incidence *relatedTo) %s %s", summary().latin1(), relatedTo->summary().latin1() ); | ||
301 | if (mReadOnly || mRelatedTo == relatedTo) return; | ||
302 | if(mRelatedTo) { | ||
303 | // updated(); | ||
304 | mRelatedTo->removeRelation(this); | ||
305 | } | ||
306 | mRelatedTo = relatedTo; | ||
307 | if (mRelatedTo) mRelatedTo->addRelation(this); | ||
308 | } | ||
309 | |||
310 | Incidence *Incidence::relatedTo() const | ||
311 | { | ||
312 | return mRelatedTo; | ||
313 | } | ||
314 | |||
315 | QPtrList<Incidence> Incidence::relations() const | ||
316 | { | ||
317 | return mRelations; | ||
318 | } | ||
319 | |||
320 | void Incidence::addRelation(Incidence *event) | ||
321 | { | ||
322 | if( mRelations.findRef( event ) == -1 ) { | ||
323 | mRelations.append(event); | ||
324 | //updated(); | ||
325 | } | ||
326 | } | ||
327 | |||
328 | void Incidence::removeRelation(Incidence *event) | ||
329 | { | ||
330 | |||
331 | mRelations.removeRef(event); | ||
332 | |||
333 | // if (event->getRelatedTo() == this) event->setRelatedTo(0); | ||
334 | } | ||
335 | |||
336 | bool Incidence::recursOn(const QDate &qd) const | ||
337 | { | ||
338 | if (recurrence()->recursOnPure(qd) && !isException(qd)) return true; | ||
339 | else return false; | ||
340 | } | ||
341 | |||
342 | void Incidence::setExDates(const DateList &exDates) | ||
343 | { | ||
344 | if (mReadOnly) return; | ||
345 | mExDates = exDates; | ||
346 | |||
347 | recurrence()->setRecurExDatesCount(mExDates.count()); | ||
348 | |||
349 | updated(); | ||
350 | } | ||
351 | |||
352 | void Incidence::addExDate(const QDate &date) | ||
353 | { | ||
354 | if (mReadOnly) return; | ||
355 | mExDates.append(date); | ||
356 | |||
357 | recurrence()->setRecurExDatesCount(mExDates.count()); | ||
358 | |||
359 | updated(); | ||
360 | } | ||
361 | |||
362 | DateList Incidence::exDates() const | ||
363 | { | ||
364 | return mExDates; | ||
365 | } | ||
366 | |||
367 | bool Incidence::isException(const QDate &date) const | ||
368 | { | ||
369 | DateList::ConstIterator it; | ||
370 | for( it = mExDates.begin(); it != mExDates.end(); ++it ) { | ||
371 | if ( (*it) == date ) { | ||
372 | return true; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | return false; | ||
377 | } | ||
378 | |||
379 | void Incidence::addAttachment(Attachment *attachment) | ||
380 | { | ||
381 | if (mReadOnly || !attachment) return; | ||
382 | mAttachments.append(attachment); | ||
383 | updated(); | ||
384 | } | ||
385 | |||
386 | void Incidence::deleteAttachment(Attachment *attachment) | ||
387 | { | ||
388 | mAttachments.removeRef(attachment); | ||
389 | } | ||
390 | |||
391 | void Incidence::deleteAttachments(const QString& mime) | ||
392 | { | ||
393 | Attachment *at = mAttachments.first(); | ||
394 | while (at) { | ||
395 | if (at->mimeType() == mime) | ||
396 | mAttachments.remove(); | ||
397 | else | ||
398 | at = mAttachments.next(); | ||
399 | } | ||
400 | } | ||
401 | |||
402 | QPtrList<Attachment> Incidence::attachments() const | ||
403 | { | ||
404 | return mAttachments; | ||
405 | } | ||
406 | |||
407 | QPtrList<Attachment> Incidence::attachments(const QString& mime) const | ||
408 | { | ||
409 | QPtrList<Attachment> attachments; | ||
410 | QPtrListIterator<Attachment> it( mAttachments ); | ||
411 | Attachment *at; | ||
412 | while ( (at = it.current()) ) { | ||
413 | if (at->mimeType() == mime) | ||
414 | attachments.append(at); | ||
415 | ++it; | ||
416 | } | ||
417 | |||
418 | return attachments; | ||
419 | } | ||
420 | |||
421 | void Incidence::setResources(const QStringList &resources) | ||
422 | { | ||
423 | if (mReadOnly) return; | ||
424 | mResources = resources; | ||
425 | updated(); | ||
426 | } | ||
427 | |||
428 | QStringList Incidence::resources() const | ||
429 | { | ||
430 | return mResources; | ||
431 | } | ||
432 | |||
433 | |||
434 | void Incidence::setPriority(int priority) | ||
435 | { | ||
436 | if (mReadOnly) return; | ||
437 | mPriority = priority; | ||
438 | updated(); | ||
439 | } | ||
440 | |||
441 | int Incidence::priority() const | ||
442 | { | ||
443 | return mPriority; | ||
444 | } | ||
445 | |||
446 | void Incidence::setSecrecy(int sec) | ||
447 | { | ||
448 | if (mReadOnly) return; | ||
449 | mSecrecy = sec; | ||
450 | updated(); | ||
451 | } | ||
452 | |||
453 | int Incidence::secrecy() const | ||
454 | { | ||
455 | return mSecrecy; | ||
456 | } | ||
457 | |||
458 | QString Incidence::secrecyStr() const | ||
459 | { | ||
460 | return secrecyName(mSecrecy); | ||
461 | } | ||
462 | |||
463 | QString Incidence::secrecyName(int secrecy) | ||
464 | { | ||
465 | switch (secrecy) { | ||
466 | case SecrecyPublic: | ||
467 | return i18n("Public"); | ||
468 | break; | ||
469 | case SecrecyPrivate: | ||
470 | return i18n("Private"); | ||
471 | break; | ||
472 | case SecrecyConfidential: | ||
473 | return i18n("Confidential"); | ||
474 | break; | ||
475 | default: | ||
476 | return i18n("Undefined"); | ||
477 | break; | ||
478 | } | ||
479 | } | ||
480 | |||
481 | QStringList Incidence::secrecyList() | ||
482 | { | ||
483 | QStringList list; | ||
484 | list << secrecyName(SecrecyPublic); | ||
485 | list << secrecyName(SecrecyPrivate); | ||
486 | list << secrecyName(SecrecyConfidential); | ||
487 | |||
488 | return list; | ||
489 | } | ||
490 | |||
491 | |||
492 | QPtrList<Alarm> Incidence::alarms() const | ||
493 | { | ||
494 | return mAlarms; | ||
495 | } | ||
496 | |||
497 | Alarm* Incidence::newAlarm() | ||
498 | { | ||
499 | Alarm* alarm = new Alarm(this); | ||
500 | mAlarms.append(alarm); | ||
501 | // updated(); | ||
502 | return alarm; | ||
503 | } | ||
504 | |||
505 | void Incidence::addAlarm(Alarm *alarm) | ||
506 | { | ||
507 | mAlarms.append(alarm); | ||
508 | updated(); | ||
509 | } | ||
510 | |||
511 | void Incidence::removeAlarm(Alarm *alarm) | ||
512 | { | ||
513 | mAlarms.removeRef(alarm); | ||
514 | updated(); | ||
515 | } | ||
516 | |||
517 | void Incidence::clearAlarms() | ||
518 | { | ||
519 | mAlarms.clear(); | ||
520 | updated(); | ||
521 | } | ||
522 | |||
523 | bool Incidence::isAlarmEnabled() const | ||
524 | { | ||
525 | Alarm* alarm; | ||
526 | for (QPtrListIterator<Alarm> it(mAlarms); (alarm = it.current()) != 0; ++it) { | ||
527 | if (alarm->enabled()) | ||
528 | return true; | ||
529 | } | ||
530 | return false; | ||
531 | } | ||
532 | |||
533 | Recurrence *Incidence::recurrence() const | ||
534 | { | ||
535 | return mRecurrence; | ||
536 | } | ||
537 | |||
538 | void Incidence::setLocation(const QString &location) | ||
539 | { | ||
540 | if (mReadOnly) return; | ||
541 | mLocation = location; | ||
542 | updated(); | ||
543 | } | ||
544 | |||
545 | QString Incidence::location() const | ||
546 | { | ||
547 | return mLocation; | ||
548 | } | ||
549 | |||
550 | ushort Incidence::doesRecur() const | ||
551 | { | ||
552 | if ( mRecurrence ) return mRecurrence->doesRecur(); | ||
553 | else return Recurrence::rNone; | ||
554 | } | ||
555 | |||
556 | QDateTime Incidence::getNextOccurence( const QDateTime& dt, bool* ok ) const | ||
557 | { | ||
558 | QDateTime incidenceStart = dt; | ||
559 | *ok = false; | ||
560 | if ( doesRecur() ) { | ||
561 | bool last; | ||
562 | recurrence()->getPreviousDateTime( incidenceStart , &last ); | ||
563 | int count = 0; | ||
564 | if ( !last ) { | ||
565 | while ( !last ) { | ||
566 | ++count; | ||
567 | incidenceStart = recurrence()->getNextDateTime( incidenceStart, &last ); | ||
568 | if ( recursOn( incidenceStart.date() ) ) { | ||
569 | last = true; // exit while llop | ||
570 | } else { | ||
571 | if ( last ) { // no alarm on last recurrence | ||
572 | return QDateTime (); | ||
573 | } | ||
574 | int year = incidenceStart.date().year(); | ||
575 | // workaround for bug in recurrence | ||
576 | if ( count == 100 || year < 1980 || year > 5000 ) { | ||
577 | return QDateTime (); | ||
578 | } | ||
579 | incidenceStart = incidenceStart.addSecs( 1 ); | ||
580 | } | ||
581 | } | ||
582 | } else { | ||
583 | return QDateTime (); | ||
584 | } | ||
585 | } else { | ||
586 | if ( hasStartDate () ) { | ||
587 | incidenceStart = dtStart(); | ||
588 | |||
589 | } | ||
590 | } | ||
591 | if ( incidenceStart > dt ) | ||
592 | *ok = true; | ||
593 | return incidenceStart; | ||
594 | } | ||