File indexing completed on 2024-06-09 05:08:37
0001 /* 0002 SPDX-FileCopyrightText: 2008 Bruno Virlet <bruno.virlet@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0 0005 */ 0006 0007 #include "monthitem.h" 0008 #include "helper.h" 0009 #include "monthgraphicsitems.h" 0010 #include "monthscene.h" 0011 #include "monthview.h" 0012 #include "prefs.h" 0013 #include "prefs_base.h" // Ugly, but needed for the Enums 0014 0015 #include <Akonadi/CalendarUtils> 0016 #include <Akonadi/EntityTreeModel> 0017 #include <Akonadi/IncidenceChanger> 0018 #include <Akonadi/TagCache> 0019 #include <CalendarSupport/KCalPrefs> 0020 #include <CalendarSupport/Utils> 0021 0022 #include <KCalUtils/IncidenceFormatter> 0023 #include <KCalUtils/RecurrenceActions> 0024 0025 #include "calendarview_debug.h" 0026 #include <KMessageBox> 0027 0028 #include <QDrag> 0029 0030 using namespace EventViews; 0031 using namespace KCalendarCore; 0032 0033 MonthItem::MonthItem(MonthScene *monthScene) 0034 : mMonthScene(monthScene) 0035 { 0036 } 0037 0038 MonthItem::~MonthItem() 0039 { 0040 deleteAll(); 0041 } 0042 0043 void MonthItem::deleteAll() 0044 { 0045 qDeleteAll(mMonthGraphicsItemList); 0046 mMonthGraphicsItemList.clear(); 0047 } 0048 0049 QWidget *MonthItem::parentWidget() const 0050 { 0051 return mMonthScene ? mMonthScene->monthView() : nullptr; 0052 } 0053 0054 void MonthItem::updateMonthGraphicsItems() 0055 { 0056 // Remove all items 0057 qDeleteAll(mMonthGraphicsItemList); 0058 mMonthGraphicsItemList.clear(); 0059 0060 const QDate monthStartDate = startDate(); 0061 const QDate monthEndDate = endDate(); 0062 0063 // For each row of the month view, create an item to build the whole 0064 // MonthItem's MonthGraphicsItems. 0065 for (QDate d = mMonthScene->mMonthView->actualStartDateTime().date(); d < mMonthScene->mMonthView->actualEndDateTime().date(); d = d.addDays(7)) { 0066 QDate end = d.addDays(6); 0067 0068 int span; 0069 QDate start; 0070 if (monthStartDate <= d && monthEndDate >= end) { // MonthItem takes the whole line 0071 span = 6; 0072 start = d; 0073 } else if (monthStartDate >= d && monthEndDate <= end) { // starts and ends on this line 0074 start = monthStartDate; 0075 span = daySpan(); 0076 } else if (d <= monthEndDate && monthEndDate <= end) { // MonthItem ends on this line 0077 span = mMonthScene->getLeftSpan(monthEndDate); 0078 start = d; 0079 } else if (d <= monthStartDate && monthStartDate <= end) { // MonthItem begins on this line 0080 span = mMonthScene->getRightSpan(monthStartDate); 0081 start = monthStartDate; 0082 } else { // MonthItem is not on the line 0083 continue; 0084 } 0085 0086 // A new item needs to be created 0087 auto newItem = new MonthGraphicsItem(this); 0088 mMonthGraphicsItemList << newItem; 0089 newItem->setStartDate(start); 0090 newItem->setDaySpan(span); 0091 } 0092 0093 if (isMoving() || isResizing()) { 0094 setZValue(100); 0095 } else { 0096 setZValue(0); 0097 } 0098 } 0099 0100 void MonthItem::beginResize() 0101 { 0102 mOverrideDaySpan = daySpan(); 0103 mOverrideStartDate = startDate(); 0104 mResizing = true; 0105 setZValue(100); 0106 } 0107 0108 void MonthItem::endResize() 0109 { 0110 setZValue(0); 0111 mResizing = false; // startDate() and daySpan() return real values again 0112 0113 if (mOverrideStartDate != startDate() || mOverrideDaySpan != daySpan()) { 0114 finalizeResize(mOverrideStartDate, mOverrideStartDate.addDays(mOverrideDaySpan)); 0115 } 0116 } 0117 0118 void MonthItem::beginMove() 0119 { 0120 mOverrideDaySpan = daySpan(); 0121 mOverrideStartDate = startDate(); 0122 mMoving = true; 0123 setZValue(100); 0124 } 0125 0126 void MonthItem::endMove() 0127 { 0128 setZValue(0); 0129 mMoving = false; // startDate() and daySpan() return real values again 0130 0131 if (mOverrideStartDate != startDate()) { 0132 finalizeMove(mOverrideStartDate); 0133 } 0134 } 0135 0136 bool MonthItem::resizeBy(int offsetToPreviousDate) 0137 { 0138 bool ret = false; 0139 if (mMonthScene->resizeType() == MonthScene::ResizeLeft) { 0140 if (mOverrideDaySpan - offsetToPreviousDate >= 0) { 0141 mOverrideStartDate = mOverrideStartDate.addDays(offsetToPreviousDate); 0142 mOverrideDaySpan = mOverrideDaySpan - offsetToPreviousDate; 0143 ret = true; 0144 } 0145 } else if (mMonthScene->resizeType() == MonthScene::ResizeRight) { 0146 if (mOverrideDaySpan + offsetToPreviousDate >= 0) { 0147 mOverrideDaySpan = mOverrideDaySpan + offsetToPreviousDate; 0148 ret = true; 0149 } 0150 } 0151 0152 if (ret) { 0153 updateMonthGraphicsItems(); 0154 } 0155 return ret; 0156 } 0157 0158 void MonthItem::moveBy(int offsetToPreviousDate) 0159 { 0160 mOverrideStartDate = mOverrideStartDate.addDays(offsetToPreviousDate); 0161 updateMonthGraphicsItems(); 0162 } 0163 0164 void MonthItem::moveTo(QDate date) 0165 { 0166 mOverrideStartDate = date; 0167 updateMonthGraphicsItems(); 0168 } 0169 0170 void MonthItem::updateGeometry() 0171 { 0172 for (MonthGraphicsItem *item : std::as_const(mMonthGraphicsItemList)) { 0173 item->updateGeometry(); 0174 } 0175 } 0176 0177 void MonthItem::setZValue(qreal z) 0178 { 0179 for (MonthGraphicsItem *item : std::as_const(mMonthGraphicsItemList)) { 0180 item->setZValue(z); 0181 } 0182 } 0183 0184 QDate MonthItem::startDate() const 0185 { 0186 if ((isMoving() || isResizing()) && mOverrideStartDate.isValid()) { 0187 return mOverrideStartDate; 0188 } 0189 0190 return realStartDate(); 0191 } 0192 0193 QDate MonthItem::endDate() const 0194 { 0195 if ((isMoving() || isResizing()) && mOverrideStartDate.isValid()) { 0196 return mOverrideStartDate.addDays(mOverrideDaySpan); 0197 } 0198 0199 return realEndDate(); 0200 } 0201 0202 int MonthItem::daySpan() const 0203 { 0204 if (isMoving() || isResizing()) { 0205 return mOverrideDaySpan; 0206 } 0207 QDateTime start(startDate().startOfDay()); 0208 QDateTime end(endDate().startOfDay()); 0209 0210 if (start.isValid() && end.isValid()) { 0211 return start.daysTo(end); 0212 } 0213 0214 return 0; 0215 } 0216 0217 bool MonthItem::greaterThan(const MonthItem *e1, const MonthItem *e2) 0218 { 0219 const int leftDaySpan = e1->daySpan(); 0220 const int rightDaySpan = e2->daySpan(); 0221 if (leftDaySpan == rightDaySpan) { 0222 const QDate leftStartDate = e1->startDate(); 0223 const QDate rightStartDate = e2->startDate(); 0224 if (!leftStartDate.isValid() || !rightStartDate.isValid()) { 0225 return false; 0226 } 0227 if (leftStartDate == rightStartDate) { 0228 if (e1->allDay() && !e2->allDay()) { 0229 return true; 0230 } 0231 if (!e1->allDay() && e2->allDay()) { 0232 return false; 0233 } 0234 return e1->greaterThanFallback(e2); 0235 } else { 0236 return leftStartDate > rightStartDate; 0237 } 0238 } 0239 return leftDaySpan > rightDaySpan; 0240 } 0241 0242 bool MonthItem::greaterThanFallback(const MonthItem *other) const 0243 { 0244 const auto h = qobject_cast<const HolidayMonthItem *>(other); 0245 0246 // If "other" is a holiday, display it first. 0247 return !h; 0248 } 0249 0250 void MonthItem::updatePosition() 0251 { 0252 if (!startDate().isValid() || !endDate().isValid()) { 0253 return; 0254 } 0255 0256 int firstFreeSpace = 0; 0257 for (QDate d = startDate(); d <= endDate(); d = d.addDays(1)) { 0258 MonthCell *cell = mMonthScene->mMonthCellMap.value(d); 0259 if (!cell) { 0260 continue; // cell can be null if the item begins outside the month 0261 } 0262 int firstFreeSpaceTmp = cell->firstFreeSpace(); 0263 if (firstFreeSpaceTmp > firstFreeSpace) { 0264 firstFreeSpace = firstFreeSpaceTmp; 0265 } 0266 } 0267 0268 for (QDate d = startDate(); d <= endDate(); d = d.addDays(1)) { 0269 MonthCell *cell = mMonthScene->mMonthCellMap.value(d); 0270 if (!cell) { 0271 continue; 0272 } 0273 cell->addMonthItem(this, firstFreeSpace); 0274 } 0275 0276 mPosition = firstFreeSpace; 0277 } 0278 0279 QList<MonthGraphicsItem *> EventViews::MonthItem::monthGraphicsItems() const 0280 { 0281 return mMonthGraphicsItemList; 0282 } 0283 0284 //----------------------------------------------------------------- 0285 // INCIDENCEMONTHITEM 0286 IncidenceMonthItem::IncidenceMonthItem(MonthScene *monthScene, 0287 const Akonadi::CollectionCalendar::Ptr &calendar, 0288 const Akonadi::Item &aitem, 0289 const KCalendarCore::Incidence::Ptr &incidence, 0290 QDate recurStartDate) 0291 : MonthItem(monthScene) 0292 , mCalendar(calendar) 0293 , mIncidence(incidence) 0294 , mAkonadiItemId(aitem.id()) 0295 { 0296 mIsEvent = CalendarSupport::hasEvent(aitem); 0297 mIsJournal = CalendarSupport::hasJournal(aitem); 0298 mIsTodo = CalendarSupport::hasTodo(aitem); 0299 0300 KCalendarCore::Incidence::Ptr inc = mIncidence; 0301 if (inc->customProperty("KABC", "BIRTHDAY") == QLatin1StringView("YES") || inc->customProperty("KABC", "ANNIVERSARY") == QLatin1StringView("YES")) { 0302 const int years = EventViews::yearDiff(inc->dtStart().date(), recurStartDate); 0303 if (years > 0) { 0304 inc = KCalendarCore::Incidence::Ptr(inc->clone()); 0305 inc->setReadOnly(false); 0306 inc->setDescription(i18np("%2 1 year", "%2 %1 years", years, i18n("Age:"))); 0307 inc->setReadOnly(true); 0308 mIncidence = inc; 0309 } 0310 } 0311 0312 connect(monthScene, &MonthScene::incidenceSelected, this, &IncidenceMonthItem::updateSelection); 0313 0314 // first set to 0, because it's used in startDate() 0315 mRecurDayOffset = 0; 0316 const auto incidenceStart = mIncidence->dtStart().toLocalTime().date(); 0317 if ((mIncidence->recurs() || mIncidence->recurrenceId().isValid()) && incidenceStart.isValid() && recurStartDate.isValid()) { 0318 mRecurDayOffset = incidenceStart.daysTo(recurStartDate); 0319 } 0320 } 0321 0322 IncidenceMonthItem::~IncidenceMonthItem() = default; 0323 0324 bool IncidenceMonthItem::greaterThanFallback(const MonthItem *other) const 0325 { 0326 const auto o = qobject_cast<const IncidenceMonthItem *>(other); 0327 if (!o) { 0328 return MonthItem::greaterThanFallback(other); 0329 } 0330 0331 if (allDay() != o->allDay()) { 0332 return allDay(); 0333 } 0334 const KCalendarCore::Incidence::Ptr otherIncidence = o->mIncidence; 0335 0336 if (mIncidence->dtStart().time() != otherIncidence->dtStart().time()) { 0337 return mIncidence->dtStart().time() < otherIncidence->dtStart().time(); 0338 } 0339 0340 // as a last resort, compare uids 0341 return mIncidence->uid() < otherIncidence->uid(); 0342 } 0343 0344 QDate IncidenceMonthItem::realStartDate() const 0345 { 0346 if (!mIncidence) { 0347 return {}; 0348 } 0349 0350 const QDateTime dt = mIncidence->dateTime(Incidence::RoleDisplayStart); 0351 const QDate start = dt.toLocalTime().date(); 0352 0353 return start.addDays(mRecurDayOffset); 0354 } 0355 0356 QDate IncidenceMonthItem::realEndDate() const 0357 { 0358 if (!mIncidence) { 0359 return {}; 0360 } 0361 0362 QDateTime dt = mIncidence->dateTime(KCalendarCore::Incidence::RoleDisplayEnd); 0363 if (!mIncidence->allDay() && dt > mIncidence->dateTime(KCalendarCore::Incidence::RoleDisplayStart)) { 0364 // If dt's time portion is 00:00:00, the incidence ends on the previous day 0365 // unless it also starts at 00:00:00 (a duration of 0). 0366 dt = dt.addMSecs(-1); 0367 } 0368 const QDate end = dt.toLocalTime().date(); 0369 0370 return end.addDays(mRecurDayOffset); 0371 } 0372 0373 bool IncidenceMonthItem::allDay() const 0374 { 0375 return mIncidence->allDay(); 0376 } 0377 0378 bool IncidenceMonthItem::isMoveable() const 0379 { 0380 return mCalendar->hasRight(Akonadi::Collection::CanChangeItem); 0381 } 0382 0383 bool IncidenceMonthItem::isResizable() const 0384 { 0385 return mCalendar->hasRight(Akonadi::Collection::CanChangeItem); 0386 } 0387 0388 void IncidenceMonthItem::finalizeMove(const QDate &newStartDate) 0389 { 0390 Q_ASSERT(isMoveable()); 0391 0392 if (startDate().isValid()) { 0393 if (newStartDate.isValid()) { 0394 updateDates(startDate().daysTo(newStartDate), startDate().daysTo(newStartDate)); 0395 } else { 0396 if (QDrag *drag = CalendarSupport::createDrag(akonadiItem(), this)) { 0397 drag->exec(); 0398 } 0399 } 0400 } 0401 } 0402 0403 void IncidenceMonthItem::finalizeResize(const QDate &newStartDate, const QDate &newEndDate) 0404 { 0405 Q_ASSERT(isResizable()); 0406 0407 if (startDate().isValid() && endDate().isValid() && newStartDate.isValid() && newEndDate.isValid()) { 0408 updateDates(startDate().daysTo(newStartDate), endDate().daysTo(newEndDate)); 0409 } 0410 } 0411 0412 void IncidenceMonthItem::updateDates(int startOffset, int endOffset) 0413 { 0414 Akonadi::IncidenceChanger *changer = monthScene()->incidenceChanger(); 0415 if (!changer || (startOffset == 0 && endOffset == 0)) { 0416 qCDebug(CALENDARVIEW_LOG) << changer << startOffset << endOffset; 0417 return; 0418 } 0419 0420 Akonadi::Item item = akonadiItem(); 0421 item.setPayload(mIncidence); 0422 if (mIncidence->recurs()) { 0423 const int res = monthScene()->mMonthView->showMoveRecurDialog(mIncidence, startDate()); 0424 switch (res) { 0425 case KCalUtils::RecurrenceActions::AllOccurrences: { 0426 // All occurrences 0427 KCalendarCore::Incidence::Ptr oldIncidence(mIncidence->clone()); 0428 setNewDates(mIncidence, startOffset, endOffset); 0429 changer->modifyIncidence(item, oldIncidence); 0430 break; 0431 } 0432 case KCalUtils::RecurrenceActions::SelectedOccurrence: // Just this occurrence 0433 case KCalUtils::RecurrenceActions::FutureOccurrences: { // All future occurrences 0434 const bool thisAndFuture = (res == KCalUtils::RecurrenceActions::FutureOccurrences); 0435 QDateTime occurrenceDate(mIncidence->dtStart()); 0436 occurrenceDate.setDate(startDate()); 0437 KCalendarCore::Incidence::Ptr newIncidence(KCalendarCore::Calendar::createException(mIncidence, occurrenceDate, thisAndFuture)); 0438 if (newIncidence) { 0439 changer->startAtomicOperation(i18n("Move occurrence(s)")); 0440 setNewDates(newIncidence, startOffset, endOffset); 0441 changer->createIncidence(newIncidence, item.parentCollection(), parentWidget()); 0442 changer->endAtomicOperation(); 0443 } else { 0444 KMessageBox::error(parentWidget(), 0445 i18n("Unable to add the exception item to the calendar. " 0446 "No change will be done."), 0447 i18nc("@title:window", "Error Occurred")); 0448 } 0449 break; 0450 } 0451 } 0452 } else { // Doesn't recur 0453 KCalendarCore::Incidence::Ptr oldIncidence(mIncidence->clone()); 0454 setNewDates(mIncidence, startOffset, endOffset); 0455 changer->modifyIncidence(item, oldIncidence); 0456 } 0457 } 0458 0459 void IncidenceMonthItem::updateSelection(const Akonadi::Item &incidence, QDate date) 0460 { 0461 Q_UNUSED(date) 0462 setSelected(incidence == akonadiItem()); 0463 } 0464 0465 QString IncidenceMonthItem::text(bool end) const 0466 { 0467 QString ret = mIncidence->summary(); 0468 if (!allDay() && !mIsJournal && monthScene()->monthView()->preferences()->showTimeInMonthView()) { 0469 // Prepend the time str to the text 0470 QString timeStr; 0471 if (mIsTodo) { 0472 KCalendarCore::Todo::Ptr todo = mIncidence.staticCast<Todo>(); 0473 timeStr = QLocale().toString(todo->dtDue().toLocalTime().time(), QLocale::ShortFormat); 0474 } else { 0475 if (!end) { 0476 QTime time; 0477 if (mIncidence->recurs()) { 0478 const auto start = mIncidence->dtStart().addDays(mRecurDayOffset).addSecs(-1); 0479 time = mIncidence->recurrence()->getNextDateTime(start).toLocalTime().time(); 0480 } else { 0481 time = mIncidence->dtStart().toLocalTime().time(); 0482 } 0483 timeStr = QLocale().toString(time, QLocale::ShortFormat); 0484 } else { 0485 KCalendarCore::Event::Ptr event = mIncidence.staticCast<Event>(); 0486 timeStr = QLocale().toString(event->dtEnd().toLocalTime().time(), QLocale::ShortFormat); 0487 } 0488 } 0489 if (!timeStr.isEmpty()) { 0490 if (!end) { 0491 ret = timeStr + QLatin1Char(' ') + ret; 0492 } else { 0493 ret = ret + QLatin1Char(' ') + timeStr; 0494 } 0495 } 0496 } 0497 0498 return ret; 0499 } 0500 0501 QString IncidenceMonthItem::toolTipText(const QDate &date) const 0502 { 0503 return KCalUtils::IncidenceFormatter::toolTipStr(Akonadi::CalendarUtils::displayName(mCalendar->model(), akonadiItem().parentCollection()), 0504 mIncidence, 0505 date, 0506 true); 0507 } 0508 0509 QList<QPixmap> IncidenceMonthItem::icons() const 0510 { 0511 QList<QPixmap> ret; 0512 0513 if (!mIncidence) { 0514 return ret; 0515 } 0516 0517 bool specialEvent = false; 0518 Akonadi::Item item = akonadiItem(); 0519 0520 const QSet<EventView::ItemIcon> icons = monthScene()->monthView()->preferences()->monthViewIcons(); 0521 0522 QString customIconName; 0523 if (icons.contains(EventViews::EventView::CalendarCustomIcon)) { 0524 const QString iconName = monthScene()->monthView()->iconForItem(item); 0525 if (!iconName.isEmpty() && iconName != QLatin1StringView("view-calendar") && iconName != QLatin1StringView("office-calendar")) { 0526 customIconName = iconName; 0527 ret << QPixmap(cachedSmallIcon(iconName)); 0528 } 0529 } 0530 0531 if (mIsEvent) { 0532 if (mIncidence->customProperty("KABC", "ANNIVERSARY") == QLatin1StringView("YES")) { 0533 specialEvent = true; 0534 ret << monthScene()->anniversaryPixmap(); 0535 } else if (mIncidence->customProperty("KABC", "BIRTHDAY") == QLatin1StringView("YES")) { 0536 specialEvent = true; 0537 // Disabling birthday icon because it's the birthday agent's icon 0538 // and we allow to display the agent's icon now. 0539 // ret << monthScene()->birthdayPixmap(); 0540 } 0541 0542 // smartins: Disabling the event Pixmap because: 0543 // 1. Save precious space so we can read the event's title better. 0544 // 2. We don't need a pixmap to tell us an item is an event we 0545 // only need one to tell us it's not, as month view was designed for events. 0546 // 3. If only to-dos and journals have a pixmap they will be distinguished 0547 // from event's much easier. 0548 0549 // ret << monthScene()->eventPixmap(); 0550 } else if ((mIsTodo || mIsJournal) && icons.contains(mIsTodo ? EventView::TaskIcon : EventView::JournalIcon)) { 0551 QDateTime occurrenceDateTime = mIncidence->dateTime(Incidence::RoleRecurrenceStart).addDays(mRecurDayOffset); 0552 0553 const QString incidenceIconName = mIncidence->iconName(occurrenceDateTime); 0554 if (customIconName != incidenceIconName) { 0555 ret << QPixmap(cachedSmallIcon(incidenceIconName)); 0556 } 0557 } 0558 0559 if (icons.contains(EventView::ReadOnlyIcon) && !mCalendar->hasRight(Akonadi::Collection::CanChangeItem) && !specialEvent) { 0560 ret << monthScene()->readonlyPixmap(); 0561 } 0562 0563 /* sorry, this looks too cluttered. disable until we can 0564 make something prettier; no idea at this time -- allen */ 0565 if (icons.contains(EventView::ReminderIcon) && mIncidence->hasEnabledAlarms() && !specialEvent) { 0566 ret << monthScene()->alarmPixmap(); 0567 } 0568 if (icons.contains(EventView::RecurringIcon) && mIncidence->recurs() && !specialEvent) { 0569 ret << monthScene()->recurPixmap(); 0570 } 0571 // TODO: check what to do with Reply 0572 0573 return ret; 0574 } 0575 0576 QColor IncidenceMonthItem::catColor() const 0577 { 0578 Q_ASSERT(mIncidence); 0579 const auto &prefs = monthScene()->monthView()->preferences(); 0580 0581 const auto &categories = mIncidence->categories(); 0582 if (categories.isEmpty() || !Akonadi::TagCache::instance()->tagColor(categories.first()).isValid()) { 0583 const auto &colorPreference = prefs->monthViewColors(); 0584 if (colorPreference == PrefsBase::CategoryOnly) { 0585 return CalendarSupport::KCalPrefs::instance()->unsetCategoryColor(); 0586 } 0587 return EventViews::resourceColor(akonadiItem(), prefs); 0588 } 0589 return Akonadi::TagCache::instance()->tagColor(categories.first()); 0590 } 0591 0592 QColor IncidenceMonthItem::bgColor() const 0593 { 0594 const auto &prefs = monthScene()->monthView()->preferences(); 0595 0596 if (!prefs->todosUseCategoryColors() && mIsTodo) { 0597 Todo::Ptr todo = Akonadi::CalendarUtils::todo(akonadiItem()); 0598 Q_ASSERT(todo); 0599 if (todo) { 0600 // this is dtDue if there's no dtRecurrence 0601 const auto dtRecurrence = todo->dtRecurrence().toLocalTime().date(); 0602 const auto today = QDate::currentDate(); 0603 if (startDate() >= dtRecurrence) { 0604 if (todo->isOverdue() && today > startDate()) { 0605 return prefs->todoOverdueColor(); 0606 } 0607 if (today == startDate() && !todo->isCompleted()) { 0608 return prefs->todoDueTodayColor(); 0609 } 0610 } 0611 } 0612 } 0613 0614 const auto &colorPreference = prefs->monthViewColors(); 0615 const auto bgDisplaysResource = colorPreference == PrefsBase::MonthItemResourceInsideCategoryOutside || colorPreference == PrefsBase::MonthItemResourceOnly; 0616 return bgDisplaysResource ? EventViews::resourceColor(akonadiItem(), prefs) : catColor(); 0617 } 0618 0619 QColor IncidenceMonthItem::frameColor() const 0620 { 0621 const auto &prefs = monthScene()->monthView()->preferences(); 0622 const auto frameDisplaysResource = 0623 (prefs->monthViewColors() == PrefsBase::MonthItemResourceOnly || prefs->monthViewColors() == PrefsBase::MonthItemCategoryInsideResourceOutside); 0624 const auto frameColor = frameDisplaysResource ? EventViews::resourceColor(akonadiItem(), prefs) : catColor(); 0625 return EventView::itemFrameColor(frameColor, selected()); 0626 } 0627 0628 Akonadi::Item IncidenceMonthItem::akonadiItem() const 0629 { 0630 if (mIncidence) { 0631 return mCalendar->item(mIncidence); 0632 } else { 0633 return {}; 0634 } 0635 } 0636 0637 KCalendarCore::Incidence::Ptr IncidenceMonthItem::incidence() const 0638 { 0639 return mIncidence; 0640 } 0641 0642 Akonadi::Item::Id IncidenceMonthItem::akonadiItemId() const 0643 { 0644 return mAkonadiItemId; 0645 } 0646 0647 Akonadi::CollectionCalendar::Ptr IncidenceMonthItem::calendar() const 0648 { 0649 return mCalendar; 0650 } 0651 0652 void IncidenceMonthItem::setNewDates(const KCalendarCore::Incidence::Ptr &incidence, int startOffset, int endOffset) 0653 { 0654 if (mIsTodo) { 0655 // For to-dos endOffset is ignored because it will always be == to startOffset because we only 0656 // support moving to-dos, not resizing them. There are no multi-day to-dos. 0657 // Lets just call it offset to reduce confusion. 0658 const int offset = startOffset; 0659 0660 KCalendarCore::Todo::Ptr todo = incidence.staticCast<Todo>(); 0661 QDateTime due = todo->dtDue(); 0662 QDateTime start = todo->dtStart(); 0663 if (due.isValid()) { // Due has priority over start. 0664 // We will only move the due date, unlike events where we move both. 0665 due = due.addDays(offset); 0666 todo->setDtDue(due); 0667 0668 if (start.isValid() && start > due) { 0669 // Start can't be bigger than due. 0670 todo->setDtStart(due); 0671 } 0672 } else if (start.isValid()) { 0673 // So we're displaying a to-do that doesn't have due date, only start... 0674 start = start.addDays(offset); 0675 todo->setDtStart(start); 0676 } else { 0677 // This never happens 0678 qCWarning(CALENDARVIEW_LOG) << "Move what? uid:" << todo->uid() << "; summary=" << todo->summary(); 0679 } 0680 } else { 0681 incidence->setDtStart(incidence->dtStart().addDays(startOffset)); 0682 if (mIsEvent) { 0683 KCalendarCore::Event::Ptr event = incidence.staticCast<Event>(); 0684 event->setDtEnd(event->dtEnd().addDays(endOffset)); 0685 } 0686 } 0687 } 0688 0689 //----------------------------------------------------------------- 0690 // HOLIDAYMONTHITEM 0691 HolidayMonthItem::HolidayMonthItem(MonthScene *monthScene, QDate date, const QString &name) 0692 : HolidayMonthItem(monthScene, date, date, name) 0693 { 0694 } 0695 0696 HolidayMonthItem::HolidayMonthItem(MonthScene *monthScene, QDate startDate, QDate endDate, const QString &name) 0697 : MonthItem(monthScene) 0698 , mStartDate(startDate) 0699 , mEndDate(endDate) 0700 , mName(name) 0701 { 0702 } 0703 0704 HolidayMonthItem::~HolidayMonthItem() = default; 0705 0706 bool HolidayMonthItem::greaterThanFallback(const MonthItem *other) const 0707 { 0708 const auto o = qobject_cast<const HolidayMonthItem *>(other); 0709 // always put holidays on top 0710 return !o; 0711 } 0712 0713 void HolidayMonthItem::finalizeMove(const QDate &newStartDate) 0714 { 0715 Q_UNUSED(newStartDate) 0716 Q_ASSERT(false); 0717 } 0718 0719 void HolidayMonthItem::finalizeResize(const QDate &newStartDate, const QDate &newEndDate) 0720 { 0721 Q_UNUSED(newStartDate) 0722 Q_UNUSED(newEndDate) 0723 Q_ASSERT(false); 0724 } 0725 0726 QList<QPixmap> HolidayMonthItem::icons() const 0727 { 0728 QList<QPixmap> ret; 0729 ret << monthScene()->holidayPixmap(); 0730 0731 return ret; 0732 } 0733 0734 QColor HolidayMonthItem::bgColor() const 0735 { 0736 // FIXME: Currently, only this value is settable in the options. 0737 // There is a monthHolidaysBackgroundColor() option too. Maybe it would be 0738 // wise to merge those two. 0739 return monthScene()->monthView()->preferences()->agendaHolidaysBackgroundColor(); 0740 } 0741 0742 QColor HolidayMonthItem::frameColor() const 0743 { 0744 return Qt::black; 0745 } 0746 0747 #include "moc_monthitem.cpp"