MauiKit Calendar

incidencewrapper.cpp
1// SPDX-FileCopyrightText: 2021 Claudio Cambra <claudio.cambra@gmail.com>
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#include <KLocalizedString>
5#include <QBitArray>
6#include <QJSValue>
7#include <incidencewrapper.h>
8#include <QDebug>
9
10IncidenceWrapper::IncidenceWrapper(QObject *parent)
11: QObject(parent)
12, Akonadi::ItemMonitor()
13{
14// connect(this, &IncidenceWrapper::incidencePtrChanged, &m_attendeesModel, [=](KCalendarCore::Incidence::Ptr incidencePtr) {
15// m_attendeesModel.setIncidencePtr(incidencePtr);
16// });
17// connect(this, &IncidenceWrapper::incidencePtrChanged, &m_recurrenceExceptionsModel, [=](KCalendarCore::Incidence::Ptr incidencePtr) {
18// m_recurrenceExceptionsModel.setIncidencePtr(incidencePtr);
19// });
20// connect(this, &IncidenceWrapper::incidencePtrChanged, &m_attachmentsModel, [=](KCalendarCore::Incidence::Ptr incidencePtr) {
21// m_attachmentsModel.setIncidencePtr(incidencePtr);
22// });
23//
24 // While generally we know of the relationship an incidence has regarding its parent,
25 // from the POV of an incidence, we have no idea of its relationship to its children.
26 // This is a limitation of KCalendarCore, which only supports one type of relationship
27 // type per incidence and throughout the PIM infrastructure it is always the 'parent'
28 // relationship that is used.
29
30 // We therefore need to rely on the ETMCalendar for this information. Since the ETMCalendar
31 // does not provide us with any specific information about the incidences changed when it
32 // updates, we unfortunately have to this the coarse way and just update everything when
33 // things change.
34 connect(CalendarManager::instance(), &CalendarManager::calendarChanged, this, &IncidenceWrapper::resetChildIncidences);
35
37 scope.fetchFullPayload();
38 scope.fetchAllAttributes();
39 scope.setFetchRelations(true);
41 setFetchScope(scope);
42
43 setNewEvent();
44}
45
46IncidenceWrapper::~IncidenceWrapper()
47{
48 cleanupChildIncidences();
49}
50
51void IncidenceWrapper::notifyDataChanged()
52{
53 Q_EMIT incidenceTypeChanged();
54 Q_EMIT incidenceTypeStrChanged();
55 Q_EMIT incidenceIconNameChanged();
56 Q_EMIT collectionIdChanged();
57 Q_EMIT parentChanged();
58 Q_EMIT parentIncidenceChanged();
59 Q_EMIT childIncidencesChanged();
60 Q_EMIT summaryChanged();
61 Q_EMIT categoriesChanged();
62 Q_EMIT descriptionChanged();
63 Q_EMIT locationChanged();
64 Q_EMIT incidenceStartChanged();
65 Q_EMIT incidenceStartDateDisplayChanged();
66 Q_EMIT incidenceStartTimeDisplayChanged();
67 Q_EMIT incidenceEndChanged();
68 Q_EMIT incidenceEndDateDisplayChanged();
69 Q_EMIT incidenceEndTimeDisplayChanged();
70 Q_EMIT timeZoneChanged();
71 Q_EMIT startTimeZoneUTCOffsetMinsChanged();
72 Q_EMIT endTimeZoneUTCOffsetMinsChanged();
73 Q_EMIT durationChanged();
74 Q_EMIT durationDisplayStringChanged();
75 Q_EMIT allDayChanged();
76 Q_EMIT priorityChanged();
77 Q_EMIT organizerChanged();
78 // Q_EMIT attendeesModelChanged();
79 Q_EMIT recurrenceDataChanged();
80 // Q_EMIT recurrenceExceptionsModelChanged();
81 // Q_EMIT attachmentsModelChanged();
82 Q_EMIT todoCompletedChanged();
83 Q_EMIT todoCompletionDtChanged();
84 Q_EMIT todoPercentCompleteChanged();
85 Q_EMIT googleConferenceUrlChanged();
86}
87
88Akonadi::Item IncidenceWrapper::incidenceItem() const
89{
90 return item();
91}
92
93void IncidenceWrapper::setIncidenceItem(const Akonadi::Item &incidenceItem)
94{
95 if (incidenceItem.hasPayload<KCalendarCore::Incidence::Ptr>()) {
96 setItem(incidenceItem);
97 setIncidencePtr(incidenceItem.payload<KCalendarCore::Incidence::Ptr>());
98
99 Q_EMIT incidenceItemChanged();
100 Q_EMIT collectionIdChanged();
101 } else {
102 qWarning() << "This is not an incidence item.";
103 }
104}
105
106KCalendarCore::Incidence::Ptr IncidenceWrapper::incidencePtr() const
107{
108 return m_incidence;
109}
110
111void IncidenceWrapper::setIncidencePtr(const KCalendarCore::Incidence::Ptr incidencePtr)
112{
113 m_incidence = incidencePtr;
114
116 m_originalIncidence = originalIncidence;
117
118 Q_EMIT incidencePtrChanged(incidencePtr);
119 Q_EMIT originalIncidencePtrChanged();
120 notifyDataChanged();
121}
122
123KCalendarCore::Incidence::Ptr IncidenceWrapper::originalIncidencePtr()
124{
125 return m_originalIncidence;
126}
127
128int IncidenceWrapper::incidenceType() const
129{
130 return m_incidence->type();
131}
132
133QString IncidenceWrapper::incidenceTypeStr() const
134{
135 return m_incidence->type() == KCalendarCore::Incidence::TypeTodo ? i18n("Task") : i18n(m_incidence->typeStr().constData());
136}
137
138QString IncidenceWrapper::incidenceIconName() const
139{
140 return m_incidence->iconName();
141}
142
143QString IncidenceWrapper::uid() const
144{
145 return m_incidence->uid();
146}
147
148qint64 IncidenceWrapper::collectionId() const
149{
150 return m_collectionId < 0 ? item().parentCollection().id() : m_collectionId;
151}
152
153void IncidenceWrapper::setCollectionId(qint64 collectionId)
154{
155 m_collectionId = collectionId;
156 Q_EMIT collectionIdChanged();
157}
158
159QString IncidenceWrapper::parent() const
160{
161 return m_incidence->relatedTo();
162}
163
164void IncidenceWrapper::setParent(QString parent)
165{
166 m_incidence->setRelatedTo(parent);
167 updateParentIncidence();
168 Q_EMIT parentChanged();
169}
170
171IncidenceWrapper *IncidenceWrapper::parentIncidence()
172{
173 updateParentIncidence();
174 return m_parentIncidence.data();
175}
176
177QVariantList IncidenceWrapper::childIncidences()
178{
179 resetChildIncidences();
180 return m_childIncidences;
181}
182
183QString IncidenceWrapper::summary() const
184{
185 return m_incidence->summary();
186}
187
188void IncidenceWrapper::setSummary(const QString &summary)
189{
190 m_incidence->setSummary(summary);
191 Q_EMIT summaryChanged();
192}
193
194QStringList IncidenceWrapper::categories()
195{
196 return m_incidence->categories();
197}
198
199void IncidenceWrapper::setCategories(QStringList categories)
200{
201 m_incidence->setCategories(categories);
202 Q_EMIT categoriesChanged();
203}
204
205QString IncidenceWrapper::description() const
206{
207 return m_incidence->description();
208}
209
210void IncidenceWrapper::setDescription(const QString &description)
211{
212 if (m_incidence->description() == description) {
213 return;
214 }
215 m_incidence->setDescription(description);
216 Q_EMIT descriptionChanged();
217}
218
219QString IncidenceWrapper::location() const
220{
221 return m_incidence->location();
222}
223
224void IncidenceWrapper::setLocation(const QString &location)
225{
226 m_incidence->setLocation(location);
227 Q_EMIT locationChanged();
228}
229
230bool IncidenceWrapper::hasGeo() const
231{
232 return m_incidence->hasGeo();
233}
234
235float IncidenceWrapper::geoLatitude() const
236{
237 return m_incidence->geoLatitude();
238}
239
240float IncidenceWrapper::geoLongitude() const
241{
242 return m_incidence->geoLongitude();
243}
244
245QDateTime IncidenceWrapper::incidenceStart() const
246{
247 return m_incidence->dtStart();
248}
249
250void IncidenceWrapper::setIncidenceStart(const QDateTime &incidenceStart, bool respectTimeZone)
251{
252 // When we receive dates from QML, these are all set to the local system timezone but
253 // have the dates and times we want. We need to preserve date and time but set the new
254 // QDateTime to have the correct timezone.
255
256 // When we set the timeZone property, however, we invariably also set the incidence start and end.
257 // This object needs no change. We therefore need to make sure to preserve the entire QDateTime object here.
258 auto oldStart = this->incidenceStart();
259
260 if (respectTimeZone) {
261 m_incidence->setDtStart(incidenceStart);
262 auto newTzEnd = incidenceEnd();
263 newTzEnd.setTimeZone(incidenceStart.timeZone());
264 setIncidenceEnd(newTzEnd, true);
265 } else {
266 const auto date = incidenceStart.date();
267 const auto time = incidenceStart.time();
269 start.setTimeZone(QTimeZone(timeZone()));
270 start.setDate(date);
271 start.setTime(time);
272 m_incidence->setDtStart(start);
273 }
274
275 auto oldStartEndDifference = oldStart.secsTo(incidenceEnd());
276 auto newEnd = this->incidenceStart().addSecs(oldStartEndDifference);
277 setIncidenceEnd(newEnd);
278
279 Q_EMIT incidenceStartChanged();
280 Q_EMIT incidenceStartDateDisplayChanged();
281 Q_EMIT incidenceStartTimeDisplayChanged();
282 Q_EMIT durationChanged();
283 Q_EMIT durationDisplayStringChanged();
284}
285
286void IncidenceWrapper::setIncidenceStartDate(int day, int month, int year)
287{
288 QDate date;
289 date.setDate(year, month, day);
290
291 auto newStart = incidenceStart();
292 newStart.setDate(date);
293
294 setIncidenceStart(newStart, true);
295}
296
297void IncidenceWrapper::setIncidenceStartTime(int hours, int minutes)
298{
299 QTime time;
300 time.setHMS(hours, minutes, 0);
301
302 auto newStart = incidenceStart();
303 newStart.setTime(time);
304
305 setIncidenceStart(newStart, true);
306}
307
308QString IncidenceWrapper::incidenceStartDateDisplay() const
309{
310 return QLocale::system().toString(incidenceStart().date(), QLocale::NarrowFormat);
311}
312
313QString IncidenceWrapper::incidenceStartTimeDisplay() const
314{
315 return QLocale::system().toString(incidenceStart().time(), QLocale::NarrowFormat);
316}
317
318QDateTime IncidenceWrapper::incidenceEnd() const
319{
320 if (m_incidence->type() == KCalendarCore::Incidence::IncidenceType::TypeEvent) {
322 return event->dtEnd();
323 } else if (m_incidence->type() == KCalendarCore::Incidence::IncidenceType::TypeTodo) {
325 return todo->dtDue();
326 }
327 return {};
328}
329
330void IncidenceWrapper::setIncidenceEnd(const QDateTime &incidenceEnd, bool respectTimeZone)
331{
333 if (respectTimeZone) {
334 end = incidenceEnd;
335 } else {
336 const auto date = incidenceEnd.date();
337 const auto time = incidenceEnd.time();
338 end.setTimeZone(QTimeZone(timeZone()));
339 end.setDate(date);
340 end.setTime(time);
341 }
342
343 if (m_incidence->type() == KCalendarCore::Incidence::IncidenceType::TypeEvent) {
345 event->setDtEnd(end);
346 } else if (m_incidence->type() == KCalendarCore::Incidence::IncidenceType::TypeTodo) {
348 todo->setDtDue(end);
349 } else {
350 qWarning() << "Unknown incidence type";
351 }
352 Q_EMIT incidenceEndChanged();
353 Q_EMIT incidenceEndDateDisplayChanged();
354 Q_EMIT incidenceEndTimeDisplayChanged();
355 Q_EMIT durationChanged();
356 Q_EMIT durationDisplayStringChanged();
357}
358
359void IncidenceWrapper::setIncidenceEndDate(int day, int month, int year)
360{
361 QDate date;
362 date.setDate(year, month, day);
363
364 auto newEnd = incidenceEnd();
365 newEnd.setDate(date);
366
367 setIncidenceEnd(newEnd, true);
368}
369
370void IncidenceWrapper::setIncidenceEndTime(int hours, int minutes)
371{
372 QTime time;
373 time.setHMS(hours, minutes, 0);
374
375 auto newEnd = incidenceEnd();
376 newEnd.setTime(time);
377
378 setIncidenceEnd(newEnd, true);
379}
380
381QString IncidenceWrapper::incidenceEndDateDisplay() const
382{
383 return QLocale::system().toString(incidenceEnd().date(), QLocale::NarrowFormat);
384}
385
386QString IncidenceWrapper::incidenceEndTimeDisplay() const
387{
388 return QLocale::system().toString(incidenceEnd().time(), QLocale::NarrowFormat);
389}
390
391void IncidenceWrapper::setIncidenceTimeToNearestQuarterHour(bool setStartTime, bool setEndTime)
392{
394 const int quarterHourInSecs = 15 * 60;
397 startTime.setSecsSinceEpoch(secsToSet);
398 if (setStartTime) {
399 setIncidenceStart(startTime, true);
400 }
401 if (setEndTime) {
402 setIncidenceEnd(startTime.addSecs(3600), true);
403 }
404}
405
406QByteArray IncidenceWrapper::timeZone() const
407{
408 return incidenceEnd().timeZone().id();
409}
410
411void IncidenceWrapper::setTimeZone(const QByteArray &timeZone)
412{
413 QDateTime start(incidenceStart());
414 if (start.isValid()) {
415 start.setTimeZone(QTimeZone(timeZone));
416 setIncidenceStart(start, true);
417 }
418
419 QDateTime end(incidenceEnd());
420 if (end.isValid()) {
421 end.setTimeZone(QTimeZone(timeZone));
422 setIncidenceEnd(end, true);
423 }
424
425 Q_EMIT timeZoneChanged();
426 Q_EMIT startTimeZoneUTCOffsetMinsChanged();
427 Q_EMIT endTimeZoneUTCOffsetMinsChanged();
428}
429
430int IncidenceWrapper::startTimeZoneUTCOffsetMins()
431{
432 return QTimeZone(timeZone()).offsetFromUtc(incidenceStart());
433}
434
435int IncidenceWrapper::endTimeZoneUTCOffsetMins()
436{
437 return QTimeZone(timeZone()).offsetFromUtc(incidenceEnd());
438}
439
440KCalendarCore::Duration IncidenceWrapper::duration() const
441{
442 return m_incidence->duration();
443}
444
445static QString formatSpelloutDuration(const KCalendarCore::Duration &duration, const KFormat &format, bool allDay)
446{
447 if (duration.asSeconds() == 0) {
448 return QString();
449 } else {
450 if (allDay) {
451 return format.formatSpelloutDuration(duration.asSeconds() * 1000 + 24 * 60 * 60 * 1000);
452 } else {
453 return format.formatSpelloutDuration(duration.asSeconds() * 1000);
454 }
455 }
456}
457
458QString IncidenceWrapper::durationDisplayString() const
459{
460 return formatSpelloutDuration(duration(), m_format, allDay());
461}
462
463bool IncidenceWrapper::allDay() const
464{
465 return m_incidence->allDay();
466}
467
468void IncidenceWrapper::setAllDay(bool allDay)
469{
470 m_incidence->setAllDay(allDay);
471 Q_EMIT allDayChanged();
472}
473
474int IncidenceWrapper::priority() const
475{
476 return m_incidence->priority();
477}
478
479void IncidenceWrapper::setPriority(int priority)
480{
481 m_incidence->setPriority(priority);
482 Q_EMIT priorityChanged();
483}
484
485KCalendarCore::Recurrence *IncidenceWrapper::recurrence() const
486{
487 KCalendarCore::Recurrence *recurrence = m_incidence->recurrence();
488 return recurrence;
489}
490
491QVariantMap IncidenceWrapper::recurrenceData()
492{
493 QBitArray weekDaysBits = m_incidence->recurrence()->days();
495
496 for (int i = 0; i < weekDaysBits.size(); i++) {
498 }
499
500 QVariantList monthPositions;
501 const auto monthPositionsToConvert = m_incidence->recurrence()->monthPositions();
502 for (const auto &pos : monthPositionsToConvert) {
503 QVariantMap positionToAdd;
504 positionToAdd[QStringLiteral("day")] = pos.day();
505 positionToAdd[QStringLiteral("pos")] = pos.pos();
506 monthPositions.append(positionToAdd);
507 }
508
509 // FYI: yearPositions() just calls monthPositions(), so we're cutting out the middleman
510 return QVariantMap{
511 {QStringLiteral("weekdays"), QVariant::fromValue(weekDaysBools)},
512 {QStringLiteral("duration"), m_incidence->recurrence()->duration()},
513 {QStringLiteral("frequency"), m_incidence->recurrence()->frequency()},
514 {QStringLiteral("startDateTime"), m_incidence->recurrence()->startDateTime()},
515 {QStringLiteral("startDateTimeDisplay"), QLocale::system().toString(m_incidence->recurrence()->startDateTime(), QLocale::NarrowFormat)},
516 {QStringLiteral("endDateTime"), m_incidence->recurrence()->endDateTime()},
517 {QStringLiteral("endDateTimeDisplay"), QLocale::system().toString(m_incidence->recurrence()->endDateTime(), QLocale::NarrowFormat)},
518 {QStringLiteral("allDay"), m_incidence->recurrence()->allDay()},
519 {QStringLiteral("type"), m_incidence->recurrence()->recurrenceType()},
520 {QStringLiteral("monthDays"), QVariant::fromValue(m_incidence->recurrence()->monthDays())},
521 {QStringLiteral("monthPositions"), monthPositions},
522 {QStringLiteral("yearDays"), QVariant::fromValue(m_incidence->recurrence()->yearDays())},
523 {QStringLiteral("yearDates"), QVariant::fromValue(m_incidence->recurrence()->yearDates())},
524 {QStringLiteral("yearMonths"), QVariant::fromValue(m_incidence->recurrence()->yearMonths())},
525 };
526}
527
528void IncidenceWrapper::setRecurrenceDataItem(const QString &key, const QVariant &value)
529{
530 QVariantMap map = recurrenceData();
531 if (map.contains(key)) {
532 if (key == QStringLiteral("weekdays") && value.canConvert<QJSValue>()) {
533 auto jsval = value.value<QJSValue>();
534
535 if (!jsval.isArray()) {
536 return;
537 }
538
539 auto vlist = jsval.toVariant().value<QVariantList>();
540 QBitArray days(7);
541
542 for (int i = 0; i < vlist.size(); i++) {
543 days[i] = vlist[i].toBool();
544 }
545
546 KCalendarCore::RecurrenceRule *rrule = m_incidence->recurrence()->defaultRRule();
548
549 for (int i = 0; i < 7; ++i) {
550 if (days.testBit(i)) {
552 positions.append(p);
553 }
554 }
555
556 rrule->setByDays(positions);
557 m_incidence->recurrence()->updated();
558
559 } else if (key == QStringLiteral("duration")) {
560 m_incidence->recurrence()->setDuration(value.toInt());
561
562 } else if (key == QStringLiteral("frequency")) {
563 m_incidence->recurrence()->setFrequency(value.toInt());
564
565 } else if ((key == QStringLiteral("startDateTime") || key == QStringLiteral("endDateTime")) && value.toDateTime().isValid()) {
566 auto dt = value.toDateTime();
568 adjustedDt.setTimeZone(incidenceEnd().timeZone());
569 adjustedDt.setDate(dt.date());
570 adjustedDt.setTime(dt.time());
571
572 if (key == QStringLiteral("startDateTime")) {
573 m_incidence->recurrence()->setStartDateTime(adjustedDt, false);
574
575 } else if (key == QStringLiteral("endDateTime")) {
576 m_incidence->recurrence()->setEndDateTime(adjustedDt);
577 }
578
579 } else if (key == QStringLiteral("allDay")) {
580 m_incidence->recurrence()->setAllDay(value.toBool());
581
582 } else if (key == QStringLiteral("monthDays") && value.canConvert<QList<int>>()) {
583 m_incidence->recurrence()->setMonthlyDate(value.value<QList<int>>());
584
585 } else if (key == QStringLiteral("yearDays") && value.canConvert<QList<int>>()) {
586 m_incidence->recurrence()->setYearlyDay(value.value<QList<int>>());
587
588 } else if (key == QStringLiteral("yearDates") && value.canConvert<QList<int>>()) {
589 m_incidence->recurrence()->setYearlyDate(value.value<QList<int>>());
590
591 } else if (key == QStringLiteral("yearMonths") && value.canConvert<QList<int>>()) {
592 m_incidence->recurrence()->setYearlyMonth(value.value<QList<int>>());
593
594 } else if (key == QStringLiteral("monthPositions") && value.canConvert<QList<QVariantMap>>()) {
596 const auto values = value.value<QList<QVariantMap>>();
597 for (const auto &pos : values) {
599 newPos.setDay(pos[QStringLiteral("day")].toInt());
600 newPos.setPos(pos[QStringLiteral("pos")].toInt());
601 newMonthPositions.append(newPos);
602 }
603
604 m_incidence->recurrence()->setMonthlyPos(newMonthPositions);
605 }
606 }
607 Q_EMIT recurrenceDataChanged();
608}
609
610QString IncidenceWrapper::googleConferenceUrl()
611{
612 return m_incidence->customProperty("LIBKGAPI", "EventHangoutLink");
613}
614
615QVariantMap IncidenceWrapper::organizer()
616{
617 auto organizerPerson = m_incidence->organizer();
618 return QVariantMap{{QStringLiteral("name"), organizerPerson.name()},
619 {QStringLiteral("email"), organizerPerson.email()},
620 {QStringLiteral("fullName"), organizerPerson.fullName()}};
621}
622
623// KCalendarCore::Attendee::List IncidenceWrapper::attendees() const
624// {
625// return m_incidence->attendees();
626// }
627//
628// AttendeesModel *IncidenceWrapper::attendeesModel()
629// {
630// return &m_attendeesModel;
631// }
632
633// RecurrenceExceptionsModel *IncidenceWrapper::recurrenceExceptionsModel()
634// {
635// return &m_recurrenceExceptionsModel;
636// }
637
638// AttachmentsModel *IncidenceWrapper::attachmentsModel()
639// {
640// return &m_attachmentsModel;
641// }
642
643bool IncidenceWrapper::todoCompleted()
644{
645 if (m_incidence->type() != KCalendarCore::IncidenceBase::TypeTodo) {
646 return false;
647 }
648
649 auto todo = m_incidence.staticCast<KCalendarCore::Todo>();
650 return todo->isCompleted();
651}
652
653void IncidenceWrapper::setTodoCompleted(bool completed)
654{
655 if (m_incidence->type() != KCalendarCore::IncidenceBase::TypeTodo) {
656 return;
657 }
658
659 auto todo = m_incidence.staticCast<KCalendarCore::Todo>();
660 todo->setCompleted(completed);
661
662 Q_EMIT todoCompletionDtChanged();
663 Q_EMIT todoPercentCompleteChanged();
664 Q_EMIT incidenceIconNameChanged();
665 Q_EMIT todoCompletedChanged();
666}
667
668QDateTime IncidenceWrapper::todoCompletionDt()
669{
670 if (m_incidence->type() != KCalendarCore::IncidenceBase::TypeTodo) {
671 return {};
672 }
673
674 auto todo = m_incidence.staticCast<KCalendarCore::Todo>();
675 return todo->completed();
676}
677
678int IncidenceWrapper::todoPercentComplete()
679{
680 if (m_incidence->type() != KCalendarCore::IncidenceBase::TypeTodo) {
681 return 0;
682 }
683
684 auto todo = m_incidence.staticCast<KCalendarCore::Todo>();
685 return todo->percentComplete();
686}
687
688void IncidenceWrapper::setTodoPercentComplete(int todoPercentComplete)
689{
690 if (m_incidence->type() != KCalendarCore::IncidenceBase::TypeTodo) {
691 return;
692 }
693
694 auto todo = m_incidence.staticCast<KCalendarCore::Todo>();
695 todo->setPercentComplete(todoPercentComplete);
696
697 Q_EMIT todoPercentCompleteChanged();
698
699 if (todoPercentComplete < 100 && todoCompleted()) {
700 setTodoCompleted(false);
701 }
702
703 Q_EMIT todoCompletedChanged();
704}
705
706void IncidenceWrapper::triggerEditMode() // You edit a clone so that the original ptr isn't messed with
707{
708 auto itemToEdit = item();
709 KCalendarCore::Incidence::Ptr clonedPtr(m_incidence->clone());
711 setIncidenceItem(itemToEdit);
712}
713
714static int nearestQuarterHour(int secsSinceEpoch)
715{
716 const int quarterHourInSecs = 60 * 15;
717 return secsSinceEpoch + (quarterHourInSecs - secsSinceEpoch % quarterHourInSecs);
718}
719
720void IncidenceWrapper::setNewEvent()
721{
725 event->setDtStart(start);
726 event->setDtEnd(start.addSecs(60 * 60));
727
729 alarm->setEnabled(true);
731 alarm->setStartOffset(-1 * 15 * 60); // 15 minutes
732
733 event->addAlarm(alarm);
734
735 setNewIncidence(event);
736}
737
738void IncidenceWrapper::setNewTodo()
739{
741 setNewIncidence(todo);
742}
743
744void IncidenceWrapper::setNewIncidence(KCalendarCore::Incidence::Ptr incidence)
745{
746 Akonadi::Item incidenceItem;
748 setIncidenceItem(incidenceItem);
749}
750
751// We need to be careful when we call updateParentIncidence and resetChildIncidences.
752// For instance, we always call them on-demand based on access to the properties and not
753// upon object construction on upon setting the incidence pointer.
754
755// Calling them both recursively down a family tree can cause a cascade of infinite
756// new IncidenceWrappers being created. Say we create a new incidence wrapper here and
757// call this new incidence's updateParentIncidence and resetChildIncidences, creating
758// a new child wrapper, creating more wrappers there, and so on.
759
760void IncidenceWrapper::updateParentIncidence()
761{
762 if (!m_incidence) {
763 return;
764 }
765
766 if (!parent().isEmpty() && (!m_parentIncidence || m_parentIncidence->uid() != parent())) {
767 m_parentIncidence.reset(new IncidenceWrapper);
768 m_parentIncidence->setIncidenceItem(CalendarManager::instance()->incidenceItem(parent()));
769 Q_EMIT parentIncidenceChanged();
770 }
771}
772
773void IncidenceWrapper::resetChildIncidences()
774{
775 cleanupChildIncidences();
776
777 if (!m_incidence) {
778 return;
779 }
780
781 const auto incidences = CalendarManager::instance()->childIncidences(uid());
782 QVariantList wrappedIncidences;
783
784 for (const auto &incidence : incidences) {
785 const auto wrappedIncidence = new IncidenceWrapper;
786 wrappedIncidence->setIncidenceItem(CalendarManager::instance()->incidenceItem(incidence));
788 }
789
790 m_childIncidences = wrappedIncidences;
791 Q_EMIT childIncidencesChanged();
792}
793
794void IncidenceWrapper::cleanupChildIncidences()
795{
796 while (!m_childIncidences.isEmpty()) {
797 const auto incidence = m_childIncidences.takeFirst();
798 const auto incidencePtr = incidence.value<IncidenceWrapper *>();
799
800 delete incidencePtr;
801 }
802}
803
804void IncidenceWrapper::addAlarms(KCalendarCore::Alarm::List alarms)
805{
806 for (int i = 0; i < alarms.size(); i++) {
807 m_incidence->addAlarm(alarms[i]);
808 }
809}
810
811void IncidenceWrapper::setRegularRecurrence(IncidenceWrapper::RecurrenceIntervals interval, int freq)
812{
813 switch (interval) {
814 case Daily:
815 m_incidence->recurrence()->setDaily(freq);
816 Q_EMIT recurrenceDataChanged();
817 return;
818 case Weekly:
819 m_incidence->recurrence()->setWeekly(freq);
820 Q_EMIT recurrenceDataChanged();
821 return;
822 case Monthly:
823 m_incidence->recurrence()->setMonthly(freq);
824 Q_EMIT recurrenceDataChanged();
825 return;
826 case Yearly:
827 m_incidence->recurrence()->setYearly(freq);
828 Q_EMIT recurrenceDataChanged();
829 return;
830 default:
831 qWarning() << "Unknown interval for recurrence" << interval;
832 return;
833 }
834}
835
836void IncidenceWrapper::setMonthlyPosRecurrence(short pos, int day)
837{
839 daysBitArray[day] = 1;
840 m_incidence->recurrence()->addMonthlyPos(pos, daysBitArray);
841}
842
843void IncidenceWrapper::setRecurrenceOccurrences(int occurrences)
844{
845 m_incidence->recurrence()->setDuration(occurrences);
846 Q_EMIT recurrenceDataChanged();
847}
848
849void IncidenceWrapper::clearRecurrences()
850{
851 m_incidence->recurrence()->clear();
852 Q_EMIT recurrenceDataChanged();
853}
854
855void IncidenceWrapper::itemChanged(const Akonadi::Item &item)
856{
859 setIncidenceItem(item);
860 }
861}
862
863// TODO remove with 22.08, won't be needed anymore
864void IncidenceWrapper::setCollection(const Akonadi::Collection &collection)
865{
866 setCollectionId(collection.id());
867}
868
869#ifndef UNITY_CMAKE_SUPPORT
870Q_DECLARE_METATYPE(KCalendarCore::Incidence::Ptr)
871#endif
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
void fetchAllAttributes(bool fetch=true)
void setFetchRelations(bool fetchRelations)
void fetchFullPayload(bool fetch=true)
void setItem(const Item &item)
void setPayload(const T &p)
Collection & parentCollection()
bool hasPayload() const
T payload() const
This class is a wrapper for a KCalendarCore::Incidence::Ptr object.
void setDtEnd(const QDateTime &dtEnd)
QSharedPointer< Event > Ptr
virtual QDateTime dtEnd() const
QSharedPointer< Todo > Ptr
QString formatSpelloutDuration(quint64 msecs) const
Q_SCRIPTABLE Q_NOREPLY void start()
QString i18n(const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Incidence::Ptr incidence(const Akonadi::Item &item)
AKONADI_CALENDAR_EXPORT KCalendarCore::Todo::Ptr todo(const Akonadi::Item &item)
const QList< QKeySequence > & end()
bool setDate(int year, int month, int day)
QDateTime addSecs(qint64 s) const const
QDateTime currentDateTime()
qint64 currentSecsSinceEpoch()
QDate date() const const
bool isValid() const const
void setSecsSinceEpoch(qint64 secs)
void setTimeZone(const QTimeZone &toZone)
QTime time() const const
QTimeZone timeZone() const const
void append(QList< T > &&value)
qsizetype size() const const
QLocale system()
QString toString(QDate date, FormatType format) const const
Q_EMITQ_EMIT
virtual bool event(QEvent *e)
T qobject_cast(QObject *object)
T * data() const const
QSharedPointer< X > staticCast() const const
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool setHMS(int h, int m, int s, int ms)
QByteArray id() const const
int offsetFromUtc(const QDateTime &atDateTime) const const
bool canConvert() const const
QVariant fromValue(T &&value)
bool toBool() const const
QDateTime toDateTime() const const
int toInt(bool *ok) const const
T value() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 17 2024 11:50:31 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.