Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package kcalendarcore for openSUSE:Factory 
checked in at 2021-08-16 10:07:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/kcalendarcore (Old)
 and      /work/SRC/openSUSE:Factory/.kcalendarcore.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "kcalendarcore"

Mon Aug 16 10:07:32 2021 rev:22 rq:912113 version:5.85.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/kcalendarcore/kcalendarcore.changes      
2021-07-16 00:00:59.645269022 +0200
+++ /work/SRC/openSUSE:Factory/.kcalendarcore.new.1899/kcalendarcore.changes    
2021-08-16 10:11:22.643113191 +0200
@@ -1,0 +2,17 @@
+Fri Aug  6 12:11:29 UTC 2021 - Christophe Giboudeaux <[email protected]>
+
+- Update to 5.85.0
+  * New feature release
+  * For more details please see:
+  * https://kde.org/announcements/frameworks/5/5.85.0
+- Changes since 5.84.0:
+  * Fixup include dir into pkgconfig file
+  * Hide fields, to enforce uniform use of setFieldDirty()
+  * Fix formating in apidoc for free busy
+  * Add ownerChanged signal
+  * Add metadata properties to calendar
+  * Add base class for calendar plugins
+  * More completion field consistency and dirtyness checks
+  * Mark mCompleted as dirty if it changes, and also reset status
+
+-------------------------------------------------------------------

Old:
----
  kcalendarcore-5.84.0.tar.xz
  kcalendarcore-5.84.0.tar.xz.sig

New:
----
  kcalendarcore-5.85.0.tar.xz
  kcalendarcore-5.85.0.tar.xz.sig

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ kcalendarcore.spec ++++++
--- /var/tmp/diff_new_pack.GDsrD9/_old  2021-08-16 10:11:23.447112248 +0200
+++ /var/tmp/diff_new_pack.GDsrD9/_new  2021-08-16 10:11:23.451112243 +0200
@@ -16,14 +16,14 @@
 #
 
 
-%define _tar_path 5.84
+%define _tar_path 5.85
 # 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 lang
 Name:           kcalendarcore
-Version:        5.84.0
+Version:        5.85.0
 Release:        0
 Summary:        Library to access and handle calendar data
 License:        LGPL-2.0-or-later


++++++ kcalendarcore-5.84.0.tar.xz -> kcalendarcore-5.85.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/CMakeLists.txt 
new/kcalendarcore-5.85.0/CMakeLists.txt
--- old/kcalendarcore-5.84.0/CMakeLists.txt     2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/CMakeLists.txt     2021-08-05 14:42:11.000000000 
+0200
@@ -1,11 +1,11 @@
 cmake_minimum_required(VERSION 3.16)
-set(KF_VERSION "5.84.0") # handled by release scripts
+set(KF_VERSION "5.85.0") # handled by release scripts
 
 project(KCalendarCore VERSION ${KF_VERSION})
 
 # ECM setup
 include(FeatureSummary)
-find_package(ECM 5.84.0  NO_MODULE)
+find_package(ECM 5.85.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)
 
@@ -119,7 +119,7 @@
 
 if (NOT WIN32)
     ecm_generate_pkgconfig_file(BASE_NAME KF5CalendarCore
-      INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR}/KCalendarCore/
+      INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KCalendarCore/
       DEPS Qt5Core
     INSTALL)
 endif()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/KF5CalendarCoreConfig.cmake.in 
new/kcalendarcore-5.85.0/KF5CalendarCoreConfig.cmake.in
--- old/kcalendarcore-5.84.0/KF5CalendarCoreConfig.cmake.in     2021-06-26 
17:11:22.000000000 +0200
+++ new/kcalendarcore-5.85.0/KF5CalendarCoreConfig.cmake.in     2021-08-05 
14:42:11.000000000 +0200
@@ -2,6 +2,7 @@
 
 include(CMakeFindDependencyMacro)
 find_dependency(Qt5Core @REQUIRED_QT_VERSION@)
+find_dependency(Qt5Gui @REQUIRED_QT_VERSION@)
 if (NOT @BUILD_SHARED_LIBS@)
     list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_LIST_DIR})
     find_dependency(LibIcal @LibIcal_MIN_VERSION@)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kcalendarcore-5.84.0/autotests/testmemorycalendar.cpp 
new/kcalendarcore-5.85.0/autotests/testmemorycalendar.cpp
--- old/kcalendarcore-5.84.0/autotests/testmemorycalendar.cpp   2021-06-26 
17:11:22.000000000 +0200
+++ new/kcalendarcore-5.85.0/autotests/testmemorycalendar.cpp   2021-08-05 
14:42:11.000000000 +0200
@@ -459,7 +459,7 @@
 
     const QDateTime now = QDateTime::currentDateTimeUtc();
 
-    // Any single modfication is updating the lastModified field.
+    // Any single modification is updating the lastModified field.
     event->setSummary(QString::fromLatin1("test"));
     QVERIFY(event->lastModified().secsTo(now) < 5);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/autotests/testrecurtodo.cpp 
new/kcalendarcore-5.85.0/autotests/testrecurtodo.cpp
--- old/kcalendarcore-5.84.0/autotests/testrecurtodo.cpp        2021-06-26 
17:11:22.000000000 +0200
+++ new/kcalendarcore-5.85.0/autotests/testrecurtodo.cpp        2021-08-05 
14:42:11.000000000 +0200
@@ -60,7 +60,7 @@
     todo.setCompleted(currentUtcDateTime);
 
     QCOMPARE(newDueDate, currentDate.addDays(1));
-    QCOMPARE(todo.dtDue(true /*first ocurrence*/).date(), dueDate);
+    QCOMPARE(todo.dtDue(true /*first occurrence*/).date(), dueDate);
 }
 
 void RecurTodoTest::testRecurrenceStart()
@@ -122,7 +122,7 @@
 
     todo.setCompleted(QDateTime::currentDateTimeUtc());
     QCOMPARE(todo.dtStart(), QDateTime(currentDate, currentTime, 
todo.dtStart().timeZone()).addDays(2));
-    QCOMPARE(todo.dtDue(true /*first ocurrence*/), QDateTime(treeDaysAgo, 
currentTime));
+    QCOMPARE(todo.dtDue(true /*first occurrence*/), QDateTime(treeDaysAgo, 
currentTime));
 }
 
 void RecurTodoTest::testIsAllDay()
