From d2a82eaec77a0f99233ea90a1b3c0e7313a8a2a3 Mon Sep 17 00:00:00 2001 From: Damien Caliste Date: Mon, 4 Jan 2021 14:21:23 +0100 Subject: [PATCH] Use the recurrenceId to delete the right occurrence. --- autotests/testmemorycalendar.cpp | 44 +++++++++++++++++++++ autotests/testmemorycalendar.h | 1 + src/memorycalendar.cpp | 66 ++++++++++++++++++++++---------- 3 files changed, 90 insertions(+), 21 deletions(-) diff --git a/autotests/testmemorycalendar.cpp b/autotests/testmemorycalendar.cpp index d73908fef..62340e9a1 100644 --- a/autotests/testmemorycalendar.cpp +++ b/autotests/testmemorycalendar.cpp @@ -404,3 +404,47 @@ void MemoryCalendarTest::testRawEvents() cal->close(); } + +void MemoryCalendarTest::testDeleteIncidence() +{ + MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc())); + + Event::Ptr event = Event::Ptr(new Event()); + event->setDtStart(QDateTime(QDate(2021, 1, 4), QTime(10, 13), + QTimeZone("Europe/Paris"))); + + QVERIFY(cal->addEvent(event)); + QVERIFY(cal->instance(event->instanceIdentifier())); + + QVERIFY(cal->deleteIncidence(event)); + QVERIFY(cal->instance(event->instanceIdentifier()).isNull()); + + event->recurrence()->setDaily(1); + event->recurrence()->setDuration(3); + QVERIFY(cal->addEvent(event)); + QVERIFY(cal->instance(event->instanceIdentifier())); + + Event::Ptr exception = Event::Ptr(event->clone()); + exception->recurrence()->clear(); + exception->setRecurrenceId(event->dtStart().addDays(1)); + exception->setDtStart(event->dtStart().addDays(1).addSecs(3600)); + QVERIFY(cal->addEvent(exception)); + QVERIFY(cal->instance(exception->instanceIdentifier())); + + Event::Ptr exception2 = Event::Ptr(event->clone()); + exception2->recurrence()->clear(); + exception2->setRecurrenceId(event->dtStart().addDays(2)); + exception2->setDtStart(event->dtStart().addDays(2).addSecs(-3600)); + QVERIFY(cal->addEvent(exception2)); + QVERIFY(cal->instance(exception2->instanceIdentifier())); + + QVERIFY(cal->deleteIncidence(exception)); + QVERIFY(cal->incidence(event->uid(), exception->recurrenceId()).isNull()); + QVERIFY(!cal->deleteIncidence(exception)); + QVERIFY(cal->incidence(event->uid(), exception2->recurrenceId())); + QVERIFY(cal->incidence(event->uid())); + + QVERIFY(cal->deleteIncidence(event)); + QVERIFY(cal->incidence(event->uid(), exception2->recurrenceId()).isNull()); + QVERIFY(cal->incidence(event->uid()).isNull()); +} diff --git a/autotests/testmemorycalendar.h b/autotests/testmemorycalendar.h index 76d6a5ebb..3eb51c34b 100644 --- a/autotests/testmemorycalendar.h +++ b/autotests/testmemorycalendar.h @@ -26,6 +26,7 @@ private Q_SLOTS: void testRawEvents(); void testRawEventsForDate(); void testVisibility(); + void testDeleteIncidence(); }; #endif diff --git a/src/memorycalendar.cpp b/src/memorycalendar.cpp index 5ee5ed439..4cd147007 100644 --- a/src/memorycalendar.cpp +++ b/src/memorycalendar.cpp @@ -89,6 +89,10 @@ public: IncidenceBase::IncidenceType type, const QDateTime &recurrenceId = {}) const; + bool deleteIncidence(const QString &uid, + IncidenceBase::IncidenceType type, + const QDateTime &recurrenceId = {}); + Incidence::Ptr deletedIncidence(const QString &uid, const QDateTime &recurrenceId, IncidenceBase::IncidenceType type) const; @@ -209,54 +213,74 @@ bool MemoryCalendar::deleteIncidence(const Incidence::Ptr &incidence) // relations is an Incidence's property, not a Todo's, so // we remove relations in deleteIncidence, not in deleteTodo. removeRelations(incidence); + // Notify while the incidence is still available, + // this is necessary so korganizer still has time to query for exceptions + notifyIncidenceAboutToBeDeleted(incidence); const Incidence::IncidenceType type = incidence->type(); - const QString uid = incidence->uid(); - auto incidenceIt = d->mIncidences[type].constFind(uid); - if (incidenceIt != d->mIncidences[type].cend()) { - // Notify while the incidence is still available, - // this is necessary so korganizer still has time to query for exceptions - notifyIncidenceAboutToBeDeleted(incidence); - - d->mIncidences[type].erase(incidenceIt); - d->mIncidencesByIdentifier.remove(incidence->instanceIdentifier()); + const QString &uid = incidence->uid(); + bool deleted = d->deleteIncidence(uid, type, incidence->recurrenceId()); + if (deleted) { 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.toTimeZone(timeZone()).date(), incidence); - } // Delete child-incidences. - if (!incidence->hasRecurrenceId()) { + if (!incidence->hasRecurrenceId() && incidence->recurs()) { deleteIncidenceInstances(incidence); } - notifyIncidenceDeleted(incidence); - return true; } else { qCWarning(KCALCORE_LOG) << incidence->typeStr() << " not found. uid=" << uid; - return false; } + notifyIncidenceDeleted(incidence); + return deleted; } bool MemoryCalendar::deleteIncidenceInstances(const Incidence::Ptr &incidence) { - d->forIncidences(d->mIncidences[incidence->type()], incidence->uid(), [this](const Incidence::Ptr &incidence) { - if (incidence->hasRecurrenceId()) { + Incidence::List instances; + for (auto it = d->mIncidences[incidence->type()].constFind(incidence->uid()), end = d->mIncidences[incidence->type()].constEnd(); it != end && it.key() == incidence->uid(); ++it) { + if (it.value()->hasRecurrenceId()) { qCDebug(KCALCORE_LOG) << "deleting child" << ", type=" << int(incidence->type()) << ", uid=" << incidence->uid() // << ", start=" << i->dtStart() << " from calendar"; - deleteIncidence(incidence); + // Don't call deleteIncidence() now since it's modifying the + // mIncidences map we're iterating over. + instances.append(it.value()); } - }); + } + for (Incidence::Ptr instance : instances) { + deleteIncidence(instance); + } return true; } //@cond PRIVATE +bool MemoryCalendar::Private::deleteIncidence(const QString &uid, + IncidenceBase::IncidenceType type, + const QDateTime &recurrenceId) +{ + for (auto it = mIncidences[type].find(uid), end = mIncidences[type].end(); it != end && it.key() == uid; ++it) { + Incidence::Ptr incidence = it.value(); + if (recurrenceId.isNull() && incidence->hasRecurrenceId()) { + continue; + } else if (!recurrenceId.isNull() && (!incidence->hasRecurrenceId() || recurrenceId != incidence->recurrenceId())) { + continue; + } + mIncidences[type].erase(it); + mIncidencesByIdentifier.remove(incidence->instanceIdentifier()); + const QDateTime dt = incidence->dateTime(Incidence::RoleCalendarHashing); + if (dt.isValid()) { + mIncidencesForDate[type].remove(dt.toTimeZone(q->timeZone()).date(), incidence); + } + return true; + } + return false; +} + void MemoryCalendar::Private::deleteAllIncidences(Incidence::IncidenceType incidenceType) { for (auto &incidence : mIncidences[incidenceType]) { -- GitLab