Eventviews

monthscene.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 "monthscene.h"
8#include "helper.h"
9#include "monthgraphicsitems.h"
10#include "monthitem.h"
11#include "monthview.h"
12#include "prefs.h"
13
14#include <CalendarSupport/Utils>
15
16#include <KColorScheme>
17#include <KLocalizedString>
18#include <QGraphicsSceneMouseEvent>
19#include <QIcon>
20#include <QResizeEvent>
21#include <QToolTip>
22
23static const int AUTO_REPEAT_DELAY = 600;
24
25using namespace EventViews;
26
27MonthScene::MonthScene(MonthView *parent)
28 : QGraphicsScene(parent)
29 , mMonthView(parent)
30 , mInitialized(false)
31 , mActionInitiated(false)
32 , mActionType(None)
33 , mStartHeight(0)
34
35{
36 mBirthdayPixmap = QIcon::fromTheme(QStringLiteral("view-calendar-birthday")).pixmap(16, 16);
37 mAnniversaryPixmap = QIcon::fromTheme(QStringLiteral("view-calendar-wedding-anniversary")).pixmap(16, 16);
38 mAlarmPixmap = QIcon::fromTheme(QStringLiteral("appointment-reminder")).pixmap(16, 16);
39 mRecurPixmap = QIcon::fromTheme(QStringLiteral("appointment-recurring")).pixmap(16, 16);
40 mReadonlyPixmap = QIcon::fromTheme(QStringLiteral("object-locked")).pixmap(16, 16);
41 mReplyPixmap = QIcon::fromTheme(QStringLiteral("mail-reply-sender")).pixmap(16, 16);
42 mHolidayPixmap = QIcon::fromTheme(QStringLiteral("view-calendar-holiday")).pixmap(16, 16);
43
44 setSceneRect(0, 0, parent->width(), parent->height());
45}
46
47MonthScene::~MonthScene()
48{
49 qDeleteAll(mMonthCellMap);
50 qDeleteAll(mManagerList);
51}
52
53MonthCell *MonthScene::selectedCell() const
54{
55 return mMonthCellMap.value(mSelectedCellDate);
56}
57
58MonthCell *MonthScene::previousCell() const
59{
60 return mPreviousCell;
61}
62
63int MonthScene::getRightSpan(QDate date) const
64{
65 MonthCell *cell = mMonthCellMap.value(date);
66 if (!cell) {
67 return 0;
68 }
69
70 return 7 - cell->x() - 1;
71}
72
73int MonthScene::getLeftSpan(QDate date) const
74{
75 MonthCell *cell = mMonthCellMap.value(date);
76 if (!cell) {
77 return 0;
78 }
79
80 return cell->x();
81}
82
83int MonthScene::maxRowCount()
84{
85 return (rowHeight() - MonthCell::topMargin()) / itemHeightIncludingSpacing();
86}
87
88int MonthScene::itemHeightIncludingSpacing()
89{
90 return MonthCell::topMargin() + 2;
91}
92
93int MonthScene::itemHeight()
94{
95 return MonthCell::topMargin();
96}
97
98MonthCell *MonthScene::firstCellForMonthItem(MonthItem *manager)
99{
100 for (QDate d = manager->startDate(); d <= manager->endDate(); d = d.addDays(1)) {
101 MonthCell *monthCell = mMonthCellMap.value(d);
102 if (monthCell) {
103 return monthCell;
104 }
105 }
106
107 return nullptr;
108}
109
110void MonthScene::updateGeometry()
111{
112 for (MonthItem *manager : std::as_const(mManagerList)) {
113 manager->updateGeometry();
114 }
115}
116
117int MonthScene::availableWidth() const
118{
119 return static_cast<int>(sceneRect().width());
120}
121
122int MonthScene::availableHeight() const
123{
124 return static_cast<int>(sceneRect().height() - headerHeight());
125}
126
127int MonthScene::columnWidth() const
128{
129 return static_cast<int>((availableWidth() - 1) / 7.);
130}
131
132int MonthScene::rowHeight() const
133{
134 return static_cast<int>((availableHeight() - 1) / 6.);
135}
136
137int MonthScene::headerHeight() const
138{
139 return 50;
140}
141
142int MonthScene::cellVerticalPos(const MonthCell *cell) const
143{
144 return headerHeight() + cell->y() * rowHeight();
145}
146
147int MonthScene::cellHorizontalPos(const MonthCell *cell) const
148{
149 return cell->x() * columnWidth();
150}
151
152int MonthScene::sceneYToMonthGridY(int yScene)
153{
154 return yScene - headerHeight();
155}
156
157int MonthScene::sceneXToMonthGridX(int xScene)
158{
159 return xScene;
160}
161
163{
164 Q_ASSERT(mScene);
165
166 PrefsPtr prefs = mScene->monthView()->preferences();
167 p->setFont(prefs->monthViewFont());
169
170 /*
171 Headers
172 */
173 QFont font = prefs->monthViewFont();
174 font.setBold(true);
175 font.setPointSize(15);
176 p->setFont(font);
177 const int dayLabelsHeight = 20;
178 const auto dayInMonth = mMonthView->averageDate();
179 p->drawText(QRect(0,
180 0, // top right
181 static_cast<int>(mScene->sceneRect().width()),
182 static_cast<int>(mScene->headerHeight() - dayLabelsHeight)),
184 i18nc("monthname year", "%1 %2", QLocale().standaloneMonthName(dayInMonth.month(), QLocale::LongFormat), dayInMonth.year()));
185
186 font.setPointSize(dayLabelsHeight - 10);
187 p->setFont(font);
188
189 const QDate start = mMonthView->actualStartDateTime().date();
190 const QDate end = mMonthView->actualEndDateTime().date();
191
192 for (QDate d = start; d <= start.addDays(6); d = d.addDays(1)) {
193 const MonthCell *const cell = mScene->mMonthCellMap.value(d);
194
195 if (!cell) {
196 // This means drawBackground() is being called before reloadIncidences(). Can happen with some
197 // themes. Bug #190191
198 return;
199 }
200
201 p->drawText(QRect(mScene->cellHorizontalPos(cell), mScene->cellVerticalPos(cell) - 15, mScene->columnWidth(), 15),
203 QLocale::system().dayName(d.dayOfWeek(), QLocale::LongFormat));
204 }
205
206 /*
207 Month grid
208 */
209 int columnWidth = mScene->columnWidth();
210 int rowHeight = mScene->rowHeight();
211 QDate todayDate{QDate::currentDate()};
212
213 const QList<QDate> workDays = CalendarSupport::workDays(mMonthView->actualStartDateTime().date(), mMonthView->actualEndDateTime().date());
214 QRect todayRect;
215 QRect selectedRect;
216 QColor holidayBg;
217 QColor workdayBg;
218 if (mMonthView->preferences()->useSystemColor()) {
219 workdayBg = palette().color(QPalette::Base);
220 holidayBg = palette().color(QPalette::AlternateBase);
221 } else {
222 workdayBg = mMonthView->preferences()->monthGridWorkHoursBackgroundColor();
223 holidayBg = mMonthView->preferences()->monthGridBackgroundColor();
224 }
225
226 for (QDate d = start; d <= end; d = d.addDays(1)) {
227 const MonthCell *const cell = mScene->mMonthCellMap.value(d);
228
229 if (!cell) {
230 // This means drawBackground() is being called before reloadIncidences(). Can happen with some
231 // themes. Bug #190191
232 return;
233 }
234
235 const QRect cellRect(mScene->cellHorizontalPos(cell), mScene->cellVerticalPos(cell), columnWidth, rowHeight);
236 if (cell == mScene->selectedCell()) {
237 selectedRect = cellRect;
238 }
239 if (cell->date() == todayDate) {
240 todayRect = cellRect;
241 }
242
243 // Draw cell
244 p->setPen(mMonthView->preferences()->monthGridBackgroundColor().darker(150));
245 p->setBrush(workDays.contains(d) ? workdayBg : holidayBg);
246 p->drawRect(cellRect);
247 if (mMonthView->isBusyDay(d)) {
248 QColor busyColor = mMonthView->preferences()->viewBgBusyColor();
249 busyColor.setAlpha(EventViews::BUSY_BACKGROUND_ALPHA);
250 p->setBrush(busyColor);
251 p->drawRect(cellRect);
252 }
253 }
254 if (!todayRect.isNull()) {
255 KColorScheme scheme(QPalette::Normal, KColorScheme::ColorSet::View);
256 p->setPen(scheme.foreground(KColorScheme::ForegroundRole::PositiveText).color());
257 p->setBrush(scheme.background(KColorScheme::BackgroundRole::PositiveBackground));
258 p->drawRect(todayRect);
259 }
260 if (!selectedRect.isNull()) {
261 const KColorScheme scheme(QPalette::Normal, KColorScheme::ColorSet::Selection);
262 auto color = scheme.background(KColorScheme::BackgroundRole::NormalBackground).color();
263 p->setPen(color);
264 color.setAlpha(EventViews::BUSY_BACKGROUND_ALPHA);
265 p->setBrush(color);
266 p->drawRect(selectedRect);
267 }
268
269 /*
270 * Draw Dates
271 */
272
273 font = mMonthView->preferences()->monthViewFont();
274 font.setPixelSize(MonthCell::topMargin() - 4);
275 p->setFont(font);
276
277 QPen oldPen;
278 if (mMonthView->preferences()->useSystemColor()) {
279 oldPen = palette().color(QPalette::WindowText).darker(150);
280 } else {
281 oldPen = mMonthView->preferences()->monthGridBackgroundColor().darker(150);
282 }
283
284 for (QDate d = mMonthView->actualStartDateTime().date(); d <= mMonthView->actualEndDateTime().date(); d = d.addDays(1)) {
285 MonthCell *const cell = mScene->mMonthCellMap.value(d);
286
287 // Draw cell header
288 int cellHeaderX = mScene->cellHorizontalPos(cell) + 1;
289 int cellHeaderY = mScene->cellVerticalPos(cell) + 1;
290 int cellHeaderWidth = columnWidth - 2;
291 int cellHeaderHeight = cell->topMargin() - 2;
292 const auto brush = KColorScheme(QPalette::Normal, KColorScheme::ColorSet::Header).background(KColorScheme::BackgroundRole::NormalBackground);
293 p->setBrush(brush);
294 p->setPen(Qt::NoPen);
295 p->drawRect(QRect(cellHeaderX, cellHeaderY, cellHeaderWidth, cellHeaderHeight));
296
297 QFont font = p->font();
298 font.setBold(cell->date() == todayDate);
299 p->setFont(font);
300
301 if (d.month() == mMonthView->currentMonth()) {
303 } else {
304 p->setPen(oldPen);
305 }
306
307 QString dayText;
308 // Prepend month name if d is the first or last day of month
309 if (d.day() == 1 || // d is the first day of month
310 d.addDays(1).day() == 1) { // d is the last day of month
311 dayText = i18nc("'Month day' for month view cells", "%1 %2", QLocale::system().monthName(d.month(), QLocale::ShortFormat), d.day());
312 } else {
313 dayText = QString::number(d.day());
314 }
315 p->drawText(QRect(mScene->cellHorizontalPos(cell), // top right
316 mScene->cellVerticalPos(cell), // of the cell
317 mScene->columnWidth() - 2,
318 cell->topMargin()),
320 dayText);
321
322 /*
323 Draw arrows if all items won't fit
324 */
325
326 // Up arrow if first item is above cell top
327 if (mScene->startHeight() != 0 && cell->hasEventBelow(mScene->startHeight())) {
328 cell->upArrow()->setPos(mScene->cellHorizontalPos(cell) + columnWidth / 2,
329 mScene->cellVerticalPos(cell) + cell->upArrow()->boundingRect().height() / 2 + 2);
330 cell->upArrow()->show();
331 } else {
332 cell->upArrow()->hide();
333 }
334
335 // Down arrow if last item is below cell bottom
336 if (!mScene->lastItemFit(cell)) {
337 cell->downArrow()->setPos(mScene->cellHorizontalPos(cell) + columnWidth / 2,
338 mScene->cellVerticalPos(cell) + rowHeight - cell->downArrow()->boundingRect().height() / 2 - 2);
339 cell->downArrow()->show();
340 } else {
341 cell->downArrow()->hide();
342 }
343 }
344}
345
346void MonthScene::resetAll()
347{
348 qDeleteAll(mMonthCellMap);
349 mMonthCellMap.clear();
350
351 qDeleteAll(mManagerList);
352 mManagerList.clear();
353
354 mSelectedItem = nullptr;
355 mActionItem = nullptr;
356 mClickedItem = nullptr;
357}
358
359Akonadi::IncidenceChanger *MonthScene::incidenceChanger() const
360{
361 return mMonthView->changer();
362}
363
364QDate MonthScene::firstDateOnRow(int row) const
365{
366 return mMonthView->actualStartDateTime().date().addDays(7 * row);
367}
368
369bool MonthScene::lastItemFit(MonthCell *cell)
370{
371 if (cell->firstFreeSpace() > maxRowCount() + startHeight()) {
372 return false;
373 } else {
374 return true;
375 }
376}
377
378int MonthScene::totalHeight()
379{
380 int max = 0;
381 for (QDate d = mMonthView->actualStartDateTime().date(); d <= mMonthView->actualEndDateTime().date(); d = d.addDays(1)) {
382 int c = mMonthCellMap[d]->firstFreeSpace();
383 if (c > max) {
384 max = c;
385 }
386 }
387
388 return max;
389}
390
391void MonthScene::wheelEvent(QGraphicsSceneWheelEvent *event)
392{
393 Q_UNUSED(event) // until we figure out what to do in here
394
395 /* int numDegrees = -event->delta() / 8;
396 int numSteps = numDegrees / 15;
397
398 if (startHeight() + numSteps < 0) {
399 numSteps = -startHeight();
400 }
401
402 int cellHeight = 0;
403
404 MonthCell *currentCell = getCellFromPos(event->scenePos());
405 if (currentCell) {
406 cellHeight = currentCell->firstFreeSpace();
407 }
408 if (cellHeight == 0) {
409 // no items in this cell, there's no point to scroll
410 return;
411 }
412
413 int newHeight;
414 int maxStartHeight = qMax(0, cellHeight - maxRowCount());
415 if (numSteps > 0 && startHeight() + numSteps >= maxStartHeight) {
416 newHeight = maxStartHeight;
417 } else {
418 newHeight = startHeight() + numSteps;
419 }
420
421 if (newHeight == startHeight()) {
422 return;
423 }
424
425 setStartHeight(newHeight);
426
427 foreach (MonthItem *manager, mManagerList) {
428 manager->updateGeometry();
429 }
430
431 invalidate(QRectF(), BackgroundLayer);
432
433 event->accept();
434 */
435}
436
437void MonthScene::scrollCellsDown()
438{
439 int newHeight = startHeight() + 1;
440 setStartHeight(newHeight);
441
442 for (MonthItem *manager : std::as_const(mManagerList)) {
443 manager->updateGeometry();
444 }
445
446 invalidate(QRectF(), BackgroundLayer);
447}
448
449void MonthScene::scrollCellsUp()
450{
451 int newHeight = startHeight() - 1;
452 setStartHeight(newHeight);
453
454 for (MonthItem *manager : std::as_const(mManagerList)) {
455 manager->updateGeometry();
456 }
457
458 invalidate(QRectF(), BackgroundLayer);
459}
460
461void MonthScene::clickOnScrollIndicator(ScrollIndicator *scrollItem)
462{
463 if (scrollItem->direction() == ScrollIndicator::UpArrow) {
464 scrollCellsUp();
465 } else if (scrollItem->direction() == ScrollIndicator::DownArrow) {
466 scrollCellsDown();
467 }
468}
469
470void MonthScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
471{
472 QPointF pos = mouseEvent->scenePos();
473 repeatTimer.stop();
474 MonthGraphicsItem *iItem = dynamic_cast<MonthGraphicsItem *>(itemAt(pos, {}));
475 if (iItem) {
476 if (iItem->monthItem()) {
478 if (tmp) {
479 selectItem(iItem->monthItem());
480 mMonthView->defaultAction(tmp->akonadiItem());
481
482 mouseEvent->accept();
483 }
484 }
485 } else {
486 QDate currentDate = getCellFromPos(pos)->date();
487 if (currentDate.isValid()) {
488 Q_EMIT newEventSignal(currentDate);
489 } else {
490 Q_EMIT newEventSignal();
491 }
492 }
493}
494
495void MonthScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
496{
497 QPointF pos = mouseEvent->scenePos();
498
499 MonthGraphicsView *view = static_cast<MonthGraphicsView *>(views().at(0));
500
501 // Change cursor depending on the part of the item it hovers to inform
502 // the user that he can resize the item.
503 if (mActionType == None) {
504 MonthGraphicsItem *iItem = dynamic_cast<MonthGraphicsItem *>(itemAt(pos, {}));
505 if (iItem) {
506 if (iItem->monthItem()->isResizable() && iItem->isBeginItem() && iItem->mapFromScene(pos).x() <= 10) {
507 view->setActionCursor(Resize);
508 } else if (iItem->monthItem()->isResizable() && iItem->isEndItem() && iItem->mapFromScene(pos).x() >= iItem->boundingRect().width() - 10) {
509 view->setActionCursor(Resize);
510 } else {
511 view->setActionCursor(None);
512 }
513 } else {
514 view->setActionCursor(None);
515 }
516 mouseEvent->accept();
517 return;
518 }
519
520 // If an item was selected during the click, we maybe have an item to move !
521 if (mActionItem) {
522 // Initiate action if not already done
523 if (!mActionInitiated && mActionType != None) {
524 if (mActionType == Move) {
525 mActionItem->beginMove();
526 } else if (mActionType == Resize) {
527 mActionItem->beginResize();
528 }
529 mActionInitiated = true;
530 }
531 view->setActionCursor(mActionType);
532
533 // Move or resize action
534 MonthCell *const currentCell = getCellFromPos(pos);
535 if (currentCell && currentCell != mPreviousCell) {
536 bool ok = true;
537 if (mActionType == Move) {
538 if (currentCell) {
539 mActionItem->moveTo(currentCell->date());
540 mActionItem->updateGeometry();
541 } else {
542 mActionItem->moveTo(QDate());
543 mActionItem->updateGeometry();
544 mActionItem->endMove();
545 mActionItem = nullptr;
546 mActionType = None;
547 mStartCell = nullptr;
548 }
549 } else if (mActionType == Resize) {
550 ok = mActionItem->resizeBy(mPreviousCell->date().daysTo(currentCell->date()));
551 mActionItem->updateGeometry();
552 }
553
554 if (ok) {
555 mPreviousCell = currentCell;
556 }
557 update();
558 }
559 mouseEvent->accept();
560 }
561}
562
563void MonthScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
564{
565 QPointF pos = mouseEvent->scenePos();
566
567 mClickedItem = nullptr;
568 mCurrentIndicator = nullptr;
569
570 MonthGraphicsItem *iItem = dynamic_cast<MonthGraphicsItem *>(itemAt(pos, {}));
571 if (iItem) {
572 mClickedItem = iItem->monthItem();
573
574 selectItem(mClickedItem);
575 if (mouseEvent->button() == Qt::RightButton) {
576 auto tmp = qobject_cast<IncidenceMonthItem *>(mClickedItem);
577 if (tmp) {
578 Q_EMIT showIncidencePopupSignal(tmp->calendar(), tmp->akonadiItem(), tmp->realStartDate());
579 }
580 }
581
582 if (mouseEvent->button() == Qt::LeftButton) {
583 // Basic initialization for resize and move
584 mActionItem = mClickedItem;
585 mStartCell = getCellFromPos(pos);
586 mPreviousCell = mStartCell;
587 mActionInitiated = false;
588
589 // Move or resize ?
590 if (iItem->monthItem()->isResizable() && iItem->isBeginItem() && iItem->mapFromScene(pos).x() <= 10) {
591 mActionType = Resize;
592 mResizeType = ResizeLeft;
593 } else if (iItem->monthItem()->isResizable() && iItem->isEndItem() && iItem->mapFromScene(pos).x() >= iItem->boundingRect().width() - 10) {
594 mActionType = Resize;
595 mResizeType = ResizeRight;
596 } else if (iItem->monthItem()->isMoveable()) {
597 mActionType = Move;
598 }
599 }
600 mouseEvent->accept();
601 } else if (ScrollIndicator *scrollItem = dynamic_cast<ScrollIndicator *>(itemAt(pos, {}))) {
602 clickOnScrollIndicator(scrollItem);
603 mCurrentIndicator = scrollItem;
604 repeatTimer.start(AUTO_REPEAT_DELAY, this);
605 } else {
606 // unselect items when clicking somewhere else
607 selectItem(nullptr);
608
609 MonthCell *cell = getCellFromPos(pos);
610 if (cell) {
611 mSelectedCellDate = cell->date();
612 update();
613 if (mouseEvent->button() == Qt::RightButton) {
614 Q_EMIT showNewEventPopupSignal();
615 }
616 mouseEvent->accept();
617 }
618 }
619}
620
621void MonthScene::timerEvent(QTimerEvent *e)
622{
623 if (e->timerId() == repeatTimer.timerId()) {
624 if (mCurrentIndicator->isVisible()) {
625 clickOnScrollIndicator(mCurrentIndicator);
626 repeatTimer.start(AUTO_REPEAT_DELAY, this);
627 } else {
628 mCurrentIndicator = nullptr;
629 repeatTimer.stop();
630 }
631 }
632}
633
634void MonthScene::helpEvent(QGraphicsSceneHelpEvent *helpEvent)
635{
636 // Find the first item that does tooltips
637 const QPointF pos = helpEvent->scenePos();
638 MonthGraphicsItem *toolTipItem = dynamic_cast<MonthGraphicsItem *>(itemAt(pos, {}));
639
640 // Show or hide the tooltip
641 QString text;
642 QPoint point;
643 if (toolTipItem) {
644 text = toolTipItem->getToolTip();
645 point = helpEvent->screenPos();
646 }
647 QToolTip::showText(point, text, helpEvent->widget());
648 helpEvent->setAccepted(!text.isEmpty());
649}
650
651void MonthScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
652{
653 QPointF pos = mouseEvent->scenePos();
654
655 static_cast<MonthGraphicsView *>(views().at(0))->setActionCursor(None);
656
657 repeatTimer.stop();
658 mCurrentIndicator = nullptr;
659
660 if (mActionItem) {
661 MonthCell *currentCell = getCellFromPos(pos);
662
663 const bool somethingChanged = currentCell && currentCell != mStartCell;
664
665 if (somethingChanged) { // We want to act if a move really happened
666 if (mActionType == Resize) {
667 mActionItem->endResize();
668 } else if (mActionType == Move) {
669 mActionItem->endMove();
670 }
671 }
672
673 mActionItem = nullptr;
674 mActionType = None;
675 mStartCell = nullptr;
676
677 mouseEvent->accept();
678 }
679}
680
681// returns true if the point is in the monthgrid (allows to avoid selecting a cell when
682// a click is outside the month grid
683bool MonthScene::isInMonthGrid(int x, int y) const
684{
685 return x >= 0 && y >= 0 && x <= availableWidth() && y <= availableHeight();
686}
687
688// The function converts the coordinates to the month grid coordinates to
689// be able to locate the cell.
690MonthCell *MonthScene::getCellFromPos(QPointF pos)
691{
692 int y = sceneYToMonthGridY(static_cast<int>(pos.y()));
693 int x = sceneXToMonthGridX(static_cast<int>(pos.x()));
694 if (!isInMonthGrid(x, y)) {
695 return nullptr;
696 }
697 int id = (int)(y / rowHeight()) * 7 + (int)(x / columnWidth());
698
699 return mMonthCellMap.value(mMonthView->actualStartDateTime().date().addDays(id));
700}
701
702void MonthScene::selectItem(MonthItem *item)
703{
704 /*
705 if (mSelectedItem == item) {
706 return;
707 }
708
709 I commented the above code so it's possible to selected a selected item.
710 korg-mobile needs that, otherwise clicking on a selected item won't bring the editor up.
711 Another solution would be to have two Q_SIGNALS: incidenceSelected() and incidenceClicked()
712 */
713
714 auto tmp = qobject_cast<IncidenceMonthItem *>(item);
715
716 if (!tmp) {
717 mSelectedItem = nullptr;
718 Q_EMIT incidenceSelected(Akonadi::Item(), QDate());
719 return;
720 }
721
722 mSelectedItem = item;
723 Q_ASSERT(CalendarSupport::hasIncidence(tmp->akonadiItem()));
724
725 if (mMonthView->selectedIncidenceDates().isEmpty()) {
726 Q_EMIT incidenceSelected(tmp->akonadiItem(), QDate());
727 } else {
728 Q_EMIT incidenceSelected(tmp->akonadiItem(), mMonthView->selectedIncidenceDates().at(0));
729 }
730 update();
731}
732
733void MonthScene::removeIncidence(const QString &uid)
734{
735 for (MonthItem *manager : std::as_const(mManagerList)) {
736 auto imi = qobject_cast<IncidenceMonthItem *>(manager);
737 if (!imi) {
738 continue;
739 }
740
741 KCalendarCore::Incidence::Ptr incidence = imi->incidence();
742 if (!incidence) {
743 continue;
744 }
745 if (incidence->uid() == uid) {
746 const auto lst = imi->monthGraphicsItems();
747 for (MonthGraphicsItem *gitem : lst) {
748 removeItem(gitem);
749 }
750 }
751 }
752}
753
754//----------------------------------------------------------
755MonthGraphicsView::MonthGraphicsView(MonthView *parent)
756 : QGraphicsView(parent)
757 , mMonthView(parent)
758{
759 setMouseTracking(true);
760}
761
762void MonthGraphicsView::setActionCursor(MonthScene::ActionType actionType)
763{
764 switch (actionType) {
765 case MonthScene::Move:
766#ifndef QT_NO_CURSOR
768#endif
769 break;
770 case MonthScene::Resize:
771#ifndef QT_NO_CURSOR
773#endif
774 break;
775#ifndef QT_NO_CURSOR
776 default:
778#endif
779 }
780}
781
782void MonthGraphicsView::setScene(MonthScene *scene)
783{
784 mScene = scene;
786}
787
788void MonthGraphicsView::resizeEvent(QResizeEvent *event)
789{
790 mScene->setSceneRect(0, 0, event->size().width(), event->size().height());
791 mScene->updateGeometry();
792}
793
794#include "moc_monthscene.cpp"
Keeps information about a month cell.
MonthItem * monthItem() const
Returns the associated MonthItem.
QRectF boundingRect() const override
Reimplemented from QGraphicsItem.
bool isBeginItem() const
Returns true if this MonthGraphicsItem is the first one of the MonthItem ones.
bool isEndItem() const
Returns true if this MonthGraphicsItem is the last one of the MonthItem ones.
void setActionCursor(MonthScene::ActionType actionType)
Change the cursor according to actionType.
void drawBackground(QPainter *painter, const QRectF &rect) override
Draws the cells.
A month item manages different MonthGraphicsItems.
Definition monthitem.h:27
void updateGeometry()
Updates geometry of all MonthGraphicsItems.
virtual bool isMoveable() const =0
Returns true if the item can be moved.
QDate startDate() const
The start date of the incidence, generally realStartDate.
virtual bool isResizable() const =0
Returns true if the item can be resized.
New month view.
Definition monthview.h:27
Graphics items which indicates that the view can be scrolled to display more events.
QSharedPointer< Incidence > Ptr
QBrush background(BackgroundRole=NormalBackground) const
QBrush foreground(ForegroundRole=NormalText) const
Q_SCRIPTABLE QString start(QString train="")
QString i18nc(const char *context, const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Incidence::Ptr incidence(const Akonadi::Item &item)
Namespace EventViews provides facilities for displaying incidences, including events,...
Definition agenda.h:33
const QColor & color() const const
QColor darker(int factor) const const
void setAlpha(int alpha)
QDate addDays(qint64 ndays) const const
QDate currentDate()
bool isValid(int year, int month, int day)
void accept()
QPainterPath mapFromScene(const QPainterPath &path) const const
void setPos(const QPointF &pos)
virtual bool event(QEvent *event) override
void invalidate(const QRectF &rect, SceneLayers layers)
QGraphicsItem * itemAt(const QPointF &position, const QTransform &deviceTransform) const const
void removeItem(QGraphicsItem *item)
void update(const QRectF &rect)
QList< QGraphicsView * > views() const const
Qt::MouseButton button() const const
QPointF scenePos() const const
virtual bool event(QEvent *event) override
QGraphicsScene * scene() const const
void setScene(QGraphicsScene *scene)
QPixmap pixmap(QWindow *window, const QSize &size, Mode mode, State state) const const
QIcon fromTheme(const QString &name)
bool contains(const AT &value) const const
QLocale system()
Q_EMITQ_EMIT
T qobject_cast(QObject *object)
void drawRect(const QRect &rectangle)
void drawText(const QPoint &position, const QString &text)
void fillRect(const QRect &rectangle, QGradient::Preset preset)
const QFont & font() const const
void setBrush(Qt::BrushStyle style)
void setFont(const QFont &font)
void setPen(Qt::PenStyle style)
QColor color() const const
qreal x() const const
qreal y() const const
bool isNull() const const
qreal height() const const
qreal width() const const
bool isEmpty() const const
QString number(double n, char format, int precision)
AlignCenter
ArrowCursor
RightButton
int timerId() const const
void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime)
void setCursor(const QCursor &)
void setMouseTracking(bool enable)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 25 2025 11:46:21 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.