@@ -264,7 +264,7 @@
     QCOMPARE(todo->recurrence()->getNextDateTime(dtdue.addDays(2)), 
QDateTime());
 }
 
-/** Test that occurrances specified by a recurrence rule are eliminated by
+/** Test that occurrences specified by a recurrence rule are eliminated by
  * exception dates.
  */
 void RecurTodoTest::testRecurrenceExdates()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/autotests/testtodo.cpp 
new/kcalendarcore-5.85.0/autotests/testtodo.cpp
--- old/kcalendarcore-5.84.0/autotests/testtodo.cpp     2021-06-26 
17:11:22.000000000 +0200
+++ new/kcalendarcore-5.85.0/autotests/testtodo.cpp     2021-08-05 
14:42:11.000000000 +0200
@@ -113,12 +113,44 @@
     QVERIFY(todo1 == todo2);
 }
 
+void TodoTest::testSetCompletedWithDate()
+{
+    Todo t;
+    t.setStatus(Incidence::StatusNone);
+    QVERIFY(!t.isCompleted());
+    QVERIFY(!t.hasCompletedDate());
+    QVERIFY(t.status() != Incidence::StatusCompleted);
+    QVERIFY(t.percentComplete() != 100);
+
+    const auto now = QDateTime::currentDateTimeUtc();
+    t.setCompleted(now);
+    QVERIFY(t.isCompleted());
+    QVERIFY(t.completed() == now);
+    QVERIFY(t.hasCompletedDate());
+    QVERIFY(t.status() == Incidence::StatusNone);
+    QVERIFY(t.percentComplete() == 100);
+}
+
+void TodoTest::testSetCompletedWithoutDate()
+{
+    Todo t;
+    t.setStatus(Incidence::StatusNeedsAction);
+    QVERIFY(!t.isCompleted());
+    QVERIFY(!t.hasCompletedDate());
+    QVERIFY(t.status() != Incidence::StatusCompleted);
+    QVERIFY(t.percentComplete() != 100);
+
+    t.setCompleted(QDateTime());
+    QVERIFY(t.isCompleted());
+    QVERIFY(!t.hasCompletedDate());
+    QVERIFY(t.status() == Incidence::StatusCompleted);
+    QVERIFY(t.percentComplete() == 100);
+}
+
 void TodoTest::testSetCompleted()
 {
-    Todo todo1, todo2, todo3;
+    Todo todo1;
     todo1.setSummary(QStringLiteral("Todo Summary"));
-    todo2.setSummary(QStringLiteral("Todo Summary"));
-    todo3.setSummary(QStringLiteral("Todo Summary"));
     QDateTime today = QDateTime::currentDateTimeUtc();
 
     // due yesterday
@@ -128,18 +160,61 @@
     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::testSetCompletedBool()
+{
+    Todo t;
+    QVERIFY(!t.isCompleted());
+    QVERIFY(!t.hasCompletedDate());
+    QVERIFY(t.status() != Incidence::StatusCompleted);
+    QVERIFY(t.percentComplete() != 100);
+
+    t.setCompleted(true);
+    QVERIFY(t.isCompleted());
+    QVERIFY(!t.hasCompletedDate());
+    QVERIFY(t.status() == Incidence::StatusCompleted);
+    QVERIFY(t.percentComplete() == 100);
+
+    const auto yesterday = QDateTime::currentDateTimeUtc().addDays(-1);
+    t.setCompleted(yesterday);
+    t.setCompleted(true);
+    QVERIFY(t.isCompleted());
+    QVERIFY(t.completed() == yesterday);
+    QVERIFY(t.status() == Incidence::StatusCompleted);
+    QVERIFY(t.percentComplete() == 100);
+
+    t.setCompleted(false);
+    QVERIFY(!t.isCompleted());
+    QVERIFY(!t.hasCompletedDate());
+    QVERIFY(t.status() == Incidence::StatusNone);
+    QVERIFY(t.percentComplete() == 0);
+}
+
+void TodoTest::testSetPercent()
+{
+    Todo t;
+    t.setStatus(Incidence::StatusCompleted);
+    t.setCompleted(QDateTime::currentDateTimeUtc());
+    t.setPercentComplete(100);
+    QVERIFY(t.percentComplete() == 100);
+    QVERIFY(t.isCompleted());
+
+    // Completion reset if necessary.
+    QVERIFY(t.hasCompletedDate());
+    t.setPercentComplete(99);
+    QVERIFY(t.percentComplete() == 99);
+    QVERIFY(!t.isCompleted());
+    QVERIFY(!t.hasCompletedDate());
+    QVERIFY(t.status() != Incidence::StatusCompleted);
+
+    t.setPercentComplete(0);
+    QVERIFY(t.percentComplete() == 0);
+    QVERIFY(!t.isCompleted());
+    QVERIFY(!t.hasCompletedDate());
+    QVERIFY(t.status() != Incidence::StatusCompleted);
 }
 
 void TodoTest::testStatus()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/autotests/testtodo.h 
new/kcalendarcore-5.85.0/autotests/testtodo.h
--- old/kcalendarcore-5.84.0/autotests/testtodo.h       2021-06-26 
17:11:22.000000000 +0200
+++ new/kcalendarcore-5.85.0/autotests/testtodo.h       2021-08-05 
14:42:11.000000000 +0200
@@ -23,6 +23,10 @@
     void testCopyIncidence();
     void testAssign();
     void testSetCompleted();
+    void testSetCompletedWithDate();
+    void testSetCompletedWithoutDate();
+    void testSetCompletedBool();
+    void testSetPercent();
     void testStatus();
     void testSerializer_data();
     void testSerializer();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/CMakeLists.txt 
new/kcalendarcore-5.85.0/src/CMakeLists.txt
--- old/kcalendarcore-5.84.0/src/CMakeLists.txt 2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/CMakeLists.txt 2021-08-05 14:42:11.000000000 
+0200
@@ -12,6 +12,7 @@
   attachment.cpp
   attendee.cpp
   calendar.cpp
+  calendarplugin.cpp
   calfilter.cpp
   calformat.cpp
   calstorage.cpp
@@ -74,8 +75,8 @@
 target_link_libraries(KF5CalendarCore
 PUBLIC
     Qt5::Core
-PRIVATE
     Qt5::Gui
+PRIVATE
     LibIcal
 )
 
@@ -90,6 +91,7 @@
   CalFormat
   CalStorage
   Calendar
+  CalendarPlugin
   Conference
   CustomProperties
   Duration
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/calendar.cpp 
new/kcalendarcore-5.85.0/src/calendar.cpp
--- old/kcalendarcore-5.84.0/src/calendar.cpp   2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/calendar.cpp   2021-08-05 14:42:11.000000000 
+0200
@@ -166,8 +166,11 @@
 
 void Calendar::setOwner(const Person &owner)
 {
-    d->mOwner = owner;
-    setModified(true);
+    if (owner != d->mOwner) {
+        d->mOwner = owner;
+        setModified(true);
+        Q_EMIT ownerChanged();
+    }
 }
 
 void Calendar::setTimeZone(const QTimeZone &timeZone)
@@ -888,8 +891,8 @@
         // Since the mOrphans dict might contain the same key (with different
         // child incidence pointers!) multiple times, take care that we remove
         // the correct one. So we need to remove all items with the given
-        // parent UID, and readd those that are not for this item. Also, there
-        // might be other entries with differnet UID that point to this
+        // parent UID, and re-add those that are not for this item. Also, there
+        // might be other entries with different UID that point to this
         // incidence (this might happen when the relatedTo of the item is
         // changed before its parent is inserted. This might happen with
         // groupware servers....). Remove them, too
@@ -915,7 +918,7 @@
                     tempList.append(i);
                 }
             }
