diff --git a/autotests/testtodo.cpp b/autotests/testtodo.cpp index 62ec3d5eb..99ae9cdaa 100644 --- a/autotests/testtodo.cpp +++ b/autotests/testtodo.cpp @@ -1,273 +1,316 @@ /* This file is part of the kcalcore library. SPDX-FileCopyrightText: 2006, 2008 Allen Winter SPDX-License-Identifier: LGPL-2.0-or-later */ #include "testtodo.h" #include "todo.h" #include "event.h" #include "attachment.h" #include QTEST_MAIN(TodoTest) using namespace KCalendarCore; void TodoTest::initTestCase() { qputenv("TZ", "GMT"); } void TodoTest::testValidity() { QDate dt = QDate::currentDate(); Todo *todo = new Todo(); todo->setDtStart(QDateTime(dt, {})); todo->setDtDue(QDateTime(dt, {}).addDays(1)); todo->setSummary(QStringLiteral("To-do1 Summary")); todo->setDescription(QStringLiteral("This is a description of the first to-do")); todo->setLocation(QStringLiteral("the place")); todo->setPercentComplete(5); QCOMPARE(todo->summary(), QStringLiteral("To-do1 Summary")); QCOMPARE(todo->location(), QStringLiteral("the place")); QCOMPARE(todo->percentComplete(), 5); } void TodoTest::testCompare() { QDate dt = QDate::currentDate(); Todo todo1; todo1.setDtStart(QDateTime(dt, {})); todo1.setDtDue(QDateTime(dt, {}).addDays(1)); todo1.setSummary(QStringLiteral("To-do1 Summary")); todo1.setDescription(QStringLiteral("This is a description of the first to-do")); todo1.setLocation(QStringLiteral("the place")); todo1.setCompleted(true); Todo todo2; todo2.setDtStart(QDateTime(dt, {}).addDays(1)); todo2.setDtDue(QDateTime(dt, {}).addDays(2)); todo2.setSummary(QStringLiteral("To-do2 Summary")); todo2.setDescription(QStringLiteral("This is a description of the second to-do")); todo2.setLocation(QStringLiteral("the other place")); todo2.setCompleted(false); QVERIFY(!(todo1 == todo2)); QCOMPARE(todo1.dtDue(), todo2.dtStart()); QCOMPARE(todo2.summary(), QStringLiteral("To-do2 Summary")); QVERIFY(!(todo1.isCompleted() == todo2.isCompleted())); } void TodoTest::testClone() { QDate dt = QDate::currentDate(); Todo todo1; todo1.setDtStart(QDateTime(dt, {})); todo1.setDtDue(QDateTime(dt, {}).addDays(1)); todo1.setSummary(QStringLiteral("Todo1 Summary")); todo1.setDescription(QStringLiteral("This is a description of the first todo")); todo1.setLocation(QStringLiteral("the place")); Todo *todo2 = todo1.clone(); QCOMPARE(todo1.summary(), todo2->summary()); QCOMPARE(todo1.dtStart(), todo2->dtStart()); QCOMPARE(todo1.dtDue(), todo2->dtDue()); QCOMPARE(todo1.description(), todo2->description()); QCOMPARE(todo1.location(), todo2->location()); QCOMPARE(todo1.isCompleted(), todo2->isCompleted()); } void TodoTest::testCopyIncidence() { QDate dt = QDate::currentDate(); Event event; event.setDtStart(QDateTime(dt, {})); event.setSummary(QStringLiteral("Event1 Summary")); event.setDescription(QStringLiteral("This is a description of the first event")); event.setLocation(QStringLiteral("the place")); Todo todo(event); QCOMPARE(todo.uid(), event.uid()); QCOMPARE(todo.dtStart(), event.dtStart()); QCOMPARE(todo.summary(), event.summary()); QCOMPARE(todo.description(), event.description()); QCOMPARE(todo.location(), event.location()); } void TodoTest::testAssign() { QDate dt = QDate::currentDate(); Todo todo1; todo1.setDtStart(QDateTime(dt, {})); todo1.setDtDue(QDateTime(dt, {}).addDays(1)); todo1.setSummary(QStringLiteral("Todo1 Summary")); todo1.setDescription(QStringLiteral("This is a description of the first todo")); todo1.setLocation(QStringLiteral("the place")); Todo todo2 = todo1; QVERIFY(todo1 == todo2); } void TodoTest::testSetCompleted() { Todo todo1, todo2, todo3; todo1.setSummary(QStringLiteral("Todo Summary")); todo2.setSummary(QStringLiteral("Todo Summary")); todo3.setSummary(QStringLiteral("Todo Summary")); QDateTime today = QDateTime::currentDateTimeUtc(); // due yesterday QDateTime originalDueDate = today.addDays(-1); todo1.setDtStart(originalDueDate); todo1.setDtDue(originalDueDate); todo1.recurrence()->setDaily(1); todo1.setCompleted(today); todo2.setCompleted(true); todo3.setStatus(Incidence::StatusCompleted); QVERIFY(originalDueDate != todo1.dtDue()); QVERIFY(!todo1.isCompleted()); QVERIFY(todo2.isCompleted()); QCOMPARE(todo2.status(), Incidence::StatusCompleted); QVERIFY(todo3.isCompleted()); todo2.setCompleted(false); QVERIFY(!todo2.isCompleted()); } void TodoTest::testStatus() { QDateTime today = QDateTime::currentDateTimeUtc(); QDateTime yesterday = today.addDays(-1); Todo todo1; todo1.setAllDay(true); todo1.setDtStart(yesterday); todo1.setDtDue(today); todo1.setPercentComplete(50); QVERIFY(todo1.isInProgress(false)); QVERIFY(!todo1.isNotStarted(false)); QVERIFY(!todo1.isOverdue()); todo1.setPercentComplete(100); QVERIFY(todo1.isCompleted()); Todo todo2 = todo1; todo2.setPercentComplete(33); todo2.setDtDue(QDateTime()); QVERIFY(todo2.isOpenEnded()); } void TodoTest::testSerializer_data() { QTest::addColumn("todo"); QDateTime today = QDateTime::currentDateTimeUtc(); QDateTime yesterday = today.addDays(-1); Todo::Ptr todo1 = Todo::Ptr(new Todo()); Todo::Ptr todo2 = Todo::Ptr(new Todo()); Todo::Ptr todo3 = Todo::Ptr(new Todo()); Todo::Ptr todo4 = Todo::Ptr(new Todo()); Todo::Ptr todo5 = Todo::Ptr(new Todo()); Todo::Ptr todo6 = Todo::Ptr(new Todo()); todo1->setSummary(QStringLiteral("Summary"), false); todo1->setDescription(QStringLiteral("description"), false); todo1->setCreated(yesterday); todo1->setRevision(50); todo1->setDtDue(yesterday); todo1->setDtStart(today); todo1->setPercentComplete(50); todo1->setLocation(QStringLiteral("location"), false); todo2->setDescription(QStringLiteral("description"), true); todo2->setSummary(QStringLiteral("Summary2"), true); todo2->setLocation(QStringLiteral("location"), true); todo2->setDtDue(yesterday); todo2->setPercentComplete(100); todo3->setDtStart(today); todo3->setPercentComplete(100); todo3->setCategories(QStringList() << QStringLiteral("a") << QStringLiteral("b") << QStringLiteral("c") << QStringLiteral("d")); todo3->setResources(QStringList() << QStringLiteral("a") << QStringLiteral("b") << QStringLiteral("c") << QStringLiteral("d")); todo3->setPriority(5); QVERIFY(!todo4->dirtyFields().contains(IncidenceBase::FieldRecurrence)); todo4->recurrence()->setDaily(1); QVERIFY(todo4->dirtyFields().contains(IncidenceBase::FieldRecurrence)); Attachment attachment(QStringLiteral("http://www.kde.org")); todo4->addAttachment(attachment); todo5->recurrence()->setDaily(1); todo5->setCompleted(today); todo5->setStatus(Incidence::StatusDraft); todo5->setSecrecy(Incidence::SecrecyPrivate); todo5->setRelatedTo(QStringLiteral("uid1"), Incidence::RelTypeParent); todo5->setHasGeo(true); todo5->setGeoLatitude(40); todo5->setGeoLongitude(40); todo5->setOrganizer(QStringLiteral("organizer@mail.com")); todo6->recurrence()->setDaily(1); todo6->setCompleted(today); todo6->setRecurrenceId(yesterday); todo6->setStatus(Incidence::StatusDraft); todo6->setSecrecy(Incidence::SecrecyPrivate); todo6->setRelatedTo(QStringLiteral("uid1"), Incidence::RelTypeParent); todo6->setHasGeo(true); todo6->setGeoLatitude(40); todo6->setGeoLongitude(40); todo6->setUid(QStringLiteral("uid22")); todo6->setLastModified(today); todo6->addContact(QStringLiteral("addContact")); // Remaining properties tested in testevent.cpp QTest::newRow("todo1") << todo1; QTest::newRow("todo2") << todo2; QTest::newRow("todo3") << todo3; QTest::newRow("todo4") << todo4; QTest::newRow("todo5") << todo5; QTest::newRow("todo6") << todo6; } void TodoTest::testSerializer() { QFETCH(KCalendarCore::Todo::Ptr, todo); IncidenceBase::Ptr incidenceBase = todo.staticCast(); QByteArray array; QDataStream stream(&array, QIODevice::WriteOnly); stream << incidenceBase; Todo::Ptr todo2 = Todo::Ptr(new Todo()); IncidenceBase::Ptr incidenceBase2 = todo2.staticCast(); QVERIFY(*todo != *todo2); QDataStream stream2(&array, QIODevice::ReadOnly); stream2 >> incidenceBase2; QVERIFY(*todo == *todo2); } void TodoTest::testRoles() { const QDateTime today = QDateTime::currentDateTimeUtc(); const QDateTime yesterday = today.addDays(-1); Todo todo; todo.setDtStart(today.addDays(-1)); todo.setDtDue(today); QCOMPARE(todo.dateTime(Incidence::RoleDisplayStart), today); QCOMPARE(todo.dateTime(Incidence::RoleDisplayEnd), today); todo.setDtDue(QDateTime()); QCOMPARE(todo.dateTime(Incidence::RoleDisplayStart), yesterday); QCOMPARE(todo.dateTime(Incidence::RoleDisplayEnd), yesterday); } + +void TodoTest::testIconNameOneoff() +{ + const QDateTime now = QDateTime::currentDateTime(); + Todo todo; + todo.setDtStart(now); + + QCOMPARE(todo.iconName(), QLatin1String("view-calendar-tasks")); + todo.setCompleted(now); + QCOMPARE(todo.iconName(), QLatin1String("task-complete")); +} + +void TodoTest::testIconNameRecurringNeverDue() +{ + const QDateTime now = QDateTime::currentDateTime(); + Todo todo; + todo.setDtStart(now); + todo.recurrence()->setDaily(1); + + QCOMPARE(todo.iconName(now), QLatin1String("view-calendar-tasks")); + + todo.setCompleted(now); + QCOMPARE(todo.iconName(now), QLatin1String("task-complete")); + QCOMPARE(todo.iconName(now.addDays(1)), QLatin1String("view-calendar-tasks")); +} + +void TodoTest::testIconNameRecurringDue() +{ + const QDateTime now = QDateTime::currentDateTime(); + const QDateTime later = now.addSecs(3600); + Todo todo; + todo.setDtStart(now); + todo.setDtDue(later, /*first=*/true); + todo.recurrence()->setDaily(1); + + QCOMPARE(todo.iconName(now), QLatin1String("view-calendar-tasks")); + QCOMPARE(todo.iconName(later), QLatin1String("view-calendar-tasks")); // Legacy case + + todo.setCompleted(now); + QCOMPARE(todo.iconName(now), QLatin1String("task-complete")); + QCOMPARE(todo.iconName(later), QLatin1String("task-complete")); // Legacy case + QCOMPARE(todo.iconName(now.addDays(1)), QLatin1String("view-calendar-tasks")); +} diff --git a/autotests/testtodo.h b/autotests/testtodo.h index f2b4536bf..277c1355b 100644 --- a/autotests/testtodo.h +++ b/autotests/testtodo.h @@ -1,32 +1,35 @@ /* This file is part of the kcalcore library. SPDX-FileCopyrightText: 2006, 2008 Allen Winter SPDX-License-Identifier: LGPL-2.0-or-later */ #ifndef TESTTODO_H #define TESTTODO_H #include class TodoTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testValidity(); void testCompare(); void testClone(); void testCopyIncidence(); void testAssign(); void testSetCompleted(); void testStatus(); void testSerializer_data(); void testSerializer(); void testRoles(); + void testIconNameOneoff(); + void testIconNameRecurringNeverDue(); + void testIconNameRecurringDue(); }; #endif diff --git a/src/todo.cpp b/src/todo.cpp index bdd6a7205..ec8e964ae 100644 --- a/src/todo.cpp +++ b/src/todo.cpp @@ -1,564 +1,564 @@ /* This file is part of the kcalcore library. SPDX-FileCopyrightText: 2001-2003 Cornelius Schumacher SPDX-FileCopyrightText: 2009 Allen Winter SPDX-License-Identifier: LGPL-2.0-or-later */ /** @file This file is part of the API for handling calendar data and defines the Todo class. @brief Provides a To-do in the sense of RFC2445. @author Cornelius Schumacher \ @author Allen Winter \ */ #include "todo.h" #include "visitor.h" #include "recurrence.h" #include "utils_p.h" #include "kcalendarcore_debug.h" #include using namespace KCalendarCore; /** Private class that helps to provide binary compatibility between releases. @internal */ //@cond PRIVATE class Q_DECL_HIDDEN KCalendarCore::Todo::Private { public: Private() {} Private(const KCalendarCore::Todo::Private &other) { init(other); } void init(const KCalendarCore::Todo::Private &other); QDateTime mDtDue; // to-do due date (if there is one) // ALSO the first occurrence of a recurring to-do QDateTime mDtRecurrence; // next occurrence (for recurring to-dos) QDateTime mCompleted; // to-do completion date (if it has been completed) int mPercentComplete = 0; // to-do percent complete [0,100] /** Returns true if the todo got a new date, else false will be returned. */ bool recurTodo(Todo *todo); }; void KCalendarCore::Todo::Private::init(const KCalendarCore::Todo::Private &other) { mDtDue = other.mDtDue; mDtRecurrence = other.mDtRecurrence; mCompleted = other.mCompleted; mPercentComplete = other.mPercentComplete; } //@endcond Todo::Todo() : d(new KCalendarCore::Todo::Private) { } Todo::Todo(const Todo &other) : Incidence(other), d(new KCalendarCore::Todo::Private(*other.d)) { } Todo::Todo(const Incidence &other) : Incidence(other) , d(new KCalendarCore::Todo::Private) { } Todo::~Todo() { delete d; } Todo *Todo::clone() const { return new Todo(*this); } IncidenceBase &Todo::assign(const IncidenceBase &other) { if (&other != this) { Incidence::assign(other); const Todo *t = static_cast(&other); d->init(*(t->d)); } return *this; } bool Todo::equals(const IncidenceBase &todo) const { if (!Incidence::equals(todo)) { return false; } else { // If they weren't the same type IncidenceBase::equals would had returned false already const Todo *t = static_cast(&todo); return ((dtDue() == t->dtDue()) || (!dtDue().isValid() && !t->dtDue().isValid())) && hasDueDate() == t->hasDueDate() && hasStartDate() == t->hasStartDate() && ((completed() == t->completed()) || (!completed().isValid() && !t->completed().isValid())) && hasCompletedDate() == t->hasCompletedDate() && percentComplete() == t->percentComplete(); } } Incidence::IncidenceType Todo::type() const { return TypeTodo; } QByteArray Todo::typeStr() const { return QByteArrayLiteral("Todo"); } void Todo::setDtDue(const QDateTime &dtDue, bool first) { startUpdates(); //int diffsecs = d->mDtDue.secsTo(dtDue); /*if (mReadOnly) return; const Alarm::List& alarms = alarms(); for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next()) { if (alarm->enabled()) { alarm->setTime(alarm->time().addSecs(diffsecs)); } }*/ if (recurs() && !first) { d->mDtRecurrence = dtDue; } else { d->mDtDue = dtDue; } if (recurs() && dtDue.isValid() && (!dtStart().isValid() || dtDue < recurrence()->startDateTime())) { qCDebug(KCALCORE_LOG) << "To-do recurrences are now calculated against DTSTART. Fixing legacy to-do."; setDtStart(dtDue); } /*const Alarm::List& alarms = alarms(); for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next()) alarm->setAlarmStart(d->mDtDue);*/ setFieldDirty(FieldDtDue); endUpdates(); } QDateTime Todo::dtDue(bool first) const { if (!hasDueDate()) { return QDateTime(); } const QDateTime start = IncidenceBase::dtStart(); if (recurs() && !first && d->mDtRecurrence.isValid()) { if (start.isValid()) { // This is the normal case, recurring to-dos have a valid DTSTART. const qint64 duration = start.daysTo(d->mDtDue); QDateTime dt = d->mDtRecurrence.addDays(duration); dt.setTime(d->mDtDue.time()); return dt; } else { // This is a legacy case, where recurrence was calculated against DTDUE return d->mDtRecurrence; } } return d->mDtDue; } bool Todo::hasDueDate() const { return d->mDtDue.isValid(); } bool Todo::hasStartDate() const { return IncidenceBase::dtStart().isValid(); } QDateTime Todo::dtStart() const { return dtStart(/*first=*/false); } QDateTime Todo::dtStart(bool first) const { if (!hasStartDate()) { return QDateTime(); } if (recurs() && !first && d->mDtRecurrence.isValid()) { return d->mDtRecurrence; } else { return IncidenceBase::dtStart(); } } bool Todo::isCompleted() const { return d->mPercentComplete == 100 || status() == StatusCompleted; } void Todo::setCompleted(bool completed) { update(); if (completed) { d->mPercentComplete = 100; setStatus(StatusCompleted); } else { d->mPercentComplete = 0; d->mCompleted = QDateTime(); setStatus(StatusNone); } setFieldDirty(FieldCompleted); setFieldDirty(FieldStatus); updated(); } QDateTime Todo::completed() const { if (hasCompletedDate()) { return d->mCompleted; } else { return QDateTime(); } } void Todo::setCompleted(const QDateTime &completed) { update(); if (!d->recurTodo(this)) { d->mPercentComplete = 100; d->mCompleted = completed.toUTC(); setFieldDirty(FieldCompleted); } updated(); } bool Todo::hasCompletedDate() const { return d->mCompleted.isValid(); } int Todo::percentComplete() const { return d->mPercentComplete; } void Todo::setPercentComplete(int percent) { if (percent > 100) { percent = 100; } else if (percent < 0) { percent = 0; } update(); d->mPercentComplete = percent; if (percent != 100) { d->mCompleted = QDateTime(); } setFieldDirty(FieldPercentComplete); updated(); } bool Todo::isInProgress(bool first) const { if (isOverdue()) { return false; } if (d->mPercentComplete > 0) { return true; } if (hasStartDate() && hasDueDate()) { if (allDay()) { QDate currDate = QDate::currentDate(); if (dtStart(first).date() <= currDate && currDate < dtDue(first).date()) { return true; } } else { QDateTime currDate = QDateTime::currentDateTimeUtc(); if (dtStart(first) <= currDate && currDate < dtDue(first)) { return true; } } } return false; } bool Todo::isOpenEnded() const { if (!hasDueDate() && !isCompleted()) { return true; } return false; } bool Todo::isNotStarted(bool first) const { if (d->mPercentComplete > 0) { return false; } if (!hasStartDate()) { return false; } if (allDay()) { if (dtStart(first).date() >= QDate::currentDate()) { return false; } } else { if (dtStart(first) >= QDateTime::currentDateTimeUtc()) { return false; } } return true; } void Todo::shiftTimes(const QTimeZone &oldZone, const QTimeZone &newZone) { Incidence::shiftTimes(oldZone, newZone); d->mDtDue = d->mDtDue.toTimeZone(oldZone); d->mDtDue.setTimeZone(newZone); if (recurs()) { d->mDtRecurrence = d->mDtRecurrence.toTimeZone(oldZone); d->mDtRecurrence.setTimeZone(newZone); } if (hasCompletedDate()) { d->mCompleted = d->mCompleted.toTimeZone(oldZone); d->mCompleted.setTimeZone(newZone); } } void Todo::setDtRecurrence(const QDateTime &dt) { d->mDtRecurrence = dt; setFieldDirty(FieldRecurrence); } QDateTime Todo::dtRecurrence() const { return d->mDtRecurrence.isValid() ? d->mDtRecurrence : d->mDtDue; } bool Todo::recursOn(const QDate &date, const QTimeZone &timeZone) const { QDate today = QDate::currentDate(); return Incidence::recursOn(date, timeZone) && !(date < today && d->mDtRecurrence.date() < today && d->mDtRecurrence > recurrence()->startDateTime()); } bool Todo::isOverdue() const { if (!dtDue().isValid()) { return false; // if it's never due, it can't be overdue } const bool inPast = allDay() ? dtDue().date() < QDate::currentDate() : dtDue() < QDateTime::currentDateTimeUtc(); return inPast && !isCompleted(); } void Todo::setAllDay(bool allday) { if (allday != allDay() && !mReadOnly) { if (hasDueDate()) { setFieldDirty(FieldDtDue); } Incidence::setAllDay(allday); } } //@cond PRIVATE bool Todo::Private::recurTodo(Todo *todo) { if (todo && todo->recurs()) { Recurrence *r = todo->recurrence(); const QDateTime recurrenceEndDateTime = r->endDateTime(); QDateTime nextOccurrenceDateTime = r->getNextDateTime(todo->dtStart()); if ((r->duration() == -1 || (nextOccurrenceDateTime.isValid() && recurrenceEndDateTime.isValid() && nextOccurrenceDateTime <= recurrenceEndDateTime))) { // We convert to the same timeSpec so we get the correct .date() const auto rightNow = QDateTime::currentDateTimeUtc().toTimeZone(nextOccurrenceDateTime.timeZone()); const bool isDateOnly = todo->allDay(); /* Now we search for the occurrence that's _after_ the currentUtcDateTime, or * if it's dateOnly, the occurrrence that's _during or after today_. * The reason we use "<" for date only, but "<=" for ocurrences with time is that * if it's date only, the user can still complete that ocurrence today, so that's * the current ocurrence that needs completing. */ while (!todo->recursAt(nextOccurrenceDateTime) || (!isDateOnly && nextOccurrenceDateTime <= rightNow) || (isDateOnly && nextOccurrenceDateTime.date() < rightNow.date())) { if (!nextOccurrenceDateTime.isValid() || (nextOccurrenceDateTime > recurrenceEndDateTime && r->duration() != -1)) { return false; } nextOccurrenceDateTime = r->getNextDateTime(nextOccurrenceDateTime); } todo->setDtRecurrence(nextOccurrenceDateTime); todo->setCompleted(false); todo->setRevision(todo->revision() + 1); return true; } } return false; } //@endcond bool Todo::accept(Visitor &v, const IncidenceBase::Ptr &incidence) { return v.visit(incidence.staticCast()); } QDateTime Todo::dateTime(DateTimeRole role) const { switch (role) { case RoleAlarmStartOffset: return dtStart(); case RoleAlarmEndOffset: return dtDue(); case RoleSort: // Sorting to-dos first compares dtDue, then dtStart if // dtDue doesn't exist return hasDueDate() ? dtDue() : dtStart(); case RoleCalendarHashing: return dtDue(); case RoleStartTimeZone: return dtStart(); case RoleEndTimeZone: return dtDue(); case RoleEndRecurrenceBase: return dtDue(); case RoleDisplayStart: case RoleDisplayEnd: return dtDue().isValid() ? dtDue() : dtStart(); case RoleAlarm: if (alarms().isEmpty()) { return QDateTime(); } else { Alarm::Ptr alarm = alarms().at(0); if (alarm->hasStartOffset() && hasStartDate()) { return dtStart(); } else if (alarm->hasEndOffset() && hasDueDate()) { return dtDue(); } else { // The application shouldn't add alarms on to-dos without dates. return QDateTime(); } } case RoleRecurrenceStart: if (dtStart().isValid()) { return dtStart(); } return dtDue(); //For the sake of backwards compatibility //where we calculated recurrences based on dtDue case RoleEnd: return dtDue(); default: return QDateTime(); } } void Todo::setDateTime(const QDateTime &dateTime, DateTimeRole role) { switch (role) { case RoleDnD: setDtDue(dateTime); break; case RoleEnd: setDtDue(dateTime, true); break; default: qCDebug(KCALCORE_LOG) << "Unhandled role" << role; } } void Todo::virtual_hook(VirtualHook id, void *data) { Q_UNUSED(id); Q_UNUSED(data); } QLatin1String Todo::mimeType() const { return Todo::todoMimeType(); } QLatin1String Todo::todoMimeType() { return QLatin1String("application/x-vnd.akonadi.calendar.todo"); } QLatin1String Todo::iconName(const QDateTime &recurrenceId) const { const bool usesCompletedTaskPixmap = isCompleted() || - (recurs() && recurrenceId.isValid() && (recurrenceId < dtDue(false))); + (recurs() && recurrenceId.isValid() && (recurrenceId < dtStart(/*first=*/false))); if (usesCompletedTaskPixmap) { return QLatin1String("task-complete"); } else { return QLatin1String("view-calendar-tasks"); } } void Todo::serialize(QDataStream &out) const { Incidence::serialize(out); serializeQDateTimeAsKDateTime(out, d->mDtDue); serializeQDateTimeAsKDateTime(out, d->mDtRecurrence); serializeQDateTimeAsKDateTime(out, d->mCompleted); out << d->mPercentComplete; } void Todo::deserialize(QDataStream &in) { Incidence::deserialize(in); deserializeKDateTimeAsQDateTime(in, d->mDtDue); deserializeKDateTimeAsQDateTime(in, d->mDtRecurrence); deserializeKDateTimeAsQDateTime(in, d->mCompleted); in >> d->mPercentComplete; } bool Todo::supportsGroupwareCommunication() const { return true; }