Commit 2637c1c1 authored by Volker Krause's avatar Volker Krause
Browse files

Determine occurrence of recurring incidences for an alarm

The main usecase for this is opening recurring events on the right
day in the calendar.

This is based on the same logic that Calendar::appendRecurringAlarms()
uses, but with ignoring two cases:
- alarms at fixed times rather than relative offsets
- recurring alarms

Handling of those cases can be added as well if needed, but those are
rare and considerably complicate the code. As we only need the
occurrence for "comfort features" rather than correct alarm displays
that seems acceptable for now.
parent 349c3066
......@@ -93,6 +93,16 @@ void AlarmNotification::setText(const QString &alarmText)
m_text = alarmText;
QDateTime AlarmNotification::occurrence() const
return m_occurrence;
void AlarmNotification::setOccurrence(const QDateTime &occurrence)
m_occurrence = occurrence;
QDateTime AlarmNotification::remindAt() const
return m_remind_at;
......@@ -44,6 +44,10 @@ public:
void setText(const QString &alarmText);
/** Occurrence time in case of recurring incidences. */
QDateTime occurrence() const;
void setOccurrence(const QDateTime &occurrence);
* @return In case of a suspended notification, the time that the notification should be displayed. Otherwise, it is empty.
......@@ -61,6 +65,7 @@ private:
QPointer<KNotification> m_notification;
QString m_uid;
QString m_text;
QDateTime m_occurrence;
QDateTime m_remind_at;
QUrl m_contextAction;
......@@ -98,11 +98,12 @@ void KalendarAlarmClient::restoreSuspendedFromConfig()
KConfigGroup suspendedAlarm(&suspendedGroup, s);
QString uid = suspendedAlarm.readEntry("UID");
QString txt = suspendedAlarm.readEntry("Text");
QDateTime occurrence = suspendedAlarm.readEntry("Occurrence", QDateTime());
QDateTime remindAt = suspendedAlarm.readEntry("RemindAt", QDateTime());
qDebug() << "restoreSuspendedFromConfig: Restoring alarm" << uid << "," << txt << "," << remindAt;
if (!uid.isEmpty() && remindAt.isValid()) {
addNotification(uid, txt, remindAt);
addNotification(uid, txt, occurrence, remindAt);
......@@ -128,6 +129,7 @@ void KalendarAlarmClient::storeNotification(AlarmNotification *notification)
KConfigGroup notificationGroup(&suspendedGroup, notification->uid());
notificationGroup.writeEntry("UID", notification->uid());
notificationGroup.writeEntry("Text", notification->text());
notificationGroup.writeEntry("Occurrence", notification->occurrence());
notificationGroup.writeEntry("RemindAt", notification->remindAt());
......@@ -140,7 +142,7 @@ void KalendarAlarmClient::removeNotification(AlarmNotification *notification)
void KalendarAlarmClient::addNotification(const QString &uid, const QString &text, const QDateTime &remindTime)
void KalendarAlarmClient::addNotification(const QString &uid, const QString &text, const QDateTime &occurrence, const QDateTime &remindTime)
AlarmNotification *notification = nullptr;
const auto it = m_notifications.constFind(uid);
......@@ -158,6 +160,7 @@ void KalendarAlarmClient::addNotification(const QString &uid, const QString &tex
// we either have no notification for this event yet, or one that is scheduled for later and that should be replaced
qDebug() << "Adding notification, uid:" << uid << "text:" << text << "remindTime:" << remindTime;
m_notifications[notification->uid()] = notification;
......@@ -206,7 +209,9 @@ void KalendarAlarmClient::checkAlarms()
const QString uid = alarm->parentUid();
addNotification(uid, alarm->text(), mLastChecked);
const auto incidence = mCalendar->incidence(uid);
const auto occurrence = occurrenceForAlarm(incidence, alarm, from);
addNotification(uid, alarm->text(), occurrence, mLastChecked);
// execute or update active alarms
......@@ -231,3 +236,42 @@ void KalendarAlarmClient::saveLastCheckTime()
cg.writeEntry("CalendarsLastChecked", mLastChecked);
// based on KCalendarCore::Calendar::appendRecurringAlarms()
KalendarAlarmClient::occurrenceForAlarm(const KCalendarCore::Incidence::Ptr &incidence, const KCalendarCore::Alarm::Ptr &alarm, const QDateTime &from) const
if (!incidence->recurs()) {
return {};
// recurring alarms not handled here for simplicity
if (alarm->repeatCount()) {
return {};
// Alarm time is defined by an offset from the event start or end time.
// Find the offset from the event start time, which is also used as the
// offset from the recurrence time.
Duration offset(0), endOffset(0);
if (alarm->hasStartOffset()) {
offset = alarm->startOffset();
} else if (alarm->hasEndOffset()) {
offset = alarm->endOffset();
endOffset = Duration(incidence->dtStart(), incidence->dateTime(Incidence::RoleAlarmEndOffset));
} else {
// alarms at a fixed time, not handled here for simplicity
return {};
// Find the incidence's earliest alarm
QDateTime alarmStart = offset.end(alarm->hasEndOffset() ? incidence->dateTime(Incidence::RoleAlarmEndOffset) : incidence->dtStart());
QDateTime baseStart = incidence->dtStart();
if (from > alarmStart) {
alarmStart = from; // don't look earlier than the earliest alarm
baseStart = (-offset).end((-endOffset).end(alarmStart));
// Find the next occurrence from the earliest possible alarm time
return incidence->recurrence()->getNextDateTime(baseStart.addSecs(-1));
......@@ -32,11 +32,12 @@ private:
void restoreSuspendedFromConfig();
void storeNotification(AlarmNotification *notification);
void removeNotification(AlarmNotification *notification);
void addNotification(const QString &uid, const QString &text, const QDateTime &remindTime);
void addNotification(const QString &uid, const QString &text, const QDateTime &occurrence, const QDateTime &remindTime);
void checkAlarms();
void setupAkonadi();
Q_REQUIRED_RESULT bool collectionsAvailable() const;
void saveLastCheckTime();
QDateTime occurrenceForAlarm(const KCalendarCore::Incidence::Ptr &incidence, const KCalendarCore::Alarm::Ptr &alarm, const QDateTime &from) const;
Akonadi::ETMCalendar::Ptr mCalendar;
Akonadi::EntityTreeModel *mETM = nullptr;
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment