Eventviews

monthitem.cpp
1/*
2 SPDX-FileCopyrightText: 2008 Bruno Virlet <bruno.virlet@gmail.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
5*/
6
7#include "monthitem.h"
8#include "helper.h"
9#include "monthgraphicsitems.h"
10#include "monthscene.h"
11#include "monthview.h"
12#include "prefs.h"
13#include "prefs_base.h" // Ugly, but needed for the Enums
14
15#include <Akonadi/CalendarUtils>
16#include <Akonadi/EntityTreeModel>
17#include <Akonadi/IncidenceChanger>
18#include <Akonadi/TagCache>
19#include <CalendarSupport/KCalPrefs>
20#include <CalendarSupport/Utils>
21
22#include <KCalUtils/IncidenceFormatter>
23#include <KCalUtils/RecurrenceActions>
24
25#include "calendarview_debug.h"
26#include <KMessageBox>
27
28#include <QDrag>
29
30using namespace EventViews;
31using namespace KCalendarCore;
32
33MonthItem::MonthItem(MonthScene *monthScene)
34 : mMonthScene(monthScene)
35{
36}
37
38MonthItem::~MonthItem()
39{
40 deleteAll();
41}
42
44{
45 qDeleteAll(mMonthGraphicsItemList);
46 mMonthGraphicsItemList.clear();
47}
48
49QWidget *MonthItem::parentWidget() const
50{
51 return mMonthScene ? mMonthScene->monthView() : nullptr;
52}
53
55{
56 // Remove all items
57 qDeleteAll(mMonthGraphicsItemList);
58 mMonthGraphicsItemList.clear();
59
60 const QDate monthStartDate = startDate();
61 const QDate monthEndDate = endDate();
62
63 // For each row of the month view, create an item to build the whole
64 // MonthItem's MonthGraphicsItems.
65 for (QDate d = mMonthScene->mMonthView->actualStartDateTime().date(); d < mMonthScene->mMonthView->actualEndDateTime().date(); d = d.addDays(7)) {
66 QDate end = d.addDays(6);
67
68 int span;
70 if (monthStartDate <= d && monthEndDate >= end) { // MonthItem takes the whole line
71 span = 6;
72 start = d;
73 } else if (monthStartDate >= d && monthEndDate <= end) { // starts and ends on this line
74 start = monthStartDate;
75 span = daySpan();
76 } else if (d <= monthEndDate && monthEndDate <= end) { // MonthItem ends on this line
77 span = mMonthScene->getLeftSpan(monthEndDate);
78 start = d;
79 } else if (d <= monthStartDate && monthStartDate <= end) { // MonthItem begins on this line
80 span = mMonthScene->getRightSpan(monthStartDate);
81 start = monthStartDate;
82 } else { // MonthItem is not on the line
83 continue;
84 }
85
86 // A new item needs to be created
87 auto newItem = new MonthGraphicsItem(this);
88 mMonthGraphicsItemList << newItem;
89 newItem->setStartDate(start);
90 newItem->setDaySpan(span);
91 }
92
93 if (isMoving() || isResizing()) {
94 setZValue(100);
95 } else {
96 setZValue(0);
97 }
98}
99
101{
102 mOverrideDaySpan = daySpan();
103 mOverrideStartDate = startDate();
104 mResizing = true;
105 setZValue(100);
106}
107
109{
110 setZValue(0);
111 mResizing = false; // startDate() and daySpan() return real values again
112
113 if (mOverrideStartDate != startDate() || mOverrideDaySpan != daySpan()) {
114 finalizeResize(mOverrideStartDate, mOverrideStartDate.addDays(mOverrideDaySpan));
115 }
116}
117
119{
120 mOverrideDaySpan = daySpan();
121 mOverrideStartDate = startDate();
122 mMoving = true;
123 setZValue(100);
124}
125
127{
128 setZValue(0);
129 mMoving = false; // startDate() and daySpan() return real values again
130
131 if (mOverrideStartDate != startDate()) {
132 finalizeMove(mOverrideStartDate);
133 }
134}
135
136bool MonthItem::resizeBy(int offsetToPreviousDate)
137{
138 bool ret = false;
139 if (mMonthScene->resizeType() == MonthScene::ResizeLeft) {
140 if (mOverrideDaySpan - offsetToPreviousDate >= 0) {
141 mOverrideStartDate = mOverrideStartDate.addDays(offsetToPreviousDate);
142 mOverrideDaySpan = mOverrideDaySpan - offsetToPreviousDate;
143 ret = true;
144 }
145 } else if (mMonthScene->resizeType() == MonthScene::ResizeRight) {
146 if (mOverrideDaySpan + offsetToPreviousDate >= 0) {
147 mOverrideDaySpan = mOverrideDaySpan + offsetToPreviousDate;
148 ret = true;
149 }
150 }
151
152 if (ret) {
154 }
155 return ret;
156}
157
158void MonthItem::moveBy(int offsetToPreviousDate)
159{
160 mOverrideStartDate = mOverrideStartDate.addDays(offsetToPreviousDate);
162}
163
165{
166 mOverrideStartDate = date;
168}
169
171{
172 for (MonthGraphicsItem *item : std::as_const(mMonthGraphicsItemList)) {
173 item->updateGeometry();
174 }
175}
176
177void MonthItem::setZValue(qreal z)
178{
179 for (MonthGraphicsItem *item : std::as_const(mMonthGraphicsItemList)) {
180 item->setZValue(z);
181 }
182}
183
185{
186 if ((isMoving() || isResizing()) && mOverrideStartDate.isValid()) {
187 return mOverrideStartDate;
188 }
189
190 return realStartDate();
191}
192
194{
195 if ((isMoving() || isResizing()) && mOverrideStartDate.isValid()) {
196 return mOverrideStartDate.addDays(mOverrideDaySpan);
197 }
198
199 return realEndDate();
200}
201
203{
204 if (isMoving() || isResizing()) {
205 return mOverrideDaySpan;
206 }
207 QDateTime start(startDate().startOfDay());
208 QDateTime end(endDate().startOfDay());
209
210 if (start.isValid() && end.isValid()) {
211 return start.daysTo(end);
212 }
213
214 return 0;
215}
216
218{
219 const int leftDaySpan = e1->daySpan();
220 const int rightDaySpan = e2->daySpan();
221 if (leftDaySpan == rightDaySpan) {
222 const QDate leftStartDate = e1->startDate();
223 const QDate rightStartDate = e2->startDate();
224 if (!leftStartDate.isValid() || !rightStartDate.isValid()) {
225 return false;
226 }
227 if (leftStartDate == rightStartDate) {
228 if (e1->allDay() && !e2->allDay()) {
229 return true;
230 }
231 if (!e1->allDay() && e2->allDay()) {
232 return false;
233 }
234 return e1->greaterThanFallback(e2);
235 } else {
236 return leftStartDate > rightStartDate;
237 }
238 }
239 return leftDaySpan > rightDaySpan;
240}
241
243{
244 const auto h = qobject_cast<const HolidayMonthItem *>(other);
245
246 // If "other" is a holiday, display it first.
247 return !h;
248}
249
251{
252 if (!startDate().isValid() || !endDate().isValid()) {
253 return;
254 }
255
256 int firstFreeSpace = 0;
257 for (QDate d = startDate(); d <= endDate(); d = d.addDays(1)) {
258 MonthCell *cell = mMonthScene->mMonthCellMap.value(d);
259 if (!cell) {
260 continue; // cell can be null if the item begins outside the month
261 }
262 int firstFreeSpaceTmp = cell->firstFreeSpace();
263 if (firstFreeSpaceTmp > firstFreeSpace) {
264 firstFreeSpace = firstFreeSpaceTmp;
265 }
266 }
267
268 for (QDate d = startDate(); d <= endDate(); d = d.addDays(1)) {
269 MonthCell *cell = mMonthScene->mMonthCellMap.value(d);
270 if (!cell) {
271 continue;
272 }
273 cell->addMonthItem(this, firstFreeSpace);
274 }
275
276 mPosition = firstFreeSpace;
277}
278
279QList<MonthGraphicsItem *> EventViews::MonthItem::monthGraphicsItems() const
280{
281 return mMonthGraphicsItemList;
282}
283
284//-----------------------------------------------------------------
285// INCIDENCEMONTHITEM
286IncidenceMonthItem::IncidenceMonthItem(MonthScene *monthScene,
287 const Akonadi::CollectionCalendar::Ptr &calendar,
288 const Akonadi::Item &aitem,
289 const KCalendarCore::Incidence::Ptr &incidence,
290 QDate recurStartDate)
291 : MonthItem(monthScene)
292 , mCalendar(calendar)
293 , mIncidence(incidence)
294 , mAkonadiItemId(aitem.id())
295{
296 mIsEvent = CalendarSupport::hasEvent(aitem);
297 mIsJournal = CalendarSupport::hasJournal(aitem);
298 mIsTodo = CalendarSupport::hasTodo(aitem);
299
300 KCalendarCore::Incidence::Ptr inc = mIncidence;
301 if (inc->customProperty("KABC", "BIRTHDAY") == QLatin1StringView("YES") || inc->customProperty("KABC", "ANNIVERSARY") == QLatin1StringView("YES")) {
302 const int years = EventViews::yearDiff(inc->dtStart().date(), recurStartDate);
303 if (years > 0) {
304 inc = KCalendarCore::Incidence::Ptr(inc->clone());
305 inc->setReadOnly(false);
306 inc->setDescription(i18np("%2 1 year", "%2 %1 years", years, i18n("Age:")));
307 inc->setReadOnly(true);
308 mIncidence = inc;
309 }
310 }
311
312 connect(monthScene, &MonthScene::incidenceSelected, this, &IncidenceMonthItem::updateSelection);
313
314 // first set to 0, because it's used in startDate()
315 mRecurDayOffset = 0;
316 const auto incidenceStart = mIncidence->dtStart().toLocalTime().date();
317 if ((mIncidence->recurs() || mIncidence->recurrenceId().isValid()) && incidenceStart.isValid() && recurStartDate.isValid()) {
318 mRecurDayOffset = incidenceStart.daysTo(recurStartDate);
319 }
320}
321
322IncidenceMonthItem::~IncidenceMonthItem() = default;
323
324bool IncidenceMonthItem::greaterThanFallback(const MonthItem *other) const
325{
326 const auto o = qobject_cast<const IncidenceMonthItem *>(other);
327 if (!o) {
328 return MonthItem::greaterThanFallback(other);
329 }
330
331 if (allDay() != o->allDay()) {
332 return allDay();
333 }
334 const KCalendarCore::Incidence::Ptr otherIncidence = o->mIncidence;
335
336 if (mIncidence->dtStart().time() != otherIncidence->dtStart().time()) {
337 return mIncidence->dtStart().time() < otherIncidence->dtStart().time();
338 }
339
340 // as a last resort, compare uids
341 return mIncidence->uid() < otherIncidence->uid();
342}
343
344QDate IncidenceMonthItem::realStartDate() const
345{
346 if (!mIncidence) {
347 return {};
348 }
349
350 const QDateTime dt = mIncidence->dateTime(Incidence::RoleDisplayStart);
351 const QDate start = dt.toLocalTime().date();
352
353 return start.addDays(mRecurDayOffset);
354}
355
356QDate IncidenceMonthItem::realEndDate() const
357{
358 if (!mIncidence) {
359 return {};
360 }
361
362 QDateTime dt = mIncidence->dateTime(KCalendarCore::Incidence::RoleDisplayEnd);
363 if (!mIncidence->allDay() && dt > mIncidence->dateTime(KCalendarCore::Incidence::RoleDisplayStart)) {
364 // If dt's time portion is 00:00:00, the incidence ends on the previous day
365 // unless it also starts at 00:00:00 (a duration of 0).
366 dt = dt.addMSecs(-1);
367 }
368 const QDate end = dt.toLocalTime().date();
369
370 return end.addDays(mRecurDayOffset);
371}
372
373bool IncidenceMonthItem::allDay() const
374{
375 return mIncidence->allDay();
376}
377
378bool IncidenceMonthItem::isMoveable() const
379{
380 return mCalendar->hasRight(Akonadi::Collection::CanChangeItem);
381}
382
383bool IncidenceMonthItem::isResizable() const
384{
385 return mCalendar->hasRight(Akonadi::Collection::CanChangeItem);
386}
387
388void IncidenceMonthItem::finalizeMove(const QDate &newStartDate)
389{
390 Q_ASSERT(isMoveable());
391
392 if (startDate().isValid()) {
393 if (newStartDate.isValid()) {
394 updateDates(startDate().daysTo(newStartDate), startDate().daysTo(newStartDate));
395 } else {
396 if (QDrag *drag = CalendarSupport::createDrag(akonadiItem(), this)) {
397 drag->exec();
398 }
399 }
400 }
401}
402
403void IncidenceMonthItem::finalizeResize(const QDate &newStartDate, const QDate &newEndDate)
404{
405 Q_ASSERT(isResizable());
406
407 if (startDate().isValid() && endDate().isValid() && newStartDate.isValid() && newEndDate.isValid()) {
408 updateDates(startDate().daysTo(newStartDate), endDate().daysTo(newEndDate));
409 }
410}
411
412void IncidenceMonthItem::updateDates(int startOffset, int endOffset)
413{
414 Akonadi::IncidenceChanger *changer = monthScene()->incidenceChanger();
415 if (!changer || (startOffset == 0 && endOffset == 0)) {
416 qCDebug(CALENDARVIEW_LOG) << changer << startOffset << endOffset;
417 return;
418 }
419
420 Akonadi::Item item = akonadiItem();
421 item.setPayload(mIncidence);
422 if (mIncidence->recurs()) {
423 const int res = monthScene()->mMonthView->showMoveRecurDialog(mIncidence, startDate());
424 switch (res) {
426 // All occurrences
427 KCalendarCore::Incidence::Ptr oldIncidence(mIncidence->clone());
428 setNewDates(mIncidence, startOffset, endOffset);
429 changer->modifyIncidence(item, oldIncidence);
430 break;
431 }
432 case KCalUtils::RecurrenceActions::SelectedOccurrence: // Just this occurrence
433 case KCalUtils::RecurrenceActions::FutureOccurrences: { // All future occurrences
434 const bool thisAndFuture = (res == KCalUtils::RecurrenceActions::FutureOccurrences);
435 QDateTime occurrenceDate(mIncidence->dtStart());
436 occurrenceDate.setDate(startDate());
437 KCalendarCore::Incidence::Ptr newIncidence(KCalendarCore::Calendar::createException(mIncidence, occurrenceDate, thisAndFuture));
438 if (newIncidence) {
439 changer->startAtomicOperation(i18n("Move occurrence(s)"));
440 setNewDates(newIncidence, startOffset, endOffset);
441 changer->createIncidence(newIncidence, item.parentCollection(), parentWidget());
442 changer->endAtomicOperation();
443 } else {
444 KMessageBox::error(parentWidget(),
445 i18n("Unable to add the exception item to the calendar. "
446 "No change will be done."),
447 i18nc("@title:window", "Error Occurred"));
448 }
449 break;
450 }
451 }
452 } else { // Doesn't recur
453 KCalendarCore::Incidence::Ptr oldIncidence(mIncidence->clone());
454 setNewDates(mIncidence, startOffset, endOffset);
455 changer->modifyIncidence(item, oldIncidence);
456 }
457}
458
459void IncidenceMonthItem::updateSelection(const Akonadi::Item &incidence, QDate date)
460{
461 Q_UNUSED(date)
462 setSelected(incidence == akonadiItem());
463}
464
465QString IncidenceMonthItem::text(bool end) const
466{
467 QString ret = mIncidence->summary();
468 if (!allDay() && !mIsJournal && monthScene()->monthView()->preferences()->showTimeInMonthView()) {
469 // Prepend the time str to the text
470 QString timeStr;
471 if (mIsTodo) {
473 timeStr = QLocale().toString(todo->dtDue().toLocalTime().time(), QLocale::ShortFormat);
474 } else {
475 if (!end) {
476 QTime time;
477 if (mIncidence->recurs()) {
478 const auto start = mIncidence->dtStart().addDays(mRecurDayOffset).addSecs(-1);
479 time = mIncidence->recurrence()->getNextDateTime(start).toLocalTime().time();
480 } else {
481 time = mIncidence->dtStart().toLocalTime().time();
482 }
483 timeStr = QLocale().toString(time, QLocale::ShortFormat);
484 } else {
485 KCalendarCore::Event::Ptr event = mIncidence.staticCast<Event>();
486 timeStr = QLocale().toString(event->dtEnd().toLocalTime().time(), QLocale::ShortFormat);
487 }
488 }
489 if (!timeStr.isEmpty()) {
490 if (!end) {
491 ret = timeStr + QLatin1Char(' ') + ret;
492 } else {
493 ret = ret + QLatin1Char(' ') + timeStr;
494 }
495 }
496 }
497
498 return ret;
499}
500
501QString IncidenceMonthItem::toolTipText(const QDate &date) const
502{
503 return KCalUtils::IncidenceFormatter::toolTipStr(Akonadi::CalendarUtils::displayName(mCalendar->model(), akonadiItem().parentCollection()),
504 mIncidence,
505 date,
506 true);
507}
508
509QList<QPixmap> IncidenceMonthItem::icons() const
510{
511 QList<QPixmap> ret;
512
513 if (!mIncidence) {
514 return ret;
515 }
516
517 bool specialEvent = false;
518 Akonadi::Item item = akonadiItem();
519
520 const QSet<EventView::ItemIcon> icons = monthScene()->monthView()->preferences()->monthViewIcons();
521
522 QString customIconName;
523 if (icons.contains(EventViews::EventView::CalendarCustomIcon)) {
524 const QString iconName = monthScene()->monthView()->iconForItem(item);
525 if (!iconName.isEmpty() && iconName != QLatin1StringView("view-calendar") && iconName != QLatin1StringView("office-calendar")) {
526 customIconName = iconName;
527 ret << QPixmap(cachedSmallIcon(iconName));
528 }
529 }
530
531 if (mIsEvent) {
532 if (mIncidence->customProperty("KABC", "ANNIVERSARY") == QLatin1StringView("YES")) {
533 specialEvent = true;
534 ret << monthScene()->anniversaryPixmap();
535 } else if (mIncidence->customProperty("KABC", "BIRTHDAY") == QLatin1StringView("YES")) {
536 specialEvent = true;
537 // Disabling birthday icon because it's the birthday agent's icon
538 // and we allow to display the agent's icon now.
539 // ret << monthScene()->birthdayPixmap();
540 }
541
542 // smartins: Disabling the event Pixmap because:
543 // 1. Save precious space so we can read the event's title better.
544 // 2. We don't need a pixmap to tell us an item is an event we
545 // only need one to tell us it's not, as month view was designed for events.
546 // 3. If only to-dos and journals have a pixmap they will be distinguished
547 // from event's much easier.
548
549 // ret << monthScene()->eventPixmap();
550 } else if ((mIsTodo || mIsJournal) && icons.contains(mIsTodo ? EventView::TaskIcon : EventView::JournalIcon)) {
551 QDateTime occurrenceDateTime = mIncidence->dateTime(Incidence::RoleRecurrenceStart).addDays(mRecurDayOffset);
552
553 const QString incidenceIconName = mIncidence->iconName(occurrenceDateTime);
554 if (customIconName != incidenceIconName) {
555 ret << QPixmap(cachedSmallIcon(incidenceIconName));
556 }
557 }
558
559 if (icons.contains(EventView::ReadOnlyIcon) && !mCalendar->hasRight(Akonadi::Collection::CanChangeItem) && !specialEvent) {
560 ret << monthScene()->readonlyPixmap();
561 }
562
563 /* sorry, this looks too cluttered. disable until we can
564 make something prettier; no idea at this time -- allen */
565 if (icons.contains(EventView::ReminderIcon) && mIncidence->hasEnabledAlarms() && !specialEvent) {
566 ret << monthScene()->alarmPixmap();
567 }
568 if (icons.contains(EventView::RecurringIcon) && mIncidence->recurs() && !specialEvent) {
569 ret << monthScene()->recurPixmap();
570 }
571 // TODO: check what to do with Reply
572
573 return ret;
574}
575
576QColor IncidenceMonthItem::catColor() const
577{
578 Q_ASSERT(mIncidence);
579 const auto &prefs = monthScene()->monthView()->preferences();
580
581 const auto &categories = mIncidence->categories();
582 if (categories.isEmpty() || !Akonadi::TagCache::instance()->tagColor(categories.first()).isValid()) {
583 const auto &colorPreference = prefs->monthViewColors();
584 if (colorPreference == PrefsBase::CategoryOnly) {
585 return CalendarSupport::KCalPrefs::instance()->unsetCategoryColor();
586 }
587 return EventViews::resourceColor(mCalendar->collection(), prefs);
588 }
589 return Akonadi::TagCache::instance()->tagColor(categories.first());
590}
591
592QColor IncidenceMonthItem::bgColor() const
593{
594 const auto &prefs = monthScene()->monthView()->preferences();
595
596 if (!prefs->todosUseCategoryColors() && mIsTodo) {
598 Q_ASSERT(todo);
599 if (todo) {
600 // this is dtDue if there's no dtRecurrence
601 const auto dtRecurrence = todo->dtRecurrence().toLocalTime().date();
602 const auto today = QDate::currentDate();
603 if (startDate() >= dtRecurrence) {
604 if (todo->isOverdue() && today > startDate()) {
605 return prefs->todoOverdueColor();
606 }
607 if (today == startDate() && !todo->isCompleted()) {
608 return prefs->todoDueTodayColor();
609 }
610 }
611 }
612 }
613
614 const auto &colorPreference = prefs->monthViewColors();
615 const auto bgDisplaysResource = colorPreference == PrefsBase::MonthItemResourceInsideCategoryOutside || colorPreference == PrefsBase::MonthItemResourceOnly;
616 return bgDisplaysResource ? EventViews::resourceColor(mCalendar->collection(), prefs) : catColor();
617}
618
619QColor IncidenceMonthItem::frameColor() const
620{
621 const auto &prefs = monthScene()->monthView()->preferences();
622 const auto frameDisplaysResource =
623 (prefs->monthViewColors() == PrefsBase::MonthItemResourceOnly || prefs->monthViewColors() == PrefsBase::MonthItemCategoryInsideResourceOutside);
624 const auto frameColor = frameDisplaysResource ? EventViews::resourceColor(mCalendar->collection(), prefs) : catColor();
625 return EventView::itemFrameColor(frameColor, selected());
626}
627
628Akonadi::Item IncidenceMonthItem::akonadiItem() const
629{
630 if (mIncidence) {
631 return mCalendar->item(mIncidence);
632 } else {
633 return {};
634 }
635}
636
637KCalendarCore::Incidence::Ptr IncidenceMonthItem::incidence() const
638{
639 return mIncidence;
640}
641
642Akonadi::Item::Id IncidenceMonthItem::akonadiItemId() const
643{
644 return mAkonadiItemId;
645}
646
647Akonadi::CollectionCalendar::Ptr IncidenceMonthItem::calendar() const
648{
649 return mCalendar;
650}
651
652void IncidenceMonthItem::setNewDates(const KCalendarCore::Incidence::Ptr &incidence, int startOffset, int endOffset)
653{
654 if (mIsTodo) {
655 // For to-dos endOffset is ignored because it will always be == to startOffset because we only
656 // support moving to-dos, not resizing them. There are no multi-day to-dos.
657 // Lets just call it offset to reduce confusion.
658 const int offset = startOffset;
659
661 QDateTime due = todo->dtDue();
662 QDateTime start = todo->dtStart();
663 if (due.isValid()) { // Due has priority over start.
664 // We will only move the due date, unlike events where we move both.
665 due = due.addDays(offset);
666 todo->setDtDue(due);
667
668 if (start.isValid() && start > due) {
669 // Start can't be bigger than due.
670 todo->setDtStart(due);
671 }
672 } else if (start.isValid()) {
673 // So we're displaying a to-do that doesn't have due date, only start...
674 start = start.addDays(offset);
675 todo->setDtStart(start);
676 } else {
677 // This never happens
678 qCWarning(CALENDARVIEW_LOG) << "Move what? uid:" << todo->uid() << "; summary=" << todo->summary();
679 }
680 } else {
681 incidence->setDtStart(incidence->dtStart().addDays(startOffset));
682 if (mIsEvent) {
684 event->setDtEnd(event->dtEnd().addDays(endOffset));
685 }
686 }
687}
688
689//-----------------------------------------------------------------
690// HOLIDAYMONTHITEM
691HolidayMonthItem::HolidayMonthItem(MonthScene *monthScene, QDate date, const QString &name)
692 : HolidayMonthItem(monthScene, date, date, name)
693{
694}
695
696HolidayMonthItem::HolidayMonthItem(MonthScene *monthScene, QDate startDate, QDate endDate, const QString &name)
697 : MonthItem(monthScene)
698 , mStartDate(startDate)
699 , mEndDate(endDate)
700 , mName(name)
701{
702}
703
704HolidayMonthItem::~HolidayMonthItem() = default;
705
706bool HolidayMonthItem::greaterThanFallback(const MonthItem *other) const
707{
708 const auto o = qobject_cast<const HolidayMonthItem *>(other);
709 // always put holidays on top
710 return !o;
711}
712
713void HolidayMonthItem::finalizeMove(const QDate &newStartDate)
714{
715 Q_UNUSED(newStartDate)
716 Q_ASSERT(false);
717}
718
719void HolidayMonthItem::finalizeResize(const QDate &newStartDate, const QDate &newEndDate)
720{
721 Q_UNUSED(newStartDate)
722 Q_UNUSED(newEndDate)
723 Q_ASSERT(false);
724}
725
726QList<QPixmap> HolidayMonthItem::icons() const
727{
728 QList<QPixmap> ret;
729 ret << monthScene()->holidayPixmap();
730
731 return ret;
732}
733
734QColor HolidayMonthItem::bgColor() const
735{
736 // FIXME: Currently, only this value is settable in the options.
737 // There is a monthHolidaysBackgroundColor() option too. Maybe it would be
738 // wise to merge those two.
739 return monthScene()->monthView()->preferences()->agendaHolidaysBackgroundColor();
740}
741
742QColor HolidayMonthItem::frameColor() const
743{
744 return Qt::black;
745}
746
747#include "moc_monthitem.cpp"
Collection & parentCollection()
void setPayload(const T &p)
QColor tagColor(const QString &tagName) const
static TagCache * instance()
EventView is the abstract base class from which all other calendar views for event data are derived.
Definition eventview.h:67
static QColor itemFrameColor(const QColor &color, bool selected)
Returns a variation of color that will be used for the border of an agenda or month item.
Keeps information about a month cell.
A MonthGraphicsItem representing a part of an event.
A month item manages different MonthGraphicsItems.
Definition monthitem.h:27
static bool greaterThan(const MonthItem *e1, const MonthItem *e2)
Compares two items to decide which to place in the view first.
void moveTo(QDate date)
Called during a drag to move the item to a particular date.
void setSelected(bool selected)
Sets the selection state of this item.
Definition monthitem.h:210
virtual void finalizeResize(const QDate &newStartDate, const QDate &newEndDate)=0
Called after a resize operation.
void updateGeometry()
Updates geometry of all MonthGraphicsItems.
bool isMoving() const
Returns true if the item is being moved.
Definition monthitem.h:167
void beginMove()
Begin a move.
MonthScene * monthScene() const
Returns the associated month scene to this item.
Definition monthitem.h:121
void endMove()
End a move.
QDate endDate() const
The end date of the incidence, generally realEndDate.
virtual bool allDay() const =0
True if this item last all the day.
void endResize()
End a resize.
void beginResize()
Begin a resize.
virtual QDate realEndDate() const =0
This is the real end date, usually the end date of the incidence.
void deleteAll()
Deletes all MonthGraphicsItem this item handles.
Definition monthitem.cpp:43
void updatePosition()
Find the lowest possible position for this item.
bool selected() const
Returns true if this item is selected.
Definition monthitem.h:105
bool resizeBy(int offsetFromPreviousDate)
Called during resize to resize the item a bit, relative to the previous resize step.
bool isResizing() const
Returns true if the item is being resized.
Definition monthitem.h:175
QDate startDate() const
The start date of the incidence, generally realStartDate.
virtual void finalizeMove(const QDate &newStartDate)=0
Called after a move operation.
void updateMonthGraphicsItems()
Update the monthgraphicsitems.
Definition monthitem.cpp:54
void moveBy(int offsetFromPreviousDate)
Called during move to move the item a bit, relative to the previous move step.
virtual bool greaterThanFallback(const MonthItem *other) const
Compare this event with a second one, if the former function is not able to sort them.
virtual QDate realStartDate() const =0
This is the real start date, usually the start date of the incidence.
int daySpan() const
The number of days this item spans.
static Incidence::Ptr createException(const Incidence::Ptr &incidence, const QDateTime &recurrenceId, bool thisAndFuture=false)
void setDtEnd(const QDateTime &dtEnd)
QSharedPointer< Incidence > Ptr
Q_SCRIPTABLE Q_NOREPLY void start()
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
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)
AKONADI_CALENDAR_EXPORT QString displayName(Akonadi::ETMCalendar *calendar, const Akonadi::Collection &collection)
Namespace EventViews provides facilities for displaying incidences, including events,...
Definition agenda.h:33
EVENTVIEWS_EXPORT QColor resourceColor(const Akonadi::Collection &collection, const PrefsPtr &preferences)
This method returns the proper resource / subresource color for the view.
Definition helper.cpp:56
QPixmap cachedSmallIcon(const QString &name)
Equivalent to SmallIcon( name ), but uses QPixmapCache.
Definition helper.cpp:83
int yearDiff(QDate start, QDate end)
Returns the number of years between the start QDate and the end QDate (i.e.
Definition helper.cpp:78
KCALUTILS_EXPORT QString toolTipStr(const QString &sourceName, const KCalendarCore::IncidenceBase::Ptr &incidence, QDate date=QDate(), bool richText=true)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
bool isValid(QStringView ifopt)
const QList< QKeySequence > & end()
QString name(StandardShortcut id)
const QList< QKeySequence > & preferences()
bool isValid() const const
QDate addDays(qint64 ndays) const const
QDate currentDate()
bool isValid(int year, int month, int day)
QDateTime addMSecs(qint64 msecs) const const
QDate date() const const
QDateTime toLocalTime() const const
QString toString(QDate date, FormatType format) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual bool event(QEvent *e)
bool contains(const QSet< T > &other) const const
QSharedPointer< X > staticCast() const const
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:12:29 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.