1 | /* |
2 | This file is part of the kcalcore library. |
3 | |
4 | Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org> |
5 | Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> |
6 | Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. |
7 | Contact: Alvaro Manera <alvaro.manera@nokia.com> |
8 | |
9 | This library is free software; you can redistribute it and/or |
10 | modify it under the terms of the GNU Library General Public |
11 | License as published by the Free Software Foundation; either |
12 | version 2 of the License, or (at your option) any later version. |
13 | |
14 | This library is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | Library General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Library General Public License |
20 | along with this library; see the file COPYING.LIB. If not, write to |
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
22 | Boston, MA 02110-1301, USA. |
23 | */ |
24 | /** |
25 | @file |
26 | This file is part of the API for handling calendar data and |
27 | defines the IncidenceBase class. |
28 | |
29 | @brief |
30 | An abstract base class that provides a common base for all calendar incidence |
31 | classes. |
32 | |
33 | @author Cornelius Schumacher \<schumacher@kde.org\> |
34 | @author Reinhold Kainhofer \<reinhold@kainhofer.com\> |
35 | */ |
36 | |
37 | #include "incidencebase.h" |
38 | #include "calformat.h" |
39 | #include "visitor.h" |
40 | |
41 | #include <QTime> |
42 | #include <KDebug> |
43 | #include <KUrl> |
44 | |
45 | #include <QtCore/QStringList> |
46 | |
47 | #define KCALCORE_MAGIC_NUMBER 0xCA1C012E |
48 | #define KCALCORE_SERIALIZATION_VERSION 1 |
49 | |
50 | using namespace KCalCore; |
51 | |
52 | /** |
53 | Private class that helps to provide binary compatibility between releases. |
54 | @internal |
55 | */ |
56 | //@cond PRIVATE |
57 | class KCalCore::IncidenceBase::Private |
58 | { |
59 | public: |
60 | Private() |
61 | : mOrganizer(0), |
62 | mUpdateGroupLevel(0), |
63 | mUpdatedPending(false), |
64 | mAllDay(true), |
65 | mHasDuration(false) |
66 | {} |
67 | |
68 | Private(const Private &other) |
69 | : mUpdateGroupLevel(0), |
70 | mUpdatedPending(false), |
71 | mAllDay(true), |
72 | mHasDuration(false) |
73 | { |
74 | init(other); |
75 | } |
76 | |
77 | ~Private() |
78 | { |
79 | } |
80 | |
81 | void init(const Private &other); |
82 | |
83 | KDateTime mLastModified; // incidence last modified date |
84 | KDateTime mDtStart; // incidence start time |
85 | Person::Ptr mOrganizer; // incidence person (owner) |
86 | QString mUid; // incidence unique id |
87 | Duration mDuration; // incidence duration |
88 | int mUpdateGroupLevel; // if non-zero, suppresses update() calls |
89 | bool mUpdatedPending; // true if an update has occurred since startUpdates() |
90 | bool mAllDay; // true if the incidence is all-day |
91 | bool mHasDuration; // true if the incidence has a duration |
92 | Attendee::List mAttendees; // list of incidence attendees |
93 | QStringList ; // list of incidence comments |
94 | QStringList mContacts; // list of incidence contacts |
95 | QList<IncidenceObserver*> mObservers; // list of incidence observers |
96 | QSet<Field> mDirtyFields; // Fields that changed since last time the incidence was created |
97 | // or since resetDirtyFlags() was called |
98 | QUrl mUrl; // incidence url property |
99 | }; |
100 | |
101 | void IncidenceBase::Private::init(const Private &other) |
102 | { |
103 | mLastModified = other.mLastModified; |
104 | mDtStart = other.mDtStart; |
105 | mOrganizer = other.mOrganizer; |
106 | mUid = other.mUid; |
107 | mDuration = other.mDuration; |
108 | mAllDay = other.mAllDay; |
109 | mHasDuration = other.mHasDuration; |
110 | |
111 | mComments = other.mComments; |
112 | mContacts = other.mContacts; |
113 | |
114 | mAttendees.clear(); |
115 | Attendee::List::ConstIterator it; |
116 | for (it = other.mAttendees.constBegin(); it != other.mAttendees.constEnd(); ++it) { |
117 | mAttendees.append(Attendee::Ptr(new Attendee(*(*it)))); |
118 | } |
119 | mUrl = other.mUrl; |
120 | } |
121 | //@endcond |
122 | |
123 | IncidenceBase::IncidenceBase() |
124 | : d(new KCalCore::IncidenceBase::Private) |
125 | { |
126 | mReadOnly = false; |
127 | setUid(CalFormat::createUniqueId()); |
128 | } |
129 | |
130 | IncidenceBase::IncidenceBase(const IncidenceBase &i) |
131 | : CustomProperties(i), |
132 | d(new KCalCore::IncidenceBase::Private(*i.d)) |
133 | { |
134 | mReadOnly = i.mReadOnly; |
135 | } |
136 | |
137 | IncidenceBase::~IncidenceBase() |
138 | { |
139 | delete d; |
140 | } |
141 | |
142 | IncidenceBase &IncidenceBase::operator=(const IncidenceBase &other) |
143 | { |
144 | Q_ASSERT(type() == other.type()); |
145 | |
146 | startUpdates(); |
147 | |
148 | // assign is virtual, will call the derived class's |
149 | IncidenceBase &ret = assign(other); |
150 | endUpdates(); |
151 | return ret; |
152 | } |
153 | |
154 | IncidenceBase &IncidenceBase::assign(const IncidenceBase &other) |
155 | { |
156 | CustomProperties::operator=(other); |
157 | d->init(*other.d); |
158 | mReadOnly = other.mReadOnly; |
159 | d->mDirtyFields.clear(); |
160 | d->mDirtyFields.insert(FieldUnknown); |
161 | return *this; |
162 | } |
163 | |
164 | bool IncidenceBase::operator==(const IncidenceBase &i2) const |
165 | { |
166 | if (i2.type() != type()) { |
167 | return false; |
168 | } else { |
169 | // equals is virtual, so here we're calling the derived class method |
170 | return equals(i2); |
171 | } |
172 | } |
173 | |
174 | bool IncidenceBase::operator!=(const IncidenceBase &i2) const |
175 | { |
176 | return !operator==(i2); |
177 | } |
178 | |
179 | bool IncidenceBase::equals(const IncidenceBase &i2) const |
180 | { |
181 | if (attendees().count() != i2.attendees().count()) { |
182 | // kDebug() << "Attendee count is different"; |
183 | return false; |
184 | } |
185 | |
186 | Attendee::List al1 = attendees(); |
187 | Attendee::List al2 = i2.attendees(); |
188 | Attendee::List::ConstIterator a1 = al1.constBegin(); |
189 | Attendee::List::ConstIterator a2 = al2.constBegin(); |
190 | //TODO Does the order of attendees in the list really matter? |
191 | //Please delete this comment if you know it's ok, kthx |
192 | for (; a1 != al1.constEnd() && a2 != al2.constEnd(); ++a1, ++a2) { |
193 | if (!(**a1 == **a2)) { |
194 | // kDebug() << "Attendees are different"; |
195 | return false; |
196 | } |
197 | } |
198 | |
199 | if (!CustomProperties::operator==(i2)) { |
200 | // kDebug() << "Properties are different"; |
201 | return false; |
202 | } |
203 | |
204 | // Don't compare lastModified, otherwise the operator is not |
205 | // of much use. We are not comparing for identity, after all. |
206 | // no need to compare mObserver |
207 | |
208 | bool a = ((dtStart() == i2.dtStart()) || (!dtStart().isValid() && !i2.dtStart().isValid())); |
209 | bool b = *(organizer().data()) == *(i2.organizer().data()); |
210 | bool c = uid() == i2.uid(); |
211 | bool d = allDay() == i2.allDay(); |
212 | bool e = duration() == i2.duration(); |
213 | bool f = hasDuration() == i2.hasDuration(); |
214 | bool g = url() == i2.url(); |
215 | |
216 | //kDebug() << a << b << c << d << e << f << g; |
217 | return a && b && c && d && e && f && g; |
218 | } |
219 | |
220 | bool IncidenceBase::accept(Visitor &v, IncidenceBase::Ptr incidence) |
221 | { |
222 | Q_UNUSED(v); |
223 | Q_UNUSED(incidence); |
224 | return false; |
225 | } |
226 | |
227 | void IncidenceBase::setUid(const QString &uid) |
228 | { |
229 | update(); |
230 | d->mUid = uid; |
231 | d->mDirtyFields.insert(FieldUid); |
232 | updated(); |
233 | } |
234 | |
235 | QString IncidenceBase::uid() const |
236 | { |
237 | return d->mUid; |
238 | } |
239 | |
240 | void IncidenceBase::setLastModified(const KDateTime &lm) |
241 | { |
242 | // DON'T! updated() because we call this from |
243 | // Calendar::updateEvent(). |
244 | |
245 | d->mDirtyFields.insert(FieldLastModified); |
246 | |
247 | // Convert to UTC and remove milliseconds part. |
248 | KDateTime current = lm.toUtc(); |
249 | QTime t = current.time(); |
250 | t.setHMS(t.hour(), t.minute(), t.second(), 0); |
251 | current.setTime(t); |
252 | |
253 | d->mLastModified = current; |
254 | } |
255 | |
256 | KDateTime IncidenceBase::lastModified() const |
257 | { |
258 | return d->mLastModified; |
259 | } |
260 | |
261 | void IncidenceBase::setOrganizer(const Person::Ptr &organizer) |
262 | { |
263 | if (organizer) { |
264 | update(); |
265 | // we don't check for readonly here, because it is |
266 | // possible that by setting the organizer we are changing |
267 | // the event's readonly status... |
268 | d->mOrganizer = organizer; |
269 | |
270 | d->mDirtyFields.insert(FieldOrganizer); |
271 | |
272 | updated(); |
273 | } |
274 | } |
275 | |
276 | void IncidenceBase::setOrganizer(const QString &o) |
277 | { |
278 | QString mail(o); |
279 | if (mail.startsWith(QLatin1String("MAILTO:" ), Qt::CaseInsensitive)) { |
280 | mail = mail.remove(0, 7); |
281 | } |
282 | |
283 | // split the string into full name plus email. |
284 | const Person::Ptr organizer = Person::fromFullName(mail); |
285 | setOrganizer(organizer); |
286 | } |
287 | |
288 | Person::Ptr IncidenceBase::organizer() const |
289 | { |
290 | if (!d->mOrganizer) |
291 | d->mOrganizer = Person::Ptr(new Person()); // init at first use only to save memory |
292 | |
293 | return d->mOrganizer; |
294 | } |
295 | |
296 | void IncidenceBase::setReadOnly(bool readOnly) |
297 | { |
298 | mReadOnly = readOnly; |
299 | } |
300 | |
301 | bool IncidenceBase::isReadOnly() const |
302 | { |
303 | return mReadOnly; |
304 | } |
305 | |
306 | void IncidenceBase::setDtStart(const KDateTime &dtStart) |
307 | { |
308 | // if ( mReadOnly ) return; |
309 | |
310 | if (!dtStart.isValid() && type() != IncidenceBase::TypeTodo) { |
311 | kWarning() << "Invalid dtStart" ; |
312 | } |
313 | |
314 | update(); |
315 | d->mDtStart = dtStart; |
316 | d->mAllDay = dtStart.isDateOnly(); |
317 | d->mDirtyFields.insert(FieldDtStart); |
318 | updated(); |
319 | } |
320 | |
321 | KDateTime IncidenceBase::dtStart() const |
322 | { |
323 | return d->mDtStart; |
324 | } |
325 | |
326 | bool IncidenceBase::allDay() const |
327 | { |
328 | return d->mAllDay; |
329 | } |
330 | |
331 | void IncidenceBase::setAllDay(bool f) |
332 | { |
333 | if (mReadOnly || f == d->mAllDay) { |
334 | return; |
335 | } |
336 | update(); |
337 | d->mAllDay = f; |
338 | if (d->mDtStart.isValid()) { |
339 | d->mDirtyFields.insert(FieldDtStart); |
340 | } |
341 | updated(); |
342 | } |
343 | |
344 | void IncidenceBase::shiftTimes(const KDateTime::Spec &oldSpec, |
345 | const KDateTime::Spec &newSpec) |
346 | { |
347 | update(); |
348 | d->mDtStart = d->mDtStart.toTimeSpec(oldSpec); |
349 | d->mDtStart.setTimeSpec(newSpec); |
350 | d->mDirtyFields.insert(FieldDtStart); |
351 | d->mDirtyFields.insert(FieldDtEnd); |
352 | updated(); |
353 | } |
354 | |
355 | void IncidenceBase::(const QString &) |
356 | { |
357 | d->mComments += comment; |
358 | } |
359 | |
360 | bool IncidenceBase::(const QString &) |
361 | { |
362 | bool found = false; |
363 | QStringList::Iterator i; |
364 | |
365 | for (i = d->mComments.begin(); !found && i != d->mComments.end(); ++i) { |
366 | if ((*i) == comment) { |
367 | found = true; |
368 | d->mComments.erase(i); |
369 | } |
370 | } |
371 | |
372 | if (found) { |
373 | d->mDirtyFields.insert(FieldComment); |
374 | } |
375 | |
376 | return found; |
377 | } |
378 | |
379 | void IncidenceBase::() |
380 | { |
381 | d->mDirtyFields.insert(FieldComment); |
382 | d->mComments.clear(); |
383 | } |
384 | |
385 | QStringList IncidenceBase::() const |
386 | { |
387 | return d->mComments; |
388 | } |
389 | |
390 | void IncidenceBase::addContact(const QString &contact) |
391 | { |
392 | if (!contact.isEmpty()) { |
393 | d->mContacts += contact; |
394 | d->mDirtyFields.insert(FieldContact); |
395 | } |
396 | } |
397 | |
398 | bool IncidenceBase::removeContact(const QString &contact) |
399 | { |
400 | bool found = false; |
401 | QStringList::Iterator i; |
402 | |
403 | for (i = d->mContacts.begin(); !found && i != d->mContacts.end(); ++i) { |
404 | if ((*i) == contact) { |
405 | found = true; |
406 | d->mContacts.erase(i); |
407 | } |
408 | } |
409 | |
410 | if (found) { |
411 | d->mDirtyFields.insert(FieldContact); |
412 | } |
413 | |
414 | return found; |
415 | } |
416 | |
417 | void IncidenceBase::clearContacts() |
418 | { |
419 | d->mDirtyFields.insert(FieldContact); |
420 | d->mContacts.clear(); |
421 | } |
422 | |
423 | QStringList IncidenceBase::contacts() const |
424 | { |
425 | return d->mContacts; |
426 | } |
427 | |
428 | void IncidenceBase::addAttendee(const Attendee::Ptr &a, bool doupdate) |
429 | { |
430 | if (!a || mReadOnly) { |
431 | return; |
432 | } |
433 | |
434 | Q_ASSERT(!d->mAttendees.contains(a)); |
435 | |
436 | if (doupdate) { |
437 | update(); |
438 | } |
439 | if (a->name().left(7).toUpper() == QLatin1String("MAILTO:" )) { |
440 | a->setName(a->name().remove(0, 7)); |
441 | } |
442 | |
443 | /* If Uid is empty, just use the pointer to Attendee (encoded to |
444 | * string) as Uid. Only thing that matters is that the Uid is unique |
445 | * insofar IncidenceBase is concerned, and this does that (albeit |
446 | * not very nicely). If these are ever saved to disk, should use |
447 | * (considerably more expensive) CalFormat::createUniqueId(). As Uid |
448 | * is not part of Attendee in iCal std, it's fairly safe bet that |
449 | * these will never hit disc though so faster generation speed is |
450 | * more important than actually being forever unique.*/ |
451 | if (a->uid().isEmpty()) { |
452 | a->setUid(QString::number((qlonglong)a.data())); |
453 | } |
454 | |
455 | d->mAttendees.append(a); |
456 | if (doupdate) { |
457 | d->mDirtyFields.insert(FieldAttendees); |
458 | updated(); |
459 | } |
460 | } |
461 | |
462 | void IncidenceBase::deleteAttendee(const Attendee::Ptr &a, bool doupdate) |
463 | { |
464 | if (!a || mReadOnly) { |
465 | return; |
466 | } |
467 | |
468 | int index = d->mAttendees.indexOf(a); |
469 | if (index >= 0) { |
470 | if (doupdate) { |
471 | update(); |
472 | } |
473 | |
474 | d->mAttendees.remove(index); |
475 | |
476 | if (doupdate) { |
477 | d->mDirtyFields.insert(FieldAttendees); |
478 | updated(); |
479 | } |
480 | } |
481 | } |
482 | |
483 | Attendee::List IncidenceBase::attendees() const |
484 | { |
485 | return d->mAttendees; |
486 | } |
487 | |
488 | int IncidenceBase::attendeeCount() const |
489 | { |
490 | return d->mAttendees.count(); |
491 | } |
492 | |
493 | void IncidenceBase::clearAttendees() |
494 | { |
495 | if (mReadOnly) { |
496 | return; |
497 | } |
498 | d->mDirtyFields.insert(FieldAttendees); |
499 | d->mAttendees.clear(); |
500 | } |
501 | |
502 | Attendee::Ptr IncidenceBase::attendeeByMail(const QString &email) const |
503 | { |
504 | Attendee::List::ConstIterator it; |
505 | for (it = d->mAttendees.constBegin(); it != d->mAttendees.constEnd(); ++it) { |
506 | if ((*it)->email() == email) { |
507 | return *it; |
508 | } |
509 | } |
510 | |
511 | return Attendee::Ptr(); |
512 | } |
513 | |
514 | Attendee::Ptr IncidenceBase::attendeeByMails(const QStringList &emails, |
515 | const QString &email) const |
516 | { |
517 | QStringList mails = emails; |
518 | if (!email.isEmpty()) { |
519 | mails.append(email); |
520 | } |
521 | |
522 | Attendee::List::ConstIterator itA; |
523 | for (itA = d->mAttendees.constBegin(); itA != d->mAttendees.constEnd(); ++itA) { |
524 | for (QStringList::const_iterator it = mails.constBegin(); it != mails.constEnd(); ++it) { |
525 | if ((*itA)->email() == (*it)) { |
526 | return *itA; |
527 | } |
528 | } |
529 | } |
530 | |
531 | return Attendee::Ptr(); |
532 | } |
533 | |
534 | Attendee::Ptr IncidenceBase::attendeeByUid(const QString &uid) const |
535 | { |
536 | Attendee::List::ConstIterator it; |
537 | for (it = d->mAttendees.constBegin(); it != d->mAttendees.constEnd(); ++it) { |
538 | if ((*it)->uid() == uid) { |
539 | return *it; |
540 | } |
541 | } |
542 | |
543 | return Attendee::Ptr(); |
544 | } |
545 | |
546 | void IncidenceBase::setDuration(const Duration &duration) |
547 | { |
548 | update(); |
549 | d->mDuration = duration; |
550 | setHasDuration(true); |
551 | d->mDirtyFields.insert(FieldDuration); |
552 | updated(); |
553 | } |
554 | |
555 | Duration IncidenceBase::duration() const |
556 | { |
557 | return d->mDuration; |
558 | } |
559 | |
560 | void IncidenceBase::setHasDuration(bool hasDuration) |
561 | { |
562 | d->mHasDuration = hasDuration; |
563 | } |
564 | |
565 | bool IncidenceBase::hasDuration() const |
566 | { |
567 | return d->mHasDuration; |
568 | } |
569 | |
570 | void IncidenceBase::setUrl(const QUrl& url) |
571 | { |
572 | d->mDirtyFields.insert(FieldUrl); |
573 | d->mUrl = url; |
574 | } |
575 | |
576 | QUrl IncidenceBase::url() const |
577 | { |
578 | return d->mUrl; |
579 | } |
580 | |
581 | void IncidenceBase::registerObserver(IncidenceBase::IncidenceObserver *observer) |
582 | { |
583 | if (observer && !d->mObservers.contains(observer)) { |
584 | d->mObservers.append(observer); |
585 | } |
586 | } |
587 | |
588 | void IncidenceBase::unRegisterObserver(IncidenceBase::IncidenceObserver *observer) |
589 | { |
590 | d->mObservers.removeAll(observer); |
591 | } |
592 | |
593 | void IncidenceBase::update() |
594 | { |
595 | if (!d->mUpdateGroupLevel) { |
596 | d->mUpdatedPending = true; |
597 | KDateTime rid = recurrenceId(); |
598 | foreach(IncidenceObserver *o, d->mObservers) { |
599 | o->incidenceUpdate(uid(), rid); |
600 | } |
601 | } |
602 | } |
603 | |
604 | void IncidenceBase::updated() |
605 | { |
606 | if (d->mUpdateGroupLevel) { |
607 | d->mUpdatedPending = true; |
608 | } else { |
609 | const KDateTime rid = recurrenceId(); |
610 | foreach(IncidenceObserver *o, d->mObservers) { |
611 | o->incidenceUpdated(uid(), rid); |
612 | } |
613 | } |
614 | } |
615 | |
616 | void IncidenceBase::startUpdates() |
617 | { |
618 | update(); |
619 | ++d->mUpdateGroupLevel; |
620 | } |
621 | |
622 | void IncidenceBase::endUpdates() |
623 | { |
624 | if (d->mUpdateGroupLevel > 0) { |
625 | if (--d->mUpdateGroupLevel == 0 && d->mUpdatedPending) { |
626 | d->mUpdatedPending = false; |
627 | updated(); |
628 | } |
629 | } |
630 | } |
631 | |
632 | void IncidenceBase::customPropertyUpdate() |
633 | { |
634 | update(); |
635 | } |
636 | |
637 | void IncidenceBase::customPropertyUpdated() |
638 | { |
639 | updated(); |
640 | } |
641 | |
642 | KDateTime IncidenceBase::recurrenceId() const |
643 | { |
644 | return KDateTime(); |
645 | } |
646 | |
647 | void IncidenceBase::resetDirtyFields() |
648 | { |
649 | d->mDirtyFields.clear(); |
650 | } |
651 | |
652 | QSet<IncidenceBase::Field> IncidenceBase::dirtyFields() const |
653 | { |
654 | return d->mDirtyFields; |
655 | } |
656 | |
657 | void IncidenceBase::setFieldDirty(IncidenceBase::Field field) |
658 | { |
659 | d->mDirtyFields.insert(field); |
660 | } |
661 | |
662 | KUrl IncidenceBase::uri() const |
663 | { |
664 | return KUrl(QLatin1String("urn:x-ical:" ) + uid()); |
665 | } |
666 | |
667 | void IncidenceBase::setDirtyFields(const QSet<IncidenceBase::Field> &dirtyFields) |
668 | { |
669 | d->mDirtyFields = dirtyFields; |
670 | } |
671 | |
672 | /** static */ |
673 | quint32 IncidenceBase::magicSerializationIdentifier() |
674 | { |
675 | return KCALCORE_MAGIC_NUMBER; |
676 | } |
677 | |
678 | QDataStream& KCalCore::operator<<(QDataStream &out, const KCalCore::IncidenceBase::Ptr &i) |
679 | { |
680 | if (!i) |
681 | return out; |
682 | |
683 | out << static_cast<quint32>(KCALCORE_MAGIC_NUMBER); // Magic number to identify KCalCore data |
684 | out << static_cast<quint32>(KCALCORE_SERIALIZATION_VERSION); |
685 | out << static_cast<qint32>(i->type()); |
686 | |
687 | out << *(static_cast<CustomProperties*>(i.data())); |
688 | out << i->d->mLastModified << i->d->mDtStart << i->organizer() << i->d->mUid << i->d->mDuration |
689 | << i->d->mAllDay << i->d->mHasDuration << i->d->mComments << i->d->mContacts |
690 | << i->d->mAttendees.count() << i->d->mUrl; |
691 | |
692 | foreach(const Attendee::Ptr &attendee, i->d->mAttendees) { |
693 | out << attendee; |
694 | } |
695 | |
696 | // Serialize the sub-class data. In KDE5 we can add new virtuals. |
697 | i->virtual_hook(KCalCore::IncidenceBase::SerializerHook, &out); |
698 | |
699 | return out; |
700 | } |
701 | |
702 | QDataStream& KCalCore::operator>>(QDataStream &in, const KCalCore::IncidenceBase::Ptr &i) |
703 | { |
704 | if (!i) |
705 | return in; |
706 | |
707 | qint32 attendeeCount, type; |
708 | quint32 magic, version; |
709 | |
710 | in >> magic; |
711 | |
712 | if (magic != KCALCORE_MAGIC_NUMBER) { |
713 | kWarning() << "Invalid magic on serialized data" ; |
714 | return in; |
715 | } |
716 | |
717 | in >> version; |
718 | |
719 | if (version > KCALCORE_MAGIC_NUMBER) { |
720 | kWarning() << "Invalid version on serialized data" ; |
721 | return in; |
722 | } |
723 | |
724 | in >> type; |
725 | |
726 | in >> *(static_cast<CustomProperties*>(i.data())); |
727 | in >> i->d->mLastModified >> i->d->mDtStart >> i->d->mOrganizer >> i->d->mUid >> i->d->mDuration |
728 | >> i->d->mAllDay >> i->d->mHasDuration >> i->d->mComments >> i->d->mContacts >> attendeeCount |
729 | >> i->d->mUrl; |
730 | |
731 | i->d->mAttendees.clear(); |
732 | for (int it=0; it<attendeeCount; it++) { |
733 | Attendee::Ptr attendee = Attendee::Ptr(new Attendee(QString(), QString())); |
734 | in >> attendee; |
735 | i->d->mAttendees.append(attendee); |
736 | } |
737 | |
738 | // Deserialize the sub-class data. In KDE5 we can add new virtuals. |
739 | i->virtual_hook(KCalCore::IncidenceBase::DeserializerHook, &in); |
740 | |
741 | return in; |
742 | } |
743 | |
744 | IncidenceBase::IncidenceObserver::~IncidenceObserver() |
745 | { |
746 | } |
747 | |