Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kcalendarcore for openSUSE:Factory checked in at 2022-04-11 23:46:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kcalendarcore (Old) and /work/SRC/openSUSE:Factory/.kcalendarcore.new.1900 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kcalendarcore" Mon Apr 11 23:46:48 2022 rev:31 rq:968143 version:5.93.0 Changes: -------- --- /work/SRC/openSUSE:Factory/kcalendarcore/kcalendarcore.changes 2022-03-14 19:35:25.566008383 +0100 +++ /work/SRC/openSUSE:Factory/.kcalendarcore.new.1900/kcalendarcore.changes 2022-04-11 23:48:00.775914340 +0200 @@ -1,0 +2,18 @@ +Sun Apr 3 10:47:01 UTC 2022 - Christophe Giboudeaux <[email protected]> + +- Update to 5.93.0 + * New feature release + * For more details please see: + * https://kde.org/announcements/frameworks/5/5.93.0 +- Changes since 5.92.0: + * Notify on notebook change for exceptions. + * Note use of low-level libical function + * Print more information about errors when loading vCalendars + * Implement notebook association when parsing iCal data. + * Correct a comment + * Fix storing of times with UTC offsets + * Second attempt to make testTodoCompletedOnce work all year + * Revert "Don't use the current date for recurring todo completion test" + * Compare QDateTime times, timespecs, and timezones + +------------------------------------------------------------------- Old: ---- kcalendarcore-5.92.0.tar.xz kcalendarcore-5.92.0.tar.xz.sig New: ---- kcalendarcore-5.93.0.tar.xz kcalendarcore-5.93.0.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kcalendarcore.spec ++++++ --- /var/tmp/diff_new_pack.Qsw4Zv/_old 2022-04-11 23:48:03.083887958 +0200 +++ /var/tmp/diff_new_pack.Qsw4Zv/_new 2022-04-11 23:48:03.091887866 +0200 @@ -16,14 +16,14 @@ # -%define _tar_path 5.92 +%define _tar_path 5.93 # Full KF5 version (e.g. 5.33.0) %{!?_kf5_version: %global _kf5_version %{version}} # Last major and minor KF5 version (e.g. 5.33) %{!?_kf5_bugfix_version: %define _kf5_bugfix_version %(echo %{_kf5_version} | awk -F. '{print $1"."$2}')} %bcond_without released Name: kcalendarcore -Version: 5.92.0 +Version: 5.93.0 Release: 0 Summary: Library to access and handle calendar data License: LGPL-2.0-or-later ++++++ kcalendarcore-5.92.0.tar.xz -> kcalendarcore-5.93.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/CMakeLists.txt new/kcalendarcore-5.93.0/CMakeLists.txt --- old/kcalendarcore-5.92.0/CMakeLists.txt 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/CMakeLists.txt 2022-04-02 11:55:43.000000000 +0200 @@ -1,11 +1,11 @@ cmake_minimum_required(VERSION 3.16) -set(KF_VERSION "5.92.0") # handled by release scripts +set(KF_VERSION "5.93.0") # handled by release scripts project(KCalendarCore VERSION ${KF_VERSION}) # ECM setup include(FeatureSummary) -find_package(ECM 5.92.0 NO_MODULE) +find_package(ECM 5.93.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/autotests/CMakeLists.txt new/kcalendarcore-5.93.0/autotests/CMakeLists.txt --- old/kcalendarcore-5.92.0/autotests/CMakeLists.txt 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/autotests/CMakeLists.txt 2022-04-02 11:55:43.000000000 +0200 @@ -30,6 +30,7 @@ testfreebusy testincidencerelation testicalformat + testidentical testjournal testmemorycalendar testperiod diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/autotests/testdateserialization.cpp new/kcalendarcore-5.93.0/autotests/testdateserialization.cpp --- old/kcalendarcore-5.92.0/autotests/testdateserialization.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/autotests/testdateserialization.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -50,7 +50,7 @@ // See bug 345565. void TestDateSerialization::testTodoCompletedOnce() { - QDateTime startDate = QDate(2022, 1, 27).startOfDay(); + QDateTime startDate = QDate(QDate::currentDate().year(), QDate::currentDate().month(), 1).startOfDay(); QDateTime dueDate{startDate.addDays(1)}; Todo::Ptr todo(new Todo); @@ -80,3 +80,26 @@ QCOMPARE(todo->dtDue(true), dueDate); QCOMPARE(todo->dtDue(false), dueDate.addMonths(1)); } + +// Check that QDateTime values with UTC offsets are handled correctly +void TestDateSerialization::testUTCOffset() +{ + QDateTime startDate({2022, 3, 6}, {10, 25}, Qt::OffsetFromUTC, 3600); + + Event::Ptr event(new Event); + event->setDtStart(startDate); + + MemoryCalendar::Ptr cal{new MemoryCalendar(QTimeZone::utc())}; + cal->addIncidence(event); + + ICalFormat format; + QString result = format.toString(cal, QString()); + + Incidence::Ptr i = format.fromString(result); + QVERIFY(i); + QCOMPARE(i->dtStart(), startDate); + // Qt::OffsetFromUTC is turned into Qt::Timezone with a "UTC+/-X" timezone right now + // but Qt::OffsetFromUTC would be equally correct here should this ever change in the future + QCOMPARE(i->dtStart().timeSpec(), Qt::TimeZone); + QCOMPARE(i->dtStart().timeZone().offsetFromUtc(i->dtStart()), 3600); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/autotests/testdateserialization.h new/kcalendarcore-5.93.0/autotests/testdateserialization.h --- old/kcalendarcore-5.92.0/autotests/testdateserialization.h 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/autotests/testdateserialization.h 2022-04-02 11:55:43.000000000 +0200 @@ -14,6 +14,7 @@ private Q_SLOTS: void testNewRecurringTodo(); void testTodoCompletedOnce(); + void testUTCOffset(); }; #endif // TESTDATESERIALIZATION_H diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/autotests/testicalformat.cpp new/kcalendarcore-5.93.0/autotests/testicalformat.cpp --- old/kcalendarcore-5.92.0/autotests/testicalformat.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/autotests/testicalformat.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -350,3 +350,42 @@ QVERIFY(event); QCOMPARE(dtStart, event->dtStart()); } + +void ICalFormatTest::testNotebook() +{ + Event::Ptr event(new Event); + event->setDtStart(QDateTime(QDate(2022, 3, 21), QTime(8, 49), Qt::UTC)); + Todo::Ptr todo(new Todo); + todo->setDtStart(QDateTime(QDate(2022, 3, 21), QTime(8, 49), Qt::UTC)); + Journal::Ptr journal(new Journal); + journal->setDtStart(QDateTime(QDate(2022, 3, 21), QTime(8, 49), Qt::UTC)); + MemoryCalendar::Ptr calendar(new MemoryCalendar(QTimeZone::utc())); + QVERIFY(calendar->addEvent(event)); + QVERIFY(calendar->addTodo(todo)); + QVERIFY(calendar->addJournal(journal)); + + ICalFormat format; + const QString data = format.toString(calendar, QString()); + QVERIFY(!format.exception()); + + calendar->close(); + QVERIFY(!calendar->event(event->uid(), event->recurrenceId())); + QVERIFY(!calendar->todo(todo->uid(), todo->recurrenceId())); + QVERIFY(!calendar->journal(journal->uid(), journal->recurrenceId())); + + const QString notebook(QString::fromLatin1("my-imported-notebook")); + QVERIFY(calendar->addNotebook(notebook, true)); + QVERIFY(format.fromString(calendar, data, false, notebook)); + + Event::Ptr reloadedEvent = calendar->event(event->uid(), event->recurrenceId()); + QVERIFY(reloadedEvent); + Todo::Ptr reloadedTodo = calendar->todo(todo->uid(), todo->recurrenceId()); + QVERIFY(reloadedTodo); + Journal::Ptr reloadedJournal = calendar->journal(journal->uid(), journal->recurrenceId()); + QVERIFY(reloadedJournal); + + QCOMPARE(calendar->incidences(notebook).length(), 3); + QCOMPARE(calendar->notebook(reloadedEvent), notebook); + QCOMPARE(calendar->notebook(reloadedTodo), notebook); + QCOMPARE(calendar->notebook(reloadedJournal), notebook); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/autotests/testicalformat.h new/kcalendarcore-5.93.0/autotests/testicalformat.h --- old/kcalendarcore-5.92.0/autotests/testicalformat.h 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/autotests/testicalformat.h 2022-04-02 11:55:43.000000000 +0200 @@ -26,6 +26,7 @@ void testRDate(); void testDateTime_data(); void testDateTime(); + void testNotebook(); }; #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/autotests/testidentical.cpp new/kcalendarcore-5.93.0/autotests/testidentical.cpp --- old/kcalendarcore-5.92.0/autotests/testidentical.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/kcalendarcore-5.93.0/autotests/testidentical.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -0,0 +1,71 @@ +/* + * SPDX-FileCopyrightText: 2022 Glen Ditchfield <[email protected]> + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +#include "incidencebase.h" + +#include <QTest> +#include <QTimeZone> + +using namespace KCalendarCore; + +class TestIdentical: public QObject +{ + Q_OBJECT +private Q_SLOTS: + + void testTrue() + { + QVERIFY( + identical(QDateTime(QDate(2022, 02, 22), QTime(22, 22, 22), Qt::LocalTime), + QDateTime(QDate(2022, 02, 22), QTime(22, 22, 22), Qt::LocalTime))); + + QVERIFY( + identical(QDateTime(QDate(2022, 02, 22), QTime(22, 22, 22), QTimeZone("Atlantic/Azores")), + QDateTime(QDate(2022, 02, 22), QTime(22, 22, 22), QTimeZone("Atlantic/Azores")))); + + QVERIFY(identical(QDateTime(), QDateTime())); + } + + void testFalse_data() + { + QTest::addColumn<QDateTime>("dt1"); + QTest::addColumn<QDateTime>("dt2"); + + QTest::newRow("date") + << QDateTime(QDate(2022, 02, 22), QTime(22, 22, 22), Qt::LocalTime) + << QDateTime(QDate(2022, 02, 23), QTime(22, 22, 22), Qt::LocalTime); + QTest::newRow("time") + << QDateTime(QDate(2022, 02, 22), QTime(22, 22, 22), Qt::LocalTime) + << QDateTime(QDate(2022, 02, 22), QTime(22, 22, 23), Qt::LocalTime); + + // Note: Qt::LocalTime is used for "floating" date-times; "this time + // in the current system time zone". + QTest::newRow("timeSpec") + << QDateTime(QDate(2022, 02, 22), QTime(22, 22, 22), Qt::LocalTime) + << QDateTime(QDate(2022, 02, 22), QTime(22, 22, 22), QTimeZone::systemTimeZone()); + + // Both zones are UTC+0. + QTest::newRow("timeZone") + << QDateTime(QDate(2022, 02, 22), QTime(22, 22, 22), QTimeZone("Africa/Abidjan")) + << QDateTime(QDate(2022, 02, 22), QTime(22, 22, 22), QTimeZone("Africa/Accra")); + + QTest::newRow("invalid timeSpec") + << QDateTime(QDate(2022, 02, 22), QTime(22, 22, 22), QDateTime().timeSpec()) + << QDateTime(); + QTest::newRow("invalid timeZone") + << QDateTime(QDate(2022, 02, 22), QTime(22, 22, 22), QDateTime().timeZone()) + << QDateTime(); + } + + void testFalse() + { + QFETCH(QDateTime, dt1); + QFETCH(QDateTime, dt2); + QVERIFY(!identical(dt1, dt2)); + } +}; + +QTEST_MAIN(TestIdentical) +#include "testidentical.moc" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/autotests/testmemorycalendar.cpp new/kcalendarcore-5.93.0/autotests/testmemorycalendar.cpp --- old/kcalendarcore-5.92.0/autotests/testmemorycalendar.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/autotests/testmemorycalendar.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -350,6 +350,71 @@ QVERIFY(!cal->isVisible(event)); } +class TestCalendarObserver: public Calendar::CalendarObserver +{ +public: + TestCalendarObserver(const Calendar::Ptr &cal) + : mCalendar(cal) + { + cal->registerObserver(this); + } + ~TestCalendarObserver() + { + mCalendar->unregisterObserver(this); + } + void calendarIncidenceChanged(const Incidence::Ptr &incidence) override + { + mUpdated.append(incidence); + } + bool hasIncidenceChanged(const Incidence::Ptr &incidence) const + { + return std::find_if(mUpdated.constBegin(), mUpdated.constEnd(), + [incidence] (const Incidence::Ptr &it) { + return (it->uid() == incidence->uid() + && it->recurrenceId() == incidence->recurrenceId()); + }) != mUpdated.constEnd(); + } + Incidence::List mUpdated; +private: + Calendar::Ptr mCalendar; +}; + +void MemoryCalendarTest::testNotebookChange() +{ + MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc())); + TestCalendarObserver observer(cal); + const QString notebook1 = QLatin1String("Notebook1"); + const QString notebook2 = QLatin1String("Notebook2"); + + QVERIFY(cal->addNotebook(notebook1, true)); + QVERIFY(cal->addNotebook(notebook2, true)); + + Event::Ptr event = Event::Ptr(new Event()); + event->setDtStart(QDateTime(QDate(2022, 3, 23), QTime(10, 12), Qt::UTC)); + event->recurrence()->setDaily(1); + Incidence::Ptr exception = Calendar::createException(event, event->dtStart().addDays(3)); + QVERIFY(exception); + exception->setDtStart(exception->recurrenceId().addSecs(1800)); + QVERIFY(cal->addIncidence(event)); + QVERIFY(cal->addIncidence(exception)); + QVERIFY(cal->notebook(event).isEmpty()); + QVERIFY(cal->notebook(exception).isEmpty()); + + QVERIFY(observer.mUpdated.isEmpty()); + QVERIFY(cal->setNotebook(event, notebook1)); + QCOMPARE(cal->notebook(event), notebook1); + QCOMPARE(cal->notebook(exception), notebook1); + QVERIFY(observer.hasIncidenceChanged(event)); + QVERIFY(observer.hasIncidenceChanged(exception)); + + observer.mUpdated.clear(); + QVERIFY(cal->setNotebook(event, notebook2)); + QCOMPARE(cal->notebook(event), notebook2); + QCOMPARE(cal->notebook(exception), notebook2); + QVERIFY(observer.hasIncidenceChanged(event)); + QVERIFY(observer.hasIncidenceChanged(exception)); +} + void MemoryCalendarTest::testRawEvents() { MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc())); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/autotests/testmemorycalendar.h new/kcalendarcore-5.93.0/autotests/testmemorycalendar.h --- old/kcalendarcore-5.92.0/autotests/testmemorycalendar.h 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/autotests/testmemorycalendar.h 2022-04-02 11:55:43.000000000 +0200 @@ -26,6 +26,7 @@ void testRawEvents(); void testRawEventsForDate(); void testVisibility(); + void testNotebookChange(); void testDeleteIncidence(); void testUpdateIncidence(); }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/calendar.cpp new/kcalendarcore-5.93.0/src/calendar.cpp --- old/kcalendarcore-5.92.0/src/calendar.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/calendar.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -433,7 +433,7 @@ d->mNotebookIncidences.insert(notebook, incidence); } notifyIncidenceChanged(inc); // for removing from old notebook - // don not remove from mUidToNotebook to keep deleted incidences + // do not remove from mUidToNotebook to keep deleted incidences d->mNotebookIncidences.remove(old, inc); } } @@ -442,6 +442,10 @@ d->mNotebookIncidences.insert(notebook, inc); qCDebug(KCALCORE_LOG) << "setting notebook" << notebook << "for" << inc->uid(); notifyIncidenceChanged(inc); // for inserting into new notebook + const Incidence::List list = instances(inc); + for (const auto &incidence : list) { + notifyIncidenceChanged(incidence); + } } return true; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/calformat.h new/kcalendarcore-5.93.0/src/calformat.h --- old/kcalendarcore-5.92.0/src/calformat.h 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/calformat.h 2022-04-02 11:55:43.000000000 +0200 @@ -66,7 +66,9 @@ virtual bool save(const Calendar::Ptr &calendar, const QString &fileName) = 0; /** - Loads a calendar from a string + Loads a calendar from a string. When a notebook is given, incidences are added to this + notebook, otherwise no notebook is associated to loaded incidences. The notebook + should already be added to the calendar, see Calendar::addNotebook(). @param calendar is the Calendar to be loaded. @param string is the QString containing the Calendar data. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/event.cpp new/kcalendarcore-5.93.0/src/event.cpp --- old/kcalendarcore-5.92.0/src/event.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/event.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -94,8 +94,7 @@ } else { // If they weren't the same type IncidenceBase::equals would had returned false already const Event *e = static_cast<const Event *>(&event); - return ((dtEnd() == e->dtEnd() && dtEnd().timeSpec() == e->dtEnd().timeSpec()) || (!dtEnd().isValid() && !e->dtEnd().isValid())) - && transparency() == e->transparency(); + return identical(dtEnd(), e->dtEnd()) && transparency() == e->transparency(); } } @@ -123,7 +122,7 @@ } Q_D(Event); - if (d->mDtEnd != dtEnd || d->mDtEnd.timeSpec() != dtEnd.timeSpec() || hasDuration() == dtEnd.isValid()) { + if (!identical(d->mDtEnd, dtEnd) || hasDuration() == dtEnd.isValid()) { update(); d->mDtEnd = dtEnd; d->mMultiDayValid = false; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/freebusy.cpp new/kcalendarcore-5.93.0/src/freebusy.cpp --- old/kcalendarcore-5.92.0/src/freebusy.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/freebusy.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -325,7 +325,7 @@ Q_D(const FreeBusy); // If they weren't the same type IncidenceBase::equals would had returned false already const FreeBusy *fb = static_cast<const FreeBusy *>(&freeBusy); - return dtEnd() == fb->dtEnd() && d->mBusyPeriods == fb->d_func()->mBusyPeriods; + return identical(dtEnd(), fb->dtEnd()) && d->mBusyPeriods == fb->d_func()->mBusyPeriods; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/icalformat.cpp new/kcalendarcore-5.93.0/src/icalformat.cpp --- old/kcalendarcore-5.92.0/src/icalformat.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/icalformat.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -81,6 +81,9 @@ file.close(); if (!text.isEmpty()) { + if (!calendar->hasValidNotebook(fileName) && !calendar->addNotebook(fileName, true)) { + qCWarning(KCALCORE_LOG) << "Unable to add" << fileName << "as a notebook in calendar"; + } if (!fromRawString(calendar, text, false, fileName)) { qCWarning(KCALCORE_LOG) << fileName << " is not a valid iCalendar file"; setException(new Exception(Exception::ParseErrorIcal)); @@ -180,7 +183,6 @@ bool ICalFormat::fromRawString(const Calendar::Ptr &cal, const QByteArray &string, bool deleted, const QString ¬ebook) { - Q_UNUSED(notebook); // Get first VCALENDAR component. // TODO: Handle more than one VCALENDAR or non-VCALENDAR top components icalcomponent *calendar; @@ -216,7 +218,7 @@ success = false; } else { // put all objects into their proper places - if (!d->mImpl->populate(cal, calendar, deleted)) { + if (!d->mImpl->populate(cal, calendar, deleted, notebook)) { qCDebug(KCALCORE_LOG) << "Could not populate calendar"; if (!exception()) { setException(new Exception(Exception::ParseErrorKcal)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/icalformat.h new/kcalendarcore-5.93.0/src/icalformat.h --- old/kcalendarcore-5.92.0/src/icalformat.h 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/icalformat.h 2022-04-02 11:55:43.000000000 +0200 @@ -68,8 +68,6 @@ /** @copydoc CalFormat::fromString() - - @note The notebook is ignored and the default one is used */ bool fromString(const Calendar::Ptr &calendar, const QString &string, bool deleted = false, const QString ¬ebook = QString()) override; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/icalformat_p.cpp new/kcalendarcore-5.93.0/src/icalformat_p.cpp --- old/kcalendarcore-5.92.0/src/icalformat_p.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/icalformat_p.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -2298,6 +2298,12 @@ return t; } +static bool dateTimeIsInUTC(const QDateTime &datetime) +{ + return datetime.timeSpec() == Qt::UTC || (datetime.timeSpec() == Qt::TimeZone && datetime.timeZone() == QTimeZone::utc()) + || (datetime.timeSpec() == Qt::OffsetFromUTC && datetime.offsetFromUtc() == 0); +} + icaltimetype ICalFormatImpl::writeICalDateTime(const QDateTime &datetime, bool dateOnly) { icaltimetype t = icaltime_null_time(); @@ -2314,9 +2320,7 @@ t.second = datetime.time().second(); } t.zone = nullptr; // zone is NOT set - if (datetime.timeSpec() == Qt::UTC || - (datetime.timeSpec() == Qt::TimeZone && datetime.timeZone() == QTimeZone::utc()) || - (datetime.timeSpec() == Qt::OffsetFromUTC && datetime.offsetFromUtc() == 0)) { + if (dateTimeIsInUTC(datetime)) { t = icaltime_convert_to_zone(t, icaltimezone_get_utc_timezone()); } return t; @@ -2384,7 +2388,7 @@ } QTimeZone qtz; - if (!icaltime_is_utc(t) && dt.timeSpec() == Qt::TimeZone) { + if (!icaltime_is_utc(t) && !dateTimeIsInUTC(dt) && dt.timeSpec() != Qt::LocalTime) { qtz = dt.timeZone(); } @@ -2659,8 +2663,6 @@ // that is used internally in the ICalFormatImpl. bool ICalFormatImpl::populate(const Calendar::Ptr &cal, icalcomponent *calendar, bool deleted, const QString ¬ebook) { - Q_UNUSED(notebook); - // qCDebug(KCALCORE_LOG)<<"Populate called"; // this function will populate the caldict dictionary and other event @@ -2776,6 +2778,9 @@ // qCDebug(KCALCORE_LOG) << "Adding todo " << todo.data() << todo->uid(); cal->addTodo(todo); // just add this one } + if (!notebook.isEmpty() && cal->todo(todo->uid(), todo->recurrenceId())) { + cal->setNotebook(todo, notebook); + } } c = icalcomponent_get_next_component(calendar, ICAL_VTODO_COMPONENT); } @@ -2816,6 +2821,9 @@ // qCDebug(KCALCORE_LOG) << "Adding event " << event.data() << event->uid(); cal->addEvent(event); // just add this one } + if (!notebook.isEmpty() && cal->event(event->uid(), event->recurrenceId())) { + cal->setNotebook(event, notebook); + } } c = icalcomponent_get_next_component(calendar, ICAL_VEVENT_COMPONENT); } @@ -2842,6 +2850,9 @@ } else { cal->addJournal(journal); // just add this one } + if (!notebook.isEmpty() && cal->journal(journal->uid(), journal->recurrenceId())) { + cal->setNotebook(journal, notebook); + } } c = icalcomponent_get_next_component(calendar, ICAL_VJOURNAL_COMPONENT); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/incidencebase.cpp new/kcalendarcore-5.93.0/src/incidencebase.cpp --- old/kcalendarcore-5.92.0/src/incidencebase.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/incidencebase.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -164,7 +164,7 @@ // of much use. We are not comparing for identity, after all. // no need to compare mObserver - bool a = ((dtStart() == other.dtStart() && dtStart().timeSpec() == other.dtStart().timeSpec()) || (!dtStart().isValid() && !other.dtStart().isValid())); + bool a = identical(dtStart(), other.dtStart()); bool b = organizer() == other.organizer(); bool c = uid() == other.uid(); bool d = allDay() == other.allDay(); @@ -267,7 +267,7 @@ qCWarning(KCALCORE_LOG) << "Invalid dtStart"; } - if (d_ptr->mDtStart != dtStart || d_ptr->mDtStart.timeSpec() != dtStart.timeSpec()) { + if (!identical(d_ptr->mDtStart, dtStart)) { update(); d_ptr->mDtStart = dtStart; d_ptr->mDirtyFields.insert(FieldDtStart); @@ -614,6 +614,11 @@ return KCALCORE_MAGIC_NUMBER; } +bool KCalendarCore::identical(QDateTime dt1, QDateTime dt2) +{ + return dt1 == dt2 && dt1.timeSpec() == dt2.timeSpec() && dt1.timeZone() == dt2.timeZone(); +} + QDataStream &KCalendarCore::operator<<(QDataStream &out, const KCalendarCore::IncidenceBase::Ptr &i) { if (!i) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/incidencebase.h new/kcalendarcore-5.93.0/src/incidencebase.h --- old/kcalendarcore-5.92.0/src/incidencebase.h 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/incidencebase.h 2022-04-02 11:55:43.000000000 +0200 @@ -779,6 +779,18 @@ }; /** + * Compare two QDateTimes for extended equality. + * + * QDateTime::operator==() in Qt 5.12 returns true if its operands represent + * the same instant in time, regardless of their time zones or TimeSpecs (and + * contrary to the documentation). This function returns true if and only if + * their times, time zones, and TimeSpecs are equal, or both are invalid(). + * + * @since 5.93 + */ +KCALENDARCORE_EXPORT bool identical(QDateTime, QDateTime); + +/** * Incidence serializer. * * @since 4.12 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/period.cpp new/kcalendarcore-5.93.0/src/period.cpp --- old/kcalendarcore-5.92.0/src/period.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/period.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -17,6 +17,7 @@ @author Cornelius Schumacher \<[email protected]\> */ +#include "incidencebase.h" #include "period.h" #include "utils_p.h" @@ -81,8 +82,8 @@ bool Period::operator==(const Period &other) const { - return ((d->mStart == other.d->mStart) || (!d->mStart.isValid() && !other.d->mStart.isValid())) - && ((d->mEnd == other.d->mEnd) || (!d->mEnd.isValid() && !other.d->mEnd.isValid())) && d->mHasDuration == other.d->mHasDuration; + return identical(d->mStart, other.d->mStart) && identical(d->mEnd, other.d->mEnd) + && d->mHasDuration == other.d->mHasDuration; } Period &Period::operator=(const Period &other) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/recurrence.cpp new/kcalendarcore-5.93.0/src/recurrence.cpp --- old/kcalendarcore-5.92.0/src/recurrence.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/recurrence.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -8,6 +8,8 @@ SPDX-License-Identifier: LGPL-2.0-or-later */ + +#include "incidencebase.h" #include "recurrence.h" #include "recurrencehelper_p.h" #include "utils_p.h" @@ -68,7 +70,7 @@ bool Recurrence::Private::operator==(const Recurrence::Private &p) const { // qCDebug(KCALCORE_LOG) << mStartDateTime << p.mStartDateTime; - if ((mStartDateTime != p.mStartDateTime && (mStartDateTime.isValid() || p.mStartDateTime.isValid())) || mAllDay != p.mAllDay + if (!identical(mStartDateTime, p.mStartDateTime) || mAllDay != p.mAllDay || mRecurReadOnly != p.mRecurReadOnly || mExDates != p.mExDates || mExDateTimes != p.mExDateTimes || mRDates != p.mRDates || mRDateTimes != p.mRDateTimes || mRDateTimePeriods != p.mRDateTimePeriods) { return false; @@ -475,7 +477,7 @@ return; } - if (dateTime != rrule->endDt()) { + if (!identical(dateTime, rrule->endDt())) { rrule->setEndDt(dateTime); updated(); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/recurrencerule.cpp new/kcalendarcore-5.93.0/src/recurrencerule.cpp --- old/kcalendarcore-5.92.0/src/recurrencerule.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/recurrencerule.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -6,6 +6,8 @@ SPDX-License-Identifier: LGPL-2.0-or-later */ + +#include "incidencebase.h" #include "recurrencerule.h" #include "kcalendarcore_debug.h" #include "recurrencehelper_p.h" @@ -813,8 +815,8 @@ bool RecurrenceRule::Private::operator==(const Private &r) const { - return mPeriod == r.mPeriod && ((mDateStart == r.mDateStart) || (!mDateStart.isValid() && !r.mDateStart.isValid())) && mDuration == r.mDuration - && ((mDateEnd == r.mDateEnd) || (!mDateEnd.isValid() && !r.mDateEnd.isValid())) && mFrequency == r.mFrequency && mIsReadOnly == r.mIsReadOnly + return mPeriod == r.mPeriod && identical(mDateStart, r.mDateStart) && mDuration == r.mDuration + && identical(mDateEnd, r.mDateEnd) && mFrequency == r.mFrequency && mIsReadOnly == r.mIsReadOnly && mAllDay == r.mAllDay && mBySeconds == r.mBySeconds && mByMinutes == r.mByMinutes && mByHours == r.mByHours && mByDays == r.mByDays && mByMonthDays == r.mByMonthDays && mByYearDays == r.mByYearDays && mByWeekNumbers == r.mByWeekNumbers && mByMonths == r.mByMonths && mBySetPos == r.mBySetPos && mWeekStart == r.mWeekStart && mNoByRules == r.mNoByRules; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/todo.cpp new/kcalendarcore-5.93.0/src/todo.cpp --- old/kcalendarcore-5.92.0/src/todo.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/todo.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -91,7 +91,7 @@ void TodoPrivate::setDtDue(const QDateTime dd) { - if (dd != mDtDue || dd.timeSpec() != mDtDue.timeSpec()) { + if (!identical(dd, mDtDue)) { mDtDue = dd; mDirtyFields.insert(IncidenceBase::FieldDtDue); } @@ -99,7 +99,7 @@ void TodoPrivate::setDtRecurrence(const QDateTime dr) { - if (dr != mDtRecurrence) { + if (!identical(dr, mDtRecurrence)) { mDtRecurrence = dr; mDirtyFields.insert(IncidenceBase::FieldRecurrenceId); } @@ -171,7 +171,7 @@ } else { // If they weren't the same type IncidenceBase::equals would had returned false already const Todo *t = static_cast<const Todo *>(&todo); - return ((dtDue() == t->dtDue() && dtDue().timeSpec() == t->dtDue().timeSpec()) || (!dtDue().isValid() && !t->dtDue().isValid())) + return identical(dtDue(), t->dtDue()) && hasDueDate() == t->hasDueDate() && hasStartDate() == t->hasStartDate() && ((completed() == t->completed()) || (!completed().isValid() && !t->completed().isValid())) && hasCompletedDate() == t->hasCompletedDate() && percentComplete() == t->percentComplete(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcalendarcore-5.92.0/src/vcalformat.cpp new/kcalendarcore-5.93.0/src/vcalformat.cpp --- old/kcalendarcore-5.92.0/src/vcalformat.cpp 2022-03-05 12:10:30.000000000 +0100 +++ new/kcalendarcore-5.93.0/src/vcalformat.cpp 2022-04-02 11:55:43.000000000 +0200 @@ -81,6 +81,11 @@ delete d; } +static void mimeErrorHandler(char *e) +{ + qCWarning(KCALCORE_LOG) << "Error parsing vCalendar file:" << e; +} + bool VCalFormat::load(const Calendar::Ptr &calendar, const QString &fileName) { d->mCalendar = calendar; @@ -89,7 +94,9 @@ // this is not necessarily only 1 vcal. Could be many vcals, or include // a vcard... + registerMimeErrorHandler(&mimeErrorHandler); // Note: vCalendar error handler provided by libical. VObject *vcal = Parse_MIME_FromFileName(const_cast<char *>(QFile::encodeName(fileName).data())); + registerMimeErrorHandler(nullptr); if (!vcal) { setException(new Exception(Exception::CalVersionUnknown));
