diff --git a/resources/kolab/pimkolab/kolabformatV2/event.cpp b/resources/kolab/pimkolab/kolabformatV2/event.cpp index 605ccb360..e2f6a9b9a 100644 --- a/resources/kolab/pimkolab/kolabformatV2/event.cpp +++ b/resources/kolab/pimkolab/kolabformatV2/event.cpp @@ -1,230 +1,230 @@ /* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "event.h" #include "utils/porting.h" #include "pimkolab_debug.h" #include using namespace KolabV2; KCalCore::Event::Ptr Event::fromXml(const QDomDocument &xmlDoc, const QString &tz) { Event event(tz); event.loadXML(xmlDoc); KCalCore::Event::Ptr kcalEvent(new KCalCore::Event()); event.saveTo(kcalEvent); return kcalEvent; } QString Event::eventToXML(const KCalCore::Event::Ptr &kcalEvent, const QString &tz) { Event event(tz, kcalEvent); return event.saveXML(); } Event::Event(const QString &tz, const KCalCore::Event::Ptr &event) : Incidence(tz, event) , mShowTimeAs(KCalCore::Event::Opaque) , mHasEndDate(false) { if (event) { setFields(event); } } Event::~Event() { } void Event::setTransparency(KCalCore::Event::Transparency transparency) { mShowTimeAs = transparency; } KCalCore::Event::Transparency Event::transparency() const { return mShowTimeAs; } void Event::setEndDate(const KDateTime &date) { mEndDate = date; mHasEndDate = true; if (mFloatingStatus == AllDay) { qCDebug(PIMKOLAB_LOG) <<"ERROR: Time on end date but no time on the event"; } mFloatingStatus = HasTime; } void Event::setEndDate(const QDate &date) { mEndDate = KDateTime(date); mHasEndDate = true; if (mFloatingStatus == HasTime) { qCDebug(PIMKOLAB_LOG) <<"ERROR: No time on end date but time on the event"; } mFloatingStatus = AllDay; } void Event::setEndDate(const QString &endDate) { if (endDate.length() > 10) { // This is a date + time setEndDate(stringToDateTime(endDate)); } else { // This is only a date setEndDate(stringToDate(endDate)); } } KDateTime Event::endDate() const { return mEndDate; } bool Event::loadAttribute(QDomElement &element) { // This method doesn't handle the color-label tag yet QString tagName = element.tagName(); if (tagName == QLatin1String("show-time-as")) { // TODO: Support tentative and outofoffice if (element.text() == QLatin1String("free")) { setTransparency(KCalCore::Event::Transparent); } else { setTransparency(KCalCore::Event::Opaque); } } else if (tagName == QLatin1String("end-date")) { setEndDate(element.text()); } else { return Incidence::loadAttribute(element); } // We handled this return true; } bool Event::saveAttributes(QDomElement &element) const { // Save the base class elements Incidence::saveAttributes(element); // TODO: Support tentative and outofoffice if (transparency() == KCalCore::Event::Transparent) { writeString(element, QStringLiteral("show-time-as"), QStringLiteral("free")); } else { writeString(element, QStringLiteral("show-time-as"), QStringLiteral("busy")); } if (mHasEndDate) { if (mFloatingStatus == HasTime) { writeString(element, QStringLiteral("end-date"), dateTimeToString(endDate())); } else { writeString(element, QStringLiteral("end-date"), dateToString(endDate().date())); } } return true; } bool Event::loadXML(const QDomDocument &document) { QDomElement top = document.documentElement(); if (top.tagName() != QLatin1String("event")) { qCWarning(PIMKOLAB_LOG) << QStringLiteral("XML error: Top tag was %1 instead of the expected event").arg(top.tagName()); return false; } for (QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isComment()) { continue; } if (n.isElement()) { QDomElement e = n.toElement(); loadAttribute(e); } else { qCDebug(PIMKOLAB_LOG) <<"Node is not a comment or an element???"; } } return true; } QString Event::saveXML() const { QDomDocument document = domTree(); QDomElement element = document.createElement(QStringLiteral("event")); element.setAttribute(QStringLiteral("version"), QStringLiteral("1.0")); saveAttributes(element); document.appendChild(element); return document.toString(); } void Event::setFields(const KCalCore::Event::Ptr &event) { Incidence::setFields(event); // note: if hasEndDate() is false and hasDuration() is true // dtEnd() returns start+duration if (event->hasEndDate() || event->hasDuration()) { if (event->allDay()) { // This is an all-day event. Don't timezone move this one mFloatingStatus = AllDay; setEndDate(event->dtEnd().date()); } else { mFloatingStatus = HasTime; - setEndDate(localToUTC(Porting::q2k(event->dtEnd()))); + setEndDate(Porting::q2k(localToUTC(event->dtEnd()))); } } else { mHasEndDate = false; } setTransparency(event->transparency()); } void Event::saveTo(const KCalCore::Event::Ptr &event) { Incidence::saveTo(event); //PORT KF5 ? method removed event->setHasEndDate( mHasEndDate ); if (mHasEndDate) { if (mFloatingStatus == AllDay) { // This is an all-day event. Don't timezone move this one event->setDtEnd(Porting::k2q(endDate())); } else { - event->setDtEnd(Porting::k2q(utcToLocal(endDate()))); + event->setDtEnd(utcToLocal(Porting::k2q(endDate()))); } } event->setTransparency(transparency()); } diff --git a/resources/kolab/pimkolab/kolabformatV2/incidence.cpp b/resources/kolab/pimkolab/kolabformatV2/incidence.cpp index 651fe5f12..c445d8dd2 100644 --- a/resources/kolab/pimkolab/kolabformatV2/incidence.cpp +++ b/resources/kolab/pimkolab/kolabformatV2/incidence.cpp @@ -1,1056 +1,1056 @@ /* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "incidence.h" #include "libkolab-version.h" #include "utils/porting.h" #include "pimkolab_debug.h" #include #include #include #include using namespace KolabV2; Incidence::Incidence(const QString &tz, const KCalCore::Incidence::Ptr &incidence) : KolabBase(tz) , mFloatingStatus(Unset) , mHasAlarm(false) , mPriority(0) { Q_UNUSED(incidence); } Incidence::~Incidence() { } void Incidence::setPriority(int priority) { mPriority = priority; } int Incidence::priority() const { return mPriority; } void Incidence::setSummary(const QString &summary) { mSummary = summary; } QString Incidence::summary() const { return mSummary; } void Incidence::setLocation(const QString &location) { mLocation = location; } QString Incidence::location() const { return mLocation; } void Incidence::setOrganizer(const Email &organizer) { mOrganizer = organizer; } KolabBase::Email Incidence::organizer() const { return mOrganizer; } void Incidence::setStartDate(const KDateTime &startDate) { mStartDate = startDate; if (mFloatingStatus == AllDay) { qCDebug(PIMKOLAB_LOG) <<"ERROR: Time on start date but no time on the event"; } mFloatingStatus = HasTime; } void Incidence::setStartDate(const QDate &startDate) { mStartDate = KDateTime(startDate); if (mFloatingStatus == HasTime) { qCDebug(PIMKOLAB_LOG) <<"ERROR: No time on start date but time on the event"; } mFloatingStatus = AllDay; } void Incidence::setStartDate(const QString &startDate) { if (startDate.length() > 10) { // This is a date + time setStartDate(stringToDateTime(startDate)); } else { // This is only a date setStartDate(stringToDate(startDate)); } } KDateTime Incidence::startDate() const { return mStartDate; } void Incidence::setAlarm(float alarm) { mAlarm = alarm; mHasAlarm = true; } float Incidence::alarm() const { return mAlarm; } Incidence::Recurrence Incidence::recurrence() const { return mRecurrence; } void Incidence::addAttendee(const Attendee &attendee) { mAttendees.append(attendee); } QList &Incidence::attendees() { return mAttendees; } const QList &Incidence::attendees() const { return mAttendees; } void Incidence::setInternalUID(const QString &iuid) { mInternalUID = iuid; } QString Incidence::internalUID() const { return mInternalUID; } bool Incidence::loadAttendeeAttribute(QDomElement &element, Attendee &attendee) { for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isComment()) { continue; } if (n.isElement()) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if (tagName == QLatin1String("display-name")) { attendee.displayName = e.text(); } else if (tagName == QLatin1String("smtp-address")) { attendee.smtpAddress = e.text(); } else if (tagName == QLatin1String("status")) { attendee.status = e.text(); } else if (tagName == QLatin1String("request-response")) { // This sets reqResp to false, if the text is "false". Otherwise it // sets it to true. This means the default setting is true. attendee.requestResponse = (e.text().toLower() != QLatin1String("false")); } else if (tagName == QLatin1String("invitation-sent")) { // Like above, only this defaults to false attendee.invitationSent = (e.text().toLower() != QLatin1String("true")); } else if (tagName == QLatin1String("role")) { attendee.role = e.text(); } else if (tagName == QLatin1String("delegated-to")) { attendee.delegate = e.text(); } else if (tagName == QLatin1String("delegated-from")) { attendee.delegator = e.text(); } else { // TODO: Unhandled tag - save for later storage qCDebug(PIMKOLAB_LOG) <<"Warning: Unhandled tag" << e.tagName(); } } else { qCDebug(PIMKOLAB_LOG) <<"Node is not a comment or an element???"; } } return true; } void Incidence::saveAttendeeAttribute(QDomElement &element, const Attendee &attendee) const { QDomElement e = element.ownerDocument().createElement(QStringLiteral("attendee")); element.appendChild(e); writeString(e, QStringLiteral("display-name"), attendee.displayName); writeString(e, QStringLiteral("smtp-address"), attendee.smtpAddress); writeString(e, QStringLiteral("status"), attendee.status); writeString(e, QStringLiteral("request-response"), (attendee.requestResponse ? QStringLiteral("true") : QStringLiteral("false"))); writeString(e, QStringLiteral("invitation-sent"), (attendee.invitationSent ? QStringLiteral("true") : QStringLiteral("false"))); writeString(e, QStringLiteral("role"), attendee.role); writeString(e, QStringLiteral("delegated-to"), attendee.delegate); writeString(e, QStringLiteral("delegated-from"), attendee.delegator); } void Incidence::saveAttendees(QDomElement &element) const { foreach (const Attendee &attendee, mAttendees) { saveAttendeeAttribute(element, attendee); } } void Incidence::saveAttachments(QDomElement &element) const { foreach (KCalCore::Attachment::Ptr a, mAttachments) { if (a->isUri()) { writeString(element, QStringLiteral("link-attachment"), a->uri()); } else if (a->isBinary()) { writeString(element, QStringLiteral("inline-attachment"), a->label()); } } } void Incidence::saveAlarms(QDomElement &element) const { if (mAlarms.isEmpty()) { return; } QDomElement list = element.ownerDocument().createElement(QStringLiteral("advanced-alarms")); element.appendChild(list); foreach (KCalCore::Alarm::Ptr a, mAlarms) { QDomElement e = list.ownerDocument().createElement(QStringLiteral("alarm")); list.appendChild(e); writeString(e, QStringLiteral("enabled"), a->enabled() ? QStringLiteral("1") : QStringLiteral("0")); if (a->hasStartOffset()) { writeString(e, QStringLiteral("start-offset"), QString::number(a->startOffset().asSeconds()/60)); } if (a->hasEndOffset()) { writeString(e, QStringLiteral("end-offset"), QString::number(a->endOffset().asSeconds()/60)); } if (a->repeatCount()) { writeString(e, QStringLiteral("repeat-count"), QString::number(a->repeatCount())); writeString(e, QStringLiteral("repeat-interval"), QString::number(a->snoozeTime().asSeconds())); } switch (a->type()) { case KCalCore::Alarm::Invalid: break; case KCalCore::Alarm::Display: e.setAttribute(QStringLiteral("type"), QStringLiteral("display")); writeString(e, QStringLiteral("text"), a->text()); break; case KCalCore::Alarm::Procedure: e.setAttribute(QStringLiteral("type"), QStringLiteral("procedure")); writeString(e, QStringLiteral("program"), a->programFile()); writeString(e, QStringLiteral("arguments"), a->programArguments()); break; case KCalCore::Alarm::Email: { e.setAttribute(QStringLiteral("type"), QStringLiteral("email")); QDomElement addresses = e.ownerDocument().createElement(QStringLiteral("addresses")); e.appendChild(addresses); foreach (const KCalCore::Person &person, a->mailAddresses()) { writeString(addresses, QStringLiteral("address"), person.fullName()); } writeString(e, QStringLiteral("subject"), a->mailSubject()); writeString(e, QStringLiteral("mail-text"), a->mailText()); QDomElement attachments = e.ownerDocument().createElement(QStringLiteral("attachments")); e.appendChild(attachments); foreach (const QString &attachment, a->mailAttachments()) { writeString(attachments, QStringLiteral("attachment"), attachment); } break; } case KCalCore::Alarm::Audio: e.setAttribute(QStringLiteral("type"), QStringLiteral("audio")); writeString(e, QStringLiteral("file"), a->audioFile()); break; default: qCWarning(PIMKOLAB_LOG) << "Unhandled alarm type:" << a->type(); break; } } } void Incidence::saveRecurrence(QDomElement &element) const { QDomElement e = element.ownerDocument().createElement(QStringLiteral("recurrence")); element.appendChild(e); e.setAttribute(QStringLiteral("cycle"), mRecurrence.cycle); if (!mRecurrence.type.isEmpty()) { e.setAttribute(QStringLiteral("type"), mRecurrence.type); } writeString(e, QStringLiteral("interval"), QString::number(mRecurrence.interval)); foreach (const QString &recurrence, mRecurrence.days) { writeString(e, QStringLiteral("day"), recurrence); } if (!mRecurrence.dayNumber.isEmpty()) { writeString(e, QStringLiteral("daynumber"), mRecurrence.dayNumber); } if (!mRecurrence.month.isEmpty()) { writeString(e, QStringLiteral("month"), mRecurrence.month); } if (!mRecurrence.rangeType.isEmpty()) { QDomElement range = element.ownerDocument().createElement(QStringLiteral("range")); e.appendChild(range); range.setAttribute(QStringLiteral("type"), mRecurrence.rangeType); QDomText t = element.ownerDocument().createTextNode(mRecurrence.range); range.appendChild(t); } foreach (const QDate &date, mRecurrence.exclusions) { writeString(e, QStringLiteral("exclusion"), dateToString(date)); } } void Incidence::loadRecurrence(const QDomElement &element) { mRecurrence.interval = 0; mRecurrence.cycle = element.attribute(QStringLiteral("cycle")); mRecurrence.type = element.attribute(QStringLiteral("type")); for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isComment()) { continue; } if (n.isElement()) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if (tagName == QLatin1String("interval")) { //kolab/issue4229, sometimes the interval value can be empty if (e.text().isEmpty() || e.text().toInt() <= 0) { mRecurrence.interval = 1; } else { mRecurrence.interval = e.text().toInt(); } } else if (tagName == QLatin1String("day")) { // can be present multiple times mRecurrence.days.append(e.text()); } else if (tagName == QLatin1String("daynumber")) { mRecurrence.dayNumber = e.text(); } else if (tagName == QLatin1String("month")) { mRecurrence.month = e.text(); } else if (tagName == QLatin1String("range")) { mRecurrence.rangeType = e.attribute(QStringLiteral("type")); mRecurrence.range = e.text(); } else if (tagName == QLatin1String("exclusion")) { mRecurrence.exclusions.append(stringToDate(e.text())); } else { // TODO: Unhandled tag - save for later storage qCDebug(PIMKOLAB_LOG) <<"Warning: Unhandled tag" << e.tagName(); } } } } static void loadAddressesHelper(const QDomElement &element, const KCalCore::Alarm::Ptr &a) { for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isComment()) { continue; } if (n.isElement()) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if (tagName == QLatin1String("address")) { a->addMailAddress(KCalCore::Person::fromFullName(e.text())); } else { qCWarning(PIMKOLAB_LOG) << "Unhandled tag" << tagName; } } } } static void loadAttachmentsHelper(const QDomElement &element, const KCalCore::Alarm::Ptr &a) { for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isComment()) { continue; } if (n.isElement()) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if (tagName == QLatin1String("attachment")) { a->addMailAttachment(e.text()); } else { qCWarning(PIMKOLAB_LOG) << "Unhandled tag" << tagName; } } } } static void loadAlarmHelper(const QDomElement &element, const KCalCore::Alarm::Ptr &a) { for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isComment()) { continue; } if (n.isElement()) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if (tagName == QLatin1String("start-offset")) { a->setStartOffset(e.text().toInt()*60); } else if (tagName == QLatin1String("end-offset")) { a->setEndOffset(e.text().toInt()*60); } else if (tagName == QLatin1String("repeat-count")) { a->setRepeatCount(e.text().toInt()); } else if (tagName == QLatin1String("repeat-interval")) { a->setSnoozeTime(e.text().toInt()); } else if (tagName == QLatin1String("text")) { a->setText(e.text()); } else if (tagName == QLatin1String("program")) { a->setProgramFile(e.text()); } else if (tagName == QLatin1String("arguments")) { a->setProgramArguments(e.text()); } else if (tagName == QLatin1String("addresses")) { loadAddressesHelper(e, a); } else if (tagName == QLatin1String("subject")) { a->setMailSubject(e.text()); } else if (tagName == QLatin1String("mail-text")) { a->setMailText(e.text()); } else if (tagName == QLatin1String("attachments")) { loadAttachmentsHelper(e, a); } else if (tagName == QLatin1String("file")) { a->setAudioFile(e.text()); } else if (tagName == QLatin1String("enabled")) { a->setEnabled(e.text().toInt() != 0); } else { qCWarning(PIMKOLAB_LOG) << "Unhandled tag" << tagName; } } } } void Incidence::loadAlarms(const QDomElement &element) { for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isComment()) { continue; } if (n.isElement()) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if (tagName == QLatin1String("alarm")) { KCalCore::Alarm::Ptr a = KCalCore::Alarm::Ptr(new KCalCore::Alarm(nullptr)); a->setEnabled(true); // default to enabled, unless some XML attribute says otherwise. QString type = e.attribute(QStringLiteral("type")); if (type == QLatin1String("display")) { a->setType(KCalCore::Alarm::Display); } else if (type == QLatin1String("procedure")) { a->setType(KCalCore::Alarm::Procedure); } else if (type == QLatin1String("email")) { a->setType(KCalCore::Alarm::Email); } else if (type == QLatin1String("audio")) { a->setType(KCalCore::Alarm::Audio); } else { qCWarning(PIMKOLAB_LOG) << "Unhandled alarm type:" << type; } loadAlarmHelper(e, a); mAlarms << a; } else { qCWarning(PIMKOLAB_LOG) << "Unhandled tag" << tagName; } } } } bool Incidence::loadAttribute(QDomElement &element) { QString tagName = element.tagName(); if (tagName == QLatin1String("priority")) { bool ok; int p = element.text().toInt(&ok); if (!ok || p < 1 || p > 9) { qCWarning(PIMKOLAB_LOG) << "Invalid \"priority\" value:" << element.text(); } else { setPriority(p); } } else if (tagName == QLatin1String("x-kcal-priority")) { //for backwards compat bool ok; int p = element.text().toInt(&ok); if (!ok || p < 0 || p > 9) { qCWarning(PIMKOLAB_LOG) << "Invalid \"x-kcal-priority\" value:" << element.text(); } else { if (priority() == 0) { setPriority(p); } } } else if (tagName == QLatin1String("summary")) { setSummary(element.text()); } else if (tagName == QLatin1String("location")) { setLocation(element.text()); } else if (tagName == QLatin1String("organizer")) { Email email; if (loadEmailAttribute(element, email)) { setOrganizer(email); return true; } else { return false; } } else if (tagName == QLatin1String("start-date")) { setStartDate(element.text()); } else if (tagName == QLatin1String("recurrence")) { loadRecurrence(element); } else if (tagName == QLatin1String("attendee")) { Attendee attendee; if (loadAttendeeAttribute(element, attendee)) { addAttendee(attendee); return true; } else { return false; } } else if (tagName == QLatin1String("link-attachment")) { mAttachments.push_back(KCalCore::Attachment::Ptr(new KCalCore::Attachment(element.text()))); } else if (tagName == QLatin1String("alarm")) { // Alarms should be minutes before. Libkcal uses event time + alarm time setAlarm(-element.text().toInt()); } else if (tagName == QLatin1String("advanced-alarms")) { loadAlarms(element); } else if (tagName == QLatin1String("x-kde-internaluid")) { setInternalUID(element.text()); } else if (tagName == QLatin1String("x-custom")) { loadCustomAttributes(element); } else if (tagName == QLatin1String("inline-attachment")) { // we handle that separately later on, so no need to create a KolabUnhandled entry for it } else { bool ok = KolabBase::loadAttribute(element); if (!ok) { // Unhandled tag - save for later storage qCDebug(PIMKOLAB_LOG) <<"Saving unhandled tag" << element.tagName(); Custom c; c.key = QByteArray("X-KDE-KolabUnhandled-") + element.tagName().toLatin1(); c.value = element.text(); mCustomList.append(c); } } // We handled this return true; } bool Incidence::saveAttributes(QDomElement &element) const { // Save the base class elements KolabBase::saveAttributes(element); if (priority() != 0) { writeString(element, QStringLiteral("priority"), QString::number(priority())); } if (mFloatingStatus == HasTime) { writeString(element, QStringLiteral("start-date"), dateTimeToString(startDate())); } else { writeString(element, QStringLiteral("start-date"), dateToString(startDate().date())); } writeString(element, QStringLiteral("summary"), summary()); writeString(element, QStringLiteral("location"), location()); saveEmailAttribute(element, organizer(), QStringLiteral("organizer")); if (!mRecurrence.cycle.isEmpty()) { saveRecurrence(element); } saveAttendees(element); saveAttachments(element); if (mHasAlarm) { // Alarms should be minutes before. Libkcal uses event time + alarm time int alarmTime = qRound(-alarm()); writeString(element, QStringLiteral("alarm"), QString::number(alarmTime)); } saveAlarms(element); writeString(element, QStringLiteral("x-kde-internaluid"), internalUID()); saveCustomAttributes(element); return true; } void Incidence::saveCustomAttributes(QDomElement &element) const { foreach (const Custom &custom, mCustomList) { QString key(custom.key); Q_ASSERT(!key.isEmpty()); if (key.startsWith(QLatin1String("X-KDE-KolabUnhandled-"))) { key = key.mid(strlen("X-KDE-KolabUnhandled-")); writeString(element, key, custom.value); } else { // Let's use attributes so that other tag-preserving-code doesn't need sub-elements QDomElement e = element.ownerDocument().createElement(QStringLiteral("x-custom")); element.appendChild(e); e.setAttribute(QStringLiteral("key"), key); e.setAttribute(QStringLiteral("value"), custom.value); } } } void Incidence::loadCustomAttributes(QDomElement &element) { Custom custom; custom.key = element.attribute(QStringLiteral("key")).toLatin1(); custom.value = element.attribute(QStringLiteral("value")); mCustomList.append(custom); } static KCalCore::Attendee::PartStat attendeeStringToStatus(const QString &s) { if (s == QLatin1String("none")) { return KCalCore::Attendee::NeedsAction; } if (s == QLatin1String("tentative")) { return KCalCore::Attendee::Tentative; } if (s == QLatin1String("declined")) { return KCalCore::Attendee::Declined; } if (s == QLatin1String("delegated")) { return KCalCore::Attendee::Delegated; } // Default: return KCalCore::Attendee::Accepted; } static QString attendeeStatusToString(KCalCore::Attendee::PartStat status) { switch (status) { case KCalCore::Attendee::NeedsAction: return QStringLiteral("none"); case KCalCore::Attendee::Accepted: return QStringLiteral("accepted"); case KCalCore::Attendee::Declined: return QStringLiteral("declined"); case KCalCore::Attendee::Tentative: return QStringLiteral("tentative"); case KCalCore::Attendee::Delegated: return QStringLiteral("delegated"); case KCalCore::Attendee::Completed: case KCalCore::Attendee::InProcess: // These don't have any meaning in the Kolab format, so just use: return QStringLiteral("accepted"); default: // Default for the case that there are more added later: return QStringLiteral("accepted"); } } static KCalCore::Attendee::Role attendeeStringToRole(const QString &s) { if (s == QLatin1String("optional")) { return KCalCore::Attendee::OptParticipant; } if (s == QLatin1String("resource")) { return KCalCore::Attendee::NonParticipant; } return KCalCore::Attendee::ReqParticipant; } static QString attendeeRoleToString(KCalCore::Attendee::Role role) { switch (role) { case KCalCore::Attendee::ReqParticipant: return QStringLiteral("required"); case KCalCore::Attendee::OptParticipant: return QStringLiteral("optional"); case KCalCore::Attendee::Chair: // We don't have the notion of chair, so use return QStringLiteral("required"); case KCalCore::Attendee::NonParticipant: // In Kolab, a non-participant is a resource return QStringLiteral("resource"); } // Default for the case that there are more added later: return QStringLiteral("required"); } static const char *s_weekDayName[] = { "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday" }; static const char *s_monthName[] = { "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december" }; void Incidence::setRecurrence(KCalCore::Recurrence *recur) { mRecurrence.interval = recur->frequency(); switch (recur->recurrenceType()) { case KCalCore::Recurrence::rMinutely: // Not handled by the kolab XML mRecurrence.cycle = QStringLiteral("minutely"); break; case KCalCore::Recurrence::rHourly: // Not handled by the kolab XML mRecurrence.cycle = QStringLiteral("hourly"); break; case KCalCore::Recurrence::rDaily: mRecurrence.cycle = QStringLiteral("daily"); break; case KCalCore::Recurrence::rWeekly: // every X weeks mRecurrence.cycle = QStringLiteral("weekly"); { QBitArray arr = recur->days(); for (int idx = 0; idx < 7; ++idx) { if (arr.testBit(idx)) { mRecurrence.days.append(s_weekDayName[idx]); } } } break; case KCalCore::Recurrence::rMonthlyPos: { mRecurrence.cycle = QStringLiteral("monthly"); mRecurrence.type = QStringLiteral("weekday"); QList monthPositions = recur->monthPositions(); if (!monthPositions.isEmpty()) { KCalCore::RecurrenceRule::WDayPos monthPos = monthPositions.first(); // TODO: Handle multiple days in the same week mRecurrence.dayNumber = QString::number(monthPos.pos()); mRecurrence.days.append(s_weekDayName[ monthPos.day()-1 ]); // Not (properly) handled(?): monthPos.negative (nth days before end of month) } break; } case KCalCore::Recurrence::rMonthlyDay: { mRecurrence.cycle = QStringLiteral("monthly"); mRecurrence.type = QStringLiteral("daynumber"); QList monthDays = recur->monthDays(); // ####### Kolab XML limitation: only the first month day is used if (!monthDays.isEmpty()) { mRecurrence.dayNumber = QString::number(monthDays.first()); } break; } case KCalCore::Recurrence::rYearlyMonth: // (day n of Month Y) { mRecurrence.cycle = QStringLiteral("yearly"); mRecurrence.type = QStringLiteral("monthday"); QList rmd = recur->yearDates(); int day = !rmd.isEmpty() ? rmd.first() : recur->startDate().day(); mRecurrence.dayNumber = QString::number(day); QList months = recur->yearMonths(); if (!months.isEmpty()) { mRecurrence.month = s_monthName[ months.first() - 1 ]; // #### Kolab XML limitation: only one month specified } break; } case KCalCore::Recurrence::rYearlyDay: // YearlyDay (day N of the year). Not supported by Outlook mRecurrence.cycle = QStringLiteral("yearly"); mRecurrence.type = QStringLiteral("yearday"); mRecurrence.dayNumber = QString::number(recur->yearDays().first()); break; case KCalCore::Recurrence::rYearlyPos: // (weekday X of week N of month Y) mRecurrence.cycle = QStringLiteral("yearly"); mRecurrence.type = QStringLiteral("weekday"); QList months = recur->yearMonths(); if (!months.isEmpty()) { mRecurrence.month = s_monthName[ months.first() - 1 ]; // #### Kolab XML limitation: only one month specified } QList monthPositions = recur->yearPositions(); if (!monthPositions.isEmpty()) { KCalCore::RecurrenceRule::WDayPos monthPos = monthPositions.first(); // TODO: Handle multiple days in the same week mRecurrence.dayNumber = QString::number(monthPos.pos()); mRecurrence.days.append(s_weekDayName[ monthPos.day()-1 ]); //mRecurrence.dayNumber = QString::number( *recur->yearNums().getFirst() ); // Not handled: monthPos.negative (nth days before end of month) } break; } int howMany = recur->duration(); if (howMany > 0) { mRecurrence.rangeType = QStringLiteral("number"); mRecurrence.range = QString::number(howMany); } else if (howMany == 0) { mRecurrence.rangeType = QStringLiteral("date"); mRecurrence.range = dateToString(recur->endDate()); } else { mRecurrence.rangeType = QStringLiteral("none"); } } void Incidence::setFields(const KCalCore::Incidence::Ptr &incidence) { KolabBase::setFields(incidence); setPriority(incidence->priority()); if (incidence->allDay()) { // This is a all-day event. Don't timezone move this one mFloatingStatus = AllDay; setStartDate(incidence->dtStart().date()); } else { mFloatingStatus = HasTime; - setStartDate(localToUTC(Porting::q2k(incidence->dtStart()))); + setStartDate(Porting::q2k(localToUTC(incidence->dtStart()))); } setSummary(incidence->summary()); setLocation(incidence->location()); // Alarm mHasAlarm = false; // Will be set to true, if we actually have one if (incidence->hasEnabledAlarms()) { const KCalCore::Alarm::List &alarms = incidence->alarms(); if (!alarms.isEmpty()) { const KCalCore::Alarm::Ptr alarm = alarms.first(); if (alarm->hasStartOffset()) { int dur = alarm->startOffset().asSeconds(); setAlarm((float)dur / 60.0); } } } if (!incidence->organizer().isEmpty()) { Email org(incidence->organizer().name(), incidence->organizer().email()); setOrganizer(org); } // Attendees: const KCalCore::Attendee::List attendees = incidence->attendees(); foreach (const KCalCore::Attendee::Ptr &kcalAttendee, attendees) { Attendee attendee; attendee.displayName = kcalAttendee->name(); attendee.smtpAddress = kcalAttendee->email(); attendee.status = attendeeStatusToString(kcalAttendee->status()); attendee.requestResponse = kcalAttendee->RSVP(); // TODO: KCalCore::Attendee::mFlag is not accessible // attendee.invitationSent = kcalAttendee->mFlag; // DF: Hmm? mFlag is set to true and never used at all.... Did you mean another field? attendee.role = attendeeRoleToString(kcalAttendee->role()); attendee.delegate = kcalAttendee->delegate(); attendee.delegator = kcalAttendee->delegator(); addAttendee(attendee); } mAttachments.clear(); // Attachments const KCalCore::Attachment::List attachments = incidence->attachments(); mAttachments.reserve(attachments.size()); for (const KCalCore::Attachment::Ptr &a : attachments) { mAttachments.push_back(a); } mAlarms.clear(); // Alarms const KCalCore::Alarm::List alarms = incidence->alarms(); mAlarms.reserve(alarms.count()); for (const KCalCore::Alarm::Ptr &a : alarms) { mAlarms.push_back(a); } if (incidence->recurs()) { setRecurrence(incidence->recurrence()); mRecurrence.exclusions = incidence->recurrence()->exDates(); } // Handle the scheduling ID if (incidence->schedulingID() == incidence->uid()) { // There is no scheduling ID setInternalUID(QString()); //krazy:exclude=nullstrassign for old broken gcc } else { // We've internally been using a different uid, so save that as the // temporary (internal) uid and restore the original uid, the one that // is used in the folder and the outside world setUid(incidence->schedulingID()); setInternalUID(incidence->uid()); } // Unhandled tags and other custom properties (see libkcal/customproperties.h) const QMap map = incidence->customProperties(); QMap::ConstIterator cit = map.begin(); QMap::ConstIterator cend = map.end(); for (; cit != cend; ++cit) { Custom c; c.key = cit.key(); c.value = cit.value(); mCustomList.append(c); } } static QBitArray daysListToBitArray(const QStringList &days) { QBitArray arr(7); arr.fill(false); foreach (const QString &day, days) { for (int i = 0; i < 7; ++i) { if (day == s_weekDayName[i]) { arr.setBit(i, true); } } } return arr; } void Incidence::saveTo(const KCalCore::Incidence::Ptr &incidence) { KolabBase::saveTo(incidence); incidence->setPriority(priority()); if (mFloatingStatus == AllDay) { // This is an all-day event. Don't timezone move this one incidence->setDtStart(Porting::k2q(startDate())); incidence->setAllDay(true); } else { - incidence->setDtStart(Porting::k2q(utcToLocal(startDate()))); + incidence->setDtStart(utcToLocal(Porting::k2q(startDate()))); incidence->setAllDay(false); } incidence->setSummary(summary()); incidence->setLocation(location()); if (mHasAlarm && mAlarms.isEmpty()) { KCalCore::Alarm::Ptr alarm = incidence->newAlarm(); alarm->setStartOffset(qRound(mAlarm * 60.0)); alarm->setEnabled(true); alarm->setType(KCalCore::Alarm::Display); } else if (!mAlarms.isEmpty()) { foreach (KCalCore::Alarm::Ptr a, mAlarms) { a->setParent(incidence.data()); incidence->addAlarm(a); } } if (organizer().displayName.isEmpty()) { incidence->setOrganizer(organizer().smtpAddress); } else { incidence->setOrganizer(organizer().displayName + QLatin1Char('<') + organizer().smtpAddress + QLatin1Char('>')); } incidence->clearAttendees(); foreach (const Attendee &attendee, mAttendees) { KCalCore::Attendee::PartStat status = attendeeStringToStatus(attendee.status); KCalCore::Attendee::Role role = attendeeStringToRole(attendee.role); KCalCore::Attendee::Ptr a(new KCalCore::Attendee(attendee.displayName, attendee.smtpAddress, attendee.requestResponse, status, role)); a->setDelegate(attendee.delegate); a->setDelegator(attendee.delegator); incidence->addAttendee(a); } incidence->clearAttachments(); foreach (const KCalCore::Attachment::Ptr &a, mAttachments) { // TODO should we copy? incidence->addAttachment(a); } if (!mRecurrence.cycle.isEmpty()) { KCalCore::Recurrence *recur = incidence->recurrence(); // yeah, this creates it // done below recur->setFrequency( mRecurrence.interval ); if (mRecurrence.cycle == QLatin1String("minutely")) { recur->setMinutely(mRecurrence.interval); } else if (mRecurrence.cycle == QLatin1String("hourly")) { recur->setHourly(mRecurrence.interval); } else if (mRecurrence.cycle == QLatin1String("daily")) { recur->setDaily(mRecurrence.interval); } else if (mRecurrence.cycle == QLatin1String("weekly")) { QBitArray rDays = daysListToBitArray(mRecurrence.days); recur->setWeekly(mRecurrence.interval, rDays); } else if (mRecurrence.cycle == QLatin1String("monthly")) { recur->setMonthly(mRecurrence.interval); if (mRecurrence.type == QLatin1String("weekday")) { recur->addMonthlyPos(mRecurrence.dayNumber.toInt(), daysListToBitArray(mRecurrence.days)); } else if (mRecurrence.type == QLatin1String("daynumber")) { recur->addMonthlyDate(mRecurrence.dayNumber.toInt()); } else { qCWarning(PIMKOLAB_LOG) <<"Unhandled monthly recurrence type" << mRecurrence.type; } } else if (mRecurrence.cycle == QLatin1String("yearly")) { recur->setYearly(mRecurrence.interval); if (mRecurrence.type == QLatin1String("monthday")) { recur->addYearlyDate(mRecurrence.dayNumber.toInt()); for (int i = 0; i < 12; ++i) { if (s_monthName[ i ] == mRecurrence.month) { recur->addYearlyMonth(i+1); } } } else if (mRecurrence.type == QLatin1String("yearday")) { recur->addYearlyDay(mRecurrence.dayNumber.toInt()); } else if (mRecurrence.type == QLatin1String("weekday")) { for (int i = 0; i < 12; ++i) { if (s_monthName[ i ] == mRecurrence.month) { recur->addYearlyMonth(i+1); } } recur->addYearlyPos(mRecurrence.dayNumber.toInt(), daysListToBitArray(mRecurrence.days)); } else { qCWarning(PIMKOLAB_LOG) <<"Unhandled yearly recurrence type" << mRecurrence.type; } } else { qCWarning(PIMKOLAB_LOG) <<"Unhandled recurrence cycle" << mRecurrence.cycle; } if (mRecurrence.rangeType == QLatin1String("number")) { recur->setDuration(mRecurrence.range.toInt()); } else if (mRecurrence.rangeType == QLatin1String("date")) { recur->setEndDate(stringToDate(mRecurrence.range)); } // "none" is default since tje set*ly methods set infinite recurrence incidence->recurrence()->setExDates(mRecurrence.exclusions); } /* If we've stored a uid to be used internally instead of the real one * (to deal with duplicates of events in different folders) before, then * restore it, so it does not change. Keep the original uid around for * scheduling purposes. */ if (!internalUID().isEmpty()) { incidence->setUid(internalUID()); incidence->setSchedulingID(uid()); } foreach (const Custom &custom, mCustomList) { incidence->setNonKDECustomProperty(custom.key, custom.value); } } QString Incidence::productID() const { return QStringLiteral("%1, Kolab resource").arg(LIBKOLAB_LIB_VERSION_STRING); } // Unhandled KCalCore::Incidence fields: // revision, status (unused), attendee.uid, // mComments, mReadOnly diff --git a/resources/kolab/pimkolab/kolabformatV2/journal.cpp b/resources/kolab/pimkolab/kolabformatV2/journal.cpp index 5e5aefd68..40bbe00d7 100644 --- a/resources/kolab/pimkolab/kolabformatV2/journal.cpp +++ b/resources/kolab/pimkolab/kolabformatV2/journal.cpp @@ -1,185 +1,185 @@ /* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "journal.h" #include "libkolab-version.h" #include "pimkolab_debug.h" #include "utils/porting.h" using namespace KolabV2; KCalCore::Journal::Ptr Journal::fromXml(const QDomDocument &xmlDoc, const QString &tz) { Journal journal(tz); journal.loadXML(xmlDoc); KCalCore::Journal::Ptr kcalJournal(new KCalCore::Journal()); journal.saveTo(kcalJournal); return kcalJournal; } QString Journal::journalToXML(const KCalCore::Journal::Ptr &kcalJournal, const QString &tz) { Journal journal(tz, kcalJournal); return journal.saveXML(); } Journal::Journal(const QString &tz, const KCalCore::Journal::Ptr &journal) : KolabBase(tz) { if (journal) { setFields(journal); } } Journal::~Journal() { } void Journal::setSummary(const QString &summary) { mSummary = summary; } QString Journal::summary() const { return mSummary; } void Journal::setStartDate(const KDateTime &startDate) { mStartDate = startDate; } KDateTime Journal::startDate() const { return mStartDate; } void Journal::setEndDate(const KDateTime &endDate) { mEndDate = endDate; } KDateTime Journal::endDate() const { return mEndDate; } bool Journal::loadAttribute(QDomElement &element) { QString tagName = element.tagName(); if (tagName == QLatin1String("summary")) { setSummary(element.text()); } else if (tagName == QLatin1String("start-date")) { setStartDate(stringToDateTime(element.text())); } else { // Not handled here return KolabBase::loadAttribute(element); } // We handled this return true; } bool Journal::saveAttributes(QDomElement &element) const { // Save the base class elements KolabBase::saveAttributes(element); writeString(element, QStringLiteral("summary"), summary()); writeString(element, QStringLiteral("start-date"), dateTimeToString(startDate())); return true; } bool Journal::loadXML(const QDomDocument &document) { QDomElement top = document.documentElement(); if (top.tagName() != QLatin1String("journal")) { qCWarning(PIMKOLAB_LOG) << QStringLiteral("XML error: Top tag was %1 instead of the expected Journal").arg(top.tagName()); return false; } for (QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isComment()) { continue; } if (n.isElement()) { QDomElement e = n.toElement(); if (!loadAttribute(e)) { // Unhandled tag - save for later storage //qDebug( "Unhandled tag: %s", e.toCString().data() ); } } else { qCDebug(PIMKOLAB_LOG) << "Node is not a comment or an element???"; } } return true; } QString Journal::saveXML() const { QDomDocument document = domTree(); QDomElement element = document.createElement(QStringLiteral("journal")); element.setAttribute(QStringLiteral("version"), QStringLiteral("1.0")); saveAttributes(element); document.appendChild(element); return document.toString(); } void Journal::saveTo(const KCalCore::Journal::Ptr &journal) const { KolabBase::saveTo(journal); journal->setSummary(summary()); - journal->setDtStart(Porting::k2q(utcToLocal(startDate()))); + journal->setDtStart(utcToLocal(Porting::k2q(startDate()))); journal->setAllDay(startDate().isDateOnly()); } void Journal::setFields(const KCalCore::Journal::Ptr &journal) { // Set baseclass fields KolabBase::setFields(journal); // Set our own fields setSummary(journal->summary()); - setStartDate(localToUTC(Porting::q2k(journal->dtStart()))); + setStartDate(Porting::q2k(localToUTC(journal->dtStart()))); } QString Journal::productID() const { return QLatin1String(LIBKOLAB_LIB_VERSION_STRING) + QLatin1String(", Kolab resource"); } diff --git a/resources/kolab/pimkolab/kolabformatV2/kolabbase.cpp b/resources/kolab/pimkolab/kolabformatV2/kolabbase.cpp index cd134d7cd..2f3ad340b 100644 --- a/resources/kolab/pimkolab/kolabformatV2/kolabbase.cpp +++ b/resources/kolab/pimkolab/kolabformatV2/kolabbase.cpp @@ -1,511 +1,511 @@ /* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "kolabbase.h" #include "utils/porting.h" #include "pimkolab_debug.h" #include #include #include #include #include using namespace KolabV2; KolabBase::KolabBase(const QString &tz) : mCreationDate(QDateTime::currentDateTime()) , mLastModified(KDateTime::currentUtcDateTime()) , mSensitivity(Public) , mTimeZone(KTimeZone(tz)) , mHasPilotSyncId(false) , mHasPilotSyncStatus(false) { } KolabBase::~KolabBase() { } void KolabBase::setFields(const KCalCore::Incidence::Ptr &incidence) { // So far unhandled KCalCore::IncidenceBase fields: // mPilotID, mSyncStatus, mFloats setUid(incidence->uid()); setBody(incidence->description()); setCategories(incidence->categoriesStr()); - setCreationDate(localToUTC(Porting::q2k(incidence->created()))); + setCreationDate(Porting::q2k(localToUTC(incidence->created()))); setLastModified(Porting::q2k(incidence->lastModified())); setSensitivity(static_cast(incidence->secrecy())); // TODO: Attachments } void KolabBase::saveTo(const KCalCore::Incidence::Ptr &incidence) const { incidence->setUid(uid()); incidence->setDescription(body()); incidence->setCategories(categories()); - incidence->setCreated(Porting::k2q(utcToLocal(creationDate()))); + incidence->setCreated(utcToLocal(Porting::k2q(creationDate()))); incidence->setLastModified(Porting::k2q(lastModified())); switch (sensitivity()) { case 1: incidence->setSecrecy(KCalCore::Incidence::SecrecyPrivate); break; case 2: incidence->setSecrecy(KCalCore::Incidence::SecrecyConfidential); break; default: incidence->setSecrecy(KCalCore::Incidence::SecrecyPublic); break; } // TODO: Attachments } void KolabBase::setFields(const KContacts::Addressee *addressee) { // An addressee does not have a creation date, so somehow we should // make one, if this is a new entry setUid(addressee->uid()); setBody(addressee->note()); setCategories(addressee->categories().join(QLatin1Char(','))); // Set creation-time and last-modification-time const QString creationString = addressee->custom(QStringLiteral("KOLAB"), QStringLiteral("CreationDate")); qCDebug(PIMKOLAB_LOG) <<"Creation time string:" << creationString; KDateTime creationDate; if (creationString.isEmpty()) { creationDate = KDateTime::currentDateTime(KDateTime::Spec(mTimeZone)); qCDebug(PIMKOLAB_LOG) <<"Creation date set to current time"; } else { creationDate = stringToDateTime(creationString); qCDebug(PIMKOLAB_LOG) <<"Creation date loaded"; } KDateTime modified = KDateTime(addressee->revision(), mTimeZone); if (!modified.isValid()) { modified = KDateTime::currentUtcDateTime(); } setLastModified(modified); if (modified < creationDate) { // It's not possible that the modification date is earlier than creation creationDate = modified; qCDebug(PIMKOLAB_LOG) <<"Creation date set to modification date"; } setCreationDate(creationDate); const QString newCreationDate = dateTimeToString(creationDate); if (creationString != newCreationDate) { // We modified the creation date, so store it for future reference const_cast(addressee) ->insertCustom(QStringLiteral("KOLAB"), QStringLiteral("CreationDate"), newCreationDate); qCDebug(PIMKOLAB_LOG) <<"Creation date modified. New one:" << newCreationDate; } switch (addressee->secrecy().type()) { case KContacts::Secrecy::Private: setSensitivity(Private); break; case KContacts::Secrecy::Confidential: setSensitivity(Confidential); break; default: setSensitivity(Public); } // TODO: Attachments } void KolabBase::saveTo(KContacts::Addressee *addressee) const { addressee->setUid(uid()); addressee->setNote(body()); addressee->setCategories(categories().split(QLatin1Char(','), QString::SkipEmptyParts)); addressee->setRevision(lastModified().toZone(mTimeZone).dateTime()); addressee->insertCustom(QStringLiteral("KOLAB"), QStringLiteral("CreationDate"), dateTimeToString(creationDate())); switch (sensitivity()) { case Private: addressee->setSecrecy(KContacts::Secrecy(KContacts::Secrecy::Private)); break; case Confidential: addressee->setSecrecy(KContacts::Secrecy(KContacts::Secrecy::Confidential)); break; default: addressee->setSecrecy(KContacts::Secrecy(KContacts::Secrecy::Public)); break; } // TODO: Attachments } void KolabBase::setFields(const KContacts::ContactGroup *contactGroup) { // A contactgroup does not have a creation date, so somehow we should // make one, if this is a new entry setUid(contactGroup->id()); // Set creation-time and last-modification-time KDateTime creationDate = KDateTime::currentDateTime(KDateTime::Spec(mTimeZone)); qCDebug(PIMKOLAB_LOG) <<"Creation date set to current time"; KDateTime modified = KDateTime::currentUtcDateTime(); setLastModified(modified); if (modified < creationDate) { // It's not possible that the modification date is earlier than creation creationDate = modified; qCDebug(PIMKOLAB_LOG) <<"Creation date set to modification date"; } setCreationDate(creationDate); } void KolabBase::saveTo(KContacts::ContactGroup *contactGroup) const { contactGroup->setId(uid()); } void KolabBase::setUid(const QString &uid) { mUid = uid; } QString KolabBase::uid() const { return mUid; } void KolabBase::setBody(const QString &body) { mBody = body; } QString KolabBase::body() const { return mBody; } void KolabBase::setCategories(const QString &categories) { mCategories = categories; } QString KolabBase::categories() const { return mCategories; } void KolabBase::setCreationDate(const KDateTime &date) { mCreationDate = date; } KDateTime KolabBase::creationDate() const { return mCreationDate; } void KolabBase::setLastModified(const KDateTime &date) { mLastModified = date; } KDateTime KolabBase::lastModified() const { return mLastModified; } void KolabBase::setSensitivity(Sensitivity sensitivity) { mSensitivity = sensitivity; } KolabBase::Sensitivity KolabBase::sensitivity() const { return mSensitivity; } void KolabBase::setPilotSyncId(unsigned long id) { mHasPilotSyncId = true; mPilotSyncId = id; } bool KolabBase::hasPilotSyncId() const { return mHasPilotSyncId; } unsigned long KolabBase::pilotSyncId() const { return mPilotSyncId; } void KolabBase::setPilotSyncStatus(int status) { mHasPilotSyncStatus = true; mPilotSyncStatus = status; } bool KolabBase::hasPilotSyncStatus() const { return mHasPilotSyncStatus; } int KolabBase::pilotSyncStatus() const { return mPilotSyncStatus; } bool KolabBase::loadEmailAttribute(QDomElement &element, Email &email) { for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isComment()) { continue; } if (n.isElement()) { QDomElement e = n.toElement(); const QString tagName = e.tagName(); if (tagName == QLatin1String("display-name")) { email.displayName = e.text(); } else if (tagName == QLatin1String("smtp-address")) { email.smtpAddress = e.text(); } else { // TODO: Unhandled tag - save for later storage qCDebug(PIMKOLAB_LOG) <<"Warning: Unhandled tag" << e.tagName(); } } else { qCDebug(PIMKOLAB_LOG) <<"Node is not a comment or an element???"; } } return true; } void KolabBase::saveEmailAttribute(QDomElement &element, const Email &email, const QString &tagName) const { QDomElement e = element.ownerDocument().createElement(tagName); element.appendChild(e); writeString(e, QStringLiteral("display-name"), email.displayName); writeString(e, QStringLiteral("smtp-address"), email.smtpAddress); } bool KolabBase::loadAttribute(QDomElement &element) { const QString tagName = element.tagName(); switch (tagName[0].toLatin1()) { case 'u': if (tagName == QLatin1String("uid")) { setUid(element.text()); return true; } break; case 'b': if (tagName == QLatin1String("body")) { setBody(element.text()); return true; } break; case 'c': if (tagName == QLatin1String("categories")) { setCategories(element.text()); return true; } if (tagName == QLatin1String("creation-date")) { setCreationDate(stringToDateTime(element.text())); return true; } break; case 'l': if (tagName == QLatin1String("last-modification-date")) { setLastModified(stringToDateTime(element.text())); return true; } break; case 's': if (tagName == QLatin1String("sensitivity")) { setSensitivity(stringToSensitivity(element.text())); return true; } break; case 'p': if (tagName == QLatin1String("product-id")) { return true; // ignore this field } if (tagName == QLatin1String("pilot-sync-id")) { setPilotSyncId(element.text().toULong()); return true; } if (tagName == QLatin1String("pilot-sync-status")) { setPilotSyncStatus(element.text().toInt()); return true; } break; default: break; } return false; } bool KolabBase::saveAttributes(QDomElement &element) const { writeString(element, QStringLiteral("product-id"), productID()); writeString(element, QStringLiteral("uid"), uid()); writeString(element, QStringLiteral("body"), body()); writeString(element, QStringLiteral("categories"), categories()); writeString(element, QStringLiteral("creation-date"), dateTimeToString(creationDate().toUtc())); writeString(element, QStringLiteral("last-modification-date"), dateTimeToString(lastModified().toUtc())); writeString(element, QStringLiteral("sensitivity"), sensitivityToString(sensitivity())); if (hasPilotSyncId()) { writeString(element, QStringLiteral("pilot-sync-id"), QString::number(pilotSyncId())); } if (hasPilotSyncStatus()) { writeString(element, QStringLiteral("pilot-sync-status"), QString::number(pilotSyncStatus())); } return true; } bool KolabBase::load(const QString &xml) { const QDomDocument document = loadDocument(xml); if (document.isNull()) { return false; } // XML file loaded into tree. Now parse it return loadXML(document); } QDomDocument KolabBase::loadDocument(const QString &xmlData) { QString errorMsg; int errorLine, errorColumn; QDomDocument document; bool ok = document.setContent(xmlData, &errorMsg, &errorLine, &errorColumn); if (!ok) { qWarning("Error loading document: %s, line %d, column %d", qPrintable(errorMsg), errorLine, errorColumn); return QDomDocument(); } return document; } QDomDocument KolabBase::domTree() { QDomDocument document; const QString p = QStringLiteral("version=\"1.0\" encoding=\"UTF-8\""); document.appendChild(document.createProcessingInstruction(QStringLiteral("xml"), p)); return document; } QString KolabBase::dateTimeToString(const KDateTime &time) { return time.toString(KDateTime::ISODate); } QString KolabBase::dateToString(const QDate &date) { return date.toString(Qt::ISODate); } KDateTime KolabBase::stringToDateTime(const QString &_date) { const QString date(_date); return KDateTime::fromString(date, KDateTime::ISODate); } QDate KolabBase::stringToDate(const QString &date) { return QDate::fromString(date, Qt::ISODate); } QString KolabBase::sensitivityToString(Sensitivity s) { switch (s) { case Private: return QStringLiteral("private"); case Confidential: return QStringLiteral("confidential"); case Public: return QStringLiteral("public"); } return QStringLiteral("What what what???"); } KolabBase::Sensitivity KolabBase::stringToSensitivity(const QString &s) { if (s == QLatin1String("private")) { return Private; } if (s == QLatin1String("confidential")) { return Confidential; } return Public; } QString KolabBase::colorToString(const QColor &color) { // Color is in the format "#RRGGBB" return color.name(); } QColor KolabBase::stringToColor(const QString &s) { return QColor(s); } void KolabBase::writeString(QDomElement &element, const QString &tag, const QString &tagString) { if (!tagString.isEmpty()) { QDomElement e = element.ownerDocument().createElement(tag); QDomText t = element.ownerDocument().createTextNode(tagString); e.appendChild(t); element.appendChild(e); } } -KDateTime KolabBase::localToUTC(const KDateTime &time) const +QDateTime KolabBase::localToUTC(const QDateTime &time) const { - return time.toUtc(); + return time.toUTC(); } -KDateTime KolabBase::utcToLocal(const KDateTime &time) const +QDateTime KolabBase::utcToLocal(const QDateTime &time) const { - KDateTime dt = time; - dt.setTimeSpec(KDateTime::UTC); + QDateTime dt = time; + dt.setTimeSpec(Qt::UTC); return dt; } diff --git a/resources/kolab/pimkolab/kolabformatV2/kolabbase.h b/resources/kolab/pimkolab/kolabformatV2/kolabbase.h index 0e048a124..835b8dfbe 100644 --- a/resources/kolab/pimkolab/kolabformatV2/kolabbase.h +++ b/resources/kolab/pimkolab/kolabformatV2/kolabbase.h @@ -1,182 +1,182 @@ /* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef KOLABV2_KOLABBASE_H #define KOLABV2_KOLABBASE_H #include #include #include #include #include namespace KContacts { class Addressee; class ContactGroup; } namespace KolabV2 { class KolabBase { public: struct Email { public: Email(const QString &name = QString(), const QString &email = QString()) : displayName(name) , smtpAddress(email) { } QString displayName; QString smtpAddress; }; enum Sensitivity { Public = 0, Private = 1, Confidential = 2 }; explicit KolabBase(const QString &time_zone = QString()); virtual ~KolabBase(); // Return a string identifying this type virtual QString type() const = 0; virtual void setUid(const QString &uid); virtual QString uid() const; virtual void setBody(const QString &body); virtual QString body() const; virtual void setCategories(const QString &categories); virtual QString categories() const; virtual void setCreationDate(const KDateTime &date); virtual KDateTime creationDate() const; virtual void setLastModified(const KDateTime &date); virtual KDateTime lastModified() const; virtual void setSensitivity(Sensitivity sensitivity); virtual Sensitivity sensitivity() const; virtual void setPilotSyncId(unsigned long id); virtual bool hasPilotSyncId() const; virtual unsigned long pilotSyncId() const; virtual void setPilotSyncStatus(int status); virtual bool hasPilotSyncStatus() const; virtual int pilotSyncStatus() const; // String - Date conversion methods static QString dateTimeToString(const KDateTime &time); static QString dateToString(const QDate &date); static KDateTime stringToDateTime(const QString &time); static QDate stringToDate(const QString &date); // String - Sensitivity conversion methods static QString sensitivityToString(Sensitivity); static Sensitivity stringToSensitivity(const QString &); // String - Color conversion methods static QString colorToString(const QColor &); static QColor stringToColor(const QString &); // Load this object by reading the XML file bool load(const QString &xml); static QDomDocument loadDocument(const QString &xmlData); // Load this QDomDocument virtual bool loadXML(const QDomDocument &xml) = 0; // Serialize this object to an XML string virtual QString saveXML() const = 0; protected: /// Read all known fields from this ical incidence void setFields(const KCalCore::Incidence::Ptr &); /// Save all known fields into this ical incidence void saveTo(const KCalCore::Incidence::Ptr &) const; /// Read all known fields from this contact void setFields(const KContacts::Addressee *); /// Save all known fields into this contact void saveTo(KContacts::Addressee *) const; /// Read all known fields from this contact group void setFields(const KContacts::ContactGroup *); /// Save all known fields into this contact groupd void saveTo(KContacts::ContactGroup *) const; // This just makes the initial dom tree with version and doctype static QDomDocument domTree(); bool loadEmailAttribute(QDomElement &element, Email &email); void saveEmailAttribute(QDomElement &element, const Email &email, const QString &tagName = QStringLiteral("email")) const; // Load the attributes of this class virtual bool loadAttribute(QDomElement &); // Save the attributes of this class virtual bool saveAttributes(QDomElement &) const; // Return the product ID virtual QString productID() const = 0; // Write a string tag static void writeString(QDomElement &, const QString &, const QString &); - KDateTime localToUTC(const KDateTime &time) const; - KDateTime utcToLocal(const KDateTime &time) const; + QDateTime localToUTC(const QDateTime &time) const; + QDateTime utcToLocal(const QDateTime &time) const; QString mUid; QString mBody; QString mCategories; KDateTime mCreationDate; KDateTime mLastModified; Sensitivity mSensitivity; KTimeZone mTimeZone; // KPilot synchronization stuff bool mHasPilotSyncId, mHasPilotSyncStatus; unsigned long mPilotSyncId; int mPilotSyncStatus; }; } #endif // KOLABV2_KOLABBASE_H diff --git a/resources/kolab/pimkolab/kolabformatV2/task.cpp b/resources/kolab/pimkolab/kolabformatV2/task.cpp index 23285672e..b0e2e866a 100644 --- a/resources/kolab/pimkolab/kolabformatV2/task.cpp +++ b/resources/kolab/pimkolab/kolabformatV2/task.cpp @@ -1,357 +1,357 @@ /* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "task.h" #include "utils/porting.h" #include "pimkolab_debug.h" #include using namespace KolabV2; KCalCore::Todo::Ptr Task::fromXml(const QDomDocument &xmlDoc, const QString &tz) { Task task(tz); task.loadXML(xmlDoc); KCalCore::Todo::Ptr todo(new KCalCore::Todo()); task.saveTo(todo); return todo; } QString Task::taskToXML(const KCalCore::Todo::Ptr &todo, const QString &tz) { Task task(tz, todo); return task.saveXML(); } Task::Task(const QString &tz, const KCalCore::Todo::Ptr &task) : Incidence(tz, task) , mPercentCompleted(0) , mStatus(KCalCore::Incidence::StatusNone) , mHasStartDate(false) , mHasDueDate(false) , mHasCompletedDate(false) { if (task) { setFields(task); } } Task::~Task() { } void Task::setPercentCompleted(int percent) { mPercentCompleted = percent; } int Task::percentCompleted() const { return mPercentCompleted; } void Task::setStatus(KCalCore::Incidence::Status status) { mStatus = status; } KCalCore::Incidence::Status Task::status() const { return mStatus; } void Task::setParent(const QString &parentUid) { mParent = parentUid; } QString Task::parent() const { return mParent; } void Task::setDueDate(const KDateTime &date) { mDueDate = date; mHasDueDate = true; } void Task::setDueDate(const QDate &date) { mDueDate = KDateTime(date); mHasDueDate = true; mFloatingStatus = AllDay; } void Task::setDueDate(const QString &date) { if (date.length() > 10) { // This is a date + time setDueDate(stringToDateTime(date)); } else { // This is only a date setDueDate(stringToDate(date)); } } KDateTime Task::dueDate() const { return mDueDate; } void Task::setHasStartDate(bool v) { mHasStartDate = v; } bool Task::hasStartDate() const { return mHasStartDate; } bool Task::hasDueDate() const { return mHasDueDate; } void Task::setCompletedDate(const KDateTime &date) { mCompletedDate = date; mHasCompletedDate = true; } KDateTime Task::completedDate() const { return mCompletedDate; } bool Task::hasCompletedDate() const { return mHasCompletedDate; } bool Task::loadAttribute(QDomElement &element) { QString tagName = element.tagName(); if (tagName == QLatin1String("completed")) { bool ok; int percent = element.text().toInt(&ok); if (!ok || percent < 0 || percent > 100) { percent = 0; } setPercentCompleted(percent); } else if (tagName == QLatin1String("status")) { if (element.text() == QLatin1String("in-progress")) { setStatus(KCalCore::Incidence::StatusInProcess); } else if (element.text() == QLatin1String("completed")) { setStatus(KCalCore::Incidence::StatusCompleted); } else if (element.text() == QLatin1String("waiting-on-someone-else")) { setStatus(KCalCore::Incidence::StatusNeedsAction); } else if (element.text() == QLatin1String("deferred")) { // Guessing a status here setStatus(KCalCore::Incidence::StatusCanceled); } else { // Default setStatus(KCalCore::Incidence::StatusNone); } } else if (tagName == QLatin1String("due-date")) { setDueDate(element.text()); } else if (tagName == QLatin1String("parent")) { setParent(element.text()); } else if (tagName == QLatin1String("x-completed-date")) { setCompletedDate(stringToDateTime(element.text())); } else if (tagName == QLatin1String("start-date")) { setHasStartDate(true); setStartDate(element.text()); } else { return Incidence::loadAttribute(element); } // We handled this return true; } bool Task::saveAttributes(QDomElement &element) const { // Save the base class elements Incidence::saveAttributes(element); writeString(element, QStringLiteral("completed"), QString::number(percentCompleted())); switch (status()) { case KCalCore::Incidence::StatusInProcess: writeString(element, QStringLiteral("status"), QStringLiteral("in-progress")); break; case KCalCore::Incidence::StatusCompleted: writeString(element, QStringLiteral("status"), QStringLiteral("completed")); break; case KCalCore::Incidence::StatusNeedsAction: writeString(element, QStringLiteral("status"), QStringLiteral("waiting-on-someone-else")); break; case KCalCore::Incidence::StatusCanceled: writeString(element, QStringLiteral("status"), QStringLiteral("deferred")); break; case KCalCore::Incidence::StatusNone: writeString(element, QStringLiteral("status"), QStringLiteral("not-started")); break; case KCalCore::Incidence::StatusTentative: case KCalCore::Incidence::StatusConfirmed: case KCalCore::Incidence::StatusDraft: case KCalCore::Incidence::StatusFinal: case KCalCore::Incidence::StatusX: // All of these are saved as StatusNone. writeString(element, QStringLiteral("status"), QStringLiteral("not-started")); break; } if (hasDueDate()) { if (mFloatingStatus == HasTime) { writeString(element, QStringLiteral("due-date"), dateTimeToString(dueDate())); } else { writeString(element, QStringLiteral("due-date"), dateToString(dueDate().date())); } } if (!parent().isNull()) { writeString(element, QStringLiteral("parent"), parent()); } if (hasCompletedDate() && percentCompleted() == 100) { writeString(element, QStringLiteral("x-completed-date"), dateTimeToString(completedDate())); } return true; } bool Task::loadXML(const QDomDocument &document) { QDomElement top = document.documentElement(); if (top.tagName() != QLatin1String("task")) { qCWarning(PIMKOLAB_LOG) << QStringLiteral("XML error: Top tag was %1 instead of the expected task").arg(top.tagName()); return false; } setHasStartDate(false); // todo's don't necessarily have one for (QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isComment()) { continue; } if (n.isElement()) { QDomElement e = n.toElement(); if (!loadAttribute(e)) { // TODO: Unhandled tag - save for later storage qCDebug(PIMKOLAB_LOG) <<"Warning: Unhandled tag" << e.tagName(); } } else { qCDebug(PIMKOLAB_LOG) <<"Node is not a comment or an element???"; } } return true; } QString Task::saveXML() const { QDomDocument document = domTree(); QDomElement element = document.createElement(QStringLiteral("task")); element.setAttribute(QStringLiteral("version"), QStringLiteral("1.0")); saveAttributes(element); if (!hasStartDate() && startDate().isValid()) { // events and journals always have a start date, but tasks don't. // Remove the entry done by the inherited save above, because we // don't have one. QDomNodeList l = element.elementsByTagName(QStringLiteral("start-date")); Q_ASSERT(l.count() == 1); element.removeChild(l.item(0)); } document.appendChild(element); return document.toString(); } void Task::setFields(const KCalCore::Todo::Ptr &task) { Incidence::setFields(task); setPercentCompleted(task->percentComplete()); setStatus(task->status()); setHasStartDate(task->hasStartDate()); if (task->hasDueDate()) { if (task->allDay()) { // This is a floating task. Don't timezone move this one mFloatingStatus = AllDay; setDueDate(KDateTime(task->dtDue().date())); } else { mFloatingStatus = HasTime; - setDueDate(localToUTC(Porting::q2k(task->dtDue()))); + setDueDate(Porting::q2k(localToUTC(task->dtDue()))); } } else { mHasDueDate = false; } if (!task->relatedTo().isEmpty()) { setParent(task->relatedTo()); } else { setParent(QString()); } if (task->hasCompletedDate() && task->percentComplete() == 100) { - setCompletedDate(localToUTC(Porting::q2k(task->completed()))); + setCompletedDate(Porting::q2k(localToUTC(task->completed()))); } else { mHasCompletedDate = false; } } void Task::saveTo(const KCalCore::Todo::Ptr &task) { Incidence::saveTo(task); task->setPercentComplete(percentCompleted()); task->setStatus(status()); //PORT KF5 task->setHasStartDate( hasStartDate() ); //PORT KF5 task->setHasDueDate( hasDueDate() ); if (hasDueDate()) { - task->setDtDue(Porting::k2q(utcToLocal(dueDate()))); + task->setDtDue(utcToLocal(Porting::k2q(dueDate()))); } if (!parent().isEmpty()) { task->setRelatedTo(parent()); } if (hasCompletedDate() && task->percentComplete() == 100) { - task->setCompleted(Porting::k2q(utcToLocal(mCompletedDate))); + task->setCompleted(utcToLocal(Porting::k2q(mCompletedDate))); } }