-            // Readd those that point to a different orphan incidence
+            // Re-add those that point to a different orphan incidence
             for (Incidence::List::Iterator incit = tempList.begin(); incit != 
tempList.end(); ++incit) {
                 d->mOrphans.insert(*uidit, *incit);
             }
@@ -1261,7 +1264,7 @@
                 }
 
                 // Adjust the 'alarmStart' date/time and find the next 
recurrence at or after it.
-                // Treate the two offsets separately in case one is daily and 
the other not.
+                // Treat the two offsets separately in case one is daily and 
the other not.
                 dt = 
incidence->recurrence()->getNextDateTime(baseStart.addSecs(-1));
                 if (!dt.isValid() || (dt = endOffset.end(offset.end(dt))) > 
to) { // adjust 'dt' to get the alarm time
                     // The next recurrence is too late.
@@ -1352,3 +1355,53 @@
     Q_UNUSED(data);
     Q_ASSERT(false);
 }
+
+QString Calendar::id() const
+{
+    return d->mId;
+}
+
+void Calendar::setId(const QString &id)
+{
+    if (d->mId != id) {
+        d->mId = id;
+        Q_EMIT idChanged();
+    }
+}
+
+QString Calendar::name() const
+{
+    return d->mName;
+}
+
+void Calendar::setName(const QString &name)
+{
+    if (d->mName != name) {
+        d->mName = name;
+        Q_EMIT nameChanged();
+    }
+}
+
+QIcon Calendar::icon() const
+{
+    return d->mIcon;
+}
+
+void Calendar::setIcon(const QIcon &icon)
+{
+    d->mIcon = icon;
+    Q_EMIT iconChanged();
+}
+
+AccessMode Calendar::accessMode() const
+{
+    return d->mAccessMode;
+}
+
+void Calendar::setAccessMode(const AccessMode mode)
+{
+    if (d->mAccessMode != mode) {
+        d->mAccessMode = mode;
+        Q_EMIT accessModeChanged();
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/calendar.h 
new/kcalendarcore-5.85.0/src/calendar.h
--- old/kcalendarcore-5.84.0/src/calendar.h     2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/calendar.h     2021-08-05 14:42:11.000000000 
+0200
@@ -43,6 +43,7 @@
 #include "todo.h"
 
 #include <QDateTime>
+#include <QIcon>
 #include <QObject>
 #include <QTimeZone>
 
@@ -95,6 +96,15 @@
 };
 
 /**
+  The calendar's access mode, i.e. whether it can be written to or is read 
only.
+  @since 5.85
+*/
+enum AccessMode {
+    ReadOnly,
+    ReadWrite,
+};
+
+/**
   @brief
   Represents the main calendar class.
 
@@ -120,7 +130,11 @@
 {
     Q_OBJECT
     Q_PROPERTY(QString productId READ productId WRITE setProductId) // 
clazy:exclude=qproperty-without-notify
-    Q_PROPERTY(KCalendarCore::Person owner READ owner WRITE setOwner)
+    Q_PROPERTY(KCalendarCore::Person owner READ owner WRITE setOwner NOTIFY 
ownerChanged)
+    Q_PROPERTY(QString id READ id WRITE setId NOTIFY idChanged)
+    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+    Q_PROPERTY(QIcon icon READ icon WRITE setIcon NOTIFY iconChanged)
+    Q_PROPERTY(AccessMode accessMode READ accessMode WRITE setAccessMode 
NOTIFY accessModeChanged)
 
 public:
     /**
@@ -264,6 +278,63 @@
     Q_REQUIRED_RESULT bool isModified() const;
 
     /**
+     * A unique identifier for this calendar.
+     * @since 5.85
+     * @see setId()
+     */
+    QString id() const;
+
+    /**
+     * set a unique identifier for this calendar.
+     * @since 5.85
+     * @see id()
+     */
+    void setId(const QString &id);
+
+    /**
+     * The user-visible name for this calendar.
+     * @since 5.85
+     * @see setName()
+     */
+    QString name() const;
+
+    /**
+     * Set the user-visible name for this calendar.
+     * @since 5.85
+     * @see name()
+     */
+    void setName(const QString &name);
+
+    /**
+     * This calendar's icon.
+     * @since 5.85
+     * @see setIconName()
+     */
+    QIcon icon() const;
+
+    /**
+     * Set this calendar's icon.
+     * @since 5.85
+     * @see icon()
+     */
+    void setIcon(const QIcon &icon);
+
+    /**
+     * This calendar's AccessMode, i.e. whether it is writable or read-only.
+     * Defaults to ReadWrite.
+     * @since 5.85
+     * @see setAccessMode()
+     */
+    AccessMode accessMode() const;
+
+    /**
+     * Set this calendar's AccessMode, i.e. whether it is writable or 
read-only.
+     * @since 5.85
+     * @see accessMode()
+     */
+    void setAccessMode(const AccessMode mode);
+
+    /**
       Clears out the current calendar, freeing all used memory etc.
     */
     virtual void close() = 0;
@@ -310,7 +381,7 @@
     virtual void startBatchAdding();
 
     /**
-       Tells the Calendar that you stoped adding a batch of incidences.
+       Tells the Calendar that you stopped adding a batch of incidences.
 
         @see startBatchAdding()
      */
@@ -1107,7 +1178,7 @@
        Returns a list of incidences that have a relation of RELTYPE parent
        to incidence @p uid.
 
-       @param uid The parent identifier whos children we want to obtain.
+       @param uid The parent identifier whose children we want to obtain.
     */
     Incidence::List relations(const QString &uid) const;
 
@@ -1301,8 +1372,8 @@
       @param alarms is a List of Alarms to be appended onto.
       @param incidence is a pointer to an Incidence containing the Alarm
       to be appended.
-      @param from is the lower range of the next Alarm repitition.
-      @param to is the upper range of the next Alarm repitition.
+      @param from is the lower range of the next Alarm repetition.
+      @param to is the upper range of the next Alarm repetition.
     */
     void appendAlarms(Alarm::List &alarms, const Incidence::Ptr &incidence, 
const QDateTime &from, const QDateTime &to) const;
 
@@ -1312,8 +1383,8 @@
       @param alarms is a List of Alarms to be appended onto.
       @param incidence is a pointer to an Incidence containing the Alarm
       to be appended.
-      @param from is the lower range of the next Alarm repitition.
-      @param to is the upper range of the next Alarm repitition.
+      @param from is the lower range of the next Alarm repetition.
+      @param to is the upper range of the next Alarm repetition.
     */
     void appendRecurringAlarms(Alarm::List &alarms, const Incidence::Ptr 
&incidence, const QDateTime &from, const QDateTime &to) const;
 
@@ -1347,6 +1418,41 @@
      */
     void filterChanged();
 
+    /**
+     * Emitted when the id changes.
+     * @since 5.85
+     * @see id()
+     */
+    void idChanged();
+
+    /**
+     * Emitted when the name changes.
+     * @since 5.85
+     * @see name()
+     */
+    void nameChanged();
+
+    /**
+     * Emitted when the icon name changes.
+     * @since 5.85
+     * @see icon()
+     */
+    void iconChanged();
+
+    /**
+     * Emitted when the AccessMode changes.
+     * @since 5.85
+     * @see accessMode()
+     */
+    void accessModeChanged();
+
+    /**
+     * Emitted when the owner changes.
+     * @since 5.85
+     * @see owner()
+     */
+    void ownerChanged();
+
 private:
     friend class ICalFormat;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/calendar_p.h 
new/kcalendarcore-5.85.0/src/calendar_p.h
--- old/kcalendarcore-5.84.0/src/calendar_p.h   2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/calendar_p.h   2021-08-05 14:42:11.000000000 
+0200
@@ -75,6 +75,10 @@
     QMap<QString, Incidence::List> mIncidenceRelations;
     bool batchAddingInProgress = false;
     bool mDeletionTracking = false;
+    QString mId;
+    QString mName;
+    QIcon mIcon;
+    AccessMode mAccessMode = ReadWrite;
 };
 
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/calendarplugin.cpp 
new/kcalendarcore-5.85.0/src/calendarplugin.cpp
--- old/kcalendarcore-5.84.0/src/calendarplugin.cpp     1970-01-01 
01:00:00.000000000 +0100
+++ new/kcalendarcore-5.85.0/src/calendarplugin.cpp     2021-08-05 
14:42:11.000000000 +0200
@@ -0,0 +1,16 @@
+/*
+  This file is part of the kcalcore library.
+
+  SPDX-FileCopyrightText: 2020 Nicolas Fella <[email protected]>
+  SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "calendarplugin.h"
+
+using namespace KCalendarCore;
+
+CalendarPlugin::CalendarPlugin(QObject *parent, const QVariantList &args)
+    : QObject(parent)
+{
+    Q_UNUSED(args)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/calendarplugin.h 
new/kcalendarcore-5.85.0/src/calendarplugin.h
--- old/kcalendarcore-5.84.0/src/calendarplugin.h       1970-01-01 
01:00:00.000000000 +0100
+++ new/kcalendarcore-5.85.0/src/calendarplugin.h       2021-08-05 
14:42:11.000000000 +0200
@@ -0,0 +1,48 @@
+/*
+  This file is part of the kcalcore library.
+
+  SPDX-FileCopyrightText: 2020 Nicolas Fella <[email protected]>
+  SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+#pragma once
+
+#include "kcalendarcore_export.h"
+
+#include <KCalendarCore/Calendar>
+
+namespace KCalendarCore
+{
+/**
+  @brief
+  A plugin that provides calendar data.
+
+  It allows calendar applications to consume data provided by multiple
+  sources, e.g. local ical files or remote calendars.
+
+  @since 5.85
+
+*/
+class KCALENDARCORE_EXPORT CalendarPlugin : public QObject
+{
+    Q_OBJECT
+public:
+    CalendarPlugin(QObject *parent, const QVariantList &args);
+
+    /**
+     * The set of calendars defined by this plugin.
+     *
+     * @return QVector of calendars.
+     */
+    virtual QVector<Calendar::Ptr> calendars() const = 0;
+
+Q_SIGNALS:
+    /**
+     * Emitted when the set of calendars changed.
+     */
+    void calendarsChanged();
+
+private:
+    void *d;
+};
+
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/calfilter.h 
new/kcalendarcore-5.85.0/src/calfilter.h
--- old/kcalendarcore-5.84.0/src/calfilter.h    2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/calfilter.h    2021-08-05 14:42:11.000000000 
+0200
@@ -109,7 +109,7 @@
 
     /**
       Applies the filter to a list of To-dos. All to-dos not matching the
-      filter criterias are removed from the list.
+      filter criteria are removed from the list.
 
       @param todoList is a list of To-dos to filter.
     */
