diff --git a/autotests/loadcalendar.cpp b/autotests/loadcalendar.cpp index 301d0292b..bfe6980d9 100644 --- a/autotests/loadcalendar.cpp +++ b/autotests/loadcalendar.cpp @@ -1,67 +1,70 @@ /* This file is part of the kcalcore library. Copyright (c) 2003 Cornelius Schumacher This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "filestorage.h" #include "memorycalendar.h" #include #include #include #include using namespace KCalCore; int main(int argc, char **argv) { QCommandLineParser parser; parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("verbose"), QStringLiteral("Verbose output"))); QCoreApplication app(argc, argv); QCoreApplication::setApplicationName(QStringLiteral("testincidence")); QCoreApplication::setApplicationVersion(QStringLiteral("0.1")); parser.process(app); MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc())); FileStorage store(cal, QStringLiteral("cal")); - store.load(); + if (!store.load()) { + qWarning() << "Error storing into memory calendar"; + return 1; + } Todo::List todoList; // Build dictionary to look up Task object from Todo uid. Each task is a // QListViewItem, and is initially added with the view as the parent. todoList = cal->rawTodos(); if (todoList.isEmpty()) { qWarning() << "Error loading calendar"; return 1; } qDebug() << (*todoList.begin())->uid(); QString result = (*todoList.begin())->customProperty(QByteArray("karm"), QByteArray("totalTaskTime")); qDebug() << result; if (result != QStringLiteral("a,b")) { qDebug() << "The string a,b was expected, but given was" << result; return 1; } else { qDebug() << "Test passed"; } } diff --git a/autotests/testattendee.cpp b/autotests/testattendee.cpp index 10e4dcc77..0e4236484 100644 --- a/autotests/testattendee.cpp +++ b/autotests/testattendee.cpp @@ -1,221 +1,221 @@ /* This file is part of the kcalcore library. Copyright (C) 2006,2008 Allen Winter Copyright (C) 2010 Casey Link Copyright (C) 2009-2010 Klaralvdalens Datakonsult AB, a KDAB Group company 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. */ #include "testattendee.h" #include "attendee.h" #include #include QTEST_MAIN(AttendeeTest) using namespace KCalCore; void AttendeeTest::testValidity() { Attendee attendee(QStringLiteral("fred"), QStringLiteral("fred@flintstone.com")); attendee.setRole(Attendee::Chair); QVERIFY(attendee.role() == Attendee::Chair); } void AttendeeTest::testType() { Attendee attendee(QStringLiteral("fred"), QStringLiteral("fred@flintstone.com")); QCOMPARE(attendee.cuType(), Attendee::Individual); QCOMPARE(attendee.cuTypeStr(), QLatin1String("INDIVIDUAL")); attendee.setCuType(attendee.cuTypeStr()); QCOMPARE(attendee.cuType(), Attendee::Individual); attendee.setCuType(QStringLiteral("INVALID")); QCOMPARE(attendee.cuType(), Attendee::Unknown); QCOMPARE(attendee.cuTypeStr(), QLatin1String("UNKNOWN")); attendee.setCuType(QStringLiteral("group")); QCOMPARE(attendee.cuType(), Attendee::Group); QCOMPARE(attendee.cuTypeStr(), QLatin1String("GROUP")); attendee.setCuType(QStringLiteral("resource")); QCOMPARE(attendee.cuType(), Attendee::Resource); QCOMPARE(attendee.cuTypeStr(), QLatin1String("RESOURCE")); attendee.setCuType(QStringLiteral("ROOM")); QCOMPARE(attendee.cuType(), Attendee::Room); QCOMPARE(attendee.cuTypeStr(), QLatin1String("ROOM")); attendee.setCuType(QStringLiteral("UNKNOWN")); QCOMPARE(attendee.cuType(), Attendee::Unknown); QCOMPARE(attendee.cuTypeStr(), QLatin1String("UNKNOWN")); attendee.setCuType(QStringLiteral("X-test")); QCOMPARE(attendee.cuType(), Attendee::Unknown); QCOMPARE(attendee.cuTypeStr(), QLatin1String("X-TEST")); attendee.setCuType(QStringLiteral("IANA-TEST")); QCOMPARE(attendee.cuType(), Attendee::Unknown); QCOMPARE(attendee.cuTypeStr(), QLatin1String("IANA-TEST")); attendee.setCuType(Attendee::Individual); QCOMPARE(attendee.cuType(), Attendee::Individual); attendee.setCuType(Attendee::Group); QCOMPARE(attendee.cuType(), Attendee::Group); attendee.setCuType(Attendee::Resource); QCOMPARE(attendee.cuType(), Attendee::Resource); attendee.setCuType(Attendee::Room); QCOMPARE(attendee.cuType(), Attendee::Room); attendee.setCuType(Attendee::Unknown); QCOMPARE(attendee.cuType(), Attendee::Unknown); } void AttendeeTest::testCompare() { Attendee attendee1(QStringLiteral("fred"), QStringLiteral("fred@flintstone.com")); Attendee attendee2(QStringLiteral("wilma"), QStringLiteral("wilma@flintstone.com")); attendee1.setRole(Attendee::ReqParticipant); attendee2.setRole(Attendee::Chair); QVERIFY(!(attendee1 == attendee2)); attendee2.setRole(Attendee::ReqParticipant); QVERIFY(!(attendee1 == attendee2)); QVERIFY(attendee1.name() == QLatin1String("fred")); } void AttendeeTest::testCompareType() { Attendee attendee1(QStringLiteral("fred"), QStringLiteral("fred@flintstone.com")); attendee1.setCuType(Attendee::Resource); Attendee attendee2 = attendee1; QCOMPARE(attendee2.cuType(), Attendee::Resource); QVERIFY(attendee1 == attendee2); attendee2.setCuType(Attendee::Individual); QVERIFY(!(attendee1 == attendee2)); } void AttendeeTest::testAssign() { Attendee attendee1(QStringLiteral("fred"), QStringLiteral("fred@flintstone.com")); Attendee attendee2 = attendee1; QVERIFY(attendee1 == attendee2); attendee2.setRole(Attendee::NonParticipant); QVERIFY(!(attendee1 == attendee2)); Attendee attendee3(attendee1); QVERIFY(attendee3 == attendee1); } void AttendeeTest::testDataStreamOut() { Attendee::Ptr attendee1(new Attendee(QStringLiteral("fred"), QStringLiteral("fred@flintstone.com"))); attendee1->setRSVP(true); attendee1->setRole(Attendee::Chair); attendee1->setUid(QStringLiteral("Shooby Doo Bop")); attendee1->setDelegate(QStringLiteral("I AM THE Delegate")); attendee1->setDelegator(QStringLiteral("AND I AM THE Delegator")); attendee1->setCuType(QStringLiteral("X-SPECIAL")); attendee1->setCustomProperty("name", QStringLiteral("value")); attendee1->setCustomProperty("foo", QStringLiteral("bar")); QByteArray byteArray; QDataStream out_stream(&byteArray, QIODevice::WriteOnly); out_stream << attendee1; QDataStream in_stream(&byteArray, QIODevice::ReadOnly); Person::Ptr person; bool rsvp; - QString name, email, delegate, delegator, cuType, uid; + QString delegate, delegator, cuType, uid; CustomProperties customProperties; Attendee::Role role; Attendee::PartStat status; uint role_int, status_int; in_stream >> person; QVERIFY(person->name() == attendee1->name()); QVERIFY(person->email() == attendee1->email()); in_stream >> rsvp; QVERIFY(rsvp == attendee1->RSVP()); in_stream >> role_int; role = Attendee::Role(role_int); QVERIFY(role == attendee1->role()); in_stream >> status_int; status = Attendee::PartStat(status_int); QVERIFY(status == attendee1->status()); in_stream >> uid; QVERIFY(uid == attendee1->uid()); in_stream >> delegate; QVERIFY(delegate == attendee1->delegate()); in_stream >> delegator; QVERIFY(delegator == attendee1->delegator()); in_stream >> cuType; QVERIFY(cuType == attendee1->cuTypeStr()); in_stream >> customProperties; QVERIFY(customProperties == attendee1->customProperties()); } void AttendeeTest::testDataStreamIn() { Attendee::Ptr attendee1(new Attendee(QStringLiteral("fred"), QStringLiteral("fred@flintstone.com"))); attendee1->setRSVP(true); attendee1->setRole(Attendee::Chair); attendee1->setCuType(QStringLiteral("IANA-FOO")); attendee1->setUid(QStringLiteral("Shooby Doo Bop")); attendee1->setDelegate(QStringLiteral("I AM THE Delegate")); attendee1->setDelegator(QStringLiteral("AND I AM THE Delegator")); attendee1->setCustomProperty("name", QStringLiteral("value")); attendee1->setCustomProperty("foo", QStringLiteral("bar")); QByteArray byteArray; QDataStream out_stream(&byteArray, QIODevice::WriteOnly); out_stream << attendee1; Attendee::Ptr attendee2; QDataStream in_stream(&byteArray, QIODevice::ReadOnly); in_stream >> attendee2; QVERIFY(attendee2); QVERIFY(attendee2->uid() == attendee1->uid()); QVERIFY(attendee2->RSVP() == attendee1->RSVP()); QVERIFY(attendee2->role() == attendee1->role()); QVERIFY(attendee2->cuTypeStr() == attendee1->cuTypeStr()); QVERIFY(attendee2->status() == attendee1->status()); QVERIFY(attendee2->delegate() == attendee1->delegate()); QVERIFY(attendee2->delegator() == attendee1->delegator()); QVERIFY(attendee2->customProperties() == attendee1->customProperties()); QVERIFY(*attendee1 == *attendee2); } diff --git a/autotests/testcreateddatecompat.cpp b/autotests/testcreateddatecompat.cpp index e3e22d55a..738915585 100644 --- a/autotests/testcreateddatecompat.cpp +++ b/autotests/testcreateddatecompat.cpp @@ -1,85 +1,85 @@ /* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "testcreateddatecompat.h" #include "icalformat.h" #include "memorycalendar.h" #include #include #include //"X-KDE-ICAL-IMPLEMENTATION-VERSION:1.0\n" const char *const icalFile32 = "BEGIN:VCALENDAR\n" "PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN\n" "VERSION:2.0\n" "BEGIN:VEVENT\n" "DTSTAMP:20031213T204753Z\n" "ORGANIZER:MAILTO:nobody@nowhere\n" "CREATED:20031213T204152Z\n" "UID:uid\n" "SEQUENCE:0\n" "LAST-MODIFIED:20031213T204152Z\n" "SUMMARY:Holladiho\n" "DTSTART:20031213T071500Z\n" "END:VEVENT\n" "END:VCALENDAR\n"; const char *const icalFile33 = "BEGIN:VCALENDAR\n" "PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN\n" "VERSION:2.0\n" "X-KDE-ICAL-IMPLEMENTATION-VERSION:1.0\n" "BEGIN:VEVENT\n" "DTSTAMP:20031213T204753Z\n" "ORGANIZER:MAILTO:nobody@nowhere\n" "CREATED:20031213T204152Z\n" "UID:uid\n" "SEQUENCE:0\n" "LAST-MODIFIED:20031213T204152Z\n" "SUMMARY:Holladiho\n" "DTSTART:20031213T071500Z\n" "END:VEVENT\n" "END:VCALENDAR\n"; void CreatedDateCompatTest::testCompat32() { KCalCore::MemoryCalendar::Ptr cal(new KCalCore::MemoryCalendar(QTimeZone::utc())); KCalCore::ICalFormat format; - format.fromRawString(cal, QByteArray(icalFile32)); + QVERIFY(format.fromRawString(cal, QByteArray(icalFile32))); KCalCore::Event::Ptr event = cal->event(QStringLiteral("uid")); QVERIFY(event); QCOMPARE(event->created(), QDateTime(QDate(2003, 12, 13), QTime(20, 47, 53), Qt::UTC)); } void CreatedDateCompatTest::testCompat33() { KCalCore::MemoryCalendar::Ptr cal(new KCalCore::MemoryCalendar(QTimeZone::utc())); KCalCore::ICalFormat format; - format.fromRawString(cal, QByteArray(icalFile33)); + QVERIFY(format.fromRawString(cal, QByteArray(icalFile33))); KCalCore::Event::Ptr event = cal->event(QStringLiteral("uid")); QVERIFY(event); QCOMPARE(event->created(), QDateTime(QDate(2003, 12, 13), QTime(20, 41, 52), Qt::UTC)); QVERIFY(!event->customProperties().contains("X-KDE-ICAL-IMPLEMENTATION-VERSION")); } QTEST_MAIN(CreatedDateCompatTest) diff --git a/autotests/testfreebusy.cpp b/autotests/testfreebusy.cpp index 8e1282286..f83d8ec5a 100644 --- a/autotests/testfreebusy.cpp +++ b/autotests/testfreebusy.cpp @@ -1,111 +1,113 @@ /* This file is part of the kcalcore library. Copyright (c) 2007-2008 Allen Winter 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. */ #include "testfreebusy.h" #include "freebusy.h" #include QTEST_MAIN(FreeBusyTest) using namespace KCalCore; void FreeBusyTest::testValidity() { const QDateTime firstDateTime(QDate(2007, 7, 23), QTime(7, 0, 0), Qt::UTC); FreeBusy fb1(firstDateTime, QDateTime(QDate(2007, 7, 23), QTime(8, 0, 0), Qt::UTC)); QCOMPARE(fb1.dtEnd(), QDateTime(QDate(2007, 7, 23), QTime(8, 0, 0), Qt::UTC)); } void FreeBusyTest::testAddSort() { Period::List periods; const QDateTime firstq1DateTime(QDate(2007, 7, 23), QTime(7, 0, 0), Qt::UTC); Period q1(firstq1DateTime, QDateTime(QDate(2007, 7, 23), QTime(8, 0, 0), Qt::UTC)); periods.append(q1); const QDateTime firstq2DateTime(QDate(2007, 8, 23), QTime(7, 0, 0), Qt::UTC); Period q2(firstq2DateTime, QDateTime(QDate(2007, 8, 23), QTime(8, 0, 0), Qt::UTC)); periods.append(q2); const QDateTime firstq3DateTime(QDate(2007, 9, 23), QTime(7, 0, 0), Qt::UTC); Period q3(firstq3DateTime, QDateTime(QDate(2007, 9, 23), QTime(8, 0, 0), Qt::UTC)); periods.append(q3); FreeBusy fb1; fb1.addPeriods(periods); const QDateTime firstfb1DateTime(QDate(2007, 10, 27), QTime(7, 0, 0), Qt::UTC); fb1.addPeriod(firstfb1DateTime, QDateTime(QDate(2007, 10, 27), QTime(8, 0, 0), Qt::UTC)); const QDateTime secondfb1DateTime(QDate(2007, 8, 27), QTime(7, 0, 0), Qt::UTC); fb1.addPeriod(secondfb1DateTime, QDateTime(QDate(2007, 8, 27), QTime(8, 0, 0), Qt::UTC)); const QDateTime thirdfb1DateTime(QDate(2007, 6, 27), QTime(7, 0, 0), Qt::UTC); fb1.addPeriod(thirdfb1DateTime, QDateTime(QDate(2007, 6, 27), QTime(8, 0, 0), Qt::UTC)); - QCOMPARE(fb1.busyPeriods().last().end(), QDateTime(QDate(2007, 10, 27), QTime(8, 0, 0), Qt::UTC)); + Period::List busyPeriods = fb1.busyPeriods(); + QVERIFY(!busyPeriods.isEmpty()); + QCOMPARE(busyPeriods.last().end(), QDateTime(QDate(2007, 10, 27), QTime(8, 0, 0), Qt::UTC)); } void FreeBusyTest::testAssign() { const QDateTime firstDateTime(QDate(2007, 7, 23), QTime(7, 0, 0), Qt::UTC); FreeBusy fb1(firstDateTime, QDateTime(QDate(2007, 7, 23), QTime(8, 0, 0), Qt::UTC)); FreeBusy fb2 = fb1; QCOMPARE(fb1, fb2); fb1.setDtStart(firstDateTime.addDays(1)); fb2.setDtStart(firstDateTime.addDays(2)); QVERIFY(!(fb1 == fb2)); FreeBusy fb3 = fb2; QCOMPARE(fb3, fb2); QDateTime dt = fb3.dtEnd(); fb3.setDtEnd(dt.addDays(1)); fb2.setDtEnd(dt.addDays(1)); QCOMPARE(fb2, fb3); } void FreeBusyTest::testDataStream() { const QDateTime firstDateTime(QDate(2007, 7, 23), QTime(7, 0, 0), Qt::UTC); FreeBusy::Ptr fb1(new FreeBusy(firstDateTime, QDateTime(QDate(2007, 7, 23), QTime(8, 0, 0), Qt::UTC))); QByteArray byteArray; QDataStream out_stream(&byteArray, QIODevice::WriteOnly); out_stream << fb1; QDataStream in_stream(&byteArray, QIODevice::ReadOnly); FreeBusy::Ptr fb2; in_stream >> fb2; QCOMPARE(fb1->dtEnd(), fb2->dtEnd()); QCOMPARE(fb1->busyPeriods(), fb2->busyPeriods()); // QVERIFY( *fb1 == *fb2 ); } diff --git a/autotests/testicalformat.cpp b/autotests/testicalformat.cpp index 5d7c99137..a251a0d67 100644 --- a/autotests/testicalformat.cpp +++ b/autotests/testicalformat.cpp @@ -1,152 +1,152 @@ /* This file is part of the kcalcore library. Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sergio Martins 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. */ #include "testicalformat.h" #include "event.h" #include "icalformat.h" #include "memorycalendar.h" #include #include #include QTEST_MAIN(ICalFormatTest) using namespace KCalCore; void ICalFormatTest::testCharsets() { ICalFormat format; const QDate currentDate = QDate::currentDate(); Event::Ptr event = Event::Ptr(new Event()); event->setUid(QStringLiteral("12345")); event->setDtStart(QDateTime(currentDate, {})); event->setDtEnd(QDateTime(currentDate.addDays(1), {})); event->setAllDay(true); // ü const QChar latin1_umlaut[] = { 0xFC, QLatin1Char('\0') }; event->setSummary(QString(latin1_umlaut)); // Test if toString( Incidence ) didn't mess charsets const QString serialized = format.toString(event.staticCast()); const QChar utf_umlaut[] = { 0xC3, 0XBC, QLatin1Char('\0') }; QVERIFY(serialized.toUtf8().contains(QString(utf_umlaut).toLatin1().constData())); QVERIFY(!serialized.toUtf8().contains(QString(latin1_umlaut).toLatin1().constData())); QVERIFY(serialized.toLatin1().contains(QString(latin1_umlaut).toLatin1().constData())); QVERIFY(!serialized.toLatin1().contains(QString(utf_umlaut).toLatin1().constData())); // test fromString( QString ) const QString serializedCalendar = QLatin1String("BEGIN:VCALENDAR\nPRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN\nVERSION:2.0\n") +serialized +QLatin1String("\nEND:VCALENDAR"); Incidence::Ptr event2 = format.fromString(serializedCalendar); QVERIFY(event->summary() == event2->summary()); QVERIFY(event2->summary().toUtf8() == QByteArray(QString(utf_umlaut).toLatin1().constData())); // test save() MemoryCalendar::Ptr calendar(new MemoryCalendar(QTimeZone::utc())); calendar->addIncidence(event); QVERIFY(format.save(calendar, QLatin1String("hommer.ics"))); // Make sure hommer.ics is in UTF-8 QFile file(QStringLiteral("hommer.ics")); QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); const QByteArray bytesFromFile = file.readAll(); QVERIFY(bytesFromFile.contains(QString(utf_umlaut).toLatin1().constData())); QVERIFY(!bytesFromFile.contains(QString(latin1_umlaut).toLatin1().constData())); file.close(); // Test load: MemoryCalendar::Ptr calendar2(new MemoryCalendar(QTimeZone::utc())); QVERIFY(format.load(calendar2, QLatin1String("hommer.ics"))); QVERIFY(calendar2->incidences().count() == 1); // qDebug() << format.toString( event.staticCast() ); // qDebug() << format.toString( calendar2->incidences().at(0) ); Event::Ptr loadedEvent = calendar2->incidences().at(0).staticCast(); QVERIFY(loadedEvent->summary().toUtf8() == QByteArray(QString(utf_umlaut).toLatin1().constData())); QVERIFY(*loadedEvent == *event); // Test fromRawString() MemoryCalendar::Ptr calendar3(new MemoryCalendar(QTimeZone::utc())); - format.fromRawString(calendar3, bytesFromFile); + QVERIFY(format.fromRawString(calendar3, bytesFromFile)); QVERIFY(calendar3->incidences().count() == 1); QVERIFY(*calendar3->incidences().at(0) == *event); QFile::remove(QStringLiteral("hommer.ics")); } void ICalFormatTest::testVolatileProperties() { // Volatile properties are not written to the serialized data ICalFormat format; const QDate currentDate = QDate::currentDate(); Event::Ptr event = Event::Ptr(new Event()); event->setUid(QStringLiteral("12345")); event->setDtStart(QDateTime(currentDate, {})); event->setDtEnd(QDateTime(currentDate.addDays(1), {})); event->setAllDay(true); event->setCustomProperty("VOLATILE", "FOO", QStringLiteral("BAR")); QString string = format.toICalString(event); Incidence::Ptr incidence = format.fromString(string); QCOMPARE(incidence->uid(), QStringLiteral("12345")); QVERIFY(incidence->customProperties().isEmpty()); } void ICalFormatTest::testCuType() { ICalFormat format; const QDate currentDate = QDate::currentDate(); Event::Ptr event(new Event()); event->setUid(QStringLiteral("12345")); event->setDtStart(QDateTime(currentDate, {})); event->setDtEnd(QDateTime(currentDate.addDays(1), {})); event->setAllDay(true); Attendee::Ptr attendee(new Attendee(QStringLiteral("fred"), QStringLiteral("fred@flintstone.com"))); attendee->setCuType(Attendee::Resource); event->addAttendee(attendee); const QString serialized = format.toString(event.staticCast()); // test fromString(QString) const QString serializedCalendar = QLatin1String("BEGIN:VCALENDAR\nPRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN\nVERSION:2.0\n") +serialized +QLatin1String("\nEND:VCALENDAR"); Incidence::Ptr event2 = format.fromString(serializedCalendar); QVERIFY(event2->attendeeCount() == 1); Attendee::Ptr attendee2 = event2->attendees()[0]; QVERIFY(attendee2->cuType() == attendee->cuType()); QVERIFY(attendee2->name() == attendee->name()); QVERIFY(attendee2->email() == attendee->email()); } diff --git a/autotests/testoccurrenceiterator.cpp b/autotests/testoccurrenceiterator.cpp index 701d59cbb..417cbd097 100644 --- a/autotests/testoccurrenceiterator.cpp +++ b/autotests/testoccurrenceiterator.cpp @@ -1,302 +1,298 @@ /* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "testoccurrenceiterator.h" #include "occurrenceiterator.h" #include "memorycalendar.h" #include "calfilter.h" #include #include #include QTEST_MAIN(TestOccurrenceIterator) void TestOccurrenceIterator::testIterationWithExceptions() { KCalCore::MemoryCalendar calendar(QTimeZone::utc()); QDateTime start(QDate(2013, 03, 10), QTime(10, 0, 0), Qt::UTC); QDateTime end(QDate(2013, 03, 10), QTime(11, 0, 0), Qt::UTC); QDateTime recurrenceId(QDate(2013, 03, 11), QTime(10, 0, 0), Qt::UTC); QDateTime exceptionStart(QDate(2013, 03, 11), QTime(12, 0, 0), Qt::UTC); QDateTime exceptionEnd(QDate(2013, 03, 11), QTime(13, 0, 0), Qt::UTC); QDateTime actualEnd(QDate(2013, 03, 12), QTime(11, 0, 0), Qt::UTC); KCalCore::Event::Ptr event1(new KCalCore::Event()); event1->setUid(QStringLiteral("event1")); event1->setSummary(QStringLiteral("event1")); event1->setDtStart(start); event1->setDtEnd(end); event1->recurrence()->setDaily(1); calendar.addEvent(event1); KCalCore::Event::Ptr exception(new KCalCore::Event()); exception->setUid(event1->uid()); exception->setSummary(QStringLiteral("exception")); exception->setRecurrenceId(recurrenceId); exception->setDtStart(exceptionStart); exception->setDtEnd(exceptionEnd); calendar.addEvent(exception); int occurrence = 0; KCalCore::OccurrenceIterator rIt(calendar, start, actualEnd); while (rIt.hasNext()) { rIt.next(); occurrence++; if (occurrence == 1) { QCOMPARE(rIt.occurrenceStartDate(), start); QCOMPARE(rIt.incidence()->summary(), event1->summary()); } if (occurrence == 2) { QCOMPARE(rIt.occurrenceStartDate(), exceptionStart); QCOMPARE(rIt.incidence()->summary(), exception->summary()); } if (occurrence == 3) { QCOMPARE(rIt.occurrenceStartDate(), start.addDays(2)); QCOMPARE(rIt.incidence()->summary(), event1->summary()); } // qDebug() << occurrence; // qDebug() << "occurrence: " << rIt.occurrenceStartDate().toString(); // qDebug() << "uid: " << rIt.incidence()->uid(); // qDebug() << "summary: " << rIt.incidence()->summary(); // qDebug() << "start: " << rIt.incidence()->dtStart().toString(); // qDebug(); } QCOMPARE(occurrence, 3); } void TestOccurrenceIterator::testEventsAndTodos() { KCalCore::MemoryCalendar calendar(QTimeZone::utc()); QDateTime start(QDate(2013, 03, 10), QTime(10, 0, 0), Qt::UTC); - QDateTime end(QDate(2013, 03, 10), QTime(11, 0, 0), Qt::UTC); - QDateTime actualEnd(QDate(2013, 03, 13), QTime(11, 0, 0), Qt::UTC); KCalCore::Event::Ptr event(new KCalCore::Event()); event->setUid(QStringLiteral("event")); event->setDtStart(start); event->recurrence()->setDaily(1); event->recurrence()->setDuration(2); calendar.addEvent(event); KCalCore::Todo::Ptr todo(new KCalCore::Todo()); todo->setUid(QStringLiteral("todo")); todo->setDtStart(start); todo->recurrence()->setDaily(1); todo->recurrence()->setDuration(2); calendar.addTodo(todo); KCalCore::OccurrenceIterator rIt(calendar, start, actualEnd); QList expectedTodoOccurrences; expectedTodoOccurrences << start << start.addDays(1); QList expectedEventOccurrences; expectedEventOccurrences << start << start.addDays(1); while (rIt.hasNext()) { rIt.next(); qDebug() << rIt.occurrenceStartDate().toString(); if (rIt.incidence()->type() == KCalCore::Incidence::TypeTodo) { QCOMPARE(expectedTodoOccurrences.removeAll(rIt.occurrenceStartDate()), 1); } else { QCOMPARE(expectedEventOccurrences.removeAll(rIt.occurrenceStartDate()), 1); } } QCOMPARE(expectedTodoOccurrences.size(), 0); QCOMPARE(expectedEventOccurrences.size(), 0); } void TestOccurrenceIterator::testFilterCompletedTodos() { KCalCore::MemoryCalendar calendar(QTimeZone::utc()); calendar.filter()->setCriteria(KCalCore::CalFilter::HideCompletedTodos); QDateTime start(QDate(2013, 03, 10), QTime(10, 0, 0), Qt::UTC); - QDateTime end(QDate(2013, 03, 10), QTime(11, 0, 0), Qt::UTC); - QDateTime actualEnd(QDate(2013, 03, 13), QTime(11, 0, 0), Qt::UTC); KCalCore::Todo::Ptr todo(new KCalCore::Todo()); todo->setUid(QStringLiteral("todo")); todo->setDtDue(start); todo->setDtStart(start); todo->recurrence()->setDaily(1); todo->recurrence()->setDuration(2); // Yes, recurring todos are weird... setting this says that all occurrences // until this one have been completed, and thus should be skipped. // that's what kontact did, so it's what we test now. todo->setDtRecurrence(start.addDays(2)); calendar.addTodo(todo); KCalCore::OccurrenceIterator rIt(calendar, start, actualEnd); QVERIFY(!rIt.hasNext()); } void TestOccurrenceIterator::testAllDayEvents() { KCalCore::MemoryCalendar calendar(QTimeZone::utc()); QDateTime start(QDate(2013, 03, 10), QTime(), Qt::UTC); QDateTime actualEnd(QDate(2013, 03, 13), QTime(11, 0, 0), Qt::UTC); KCalCore::Event::Ptr event(new KCalCore::Event()); event->setUid(QStringLiteral("event")); event->setDtStart(start); event->setAllDay(true); event->recurrence()->setDaily(1); event->recurrence()->setDuration(2); calendar.addEvent(event); KCalCore::OccurrenceIterator rIt(calendar, start, actualEnd); QList expectedEventOccurrences; expectedEventOccurrences << start << start.addDays(1); while (rIt.hasNext()) { rIt.next(); qDebug() << rIt.occurrenceStartDate().toString(); QCOMPARE(expectedEventOccurrences.removeAll(rIt.occurrenceStartDate()), 1); } QCOMPARE(expectedEventOccurrences.size(), 0); } void TestOccurrenceIterator::testWithExceptionThisAndFuture() { KCalCore::MemoryCalendar calendar(QTimeZone::utc()); QDateTime start(QDate(2013, 03, 10), QTime(10, 0, 0), Qt::UTC); QDateTime end(QDate(2013, 03, 10), QTime(11, 0, 0), Qt::UTC); QDateTime recurrenceId1(QDate(2013, 03, 11), QTime(10, 0, 0), Qt::UTC); QDateTime exceptionStart1(QDate(2013, 03, 11), QTime(12, 0, 0), Qt::UTC); QDateTime exceptionEnd1(QDate(2013, 03, 11), QTime(13, 0, 0), Qt::UTC); QDateTime recurrenceId2(QDate(2013, 03, 13), QTime(10, 0, 0), Qt::UTC); QDateTime exceptionStart2(QDate(2013, 03, 13), QTime(14, 0, 0), Qt::UTC); QDateTime exceptionEnd2(QDate(2013, 03, 13), QTime(15, 0, 0), Qt::UTC); QDateTime actualEnd(QDate(2013, 03, 14), QTime(11, 0, 0), Qt::UTC); KCalCore::Event::Ptr event1(new KCalCore::Event()); event1->setUid(QStringLiteral("event1")); event1->setSummary(QStringLiteral("event1")); event1->setDtStart(start); event1->setDtEnd(end); event1->recurrence()->setDaily(1); calendar.addEvent(event1); KCalCore::Event::Ptr exception1(new KCalCore::Event()); exception1->setUid(event1->uid()); exception1->setSummary(QStringLiteral("exception1")); exception1->setRecurrenceId(recurrenceId1); exception1->setThisAndFuture(true); exception1->setDtStart(exceptionStart1); exception1->setDtEnd(exceptionEnd1); calendar.addEvent(exception1); KCalCore::Event::Ptr exception2(new KCalCore::Event()); exception2->setUid(event1->uid()); exception2->setSummary(QStringLiteral("exception2")); exception2->setRecurrenceId(recurrenceId2); exception2->setDtStart(exceptionStart2); exception2->setDtEnd(exceptionEnd2); calendar.addEvent(exception2); int occurrence = 0; KCalCore::OccurrenceIterator rIt(calendar, start, actualEnd); while (rIt.hasNext()) { rIt.next(); occurrence++; // qDebug() << occurrence; // qDebug() << "occurrence: " << rIt.occurrenceStartDate().toString(); // qDebug() << "uid: " << rIt.incidence()->uid(); // qDebug() << "summary: " << rIt.incidence()->summary(); // qDebug() << "start: " << rIt.incidence()->dtStart().toString(); // qDebug(); QCOMPARE(rIt.recurrenceId(), start.addDays(occurrence - 1)); if (occurrence == 1) { QCOMPARE(rIt.occurrenceStartDate(), start); QCOMPARE(rIt.incidence()->summary(), event1->summary()); } if (occurrence == 2) { QCOMPARE(rIt.occurrenceStartDate(), exceptionStart1); QCOMPARE(rIt.incidence()->summary(), exception1->summary()); } if (occurrence == 3) { QCOMPARE(rIt.occurrenceStartDate(), exceptionStart1.addDays(1)); QCOMPARE(rIt.incidence()->summary(), exception1->summary()); } if (occurrence == 4) { QCOMPARE(rIt.occurrenceStartDate(), exceptionStart2); QCOMPARE(rIt.incidence()->summary(), exception2->summary()); } if (occurrence == 5) { QCOMPARE(rIt.occurrenceStartDate(), exceptionStart1.addDays(3)); QCOMPARE(rIt.incidence()->summary(), exception1->summary()); } } QCOMPARE(occurrence, 5); } void TestOccurrenceIterator::testSubDailyRecurrences() { KCalCore::MemoryCalendar calendar(QTimeZone::utc()); QDateTime start(QDate(2013, 03, 10), QTime(10, 0, 0), Qt::UTC); QDateTime actualEnd(QDate(2013, 03, 10), QTime(13, 0, 0), Qt::UTC); KCalCore::Event::Ptr event(new KCalCore::Event()); event->setUid(QStringLiteral("event")); event->setDtStart(start); event->recurrence()->setHourly(1); event->recurrence()->setDuration(2); calendar.addEvent(event); KCalCore::OccurrenceIterator rIt(calendar, start, actualEnd); QList expectedEventOccurrences; expectedEventOccurrences << start << start.addSecs(60 * 60); while (rIt.hasNext()) { rIt.next(); qDebug() << rIt.occurrenceStartDate().toString(); QCOMPARE(expectedEventOccurrences.removeAll(rIt.occurrenceStartDate()), 1); } QCOMPARE(expectedEventOccurrences.size(), 0); } void TestOccurrenceIterator::testJournals() { KCalCore::MemoryCalendar calendar(QTimeZone::utc()); const QDateTime today = QDateTime::currentDateTimeUtc(); const QDateTime yesterday = today.addDays(-1); const QDateTime tomorrow = today.addDays(1); KCalCore::Journal::Ptr journal(new KCalCore::Journal()); journal->setUid(QStringLiteral("journal")); journal->setDtStart(today); calendar.addJournal(journal); KCalCore::OccurrenceIterator rIt(calendar, yesterday, tomorrow); QVERIFY(rIt.hasNext()); rIt.next(); QCOMPARE(rIt.occurrenceStartDate(), today); QVERIFY(!rIt.hasNext()); KCalCore::OccurrenceIterator rIt2(calendar, tomorrow, tomorrow.addDays(1)); QVERIFY(!rIt2.hasNext()); } diff --git a/src/memorycalendar.cpp b/src/memorycalendar.cpp index df5e9ee94..5e9ec346c 100644 --- a/src/memorycalendar.cpp +++ b/src/memorycalendar.cpp @@ -1,873 +1,872 @@ /* This file is part of the kcalcore library. Copyright (c) 1998 Preston Brown Copyright (c) 2001,2003,2004 Cornelius Schumacher Copyright (C) 2003-2004 Reinhold Kainhofer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** @file This file is part of the API for handling calendar data and defines the MemoryCalendar class. @brief This class provides a calendar stored as a local file. @author Preston Brown \ @author Cornelius Schumacher \ */ #include "memorycalendar.h" #include "kcalcore_debug.h" #include "utils.h" #include "calformat.h" #include template static QVector values(const QMultiHash &c) { QVector v; v.reserve(c.size()); for (typename QMultiHash::const_iterator it = c.begin(), end = c.end(); it != end; ++it) { v.push_back(it.value()); } return v; } template static QVector values(const QMultiHash &c, const K &x) { QVector v; typename QMultiHash::const_iterator it = c.find(x); while (it != c.end() && it.key() == x) { v.push_back(it.value()); ++it; } return v; } using namespace KCalCore; /** Private class that helps to provide binary compatibility between releases. @internal */ //@cond PRIVATE class Q_DECL_HIDDEN KCalCore::MemoryCalendar::Private { public: Private(MemoryCalendar *qq) : q(qq), mFormat(nullptr) { } ~Private() { } MemoryCalendar *q; CalFormat *mFormat; // calendar format QString mIncidenceBeingUpdated; // Instance identifier of Incidence currently being updated /** * List of all incidences. * First indexed by incidence->type(), then by incidence->uid(); */ QMap > mIncidences; /** * Has all incidences, indexed by identifier. */ QHash mIncidencesByIdentifier; /** * List of all deleted incidences. * First indexed by incidence->type(), then by incidence->uid(); */ QMap > mDeletedIncidences; /** * Contains incidences ( to-dos; non-recurring, non-multiday events; journals; ) * indexed by start/due date. * * The QMap key is the incidence->type(). * The QMultiHash key is the dtStart/dtDue().toString() * * Note: We had 3 variables, mJournalsForDate, mTodosForDate and mEventsForDate * but i merged them into one (indexed by type) because it simplifies code using * it. No need to if else based on type. */ QMap > mIncidencesForDate; void insertIncidence(const Incidence::Ptr &incidence); Incidence::Ptr incidence(const QString &uid, const IncidenceBase::IncidenceType type, const QDateTime &recurrenceId = {}) const; Incidence::Ptr deletedIncidence(const QString &uid, const QDateTime &recurrenceId, const IncidenceBase::IncidenceType type) const; void deleteAllIncidences(const IncidenceBase::IncidenceType type); }; //@endcond MemoryCalendar::MemoryCalendar(const QTimeZone &timeZone) : Calendar(timeZone), d(new KCalCore::MemoryCalendar::Private(this)) { } MemoryCalendar::MemoryCalendar(const QByteArray &timeZoneId) : Calendar(timeZoneId), d(new KCalCore::MemoryCalendar::Private(this)) { } MemoryCalendar::~MemoryCalendar() { close(); delete d; } void MemoryCalendar::close() { setObserversEnabled(false); // Don't call the virtual function deleteEvents() etc, the base class might have // other ways of deleting the data. d->deleteAllIncidences(Incidence::TypeEvent); d->deleteAllIncidences(Incidence::TypeTodo); d->deleteAllIncidences(Incidence::TypeJournal); d->mIncidencesByIdentifier.clear(); d->mDeletedIncidences.clear(); setModified(false); setObserversEnabled(true); } bool MemoryCalendar::deleteIncidence(const Incidence::Ptr &incidence) { // Handle orphaned children // relations is an Incidence's property, not a Todo's, so // we remove relations in deleteIncidence, not in deleteTodo. removeRelations(incidence); const Incidence::IncidenceType type = incidence->type(); const QString uid = incidence->uid(); if (d->mIncidences[type].contains(uid, incidence)) { // Notify while the incidence is still available, // this is necessary so korganizer still has time to query for exceptions notifyIncidenceAboutToBeDeleted(incidence); d->mIncidences[type].remove(uid, incidence); d->mIncidencesByIdentifier.remove(incidence->instanceIdentifier()); setModified(true); if (deletionTracking()) { d->mDeletedIncidences[type].insert(uid, incidence); } const QDateTime dt = incidence->dateTime(Incidence::RoleCalendarHashing); if (dt.isValid()) { d->mIncidencesForDate[type].remove(dt.date().toString(), incidence); } // Delete child-incidences. if (!incidence->hasRecurrenceId()) { deleteIncidenceInstances(incidence); } notifyIncidenceDeleted(incidence); return true; } else { qCWarning(KCALCORE_LOG) << incidence->typeStr() << " not found. uid=" << uid; return false; } } bool MemoryCalendar::deleteIncidenceInstances(const Incidence::Ptr &incidence) { const Incidence::IncidenceType type = incidence->type(); Incidence::List values = ::values(d->mIncidences[type], incidence->uid()); for (auto it = values.constBegin(); it != values.constEnd(); ++it) { Incidence::Ptr i = *it; if (i->hasRecurrenceId()) { qCDebug(KCALCORE_LOG) << "deleting child" << ", type=" << int(type) << ", uid=" << i->uid() // << ", start=" << i->dtStart() << " from calendar"; deleteIncidence(i); } } return true; } //@cond PRIVATE void MemoryCalendar::Private::deleteAllIncidences(const Incidence::IncidenceType incidenceType) { QHashIteratori(mIncidences[incidenceType]); while (i.hasNext()) { i.next(); q->notifyIncidenceAboutToBeDeleted(i.value()); i.value()->unRegisterObserver(q); } mIncidences[incidenceType].clear(); mIncidencesForDate[incidenceType].clear(); } Incidence::Ptr MemoryCalendar::Private::incidence(const QString &uid, const Incidence::IncidenceType type, const QDateTime &recurrenceId) const { Incidence::List values = ::values(mIncidences[type], uid); for (auto it = values.constBegin(); it != values.constEnd(); ++it) { Incidence::Ptr i = *it; if (recurrenceId.isNull()) { if (!i->hasRecurrenceId()) { return i; } } else { if (i->hasRecurrenceId() && i->recurrenceId() == recurrenceId) { return i; } } } return Incidence::Ptr(); } Incidence::Ptr MemoryCalendar::Private::deletedIncidence(const QString &uid, const QDateTime &recurrenceId, const IncidenceBase::IncidenceType type) const { if (!q->deletionTracking()) { return Incidence::Ptr(); } Incidence::List values = ::values(mDeletedIncidences[type], uid); for (auto it = values.constBegin(); it != values.constEnd(); ++it) { Incidence::Ptr i = *it; if (recurrenceId.isNull()) { if (!i->hasRecurrenceId()) { return i; } } else { if (i->hasRecurrenceId() && i->recurrenceId() == recurrenceId) { return i; } } } return Incidence::Ptr(); } void MemoryCalendar::Private::insertIncidence(const Incidence::Ptr &incidence) { const QString uid = incidence->uid(); const Incidence::IncidenceType type = incidence->type(); if (!mIncidences[type].contains(uid, incidence)) { mIncidences[type].insert(uid, incidence); mIncidencesByIdentifier.insert(incidence->instanceIdentifier(), incidence); const QDateTime dt = incidence->dateTime(Incidence::RoleCalendarHashing); if (dt.isValid()) { mIncidencesForDate[type].insert(dt.date().toString(), incidence); } } else { #ifndef NDEBUG // if we already have an to-do with this UID, it must be the same incidence, // otherwise something's really broken Q_ASSERT(mIncidences[type].value(uid) == incidence); #endif } } //@endcond bool MemoryCalendar::addIncidence(const Incidence::Ptr &incidence) { d->insertIncidence(incidence); notifyIncidenceAdded(incidence); incidence->registerObserver(this); setupRelations(incidence); setModified(true); return true; } bool MemoryCalendar::addEvent(const Event::Ptr &event) { return addIncidence(event); } bool MemoryCalendar::deleteEvent(const Event::Ptr &event) { return deleteIncidence(event); } bool MemoryCalendar::deleteEventInstances(const Event::Ptr &event) { return deleteIncidenceInstances(event); } Event::Ptr MemoryCalendar::event(const QString &uid, const QDateTime &recurrenceId) const { return d->incidence(uid, Incidence::TypeEvent, recurrenceId).staticCast(); } Event::Ptr MemoryCalendar::deletedEvent(const QString &uid, const QDateTime &recurrenceId) const { return d->deletedIncidence(uid, recurrenceId, Incidence::TypeEvent).staticCast(); } bool MemoryCalendar::addTodo(const Todo::Ptr &todo) { return addIncidence(todo); } bool MemoryCalendar::deleteTodo(const Todo::Ptr &todo) { return deleteIncidence(todo); } bool MemoryCalendar::deleteTodoInstances(const Todo::Ptr &todo) { return deleteIncidenceInstances(todo); } Todo::Ptr MemoryCalendar::todo(const QString &uid, const QDateTime &recurrenceId) const { return d->incidence(uid, Incidence::TypeTodo, recurrenceId).staticCast(); } Todo::Ptr MemoryCalendar::deletedTodo(const QString &uid, const QDateTime &recurrenceId) const { return d->deletedIncidence(uid, recurrenceId, Incidence::TypeTodo).staticCast(); } Todo::List MemoryCalendar::rawTodos(TodoSortField sortField, SortDirection sortDirection) const { Todo::List todoList; todoList.reserve(d->mIncidences[Incidence::TypeTodo].count()); QHashIteratori(d->mIncidences[Incidence::TypeTodo]); while (i.hasNext()) { i.next(); todoList.append(i.value().staticCast()); } return Calendar::sortTodos(todoList, sortField, sortDirection); } Todo::List MemoryCalendar::deletedTodos(TodoSortField sortField, SortDirection sortDirection) const { if (!deletionTracking()) { return Todo::List(); } Todo::List todoList; todoList.reserve(d->mDeletedIncidences[Incidence::TypeTodo].count()); QHashIteratori(d->mDeletedIncidences[Incidence::TypeTodo]); while (i.hasNext()) { i.next(); todoList.append(i.value().staticCast()); } return Calendar::sortTodos(todoList, sortField, sortDirection); } Todo::List MemoryCalendar::todoInstances(const Incidence::Ptr &todo, TodoSortField sortField, SortDirection sortDirection) const { Todo::List list; Incidence::List values = ::values(d->mIncidences[Incidence::TypeTodo], todo->uid()); for (auto it = values.constBegin(); it != values.constEnd(); ++it) { Todo::Ptr t = (*it).staticCast(); if (t->hasRecurrenceId()) { list.append(t); } } return Calendar::sortTodos(list, sortField, sortDirection); } Todo::List MemoryCalendar::rawTodosForDate(const QDate &date) const { Todo::List todoList; Todo::Ptr t; const QString dateStr = date.toString(); QMultiHash::const_iterator it = d->mIncidencesForDate[Incidence::TypeTodo].constFind(dateStr); while (it != d->mIncidencesForDate[Incidence::TypeTodo].constEnd() && it.key() == dateStr) { t = it.value().staticCast(); todoList.append(t); ++it; } // Iterate over all todos. Look for recurring todoss that occur on this date QHashIteratori(d->mIncidences[Incidence::TypeTodo]); while (i.hasNext()) { i.next(); t = i.value().staticCast(); if (t->recurs()) { if (t->recursOn(date, timeZone())) { todoList.append(t); } } } return todoList; } Todo::List MemoryCalendar::rawTodos(const QDate &start, const QDate &end, const QTimeZone &timeZone, bool inclusive) const { Q_UNUSED(inclusive); // use only exact dtDue/dtStart, not dtStart and dtEnd Todo::List todoList; const auto ts = timeZone.isValid() ? timeZone : this->timeZone(); QDateTime st(start, QTime(0, 0, 0), ts); QDateTime nd(end, QTime(23, 59, 59, 999), ts); // Get todos QHashIteratori(d->mIncidences[Incidence::TypeTodo]); Todo::Ptr todo; while (i.hasNext()) { i.next(); todo = i.value().staticCast(); if (!isVisible(todo)) { continue; } QDateTime rStart = todo->hasDueDate() ? todo->dtDue() : todo->hasStartDate() ? todo->dtStart() : QDateTime(); if (!rStart.isValid()) { continue; } if (!todo->recurs()) { // non-recurring todos if (nd.isValid() && nd < rStart) { continue; } if (st.isValid() && rStart < st) { continue; } } else { // recurring events switch (todo->recurrence()->duration()) { case -1: // infinite break; case 0: // end date given default: // count given QDateTime rEnd(todo->recurrence()->endDate(), QTime(23, 59, 59, 999), ts); if (!rEnd.isValid()) { continue; } if (st.isValid() && rEnd < st) { continue; } break; } // switch(duration) } //if(recurs) todoList.append(todo); } return todoList; } Alarm::List MemoryCalendar::alarmsTo(const QDateTime &to) const { return alarms(QDateTime(QDate(1900, 1, 1), QTime(0, 0, 0)), to); } Alarm::List MemoryCalendar::alarms(const QDateTime &from, const QDateTime &to, bool excludeBlockedAlarms) const { Q_UNUSED(excludeBlockedAlarms); Alarm::List alarmList; QHashIteratorie(d->mIncidences[Incidence::TypeEvent]); Event::Ptr e; while (ie.hasNext()) { ie.next(); e = ie.value().staticCast(); if (e->recurs()) { appendRecurringAlarms(alarmList, e, from, to); } else { appendAlarms(alarmList, e, from, to); } } QHashIteratorit(d->mIncidences[Incidence::TypeTodo]); Todo::Ptr t; while (it.hasNext()) { it.next(); t = it.value().staticCast(); if (!t->isCompleted()) { appendAlarms(alarmList, t, from, to); if (t->recurs()) { appendRecurringAlarms(alarmList, t, from, to); } else { appendAlarms(alarmList, t, from, to); } } } return alarmList; } void MemoryCalendar::incidenceUpdate(const QString &uid, const QDateTime &recurrenceId) { Incidence::Ptr inc = incidence(uid, recurrenceId); if (inc) { if (!d->mIncidenceBeingUpdated.isEmpty()) { qCWarning(KCALCORE_LOG) << "Incidence::update() called twice without an updated() call in between."; } // Save it so we can detect changes to uid or recurringId. d->mIncidenceBeingUpdated = inc->instanceIdentifier(); const QDateTime dt = inc->dateTime(Incidence::RoleCalendarHashing); if (dt.isValid()) { const Incidence::IncidenceType type = inc->type(); d->mIncidencesForDate[type].remove(dt.date().toString(), inc); } } } void MemoryCalendar::incidenceUpdated(const QString &uid, const QDateTime &recurrenceId) { Incidence::Ptr inc = incidence(uid, recurrenceId); if (inc) { if (d->mIncidenceBeingUpdated.isEmpty()) { qCWarning(KCALCORE_LOG) << "Incidence::updated() called twice without an update() call in between."; } else if (inc->instanceIdentifier() != d->mIncidenceBeingUpdated) { // Instance identifier changed, update our hash table d->mIncidencesByIdentifier.remove(d->mIncidenceBeingUpdated); d->mIncidencesByIdentifier.insert(inc->instanceIdentifier(), inc); } d->mIncidenceBeingUpdated = QString(); inc->setLastModified(QDateTime::currentDateTimeUtc()); // we should probably update the revision number here, // or internally in the Event itself when certain things change. // need to verify with ical documentation. const QDateTime dt = inc->dateTime(Incidence::RoleCalendarHashing); if (dt.isValid()) { const Incidence::IncidenceType type = inc->type(); d->mIncidencesForDate[type].insert(dt.date().toString(), inc); } notifyIncidenceChanged(inc); setModified(true); } } Event::List MemoryCalendar::rawEventsForDate(const QDate &date, const QTimeZone &timeZone, EventSortField sortField, SortDirection sortDirection) const { Event::List eventList; if (!date.isValid()) { // There can't be events on invalid dates return eventList; } Event::Ptr ev; // Find the hash for the specified date const QString dateStr = date.toString(); QMultiHash::const_iterator it = d->mIncidencesForDate[Incidence::TypeEvent].constFind(dateStr); // Iterate over all non-recurring, single-day events that start on this date const auto ts = timeZone.isValid() ? timeZone : this->timeZone(); while (it != d->mIncidencesForDate[Incidence::TypeEvent].constEnd() && it.key() == dateStr) { ev = it.value().staticCast(); QDateTime end(ev->dtEnd().toTimeZone(ev->dtStart().timeZone())); if (ev->allDay()) { end.setTime(QTime()); } else { end = end.addSecs(-1); } if (end.date() >= date) { eventList.append(ev); } ++it; } // Iterate over all events. Look for recurring events that occur on this date QHashIteratori(d->mIncidences[Incidence::TypeEvent]); while (i.hasNext()) { i.next(); ev = i.value().staticCast(); if (ev->recurs()) { if (ev->isMultiDay()) { int extraDays = ev->dtStart().date().daysTo(ev->dtEnd().date()); for (int i = 0; i <= extraDays; ++i) { if (ev->recursOn(date.addDays(-i), ts)) { eventList.append(ev); break; } } } else { if (ev->recursOn(date, ts)) { eventList.append(ev); } } } else { if (ev->isMultiDay()) { if (ev->dtStart().date() <= date && ev->dtEnd().date() >= date) { eventList.append(ev); } } } } return Calendar::sortEvents(eventList, sortField, sortDirection); } Event::List MemoryCalendar::rawEvents(const QDate &start, const QDate &end, const QTimeZone &timeZone, bool inclusive) const { Event::List eventList; const auto ts = timeZone.isValid() ? timeZone : this->timeZone(); QDateTime st(start, QTime(0, 0, 0), ts); QDateTime nd(end, QTime(23, 59, 59, 999), ts); - QDateTime yesterStart = st.addDays(-1); // Get non-recurring events QHashIteratori(d->mIncidences[Incidence::TypeEvent]); Event::Ptr event; while (i.hasNext()) { i.next(); event = i.value().staticCast(); QDateTime rStart = event->dtStart(); if (nd < rStart) { continue; } if (inclusive && rStart < st) { continue; } if (!event->recurs()) { // non-recurring events QDateTime rEnd = event->dtEnd(); if (rEnd < st) { continue; } if (inclusive && nd < rEnd) { continue; } } else { // recurring events switch (event->recurrence()->duration()) { case -1: // infinite if (inclusive) { continue; } break; case 0: // end date given default: // count given QDateTime rEnd(event->recurrence()->endDate(), QTime(23, 59, 59, 999), ts); if (!rEnd.isValid()) { continue; } if (rEnd < st) { continue; } if (inclusive && nd < rEnd) { continue; } break; } // switch(duration) } //if(recurs) eventList.append(event); } return eventList; } Event::List MemoryCalendar::rawEventsForDate(const QDateTime &kdt) const { return rawEventsForDate(kdt.date(), kdt.timeZone()); } Event::List MemoryCalendar::rawEvents(EventSortField sortField, SortDirection sortDirection) const { Event::List eventList; eventList.reserve(d->mIncidences[Incidence::TypeEvent].count()); QHashIterator i(d->mIncidences[Incidence::TypeEvent]); while (i.hasNext()) { i.next(); eventList.append(i.value().staticCast()); } return Calendar::sortEvents(eventList, sortField, sortDirection); } Event::List MemoryCalendar::deletedEvents(EventSortField sortField, SortDirection sortDirection) const { if (!deletionTracking()) { return Event::List(); } Event::List eventList; eventList.reserve(d->mDeletedIncidences[Incidence::TypeEvent].count()); QHashIteratori(d->mDeletedIncidences[Incidence::TypeEvent]); while (i.hasNext()) { i.next(); eventList.append(i.value().staticCast()); } return Calendar::sortEvents(eventList, sortField, sortDirection); } Event::List MemoryCalendar::eventInstances(const Incidence::Ptr &event, EventSortField sortField, SortDirection sortDirection) const { Event::List list; Incidence::List values = ::values(d->mIncidences[Incidence::TypeEvent], event->uid()); for (auto it = values.constBegin(); it != values.constEnd(); ++it) { Event::Ptr ev = (*it).staticCast(); if (ev->hasRecurrenceId()) { list.append(ev); } } return Calendar::sortEvents(list, sortField, sortDirection); } bool MemoryCalendar::addJournal(const Journal::Ptr &journal) { return addIncidence(journal); } bool MemoryCalendar::deleteJournal(const Journal::Ptr &journal) { return deleteIncidence(journal); } bool MemoryCalendar::deleteJournalInstances(const Journal::Ptr &journal) { return deleteIncidenceInstances(journal); } Journal::Ptr MemoryCalendar::journal(const QString &uid, const QDateTime &recurrenceId) const { return d->incidence(uid, Incidence::TypeJournal, recurrenceId).staticCast(); } Journal::Ptr MemoryCalendar::deletedJournal(const QString &uid, const QDateTime &recurrenceId) const { return d->deletedIncidence(uid, recurrenceId, Incidence::TypeJournal).staticCast(); } Journal::List MemoryCalendar::rawJournals(JournalSortField sortField, SortDirection sortDirection) const { Journal::List journalList; QHashIteratori(d->mIncidences[Incidence::TypeJournal]); while (i.hasNext()) { i.next(); journalList.append(i.value().staticCast()); } return Calendar::sortJournals(journalList, sortField, sortDirection); } Journal::List MemoryCalendar::deletedJournals(JournalSortField sortField, SortDirection sortDirection) const { if (!deletionTracking()) { return Journal::List(); } Journal::List journalList; journalList.reserve(d->mDeletedIncidences[Incidence::TypeJournal].count()); QHashIteratori(d->mDeletedIncidences[Incidence::TypeJournal]); while (i.hasNext()) { i.next(); journalList.append(i.value().staticCast()); } return Calendar::sortJournals(journalList, sortField, sortDirection); } Journal::List MemoryCalendar::journalInstances(const Incidence::Ptr &journal, JournalSortField sortField, SortDirection sortDirection) const { Journal::List list; Incidence::List values = ::values(d->mIncidences[Incidence::TypeJournal], journal->uid()); for (auto it = values.constBegin(); it != values.constEnd(); ++it) { Journal::Ptr j = (*it).staticCast(); if (j->hasRecurrenceId()) { list.append(j); } } return Calendar::sortJournals(list, sortField, sortDirection); } Journal::List MemoryCalendar::rawJournalsForDate(const QDate &date) const { Journal::List journalList; Journal::Ptr j; QString dateStr = date.toString(); QMultiHash::const_iterator it = d->mIncidencesForDate[Incidence::TypeJournal].constFind(dateStr); while (it != d->mIncidencesForDate[Incidence::TypeJournal].constEnd() && it.key() == dateStr) { j = it.value().staticCast(); journalList.append(j); ++it; } return journalList; } Incidence::Ptr MemoryCalendar::instance(const QString &identifier) const { return d->mIncidencesByIdentifier.value(identifier); } void MemoryCalendar::virtual_hook(int id, void *data) { Q_UNUSED(id); Q_UNUSED(data); Q_ASSERT(false); }