1 // SPDX-FileCopyrightText: 2021 Claudio Cambra <claudio.cambra@gmail.com>
2 // SPDX-License-Identifier: LGPL-2.1-or-later
3
4 #include "kalendar_debug.h"
5 #include <KLocalizedString>
6 #include <QBitArray>
7 #include <QJSValue>
8 #include <incidencewrapper.h>
9
IncidenceWrapper(QObject * parent)10 IncidenceWrapper::IncidenceWrapper(QObject *parent)
11 : QObject(parent)
12 , Akonadi::ItemMonitor()
13 {
14 // Change incidence pointer in remindersmodel if changed here
15 connect(this, &IncidenceWrapper::incidencePtrChanged, &m_remindersModel, [=](KCalendarCore::Incidence::Ptr incidencePtr) {
16 m_remindersModel.setIncidencePtr(incidencePtr);
17 });
18 connect(this, &IncidenceWrapper::incidencePtrChanged, &m_attendeesModel, [=](KCalendarCore::Incidence::Ptr incidencePtr) {
19 m_attendeesModel.setIncidencePtr(incidencePtr);
20 });
21 connect(this, &IncidenceWrapper::incidencePtrChanged, &m_recurrenceExceptionsModel, [=](KCalendarCore::Incidence::Ptr incidencePtr) {
22 m_recurrenceExceptionsModel.setIncidencePtr(incidencePtr);
23 });
24 connect(this, &IncidenceWrapper::incidencePtrChanged, &m_attachmentsModel, [=](KCalendarCore::Incidence::Ptr incidencePtr) {
25 m_attachmentsModel.setIncidencePtr(incidencePtr);
26 });
27
28 Akonadi::ItemFetchScope scope;
29 scope.fetchFullPayload();
30 scope.fetchAllAttributes();
31 scope.setFetchRelations(true);
32 scope.setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
33 setFetchScope(scope);
34
35 setNewEvent();
36 }
37
38 IncidenceWrapper::~IncidenceWrapper() = default;
39
notifyDataChanged()40 void IncidenceWrapper::notifyDataChanged()
41 {
42 Q_EMIT incidenceTypeChanged();
43 Q_EMIT incidenceTypeStrChanged();
44 Q_EMIT incidenceIconNameChanged();
45 Q_EMIT collectionIdChanged();
46 Q_EMIT summaryChanged();
47 Q_EMIT categoriesChanged();
48 Q_EMIT descriptionChanged();
49 Q_EMIT locationChanged();
50 Q_EMIT incidenceStartChanged();
51 Q_EMIT incidenceStartDateDisplayChanged();
52 Q_EMIT incidenceStartTimeDisplayChanged();
53 Q_EMIT incidenceEndChanged();
54 Q_EMIT incidenceEndDateDisplayChanged();
55 Q_EMIT incidenceEndTimeDisplayChanged();
56 Q_EMIT timeZoneChanged();
57 Q_EMIT startTimeZoneUTCOffsetMinsChanged();
58 Q_EMIT endTimeZoneUTCOffsetMinsChanged();
59 Q_EMIT allDayChanged();
60 Q_EMIT priorityChanged();
61 Q_EMIT remindersModelChanged();
62 Q_EMIT organizerChanged();
63 Q_EMIT attendeesModelChanged();
64 Q_EMIT recurrenceDataChanged();
65 Q_EMIT recurrenceExceptionsModelChanged();
66 Q_EMIT attachmentsModelChanged();
67 Q_EMIT todoCompletedChanged();
68 Q_EMIT todoCompletionDtChanged();
69 Q_EMIT todoPercentCompleteChanged();
70 }
71
incidenceItem() const72 Akonadi::Item IncidenceWrapper::incidenceItem() const
73 {
74 return item();
75 }
76
setIncidenceItem(const Akonadi::Item & incidenceItem)77 void IncidenceWrapper::setIncidenceItem(const Akonadi::Item &incidenceItem)
78 {
79 if (incidenceItem.hasPayload<KCalendarCore::Incidence::Ptr>()) {
80 setItem(incidenceItem);
81 setIncidencePtr(incidenceItem.payload<KCalendarCore::Incidence::Ptr>());
82 Q_EMIT incidenceItemChanged();
83 Q_EMIT collectionIdChanged();
84 } else {
85 qCWarning(KALENDAR_LOG) << "This is not an incidence item.";
86 }
87 }
88
incidencePtr() const89 KCalendarCore::Incidence::Ptr IncidenceWrapper::incidencePtr() const
90 {
91 return m_incidence;
92 }
93
setIncidencePtr(const KCalendarCore::Incidence::Ptr incidencePtr)94 void IncidenceWrapper::setIncidencePtr(const KCalendarCore::Incidence::Ptr incidencePtr)
95 {
96 m_incidence = incidencePtr;
97
98 KCalendarCore::Incidence::Ptr originalIncidence(incidencePtr->clone());
99 m_originalIncidence = originalIncidence;
100
101 Q_EMIT incidencePtrChanged(incidencePtr);
102 Q_EMIT originalIncidencePtrChanged();
103 notifyDataChanged();
104 }
105
originalIncidencePtr()106 KCalendarCore::Incidence::Ptr IncidenceWrapper::originalIncidencePtr()
107 {
108 return m_originalIncidence;
109 }
110
incidenceType() const111 int IncidenceWrapper::incidenceType() const
112 {
113 return m_incidence->type();
114 }
115
incidenceTypeStr() const116 QString IncidenceWrapper::incidenceTypeStr() const
117 {
118 return m_incidence->type() == KCalendarCore::Incidence::TypeTodo ? i18n("Task") : i18n(m_incidence->typeStr());
119 }
120
incidenceIconName() const121 QString IncidenceWrapper::incidenceIconName() const
122 {
123 return m_incidence->iconName();
124 }
125
uid() const126 QString IncidenceWrapper::uid() const
127 {
128 return m_incidence->uid();
129 }
130
collectionId() const131 qint64 IncidenceWrapper::collectionId() const
132 {
133 return m_collectionId < 0 ? item().parentCollection().id() : m_collectionId;
134 }
135
setCollectionId(qint64 collectionId)136 void IncidenceWrapper::setCollectionId(qint64 collectionId)
137 {
138 m_collectionId = collectionId;
139 Q_EMIT collectionIdChanged();
140 }
141
parent() const142 QString IncidenceWrapper::parent() const
143 {
144 return m_incidence->relatedTo();
145 }
146
setParent(QString parent)147 void IncidenceWrapper::setParent(QString parent)
148 {
149 m_incidence->setRelatedTo(parent);
150 Q_EMIT parentChanged();
151 }
152
summary() const153 QString IncidenceWrapper::summary() const
154 {
155 return m_incidence->summary();
156 }
157
setSummary(const QString & summary)158 void IncidenceWrapper::setSummary(const QString &summary)
159 {
160 m_incidence->setSummary(summary);
161 Q_EMIT summaryChanged();
162 }
163
categories()164 QStringList IncidenceWrapper::categories()
165 {
166 return m_incidence->categories();
167 }
168
setCategories(QStringList categories)169 void IncidenceWrapper::setCategories(QStringList categories)
170 {
171 m_incidence->setCategories(categories);
172 Q_EMIT categoriesChanged();
173 }
174
description() const175 QString IncidenceWrapper::description() const
176 {
177 return m_incidence->description();
178 }
179
setDescription(const QString & description)180 void IncidenceWrapper::setDescription(const QString &description)
181 {
182 if (m_incidence->description() == description) {
183 return;
184 }
185 m_incidence->setDescription(description);
186 Q_EMIT descriptionChanged();
187 }
188
location() const189 QString IncidenceWrapper::location() const
190 {
191 return m_incidence->location();
192 }
193
setLocation(const QString & location)194 void IncidenceWrapper::setLocation(const QString &location)
195 {
196 m_incidence->setLocation(location);
197 Q_EMIT locationChanged();
198 }
199
hasGeo() const200 bool IncidenceWrapper::hasGeo() const
201 {
202 return m_incidence->hasGeo();
203 }
204
geoLatitude() const205 float IncidenceWrapper::geoLatitude() const
206 {
207 return m_incidence->geoLatitude();
208 }
209
geoLongitude() const210 float IncidenceWrapper::geoLongitude() const
211 {
212 return m_incidence->geoLongitude();
213 }
214
incidenceStart() const215 QDateTime IncidenceWrapper::incidenceStart() const
216 {
217 return m_incidence->dtStart();
218 }
219
setIncidenceStart(const QDateTime & incidenceStart,bool respectTimeZone)220 void IncidenceWrapper::setIncidenceStart(const QDateTime &incidenceStart, bool respectTimeZone)
221 {
222 // When we receive dates from QML, these are all set to the local system timezone but
223 // have the dates and times we want. We need to preserve date and time but set the new
224 // QDateTime to have the correct timezone.
225
226 // When we set the timeZone property, however, we invariably also set the incidence start and end.
227 // This object needs no change. We therefore need to make sure to preserve the entire QDateTime object here.
228 auto oldStart = this->incidenceStart();
229
230 if (respectTimeZone) {
231 m_incidence->setDtStart(incidenceStart);
232 auto newTzEnd = incidenceEnd();
233 newTzEnd.setTimeZone(incidenceStart.timeZone());
234 setIncidenceEnd(newTzEnd, true);
235 } else {
236 const auto date = incidenceStart.date();
237 const auto time = incidenceStart.time();
238 QDateTime start;
239 start.setTimeZone(QTimeZone(timeZone()));
240 start.setDate(date);
241 start.setTime(time);
242 m_incidence->setDtStart(start);
243 }
244
245 auto oldStartEndDifference = oldStart.secsTo(incidenceEnd());
246 auto newEnd = this->incidenceStart().addSecs(oldStartEndDifference);
247 setIncidenceEnd(newEnd);
248
249 Q_EMIT incidenceStartChanged();
250 Q_EMIT incidenceStartDateDisplayChanged();
251 Q_EMIT incidenceStartTimeDisplayChanged();
252 }
253
setIncidenceStartDate(int day,int month,int year)254 void IncidenceWrapper::setIncidenceStartDate(int day, int month, int year)
255 {
256 QDate date;
257 date.setDate(year, month, day);
258
259 auto newStart = incidenceStart();
260 newStart.setDate(date);
261
262 setIncidenceStart(newStart, true);
263 }
264
setIncidenceStartTime(int hours,int minutes)265 void IncidenceWrapper::setIncidenceStartTime(int hours, int minutes)
266 {
267 QTime time;
268 time.setHMS(hours, minutes, 0);
269
270 auto newStart = incidenceStart();
271 newStart.setTime(time);
272
273 setIncidenceStart(newStart, true);
274 }
275
incidenceStartDateDisplay() const276 QString IncidenceWrapper::incidenceStartDateDisplay() const
277 {
278 return QLocale::system().toString(incidenceStart().date(), QLocale::NarrowFormat);
279 }
280
incidenceStartTimeDisplay() const281 QString IncidenceWrapper::incidenceStartTimeDisplay() const
282 {
283 return QLocale::system().toString(incidenceStart().time(), QLocale::NarrowFormat);
284 }
285
incidenceEnd() const286 QDateTime IncidenceWrapper::incidenceEnd() const
287 {
288 if (m_incidence->type() == KCalendarCore::Incidence::IncidenceType::TypeEvent) {
289 KCalendarCore::Event::Ptr event = m_incidence.staticCast<KCalendarCore::Event>();
290 return event->dtEnd();
291 } else if (m_incidence->type() == KCalendarCore::Incidence::IncidenceType::TypeTodo) {
292 KCalendarCore::Todo::Ptr todo = m_incidence.staticCast<KCalendarCore::Todo>();
293 return todo->dtDue();
294 }
295 return {};
296 }
297
setIncidenceEnd(const QDateTime & incidenceEnd,bool respectTimeZone)298 void IncidenceWrapper::setIncidenceEnd(const QDateTime &incidenceEnd, bool respectTimeZone)
299 {
300 QDateTime end;
301 if (respectTimeZone) {
302 end = incidenceEnd;
303 } else {
304 const auto date = incidenceEnd.date();
305 const auto time = incidenceEnd.time();
306 end.setTimeZone(QTimeZone(timeZone()));
307 end.setDate(date);
308 end.setTime(time);
309 }
310
311 if (m_incidence->type() == KCalendarCore::Incidence::IncidenceType::TypeEvent) {
312 KCalendarCore::Event::Ptr event = m_incidence.staticCast<KCalendarCore::Event>();
313 event->setDtEnd(end);
314 } else if (m_incidence->type() == KCalendarCore::Incidence::IncidenceType::TypeTodo) {
315 KCalendarCore::Todo::Ptr todo = m_incidence.staticCast<KCalendarCore::Todo>();
316 todo->setDtDue(end);
317 } else {
318 qCWarning(KALENDAR_LOG) << "Unknown incidence type";
319 }
320 Q_EMIT incidenceEndChanged();
321 Q_EMIT incidenceEndDateDisplayChanged();
322 Q_EMIT incidenceEndTimeDisplayChanged();
323 }
324
setIncidenceEndDate(int day,int month,int year)325 void IncidenceWrapper::setIncidenceEndDate(int day, int month, int year)
326 {
327 QDate date;
328 date.setDate(year, month, day);
329
330 auto newEnd = incidenceEnd();
331 newEnd.setDate(date);
332
333 setIncidenceEnd(newEnd, true);
334 }
335
setIncidenceEndTime(int hours,int minutes)336 void IncidenceWrapper::setIncidenceEndTime(int hours, int minutes)
337 {
338 QTime time;
339 time.setHMS(hours, minutes, 0);
340
341 auto newEnd = incidenceEnd();
342 newEnd.setTime(time);
343
344 setIncidenceEnd(newEnd, true);
345 }
346
incidenceEndDateDisplay() const347 QString IncidenceWrapper::incidenceEndDateDisplay() const
348 {
349 return QLocale::system().toString(incidenceEnd().date(), QLocale::NarrowFormat);
350 }
351
incidenceEndTimeDisplay() const352 QString IncidenceWrapper::incidenceEndTimeDisplay() const
353 {
354 return QLocale::system().toString(incidenceEnd().time(), QLocale::NarrowFormat);
355 }
356
timeZone() const357 QByteArray IncidenceWrapper::timeZone() const
358 {
359 return incidenceEnd().timeZone().id();
360 }
361
setTimeZone(const QByteArray & timeZone)362 void IncidenceWrapper::setTimeZone(const QByteArray &timeZone)
363 {
364 QDateTime start(incidenceStart());
365 if (start.isValid()) {
366 start.setTimeZone(QTimeZone(timeZone));
367 setIncidenceStart(start, true);
368 }
369
370 QDateTime end(incidenceEnd());
371 if (end.isValid()) {
372 end.setTimeZone(QTimeZone(timeZone));
373 setIncidenceEnd(end, true);
374 }
375
376 Q_EMIT timeZoneChanged();
377 Q_EMIT startTimeZoneUTCOffsetMinsChanged();
378 Q_EMIT endTimeZoneUTCOffsetMinsChanged();
379 }
380
startTimeZoneUTCOffsetMins()381 int IncidenceWrapper::startTimeZoneUTCOffsetMins()
382 {
383 return QTimeZone(timeZone()).offsetFromUtc(incidenceStart());
384 }
385
endTimeZoneUTCOffsetMins()386 int IncidenceWrapper::endTimeZoneUTCOffsetMins()
387 {
388 return QTimeZone(timeZone()).offsetFromUtc(incidenceEnd());
389 }
390
allDay() const391 bool IncidenceWrapper::allDay() const
392 {
393 return m_incidence->allDay();
394 }
395
setAllDay(bool allDay)396 void IncidenceWrapper::setAllDay(bool allDay)
397 {
398 m_incidence->setAllDay(allDay);
399 Q_EMIT allDayChanged();
400 }
401
priority() const402 int IncidenceWrapper::priority() const
403 {
404 return m_incidence->priority();
405 }
406
setPriority(int priority)407 void IncidenceWrapper::setPriority(int priority)
408 {
409 m_incidence->setPriority(priority);
410 Q_EMIT priorityChanged();
411 }
412
recurrence() const413 KCalendarCore::Recurrence *IncidenceWrapper::recurrence() const
414 {
415 KCalendarCore::Recurrence *recurrence = m_incidence->recurrence();
416 return recurrence;
417 }
418
recurrenceData()419 QVariantMap IncidenceWrapper::recurrenceData()
420 {
421 QBitArray weekDaysBits = m_incidence->recurrence()->days();
422 QVector<bool> weekDaysBools(7);
423
424 for (int i = 0; i < weekDaysBits.size(); i++) {
425 weekDaysBools[i] = weekDaysBits[i];
426 }
427
428 QVariantList monthPositions;
429 const auto monthPositionsToConvert = m_incidence->recurrence()->monthPositions();
430 for (const auto &pos : monthPositionsToConvert) {
431 QVariantMap positionToAdd;
432 positionToAdd[QStringLiteral("day")] = pos.day();
433 positionToAdd[QStringLiteral("pos")] = pos.pos();
434 monthPositions.append(positionToAdd);
435 }
436
437 // FYI: yearPositions() just calls monthPositions(), so we're cutting out the middleman
438 return QVariantMap{
439 {QStringLiteral("weekdays"), QVariant::fromValue(weekDaysBools)},
440 {QStringLiteral("duration"), m_incidence->recurrence()->duration()},
441 {QStringLiteral("frequency"), m_incidence->recurrence()->frequency()},
442 {QStringLiteral("startDateTime"), m_incidence->recurrence()->startDateTime()},
443 {QStringLiteral("startDateTimeDisplay"), QLocale::system().toString(m_incidence->recurrence()->startDateTime(), QLocale::NarrowFormat)},
444 {QStringLiteral("endDateTime"), m_incidence->recurrence()->endDateTime()},
445 {QStringLiteral("endDateTimeDisplay"), QLocale::system().toString(m_incidence->recurrence()->endDateTime(), QLocale::NarrowFormat)},
446 {QStringLiteral("allDay"), m_incidence->recurrence()->allDay()},
447 {QStringLiteral("type"), m_incidence->recurrence()->recurrenceType()},
448 {QStringLiteral("monthDays"), QVariant::fromValue(m_incidence->recurrence()->monthDays())},
449 {QStringLiteral("monthPositions"), monthPositions},
450 {QStringLiteral("yearDays"), QVariant::fromValue(m_incidence->recurrence()->yearDays())},
451 {QStringLiteral("yearDates"), QVariant::fromValue(m_incidence->recurrence()->yearDates())},
452 {QStringLiteral("yearMonths"), QVariant::fromValue(m_incidence->recurrence()->yearMonths())},
453 };
454 }
455
setRecurrenceDataItem(const QString & key,const QVariant & value)456 void IncidenceWrapper::setRecurrenceDataItem(const QString &key, const QVariant &value)
457 {
458 QVariantMap map = recurrenceData();
459 if (map.contains(key)) {
460 if (key == QStringLiteral("weekdays") && value.canConvert<QJSValue>()) {
461 auto jsval = value.value<QJSValue>();
462
463 if (!jsval.isArray()) {
464 return;
465 }
466
467 auto vlist = jsval.toVariant().value<QVariantList>();
468 QBitArray days(7);
469
470 for (int i = 0; i < vlist.size(); i++) {
471 days[i] = vlist[i].toBool();
472 }
473
474 KCalendarCore::RecurrenceRule *rrule = m_incidence->recurrence()->defaultRRule();
475 QList<KCalendarCore::RecurrenceRule::WDayPos> positions;
476
477 for (int i = 0; i < 7; ++i) {
478 if (days.testBit(i)) {
479 KCalendarCore::RecurrenceRule::WDayPos p(0, i + 1);
480 positions.append(p);
481 }
482 }
483
484 rrule->setByDays(positions);
485 m_incidence->recurrence()->updated();
486
487 } else if (key == QStringLiteral("duration")) {
488 m_incidence->recurrence()->setDuration(value.toInt());
489
490 } else if (key == QStringLiteral("frequency")) {
491 m_incidence->recurrence()->setFrequency(value.toInt());
492
493 } else if ((key == QStringLiteral("startDateTime") || key == QStringLiteral("endDateTime")) && value.toDateTime().isValid()) {
494 auto dt = value.toDateTime();
495 QDateTime adjustedDt;
496 adjustedDt.setTimeZone(incidenceEnd().timeZone());
497 adjustedDt.setDate(dt.date());
498 adjustedDt.setTime(dt.time());
499
500 if (key == QStringLiteral("startDateTime")) {
501 m_incidence->recurrence()->setStartDateTime(adjustedDt, false);
502
503 } else if (key == QStringLiteral("endDateTime")) {
504 m_incidence->recurrence()->setEndDateTime(adjustedDt);
505 }
506
507 } else if (key == QStringLiteral("allDay")) {
508 m_incidence->recurrence()->setAllDay(value.toBool());
509
510 } else if (key == QStringLiteral("monthDays") && value.canConvert<QList<int>>()) {
511 m_incidence->recurrence()->setMonthlyDate(value.value<QList<int>>());
512
513 } else if (key == QStringLiteral("yearDays") && value.canConvert<QList<int>>()) {
514 m_incidence->recurrence()->setYearlyDay(value.value<QList<int>>());
515
516 } else if (key == QStringLiteral("yearDates") && value.canConvert<QList<int>>()) {
517 m_incidence->recurrence()->setYearlyDate(value.value<QList<int>>());
518
519 } else if (key == QStringLiteral("yearMonths") && value.canConvert<QList<int>>()) {
520 m_incidence->recurrence()->setYearlyMonth(value.value<QList<int>>());
521
522 } else if (key == QStringLiteral("monthPositions") && value.canConvert<QList<QVariantMap>>()) {
523 QList<KCalendarCore::RecurrenceRule::WDayPos> newMonthPositions;
524 const auto values = value.value<QList<QVariantMap>>();
525 for (const auto &pos : values) {
526 KCalendarCore::RecurrenceRule::WDayPos newPos;
527 newPos.setDay(pos[QStringLiteral("day")].toInt());
528 newPos.setPos(pos[QStringLiteral("pos")].toInt());
529 newMonthPositions.append(newPos);
530 }
531
532 m_incidence->recurrence()->setMonthlyPos(newMonthPositions);
533 }
534 }
535 Q_EMIT recurrenceDataChanged();
536 }
537
organizer()538 QVariantMap IncidenceWrapper::organizer()
539 {
540 auto organizerPerson = m_incidence->organizer();
541 return QVariantMap{{QStringLiteral("name"), organizerPerson.name()},
542 {QStringLiteral("email"), organizerPerson.email()},
543 {QStringLiteral("fullName"), organizerPerson.fullName()}};
544 }
545
attendees() const546 KCalendarCore::Attendee::List IncidenceWrapper::attendees() const
547 {
548 return m_incidence->attendees();
549 }
550
remindersModel()551 RemindersModel *IncidenceWrapper::remindersModel()
552 {
553 return &m_remindersModel;
554 }
555
attendeesModel()556 AttendeesModel *IncidenceWrapper::attendeesModel()
557 {
558 return &m_attendeesModel;
559 }
560
recurrenceExceptionsModel()561 RecurrenceExceptionsModel *IncidenceWrapper::recurrenceExceptionsModel()
562 {
563 return &m_recurrenceExceptionsModel;
564 }
565
attachmentsModel()566 AttachmentsModel *IncidenceWrapper::attachmentsModel()
567 {
568 return &m_attachmentsModel;
569 }
570
todoCompleted()571 bool IncidenceWrapper::todoCompleted()
572 {
573 if (m_incidence->type() != KCalendarCore::IncidenceBase::TypeTodo) {
574 return false;
575 }
576
577 auto todo = m_incidence.staticCast<KCalendarCore::Todo>();
578 return todo->isCompleted();
579 }
580
setTodoCompleted(bool completed)581 void IncidenceWrapper::setTodoCompleted(bool completed)
582 {
583 if (m_incidence->type() != KCalendarCore::IncidenceBase::TypeTodo) {
584 return;
585 }
586
587 auto todo = m_incidence.staticCast<KCalendarCore::Todo>();
588 todo->setCompleted(completed);
589
590 Q_EMIT todoCompletionDtChanged();
591 Q_EMIT todoPercentCompleteChanged();
592 Q_EMIT incidenceIconNameChanged();
593 Q_EMIT todoCompletedChanged();
594 }
595
todoCompletionDt()596 QDateTime IncidenceWrapper::todoCompletionDt()
597 {
598 if (m_incidence->type() != KCalendarCore::IncidenceBase::TypeTodo) {
599 return {};
600 }
601
602 auto todo = m_incidence.staticCast<KCalendarCore::Todo>();
603 return todo->completed();
604 }
605
todoPercentComplete()606 int IncidenceWrapper::todoPercentComplete()
607 {
608 if (m_incidence->type() != KCalendarCore::IncidenceBase::TypeTodo) {
609 return 0;
610 }
611
612 auto todo = m_incidence.staticCast<KCalendarCore::Todo>();
613 return todo->percentComplete();
614 }
615
setTodoPercentComplete(int todoPercentComplete)616 void IncidenceWrapper::setTodoPercentComplete(int todoPercentComplete)
617 {
618 if (m_incidence->type() != KCalendarCore::IncidenceBase::TypeTodo) {
619 return;
620 }
621
622 auto todo = m_incidence.staticCast<KCalendarCore::Todo>();
623 todo->setPercentComplete(todoPercentComplete);
624
625 Q_EMIT todoPercentCompleteChanged();
626
627 if (todoPercentComplete < 100 && todoCompleted()) {
628 setTodoCompleted(false);
629 }
630
631 Q_EMIT todoCompletedChanged();
632 }
633
triggerEditMode()634 void IncidenceWrapper::triggerEditMode() // You edit a clone so that the original ptr isn't messed with
635 {
636 KCalendarCore::Incidence::Ptr clonedPtr(m_incidence->clone());
637 setIncidencePtr(clonedPtr);
638 }
639
nearestQuarterHour(int secsSinceEpoch)640 static int nearestQuarterHour(int secsSinceEpoch)
641 {
642 const int quarterHourInSecs = 60 * 15;
643 return secsSinceEpoch + (quarterHourInSecs - secsSinceEpoch % quarterHourInSecs);
644 }
645
setNewEvent()646 void IncidenceWrapper::setNewEvent()
647 {
648 auto event = KCalendarCore::Event::Ptr(new KCalendarCore::Event);
649 QDateTime start;
650 start.setSecsSinceEpoch(nearestQuarterHour(QDateTime::currentSecsSinceEpoch()));
651 event->setDtStart(start);
652 event->setDtEnd(start.addSecs(60 * 60));
653
654 Akonadi::Item incidenceItem;
655 incidenceItem.setPayload<KCalendarCore::Event::Ptr>(event);
656 setIncidenceItem(incidenceItem);
657 }
658
setNewTodo()659 void IncidenceWrapper::setNewTodo()
660 {
661 auto todo = KCalendarCore::Todo::Ptr(new KCalendarCore::Todo);
662 Akonadi::Item incidenceItem;
663 incidenceItem.setPayload<KCalendarCore::Todo::Ptr>(todo);
664 setIncidenceItem(incidenceItem);
665 }
666
addAlarms(KCalendarCore::Alarm::List alarms)667 void IncidenceWrapper::addAlarms(KCalendarCore::Alarm::List alarms)
668 {
669 for (int i = 0; i < alarms.size(); i++) {
670 m_incidence->addAlarm(alarms[i]);
671 }
672 }
673
setRegularRecurrence(IncidenceWrapper::RecurrenceIntervals interval,int freq)674 void IncidenceWrapper::setRegularRecurrence(IncidenceWrapper::RecurrenceIntervals interval, int freq)
675 {
676 switch (interval) {
677 case Daily:
678 m_incidence->recurrence()->setDaily(freq);
679 Q_EMIT recurrenceDataChanged();
680 return;
681 case Weekly:
682 m_incidence->recurrence()->setWeekly(freq);
683 Q_EMIT recurrenceDataChanged();
684 return;
685 case Monthly:
686 m_incidence->recurrence()->setMonthly(freq);
687 Q_EMIT recurrenceDataChanged();
688 return;
689 case Yearly:
690 m_incidence->recurrence()->setYearly(freq);
691 Q_EMIT recurrenceDataChanged();
692 return;
693 default:
694 qCWarning(KALENDAR_LOG) << "Unknown interval for recurrence" << interval;
695 return;
696 }
697 }
698
setMonthlyPosRecurrence(short pos,int day)699 void IncidenceWrapper::setMonthlyPosRecurrence(short pos, int day)
700 {
701 QBitArray daysBitArray(7);
702 daysBitArray[day] = 1;
703 m_incidence->recurrence()->addMonthlyPos(pos, daysBitArray);
704 }
705
setRecurrenceOccurrences(int occurrences)706 void IncidenceWrapper::setRecurrenceOccurrences(int occurrences)
707 {
708 m_incidence->recurrence()->setDuration(occurrences);
709 Q_EMIT recurrenceDataChanged();
710 }
711
clearRecurrences()712 void IncidenceWrapper::clearRecurrences()
713 {
714 m_incidence->recurrence()->clear();
715 Q_EMIT recurrenceDataChanged();
716 }
717
itemChanged(const Akonadi::Item & item)718 void IncidenceWrapper::itemChanged(const Akonadi::Item &item)
719 {
720 if (item.hasPayload<KCalendarCore::Incidence::Ptr>()) {
721 qCDebug(KALENDAR_LOG) << item.payload<KCalendarCore::Incidence::Ptr>()->summary() << item.parentCollection().id();
722 setIncidencePtr(item.payload<KCalendarCore::Incidence::Ptr>());
723 }
724 }
725
726 Q_DECLARE_METATYPE(KCalendarCore::Incidence::Ptr);
727