@@ -117,7 +117,7 @@
 
     /**
       Applies the filter to a list of Journals. All journals not matching the
-      filter criterias are removed from the list.
+      filter criteria are removed from the list.
 
       @param journalList is a list of Journals to filter.
     */
@@ -162,7 +162,7 @@
 
     /**
       Sets the list of email addresses to be considered when filtering
-      incidences according ot the #HideNoMatchingAttendeeTodos criteria.
+      incidences according to the #HideNoMatchingAttendeeTodos criteria.
 
       @param emailList is a QStringList of email addresses.
       @see emailList().
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/conference.h 
new/kcalendarcore-5.85.0/src/conference.h
--- old/kcalendarcore-5.84.0/src/conference.h   2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/conference.h   2021-08-05 14:42:11.000000000 
+0200
@@ -46,7 +46,7 @@
     /**
       Constructs a conference consisting of a @p uri, description of
       the URI (@p label), list of features of the conference (@p features)
-      and @p langauge.
+      and @p language.
 
       @param uri Uri to join the conference.
       @param label Label of the URI.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/filestorage.cpp 
new/kcalendarcore-5.85.0/src/filestorage.cpp
--- old/kcalendarcore-5.84.0/src/filestorage.cpp        2021-06-26 
17:11:22.000000000 +0200
+++ new/kcalendarcore-5.85.0/src/filestorage.cpp        2021-08-05 
14:42:11.000000000 +0200
@@ -153,7 +153,7 @@
         calendar()->setModified(false);
     } else {
         if (!format->exception()) {
-            qCDebug(KCALCORE_LOG) << "Error. There should be an expection 
set.";
+            qCDebug(KCALCORE_LOG) << "Error. There should be an exception 
set.";
         } else {
             qCDebug(KCALCORE_LOG) << int(format->exception()->code());
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/freebusy.h 
new/kcalendarcore-5.85.0/src/freebusy.h
--- old/kcalendarcore-5.84.0/src/freebusy.h     2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/freebusy.h     2021-08-05 14:42:11.000000000 
+0200
@@ -34,7 +34,9 @@
   @brief
   Provides information about the free/busy time of a calendar.
 
-  A free/busy is a collection of Periods (@see Period).
+  A free/busy is a collection of Periods.
+  
+  @see Period.
 */
 class KCALENDARCORE_EXPORT FreeBusy : public IncidenceBase
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/icalformat_p.cpp 
new/kcalendarcore-5.85.0/src/icalformat_p.cpp
--- old/kcalendarcore-5.84.0/src/icalformat_p.cpp       2021-06-26 
17:11:22.000000000 +0200
+++ new/kcalendarcore-5.85.0/src/icalformat_p.cpp       2021-08-05 
14:42:11.000000000 +0200
@@ -966,7 +966,7 @@
     r.week_start = static_cast<icalrecurrencetype_weekday>(recur->weekStart() 
% 7 + 1);
 
     if (recur->frequency() > 1) {
-        // Dont' write out INTERVAL=1, because that's the default anyway
+        // Don't write out INTERVAL=1, because that's the default anyway
         r.interval = static_cast<short>(recur->frequency());
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/incidencebase.h 
new/kcalendarcore-5.85.0/src/incidencebase.h
--- old/kcalendarcore-5.84.0/src/incidencebase.h        2021-06-26 
17:11:22.000000000 +0200
+++ new/kcalendarcore-5.85.0/src/incidencebase.h        2021-08-05 
14:42:11.000000000 +0200
@@ -271,7 +271,7 @@
      </pre>
 
      @param v is a reference to a Visitor object.
-     @param incidence is a valid IncidenceBase object for visting.
+     @param incidence is a valid IncidenceBase object for visiting.
     */
     virtual bool accept(Visitor &v, const IncidenceBase::Ptr &incidence);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/recurrence.h 
new/kcalendarcore-5.85.0/src/recurrence.h
--- old/kcalendarcore-5.84.0/src/recurrence.h   2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/recurrence.h   2021-08-05 14:42:11.000000000 
+0200
@@ -512,7 +512,7 @@
      * Example: pos = 2, and bits 0 and 2 are set in days
      *   If months are specified (via addYearlyMonth), e.g. March, the rule is
      *   to repeat every year on the 2nd Monday and Wednesday of March.
-     *   If no months are specified, the fule is to repeat every year on the
+     *   If no months are specified, the file is to repeat every year on the
      *   2nd Monday and Wednesday of the year.
      */
     void addYearlyPos(short pos, const QBitArray &days);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/recurrencerule.cpp 
new/kcalendarcore-5.85.0/src/recurrencerule.cpp
--- old/kcalendarcore-5.84.0/src/recurrencerule.cpp     2021-06-26 
17:11:22.000000000 +0200
+++ new/kcalendarcore-5.85.0/src/recurrencerule.cpp     2021-08-05 
14:42:11.000000000 +0200
@@ -1111,7 +1111,7 @@
 //    * The following recurrences may never occur:
 //    * - For rMonthlyDay: if the frequency is a whole number of years.
 //    * - For rMonthlyPos: if the frequency is an even whole number of years.
-//    * - For rYearlyDay, rYearlyMonth: if the frequeny is a multiple of 4 
years.
+//    * - For rYearlyDay, rYearlyMonth: if the frequency is a multiple of 4 
years.
 //    * - For rYearlyPos: if the frequency is an even number of years.
 //    * The maximum number of iterations needed, assuming that it does 
actually occur,
 //    * was found empirically.
@@ -1955,7 +1955,7 @@
         if (merged.merge(mConstraints[i])) {
             // If the information is incomplete, we can't use this constraint
             if (merged.year > 0 && merged.hour >= 0 && merged.minute >= 0 && 
merged.second >= 0) {
-                // We have a valid constraint, so get all datetimes that match 
it andd
+                // We have a valid constraint, so get all datetimes that match 
it and
                 // append it to all date/times of this interval
                 QList<QDateTime> lstnew = merged.dateTimes(type);
                 lst += lstnew;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/sorting.cpp 
new/kcalendarcore-5.85.0/src/sorting.cpp
--- old/kcalendarcore-5.84.0/src/sorting.cpp    2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/sorting.cpp    2021-08-05 14:42:11.000000000 
+0200
@@ -97,7 +97,7 @@
     * the result cannot be guaranteed to be correct, since by definition they
     * contain no information about time zones or daylight savings changes.
     *
-    * @return DateTimeComparison indicating teh relationship of dt1 to dt2
+    * @return DateTimeComparison indicating the relationship of dt1 to dt2
     * @see operator==(), operator!=(), operator<(), operator<=(), 
operator>=(), operator>()
     */
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/todo.cpp 
new/kcalendarcore-5.85.0/src/todo.cpp
--- old/kcalendarcore-5.84.0/src/todo.cpp       2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/todo.cpp       2021-08-05 14:42:11.000000000 
+0200
@@ -36,22 +36,51 @@
 //@cond PRIVATE
 class Q_DECL_HIDDEN KCalendarCore::Todo::Private
 {
+    Todo *const q;
+
+    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]
+
 public:
-    Private()
+
+    Private(Todo *todo)
+        : q(todo)
     {
     }
-    Private(const KCalendarCore::Todo::Private &other)
+
+    Private(Todo * todo, const KCalendarCore::Todo::Private &other)
+        : q(todo)
     {
         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]
+    void setDtDue(const QDateTime dd);
+    QDateTime dtDue() const
+    {
+        return mDtDue;
+    }
+
+    void setDtRecurrence(const QDateTime dr);
+    QDateTime dtRecurrence() const
+    {
+        return mDtRecurrence;
+    }
+
+    void setCompleted(const QDateTime dc);
+    QDateTime completed() const
+    {
+        return mCompleted;
+    }
+
+    void setPercentComplete(const int pc);
+    int percentComplete()
+    {
+        return mPercentComplete;
+    }
 
     /**
       Returns true if the todo got a new date, else false will be returned.
@@ -59,6 +88,38 @@
     bool recurTodo(Todo *todo);
 };
 
+void Todo::Private::setDtDue(const QDateTime dd)
+{
+    if (dd != mDtDue) {
+        mDtDue = dd;
+        q->setFieldDirty(FieldDtDue);
+    }
+}
+
+void Todo::Private::setDtRecurrence(const QDateTime dr)
+{
+    if (dr != mDtRecurrence) {
+        mDtRecurrence = dr;
+        q->setFieldDirty(FieldRecurrenceId);
+    }
+}
+
+void Todo::Private::setCompleted(const QDateTime dc)
+{
+    if (dc != mCompleted) {
+        mCompleted = dc.toUTC();
+        q->setFieldDirty(FieldCompleted);
+    }
+}
+
+void Todo::Private::setPercentComplete(const int pc)
+{
+    if (pc != mPercentComplete) {
+        mPercentComplete = pc;
+        q->setFieldDirty(FieldPercentComplete);
+    }
+}
+
 void KCalendarCore::Todo::Private::init(const KCalendarCore::Todo::Private 
&other)
 {
     mDtDue = other.mDtDue;
@@ -70,7 +131,7 @@
 //@endcond
 
 Todo::Todo()
-    : d(new KCalendarCore::Todo::Private)
+    : d(new KCalendarCore::Todo::Private(this))
 {
 }
 
@@ -82,7 +143,7 @@
 
 Todo::Todo(const Incidence &other)
     : Incidence(other)
-    , d(new KCalendarCore::Todo::Private)
+    , d(new KCalendarCore::Todo::Private(this))
 {
 }
 
@@ -143,9 +204,9 @@
     }*/
 
     if (recurs() && !first) {
-        d->mDtRecurrence = dtDue;
+        d->setDtRecurrence(dtDue);
     } else {
-        d->mDtDue = dtDue;
+        d->setDtDue(dtDue);
     }
 
     if (recurs() && dtDue.isValid() && (!dtStart().isValid() || dtDue < 
recurrence()->startDateTime())) {
@@ -156,7 +217,6 @@
     /*const Alarm::List& alarms = alarms();
     for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next())
       alarm->setAlarmStart(d->mDtDue);*/
-    setFieldDirty(FieldDtDue);
     endUpdates();
 }
 
@@ -167,25 +227,25 @@
     }
 
     const QDateTime start = IncidenceBase::dtStart();
-    if (recurs() && !first && d->mDtRecurrence.isValid()) {
+    if (recurs() && !first && d->dtRecurrence().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());
+            const qint64 duration = start.daysTo(d->dtDue());
+            QDateTime dt = d->dtRecurrence().addDays(duration);
+            dt.setTime(d->dtDue().time());
             return dt;
         } else {
             // This is a legacy case, where recurrence was calculated against 
DTDUE
-            return d->mDtRecurrence;
+            return d->dtRecurrence();
         }
     }
 
-    return d->mDtDue;
+    return d->dtDue();
 }
 
 bool Todo::hasDueDate() const
 {
-    return d->mDtDue.isValid();
+    return d->dtDue().isValid();
 }
 
 bool Todo::hasStartDate() const
