diff --git a/kcalcore/event.cpp b/kcalcore/event.cpp index 8f8b81a9a..72c43d95c 100644 --- a/kcalcore/event.cpp +++ b/kcalcore/event.cpp @@ -1,378 +1,380 @@ /* This file is part of the kcalcore library. Copyright (c) 2001 Cornelius Schumacher This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** @file This file is part of the API for handling calendar data and defines the Event class. @brief This class provides an Event in the sense of RFC2445. @author Cornelius Schumacher \ */ #include "event.h" #include "visitor.h" #include #include using namespace KCalCore; /** Private class that helps to provide binary compatibility between releases. @internal */ //@cond PRIVATE class KCalCore::Event::Private { public: Private() : mHasEndDate(false), mTransparency(Opaque), mMultiDayValid(false), mMultiDay(false) {} Private(const KCalCore::Event::Private &other) : mDtEnd(other.mDtEnd), mHasEndDate(other.mHasEndDate), mTransparency(other.mTransparency), mMultiDayValid(false), mMultiDay(false) {} KDateTime mDtEnd; bool mHasEndDate; Transparency mTransparency; bool mMultiDayValid; bool mMultiDay; }; //@endcond Event::Event() : d(new KCalCore::Event::Private) { } Event::Event(const Event &other) : Incidence(other), d(new KCalCore::Event::Private(*other.d)) { } Event::Event(const Incidence &other) : Incidence(other) , d(new KCalCore::Event::Private) { } Event::~Event() { delete d; } Event *Event::clone() const { return new Event(*this); } IncidenceBase &Event::assign(const IncidenceBase &other) { if (&other != this) { Incidence::assign(other); const Event *e = static_cast(&other); *d = *(e->d); } return *this; } bool Event::equals(const IncidenceBase &event) const { if (!Incidence::equals(event)) { return false; } else { // If they weren't the same type IncidenceBase::equals would had returned false already const Event *e = static_cast(&event); return ((dtEnd() == e->dtEnd()) || (!dtEnd().isValid() && !e->dtEnd().isValid())) && hasEndDate() == e->hasEndDate() && transparency() == e->transparency(); } } Incidence::IncidenceType Event::type() const { return TypeEvent; } QByteArray Event::typeStr() const { return "Event"; } void Event::setDtStart(const KDateTime &dt) { d->mMultiDayValid = false; Incidence::setDtStart(dt); } void Event::setDtEnd(const KDateTime &dtEnd) { if (mReadOnly) { return; } - if (d->mDtEnd != dtEnd || d->mHasEndDate != dtEnd.isValid()) { + if (d->mDtEnd != dtEnd || + d->mDtEnd.timeSpec() != dtEnd.timeSpec() || + d->mHasEndDate != dtEnd.isValid()) { update(); d->mDtEnd = dtEnd; d->mMultiDayValid = false; d->mHasEndDate = dtEnd.isValid(); if (d->mHasEndDate) { setHasDuration(false); } setFieldDirty(FieldDtEnd); updated(); } } KDateTime Event::dtEnd() const { if (hasEndDate()) { return d->mDtEnd; } if (hasDuration()) { if (allDay()) { // For all day events, dtEnd is always inclusive KDateTime end = duration().end(dtStart()).addDays(-1); return end >= dtStart() ? end : dtStart(); } else { return duration().end(dtStart()); } } // It is valid for a VEVENT to be without a DTEND. See RFC2445, Sect4.6.1. // Be careful to use Event::dateEnd() as appropriate due to this possibility. return dtStart(); } QDate Event::dateEnd() const { KDateTime end = dtEnd().toTimeSpec(dtStart()); if (allDay()) { return end.date(); } else { return end.addSecs(-1).date(); } } void Event::setHasEndDate(bool b) { d->mHasEndDate = b; setFieldDirty(FieldDtEnd); } bool Event::hasEndDate() const { return d->mHasEndDate; } bool Event::isMultiDay(const KDateTime::Spec &spec) const { // First off, if spec's not valid, we can check for cache if (!spec.isValid() && d->mMultiDayValid) { return d->mMultiDay; } // Not in cache -> do it the hard way KDateTime start, end; if (!spec.isValid()) { start = dtStart(); end = dtEnd(); } else { start = dtStart().toTimeSpec(spec); end = dtEnd().toTimeSpec(spec); } bool multi = (start < end && start.date() != end.date()); // End date is non inclusive // If we have an incidence that duration is one day and ends with a start of a new day // than it is not a multiday event if (multi && end.time() != QTime(0,0,0)) { multi = start.daysTo(end) > 1; } // Update the cache // Also update Cache if spec is invalid /*if (spec.isValid()) { d->mMultiDayValid = true; d->mMultiDay = multi; } */ d->mMultiDayValid = true; d->mMultiDay = multi; return multi; } void Event::shiftTimes(const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec) { Incidence::shiftTimes(oldSpec, newSpec); if (hasEndDate()) { d->mDtEnd = d->mDtEnd.toTimeSpec(oldSpec); d->mDtEnd.setTimeSpec(newSpec); } } void Event::setTransparency(Event::Transparency transparency) { if (mReadOnly) { return; } update(); d->mTransparency = transparency; setFieldDirty(FieldTransparency); updated(); } Event::Transparency Event::transparency() const { return d->mTransparency; } void Event::setDuration(const Duration &duration) { setDtEnd(KDateTime()); Incidence::setDuration(duration); } void Event::setAllDay(bool allday) { if (allday != allDay() && !mReadOnly) { setFieldDirty(FieldDtEnd); Incidence::setAllDay(allday); } } bool Event::accept(Visitor &v, IncidenceBase::Ptr incidence) { return v.visit(incidence.staticCast()); } KDateTime Event::dateTime(DateTimeRole role) const { switch (role) { case RoleRecurrenceStart: case RoleAlarmStartOffset: case RoleStartTimeZone: case RoleSort: return dtStart(); case RoleCalendarHashing: return !recurs() && !isMultiDay() ? dtStart() : KDateTime(); case RoleAlarmEndOffset: case RoleEndTimeZone: case RoleEndRecurrenceBase: case RoleEnd: case RoleDisplayEnd: return dtEnd(); case RoleDisplayStart: return dtStart(); case RoleAlarm: if (alarms().isEmpty()) { return KDateTime(); } else { Alarm::Ptr alarm = alarms().first(); return alarm->hasStartOffset() ? dtStart() : dtEnd(); } break; default: return KDateTime(); } } void Event::setDateTime(const KDateTime &dateTime, DateTimeRole role) { switch (role) { case RoleDnD: { const int duration = dtStart().secsTo(dtEnd()); setDtStart(dateTime); setDtEnd(dateTime.addSecs(duration <= 0 ? 3600 : duration)); break; } case RoleEnd: setDtEnd(dateTime); break; default: kDebug() << "Unhandled role" << role; } } void Event::virtual_hook(int id, void *data) { switch (static_cast(id)) { case IncidenceBase::SerializerHook: serialize(*reinterpret_cast(data)); break; case IncidenceBase::DeserializerHook: deserialize(*reinterpret_cast(data)); break; default: Q_ASSERT(false); } } QLatin1String KCalCore::Event::mimeType() const { return Event::eventMimeType(); } QLatin1String Event::eventMimeType() { return QLatin1String("application/x-vnd.akonadi.calendar.event"); } QLatin1String Event::iconName(const KDateTime &) const { return QLatin1String("view-calendar-day"); } void Event::serialize(QDataStream &out) { Incidence::serialize(out); out << d->mDtEnd << d->mHasEndDate << static_cast(d->mTransparency) << d->mMultiDayValid << d->mMultiDay; } void Event::deserialize(QDataStream &in) { Incidence::deserialize(in); in >> d->mDtEnd >> d->mHasEndDate; quint32 transp; in >> transp; d->mTransparency = static_cast(transp); in >> d->mMultiDayValid >> d->mMultiDay; } diff --git a/kcalcore/incidencebase.cpp b/kcalcore/incidencebase.cpp index 975944483..e32a1525a 100644 --- a/kcalcore/incidencebase.cpp +++ b/kcalcore/incidencebase.cpp @@ -1,748 +1,750 @@ /* This file is part of the kcalcore library. Copyright (c) 2001,2004 Cornelius Schumacher Copyright (C) 2003-2004 Reinhold Kainhofer Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. Contact: Alvaro Manera This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** @file This file is part of the API for handling calendar data and defines the IncidenceBase class. @brief An abstract base class that provides a common base for all calendar incidence classes. @author Cornelius Schumacher \ @author Reinhold Kainhofer \ */ #include "incidencebase.h" #include "calformat.h" #include "visitor.h" #include #include #include #include #define KCALCORE_MAGIC_NUMBER 0xCA1C012E #define KCALCORE_SERIALIZATION_VERSION 1 using namespace KCalCore; /** Private class that helps to provide binary compatibility between releases. @internal */ //@cond PRIVATE class KCalCore::IncidenceBase::Private { public: Private() : mOrganizer(0), mUpdateGroupLevel(0), mUpdatedPending(false), mAllDay(true), mHasDuration(false) {} Private(const Private &other) : mUpdateGroupLevel(0), mUpdatedPending(false), mAllDay(true), mHasDuration(false) { init(other); } ~Private() { } void init(const Private &other); KDateTime mLastModified; // incidence last modified date KDateTime mDtStart; // incidence start time Person::Ptr mOrganizer; // incidence person (owner) QString mUid; // incidence unique id Duration mDuration; // incidence duration int mUpdateGroupLevel; // if non-zero, suppresses update() calls bool mUpdatedPending; // true if an update has occurred since startUpdates() bool mAllDay; // true if the incidence is all-day bool mHasDuration; // true if the incidence has a duration Attendee::List mAttendees; // list of incidence attendees QStringList mComments; // list of incidence comments QStringList mContacts; // list of incidence contacts QList mObservers; // list of incidence observers QSet mDirtyFields; // Fields that changed since last time the incidence was created // or since resetDirtyFlags() was called QUrl mUrl; // incidence url property }; void IncidenceBase::Private::init(const Private &other) { mLastModified = other.mLastModified; mDtStart = other.mDtStart; mOrganizer = other.mOrganizer; mUid = other.mUid; mDuration = other.mDuration; mAllDay = other.mAllDay; mHasDuration = other.mHasDuration; mComments = other.mComments; mContacts = other.mContacts; mAttendees.clear(); Attendee::List::ConstIterator it; for (it = other.mAttendees.constBegin(); it != other.mAttendees.constEnd(); ++it) { mAttendees.append(Attendee::Ptr(new Attendee(*(*it)))); } mUrl = other.mUrl; } //@endcond IncidenceBase::IncidenceBase() : d(new KCalCore::IncidenceBase::Private) { mReadOnly = false; setUid(CalFormat::createUniqueId()); } IncidenceBase::IncidenceBase(const IncidenceBase &i) : CustomProperties(i), d(new KCalCore::IncidenceBase::Private(*i.d)) { mReadOnly = i.mReadOnly; } IncidenceBase::~IncidenceBase() { delete d; } IncidenceBase &IncidenceBase::operator=(const IncidenceBase &other) { Q_ASSERT(type() == other.type()); startUpdates(); // assign is virtual, will call the derived class's IncidenceBase &ret = assign(other); endUpdates(); return ret; } IncidenceBase &IncidenceBase::assign(const IncidenceBase &other) { CustomProperties::operator=(other); d->init(*other.d); mReadOnly = other.mReadOnly; d->mDirtyFields.clear(); d->mDirtyFields.insert(FieldUnknown); return *this; } bool IncidenceBase::operator==(const IncidenceBase &i2) const { if (i2.type() != type()) { return false; } else { // equals is virtual, so here we're calling the derived class method return equals(i2); } } bool IncidenceBase::operator!=(const IncidenceBase &i2) const { return !operator==(i2); } bool IncidenceBase::equals(const IncidenceBase &i2) const { if (attendees().count() != i2.attendees().count()) { // kDebug() << "Attendee count is different"; return false; } Attendee::List al1 = attendees(); Attendee::List al2 = i2.attendees(); Attendee::List::ConstIterator a1 = al1.constBegin(); Attendee::List::ConstIterator a2 = al2.constBegin(); //TODO Does the order of attendees in the list really matter? //Please delete this comment if you know it's ok, kthx for (; a1 != al1.constEnd() && a2 != al2.constEnd(); ++a1, ++a2) { if (!(**a1 == **a2)) { // kDebug() << "Attendees are different"; return false; } } if (!CustomProperties::operator==(i2)) { // kDebug() << "Properties are different"; return false; } // Don't compare lastModified, otherwise the operator is not // of much use. We are not comparing for identity, after all. // no need to compare mObserver bool a = ((dtStart() == i2.dtStart()) || (!dtStart().isValid() && !i2.dtStart().isValid())); bool b = *(organizer().data()) == *(i2.organizer().data()); bool c = uid() == i2.uid(); bool d = allDay() == i2.allDay(); bool e = duration() == i2.duration(); bool f = hasDuration() == i2.hasDuration(); bool g = url() == i2.url(); //kDebug() << a << b << c << d << e << f << g; return a && b && c && d && e && f && g; } bool IncidenceBase::accept(Visitor &v, IncidenceBase::Ptr incidence) { Q_UNUSED(v); Q_UNUSED(incidence); return false; } void IncidenceBase::setUid(const QString &uid) { if (d->mUid != uid) { update(); d->mUid = uid; d->mDirtyFields.insert(FieldUid); updated(); } } QString IncidenceBase::uid() const { return d->mUid; } void IncidenceBase::setLastModified(const KDateTime &lm) { // DON'T! updated() because we call this from // Calendar::updateEvent(). d->mDirtyFields.insert(FieldLastModified); // Convert to UTC and remove milliseconds part. KDateTime current = lm.toUtc(); QTime t = current.time(); t.setHMS(t.hour(), t.minute(), t.second(), 0); current.setTime(t); d->mLastModified = current; } KDateTime IncidenceBase::lastModified() const { return d->mLastModified; } void IncidenceBase::setOrganizer(const Person::Ptr &organizer) { if (organizer) { update(); // we don't check for readonly here, because it is // possible that by setting the organizer we are changing // the event's readonly status... d->mOrganizer = organizer; d->mDirtyFields.insert(FieldOrganizer); updated(); } } void IncidenceBase::setOrganizer(const QString &o) { QString mail(o); if (mail.startsWith(QLatin1String("MAILTO:"), Qt::CaseInsensitive)) { mail = mail.remove(0, 7); } // split the string into full name plus email. const Person::Ptr organizer = Person::fromFullName(mail); setOrganizer(organizer); } Person::Ptr IncidenceBase::organizer() const { if (!d->mOrganizer) d->mOrganizer = Person::Ptr(new Person()); // init at first use only to save memory return d->mOrganizer; } void IncidenceBase::setReadOnly(bool readOnly) { mReadOnly = readOnly; } bool IncidenceBase::isReadOnly() const { return mReadOnly; } void IncidenceBase::setDtStart(const KDateTime &dtStart) { // if ( mReadOnly ) return; if (!dtStart.isValid() && type() != IncidenceBase::TypeTodo) { kWarning() << "Invalid dtStart"; } - if (d->mDtStart != dtStart || d->mAllDay != dtStart.isDateOnly()) { + if (d->mDtStart != dtStart || + d->mDtStart.timeSpec() != dtStart.timeSpec() || + d->mAllDay != dtStart.isDateOnly()) { update(); d->mDtStart = dtStart; d->mAllDay = dtStart.isDateOnly(); d->mDirtyFields.insert(FieldDtStart); updated(); } } KDateTime IncidenceBase::dtStart() const { return d->mDtStart; } bool IncidenceBase::allDay() const { return d->mAllDay; } void IncidenceBase::setAllDay(bool f) { if (mReadOnly || f == d->mAllDay) { return; } update(); d->mAllDay = f; if (d->mDtStart.isValid()) { d->mDirtyFields.insert(FieldDtStart); } updated(); } void IncidenceBase::shiftTimes(const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec) { update(); d->mDtStart = d->mDtStart.toTimeSpec(oldSpec); d->mDtStart.setTimeSpec(newSpec); d->mDirtyFields.insert(FieldDtStart); d->mDirtyFields.insert(FieldDtEnd); updated(); } void IncidenceBase::addComment(const QString &comment) { d->mComments += comment; } bool IncidenceBase::removeComment(const QString &comment) { bool found = false; QStringList::Iterator i; for (i = d->mComments.begin(); !found && i != d->mComments.end(); ++i) { if ((*i) == comment) { found = true; d->mComments.erase(i); } } if (found) { d->mDirtyFields.insert(FieldComment); } return found; } void IncidenceBase::clearComments() { d->mDirtyFields.insert(FieldComment); d->mComments.clear(); } QStringList IncidenceBase::comments() const { return d->mComments; } void IncidenceBase::addContact(const QString &contact) { if (!contact.isEmpty()) { d->mContacts += contact; d->mDirtyFields.insert(FieldContact); } } bool IncidenceBase::removeContact(const QString &contact) { bool found = false; QStringList::Iterator i; for (i = d->mContacts.begin(); !found && i != d->mContacts.end(); ++i) { if ((*i) == contact) { found = true; d->mContacts.erase(i); } } if (found) { d->mDirtyFields.insert(FieldContact); } return found; } void IncidenceBase::clearContacts() { d->mDirtyFields.insert(FieldContact); d->mContacts.clear(); } QStringList IncidenceBase::contacts() const { return d->mContacts; } void IncidenceBase::addAttendee(const Attendee::Ptr &a, bool doupdate) { if (!a || mReadOnly) { return; } Q_ASSERT(!d->mAttendees.contains(a)); if (doupdate) { update(); } if (a->name().left(7).toUpper() == QLatin1String("MAILTO:")) { a->setName(a->name().remove(0, 7)); } /* If Uid is empty, just use the pointer to Attendee (encoded to * string) as Uid. Only thing that matters is that the Uid is unique * insofar IncidenceBase is concerned, and this does that (albeit * not very nicely). If these are ever saved to disk, should use * (considerably more expensive) CalFormat::createUniqueId(). As Uid * is not part of Attendee in iCal std, it's fairly safe bet that * these will never hit disc though so faster generation speed is * more important than actually being forever unique.*/ if (a->uid().isEmpty()) { a->setUid(QString::number((qlonglong)a.data())); } d->mAttendees.append(a); if (doupdate) { d->mDirtyFields.insert(FieldAttendees); updated(); } } void IncidenceBase::deleteAttendee(const Attendee::Ptr &a, bool doupdate) { if (!a || mReadOnly) { return; } int index = d->mAttendees.indexOf(a); if (index >= 0) { if (doupdate) { update(); } d->mAttendees.remove(index); if (doupdate) { d->mDirtyFields.insert(FieldAttendees); updated(); } } } Attendee::List IncidenceBase::attendees() const { return d->mAttendees; } int IncidenceBase::attendeeCount() const { return d->mAttendees.count(); } void IncidenceBase::clearAttendees() { if (mReadOnly) { return; } d->mDirtyFields.insert(FieldAttendees); d->mAttendees.clear(); } Attendee::Ptr IncidenceBase::attendeeByMail(const QString &email) const { Attendee::List::ConstIterator it; for (it = d->mAttendees.constBegin(); it != d->mAttendees.constEnd(); ++it) { if ((*it)->email() == email) { return *it; } } return Attendee::Ptr(); } Attendee::Ptr IncidenceBase::attendeeByMails(const QStringList &emails, const QString &email) const { QStringList mails = emails; if (!email.isEmpty()) { mails.append(email); } Attendee::List::ConstIterator itA; for (itA = d->mAttendees.constBegin(); itA != d->mAttendees.constEnd(); ++itA) { for (QStringList::const_iterator it = mails.constBegin(); it != mails.constEnd(); ++it) { if ((*itA)->email() == (*it)) { return *itA; } } } return Attendee::Ptr(); } Attendee::Ptr IncidenceBase::attendeeByUid(const QString &uid) const { Attendee::List::ConstIterator it; for (it = d->mAttendees.constBegin(); it != d->mAttendees.constEnd(); ++it) { if ((*it)->uid() == uid) { return *it; } } return Attendee::Ptr(); } void IncidenceBase::setDuration(const Duration &duration) { update(); d->mDuration = duration; setHasDuration(true); d->mDirtyFields.insert(FieldDuration); updated(); } Duration IncidenceBase::duration() const { return d->mDuration; } void IncidenceBase::setHasDuration(bool hasDuration) { d->mHasDuration = hasDuration; } bool IncidenceBase::hasDuration() const { return d->mHasDuration; } void IncidenceBase::setUrl(const QUrl& url) { d->mDirtyFields.insert(FieldUrl); d->mUrl = url; } QUrl IncidenceBase::url() const { return d->mUrl; } void IncidenceBase::registerObserver(IncidenceBase::IncidenceObserver *observer) { if (observer && !d->mObservers.contains(observer)) { d->mObservers.append(observer); } } void IncidenceBase::unRegisterObserver(IncidenceBase::IncidenceObserver *observer) { d->mObservers.removeAll(observer); } void IncidenceBase::update() { if (!d->mUpdateGroupLevel) { d->mUpdatedPending = true; foreach(IncidenceObserver *o, d->mObservers) { o->incidenceUpdate(this); } } } void IncidenceBase::updated() { if (d->mUpdateGroupLevel) { d->mUpdatedPending = true; } else { foreach(IncidenceObserver *o, d->mObservers) { o->incidenceUpdated(this); } } } void IncidenceBase::startUpdates() { update(); ++d->mUpdateGroupLevel; } void IncidenceBase::endUpdates() { if (d->mUpdateGroupLevel > 0) { if (--d->mUpdateGroupLevel == 0 && d->mUpdatedPending) { d->mUpdatedPending = false; updated(); } } } void IncidenceBase::customPropertyUpdate() { update(); } void IncidenceBase::customPropertyUpdated() { updated(); } KDateTime IncidenceBase::recurrenceId() const { return KDateTime(); } void IncidenceBase::resetDirtyFields() { d->mDirtyFields.clear(); } QSet IncidenceBase::dirtyFields() const { return d->mDirtyFields; } void IncidenceBase::setFieldDirty(IncidenceBase::Field field) { d->mDirtyFields.insert(field); } KUrl IncidenceBase::uri() const { return KUrl(QLatin1String("urn:x-ical:") + uid()); } void IncidenceBase::setDirtyFields(const QSet &dirtyFields) { d->mDirtyFields = dirtyFields; } /** static */ quint32 IncidenceBase::magicSerializationIdentifier() { return KCALCORE_MAGIC_NUMBER; } QDataStream& KCalCore::operator<<(QDataStream &out, const KCalCore::IncidenceBase::Ptr &i) { if (!i) return out; out << static_cast(KCALCORE_MAGIC_NUMBER); // Magic number to identify KCalCore data out << static_cast(KCALCORE_SERIALIZATION_VERSION); out << static_cast(i->type()); out << *(static_cast(i.data())); out << i->d->mLastModified << i->d->mDtStart << i->organizer() << i->d->mUid << i->d->mDuration << i->d->mAllDay << i->d->mHasDuration << i->d->mComments << i->d->mContacts << i->d->mAttendees.count() << i->d->mUrl; foreach(const Attendee::Ptr &attendee, i->d->mAttendees) { out << attendee; } // Serialize the sub-class data. In KDE5 we can add new virtuals. i->virtual_hook(KCalCore::IncidenceBase::SerializerHook, &out); return out; } QDataStream& KCalCore::operator>>(QDataStream &in, const KCalCore::IncidenceBase::Ptr &i) { if (!i) return in; qint32 attendeeCount, type; quint32 magic, version; in >> magic; if (magic != KCALCORE_MAGIC_NUMBER) { kWarning() << "Invalid magic on serialized data"; return in; } in >> version; if (version > KCALCORE_MAGIC_NUMBER) { kWarning() << "Invalid version on serialized data"; return in; } in >> type; in >> *(static_cast(i.data())); in >> i->d->mLastModified >> i->d->mDtStart >> i->d->mOrganizer >> i->d->mUid >> i->d->mDuration >> i->d->mAllDay >> i->d->mHasDuration >> i->d->mComments >> i->d->mContacts >> attendeeCount >> i->d->mUrl; i->d->mAttendees.clear(); for (int it=0; it> attendee; i->d->mAttendees.append(attendee); } // Deserialize the sub-class data. In KDE5 we can add new virtuals. i->virtual_hook(KCalCore::IncidenceBase::DeserializerHook, &in); return in; } IncidenceBase::IncidenceObserver::~IncidenceObserver() { }