@@ -204,8 +264,8 @@
         return QDateTime();
     }
 
-    if (recurs() && !first && d->mDtRecurrence.isValid()) {
-        return d->mDtRecurrence;
+    if (recurs() && !first && d->dtRecurrence().isValid()) {
+        return d->dtRecurrence();
     } else {
         return IncidenceBase::dtStart();
     }
@@ -213,29 +273,29 @@
 
 bool Todo::isCompleted() const
 {
-    return d->mPercentComplete == 100 || status() == StatusCompleted;
+    return d->percentComplete() == 100 || status() == StatusCompleted || 
hasCompletedDate();
 }
 
 void Todo::setCompleted(bool completed)
 {
     update();
     if (completed) {
-        d->mPercentComplete = 100;
-        setStatus(StatusCompleted);
+        d->setPercentComplete(100);
     } else {
-        d->mPercentComplete = 0;
-        d->mCompleted = QDateTime();
-        setStatus(StatusNone);
+        d->setPercentComplete(0);
+        if (hasCompletedDate()) {
+            d->setCompleted(QDateTime());
+        }
     }
-    setFieldDirty(FieldCompleted);
-    setFieldDirty(FieldStatus);
     updated();
+
+    setStatus(completed ? StatusCompleted : StatusNone);    // Calls 
update()/updated().
 }
 
 QDateTime Todo::completed() const
 {
     if (hasCompletedDate()) {
-        return d->mCompleted;
+        return d->completed();
     } else {
         return QDateTime();
     }
@@ -245,21 +305,23 @@
 {
     update();
     if (!d->recurTodo(this)) {
-        d->mPercentComplete = 100;
-        d->mCompleted = completed.toUTC();
-        setFieldDirty(FieldCompleted);
+        d->setPercentComplete(100);
+        d->setCompleted(completed);
     }
     updated();
+    if (status() != StatusNone) {
+        setStatus(StatusCompleted); // Calls update()/updated()
+    }
 }
 
 bool Todo::hasCompletedDate() const
 {
-    return d->mCompleted.isValid();
+    return d->completed().isValid();
 }
 
 int Todo::percentComplete() const
 {
-    return d->mPercentComplete;
+    return d->percentComplete();
 }
 
 void Todo::setPercentComplete(int percent)
@@ -271,12 +333,14 @@
     }
 
     update();
-    d->mPercentComplete = percent;
+    d->setPercentComplete(percent);
     if (percent != 100) {
-        d->mCompleted = QDateTime();
+        d->setCompleted(QDateTime());
     }
-    setFieldDirty(FieldPercentComplete);
     updated();
+    if (percent != 100 && status() == Incidence::StatusCompleted) {
+        setStatus(Incidence::StatusNone);   // Calls update()/updated().
+    }
 }
 
 bool Todo::isInProgress(bool first) const
@@ -285,7 +349,7 @@
         return false;
     }
 
-    if (d->mPercentComplete > 0) {
+    if (d->percentComplete() > 0) {
         return true;
     }
 
@@ -316,7 +380,7 @@
 
 bool Todo::isNotStarted(bool first) const
 {
-    if (d->mPercentComplete > 0) {
+    if (d->percentComplete() > 0) {
         return false;
     }
 
@@ -339,33 +403,35 @@
 void Todo::shiftTimes(const QTimeZone &oldZone, const QTimeZone &newZone)
 {
     Incidence::shiftTimes(oldZone, newZone);
-    d->mDtDue = d->mDtDue.toTimeZone(oldZone);
-    d->mDtDue.setTimeZone(newZone);
+    auto dt = d->dtDue().toTimeZone(oldZone);
+    dt.setTimeZone(newZone);
+    d->setDtDue(dt);
     if (recurs()) {
-        d->mDtRecurrence = d->mDtRecurrence.toTimeZone(oldZone);
-        d->mDtRecurrence.setTimeZone(newZone);
+        auto dr = d->dtRecurrence().toTimeZone(oldZone);
+        dr.setTimeZone(newZone);
+        d->setDtRecurrence(dr);
     }
     if (hasCompletedDate()) {
-        d->mCompleted = d->mCompleted.toTimeZone(oldZone);
-        d->mCompleted.setTimeZone(newZone);
+        auto dc = d->completed().toTimeZone(oldZone);
+        dc.setTimeZone(newZone);
+        d->setCompleted(dc);
     }
 }
 
 void Todo::setDtRecurrence(const QDateTime &dt)
 {
-    d->mDtRecurrence = dt;
-    setFieldDirty(FieldRecurrence);
+    d->setDtRecurrence(dt);
 }
 
 QDateTime Todo::dtRecurrence() const
 {
-    return d->mDtRecurrence.isValid() ? d->mDtRecurrence : d->mDtDue;
+    return d->dtRecurrence().isValid() ? d->dtRecurrence() : d->dtDue();
 }
 
 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());
+    return Incidence::recursOn(date, timeZone) && !(date < today && 
d->dtRecurrence().date() < today && d->dtRecurrence() > 
recurrence()->startDateTime());
 }
 
 bool Todo::isOverdue() const
@@ -404,9 +470,9 @@
 
             /* 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.
+             * The reason we use "<" for date only, but "<=" for occurrences 
with time is that
+             * if it's date only, the user can still complete that occurrence 
today, so that's
+             * the current occurrence that needs completing.
              */
             while (!todo->recursAt(nextOccurrenceDateTime) || (!isDateOnly && 
nextOccurrenceDateTime <= rightNow)
                    || (isDateOnly && nextOccurrenceDateTime.date() < 
rightNow.date())) {
@@ -526,19 +592,22 @@
 void Todo::serialize(QDataStream &out) const
 {
     Incidence::serialize(out);
-    serializeQDateTimeAsKDateTime(out, d->mDtDue);
-    serializeQDateTimeAsKDateTime(out, d->mDtRecurrence);
-    serializeQDateTimeAsKDateTime(out, d->mCompleted);
-    out << d->mPercentComplete;
+    serializeQDateTimeAsKDateTime(out, d->dtDue());
+    serializeQDateTimeAsKDateTime(out, d->dtRecurrence());
+    serializeQDateTimeAsKDateTime(out, d->completed());
+    out << d->percentComplete();
 }
 
 void Todo::deserialize(QDataStream &in)
 {
     Incidence::deserialize(in);
-    deserializeKDateTimeAsQDateTime(in, d->mDtDue);
-    deserializeKDateTimeAsQDateTime(in, d->mDtRecurrence);
-    deserializeKDateTimeAsQDateTime(in, d->mCompleted);
-    in >> d->mPercentComplete;
+    d->setDtDue(deserializeKDateTimeAsQDateTime(in));
+    d->setDtRecurrence(deserializeKDateTimeAsQDateTime(in));
+    d->setCompleted(deserializeKDateTimeAsQDateTime(in));
+    int pc;
+    in >> pc;
+    d->setPercentComplete(pc);
+    resetDirtyFields();
 }
 
 bool Todo::supportsGroupwareCommunication() const
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/todo.h 
new/kcalendarcore-5.85.0/src/todo.h
--- old/kcalendarcore-5.84.0/src/todo.h 2021-06-26 17:11:22.000000000 +0200
+++ new/kcalendarcore-5.85.0/src/todo.h 2021-08-05 14:42:11.000000000 +0200
@@ -137,8 +137,9 @@
     Q_REQUIRED_RESULT QDateTime dtStart(bool first) const;
 
     /**
-      Returns if the todo is 100% completed.
-      @return true if the todo is 100% completed; false otherwise.
+      Returns whether the todo is completed or not.
+      @return true if the todo is 100% completed, has status @c 
StatusCompleted,
+      or has a completed date; false otherwise.
 
       @see isOverdue, isInProgress(), isOpenEnded(), isNotStarted(bool),
       setCompleted(), percentComplete()
@@ -146,12 +147,15 @@
     Q_REQUIRED_RESULT bool isCompleted() const;
 
     /**
-      Sets completed state.
+      Sets completion percentage and status.
 
-      @param completed If true set completed state to 100%, if false set
-      completed state to 0%.
+      @param completed If  @c true, percentage complete is set to 100%, and
+      status is set to @c StatusCompleted;  the completion date is @b not set 
or cleared.
+      If @c false, percentage complete is set to 0%,
+      status is set to @c StatusNone, and the completion date is cleared.
 
-      @see isCompleted(), percentComplete()
+
+      @see isCompleted(), percentComplete(), hasCompletedDate()
     */
     void setCompleted(bool completed);
 
@@ -163,11 +167,13 @@
     Q_REQUIRED_RESULT int percentComplete() const;
 
     /**
-      Sets what percentage of the to-do is completed. Valid values are in the
-      range from 0 to 100.
+      Sets what percentage of the to-do is completed.
+
+      To prevent inconsistency, if @p percent is not 100, completed() is 
cleared,
+      and if status() is StatusCompleted it is reset to StatusNone.
 
-      @param percent is the completion percentage, which as integer value
-      between 0 and 100, inclusive.
+      @param percent is the completion percentage.  Values greater than 100 are
+      treated as 100; values less than p are treated as 0.
 
       @see isCompleted(), setCompleted()
     */
@@ -176,13 +182,23 @@
     /**
       Returns the to-do was completion datetime.
 
-      @return A QDateTime for the completeion datetime of the to-do.
+      @return A QDateTime for the completion datetime of the to-do.
       @see hasCompletedDate()
     */
     Q_REQUIRED_RESULT QDateTime completed() const;
 
     /**
-      Sets date and time of completion.
+      Marks this Todo, or its current recurrence, as completed.
+
+      If the todo does not recur, its completion percentage is set to 100%,
+      and its completion date is set to @p completeDate.  If its status is not
+      StatusNone, it is set to StatusCompleted.
+
+      @note
+      If @p completeDate is invalid, the completion date is cleared, but the
+      todo is still "complete".
+
+      If the todo recurs, the first incomplete recurrence is marked complete.
 
       @param completeDate is the to-do completion date.
       @see completed(), hasCompletedDate()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/utils.cpp 
new/kcalendarcore-5.85.0/src/utils.cpp
--- old/kcalendarcore-5.84.0/src/utils.cpp      2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/utils.cpp      2021-08-05 14:42:11.000000000 
+0200
@@ -66,6 +66,41 @@
     in >> flags;
 }
 
+QDateTime KCalendarCore::deserializeKDateTimeAsQDateTime(QDataStream &in)
+{
+    QDateTime dt;
+    QDate date;
+    QTime time;
+    quint8 ts, flags;
+
+    in >> date >> time >> ts;
+    switch (static_cast<uchar>(ts)) {
+    case 'u':
+        dt = QDateTime(date, time, Qt::UTC);
+        break;
+    case 'o': {
+        int offset;
+        in >> offset;
+        dt = QDateTime(date, time, Qt::OffsetFromUTC, offset);
+        break;
+    }
+    case 'z': {
+        QString tzid;
+        in >> tzid;
+        dt = QDateTime(date, time, QTimeZone(tzid.toUtf8()));
+        break;
+    }
+    case 'c':
+        dt = QDateTime(date, time, Qt::LocalTime);
+        break;
+    }
+
+    // unused, we don't have a special handling for date-only QDateTime
+    in >> flags;
+
+    return dt;
+}
+
 void KCalendarCore::serializeQTimeZoneAsSpec(QDataStream &out, const QTimeZone 
&tz)
 {
     out << static_cast<quint8>('z') << (tz.isValid() ? 
QString::fromUtf8(tz.id()) : QString());
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/utils_p.h 
new/kcalendarcore-5.85.0/src/utils_p.h
--- old/kcalendarcore-5.84.0/src/utils_p.h      2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/utils_p.h      2021-08-05 14:42:11.000000000 
+0200
@@ -22,6 +22,7 @@
  */
 void serializeQDateTimeAsKDateTime(QDataStream &out, const QDateTime &dt);
 KCALENDARCORE_EXPORT void deserializeKDateTimeAsQDateTime(QDataStream &in, 
QDateTime &dt);
+KCALENDARCORE_EXPORT QDateTime deserializeKDateTimeAsQDateTime(QDataStream 
&in);
 
 void serializeQDateTimeList(QDataStream &out, const QList<QDateTime> &list);
 void deserializeQDateTimeList(QDataStream &in, QList<QDateTime> &list);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kcalendarcore-5.84.0/src/vcalformat.cpp 
new/kcalendarcore-5.85.0/src/vcalformat.cpp
--- old/kcalendarcore-5.84.0/src/vcalformat.cpp 2021-06-26 17:11:22.000000000 
+0200
+++ new/kcalendarcore-5.85.0/src/vcalformat.cpp 2021-08-05 14:42:11.000000000 
+0200
@@ -1496,7 +1496,7 @@
                 if (hasTimeZone && !aTodo->allDay() && 
aTodo->dtStart().timeZone() == QTimeZone::utc()) {
                     // This sounds stupid but is how others are doing it, so 
here
                     // we go. If there is a TZ in the VCALENDAR even if the 
dtStart
-                    // and dtend are in UTC, clients interpret it usint alse 
the TZ defined
+                    // and dtend are in UTC, clients interpret it using also 
the TZ defined
                     // in the Calendar. I know it sounds braindead but oh well
                     int utcOffSet = aTodo->dtStart().offsetFromUtc();
                     QDateTime dtStart(aTodo->dtStart().addSecs(utcOffSet));

Reply via email to