9#include "monthgraphicsitems.h"
14#include <CalendarSupport/Utils>
16#include <KColorScheme>
17#include <KLocalizedString>
18#include <QGraphicsSceneMouseEvent>
20#include <QResizeEvent>
23static const int AUTO_REPEAT_DELAY = 600;
31 , mActionInitiated(false)
44 setSceneRect(0, 0, parent->width(), parent->height());
47MonthScene::~MonthScene()
49 qDeleteAll(mMonthCellMap);
50 qDeleteAll(mManagerList);
53MonthCell *MonthScene::selectedCell()
const
55 return mMonthCellMap.value(mSelectedCellDate);
58MonthCell *MonthScene::previousCell()
const
63int MonthScene::getRightSpan(QDate date)
const
65 MonthCell *cell = mMonthCellMap.value(date);
70 return 7 - cell->x() - 1;
73int MonthScene::getLeftSpan(QDate date)
const
75 MonthCell *cell = mMonthCellMap.value(date);
83int MonthScene::maxRowCount()
85 return (rowHeight() - MonthCell::topMargin()) / itemHeightIncludingSpacing();
88int MonthScene::itemHeightIncludingSpacing()
90 return MonthCell::topMargin() + 2;
93int MonthScene::itemHeight()
95 return MonthCell::topMargin();
100 for (QDate d = manager->
startDate(); d <= manager->endDate(); d = d.
addDays(1)) {
101 MonthCell *monthCell = mMonthCellMap.value(d);
110void MonthScene::updateGeometry()
112 for (MonthItem *manager : std::as_const(mManagerList)) {
117int MonthScene::availableWidth()
const
119 return static_cast<int>(
sceneRect().width());
122int MonthScene::availableHeight()
const
124 return static_cast<int>(
sceneRect().height() - headerHeight());
127int MonthScene::columnWidth()
const
129 return static_cast<int>((availableWidth() - 1) / 7.);
132int MonthScene::rowHeight()
const
134 return static_cast<int>((availableHeight() - 1) / 6.);
137int MonthScene::headerHeight()
const
142int MonthScene::cellVerticalPos(
const MonthCell *cell)
const
144 return headerHeight() + cell->y() * rowHeight();
147int MonthScene::cellHorizontalPos(
const MonthCell *cell)
const
149 return cell->x() * columnWidth();
152int MonthScene::sceneYToMonthGridY(
int yScene)
154 return yScene - headerHeight();
157int MonthScene::sceneXToMonthGridX(
int xScene)
166 PrefsPtr prefs = mScene->monthView()->preferences();
167 p->
setFont(prefs->monthViewFont());
175 font.setPointSize(15);
177 const int dayLabelsHeight = 20;
178 const auto dayInMonth = mMonthView->averageDate();
181 static_cast<int>(mScene->sceneRect().width()),
182 static_cast<int>(mScene->headerHeight() - dayLabelsHeight)),
186 font.setPointSize(dayLabelsHeight - 10);
189 const QDate start = mMonthView->actualStartDateTime().date();
190 const QDate end = mMonthView->actualEndDateTime().date();
193 const MonthCell *
const cell = mScene->mMonthCellMap.value(d);
201 p->
drawText(
QRect(mScene->cellHorizontalPos(cell), mScene->cellVerticalPos(cell) - 15, mScene->columnWidth(), 15),
209 int columnWidth = mScene->columnWidth();
210 int rowHeight = mScene->rowHeight();
213 const QList<QDate> workDays = CalendarSupport::workDays(mMonthView->actualStartDateTime().date(), mMonthView->actualEndDateTime().date());
218 if (mMonthView->preferences()->useSystemColor()) {
222 workdayBg = mMonthView->preferences()->monthGridWorkHoursBackgroundColor();
223 holidayBg = mMonthView->preferences()->monthGridBackgroundColor();
226 for (
QDate d =
start; d <= end; d = d.addDays(1)) {
227 const MonthCell *
const cell = mScene->mMonthCellMap.value(d);
235 const QRect cellRect(mScene->cellHorizontalPos(cell), mScene->cellVerticalPos(cell), columnWidth, rowHeight);
236 if (cell == mScene->selectedCell()) {
237 selectedRect = cellRect;
239 if (cell->date() == todayDate) {
240 todayRect = cellRect;
244 p->
setPen(mMonthView->preferences()->monthGridBackgroundColor().darker(150));
247 if (mMonthView->isBusyDay(d)) {
248 QColor busyColor = mMonthView->preferences()->viewBgBusyColor();
249 busyColor.
setAlpha(EventViews::BUSY_BACKGROUND_ALPHA);
254 if (!todayRect.
isNull()) {
260 if (!selectedRect.
isNull()) {
262 auto color = scheme.
background(KColorScheme::BackgroundRole::NormalBackground).
color();
264 color.setAlpha(EventViews::BUSY_BACKGROUND_ALPHA);
273 font = mMonthView->preferences()->monthViewFont();
274 font.setPixelSize(MonthCell::topMargin() - 4);
278 if (mMonthView->preferences()->useSystemColor()) {
281 oldPen = mMonthView->preferences()->monthGridBackgroundColor().darker(150);
284 for (
QDate d = mMonthView->actualStartDateTime().date(); d <= mMonthView->actualEndDateTime().date(); d = d.
addDays(1)) {
285 MonthCell *
const cell = mScene->mMonthCellMap.value(d);
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;
295 p->
drawRect(
QRect(cellHeaderX, cellHeaderY, cellHeaderWidth, cellHeaderHeight));
298 font.setBold(cell->date() == todayDate);
301 if (d.month() == mMonthView->currentMonth()) {
310 d.addDays(1).day() == 1) {
316 mScene->cellVerticalPos(cell),
317 mScene->columnWidth() - 2,
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();
332 cell->upArrow()->
hide();
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();
341 cell->downArrow()->
hide();
346void MonthScene::resetAll()
348 qDeleteAll(mMonthCellMap);
349 mMonthCellMap.clear();
351 qDeleteAll(mManagerList);
352 mManagerList.clear();
354 mSelectedItem =
nullptr;
355 mActionItem =
nullptr;
356 mClickedItem =
nullptr;
359Akonadi::IncidenceChanger *MonthScene::incidenceChanger()
const
361 return mMonthView->changer();
364QDate MonthScene::firstDateOnRow(
int row)
const
366 return mMonthView->actualStartDateTime().date().addDays(7 * row);
369bool MonthScene::lastItemFit(
MonthCell *cell)
371 if (cell->firstFreeSpace() > maxRowCount() + startHeight()) {
378int MonthScene::totalHeight()
381 for (QDate d = mMonthView->actualStartDateTime().date(); d <= mMonthView->actualEndDateTime().date(); d = d.
addDays(1)) {
382 int c = mMonthCellMap[d]->firstFreeSpace();
391void MonthScene::wheelEvent(QGraphicsSceneWheelEvent *event)
437void MonthScene::scrollCellsDown()
439 int newHeight = startHeight() + 1;
440 setStartHeight(newHeight);
442 for (MonthItem *manager : std::as_const(mManagerList)) {
449void MonthScene::scrollCellsUp()
451 int newHeight = startHeight() - 1;
452 setStartHeight(newHeight);
454 for (MonthItem *manager : std::as_const(mManagerList)) {
463 if (scrollItem->direction() == ScrollIndicator::UpArrow) {
465 }
else if (scrollItem->direction() == ScrollIndicator::DownArrow) {
470void MonthScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
472 QPointF pos = mouseEvent->
scenePos();
474 MonthGraphicsItem *iItem =
dynamic_cast<MonthGraphicsItem *
>(
itemAt(pos, {}));
480 mMonthView->defaultAction(tmp->akonadiItem());
486 QDate currentDate = getCellFromPos(pos)->date();
488 Q_EMIT newEventSignal(currentDate);
495void MonthScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
497 QPointF pos = mouseEvent->
scenePos();
499 MonthGraphicsView *view =
static_cast<MonthGraphicsView *
>(
views().at(0));
503 if (mActionType == None) {
504 MonthGraphicsItem *iItem =
dynamic_cast<MonthGraphicsItem *
>(
itemAt(pos, {}));
523 if (!mActionInitiated && mActionType != None) {
524 if (mActionType == Move) {
525 mActionItem->beginMove();
526 }
else if (mActionType == Resize) {
527 mActionItem->beginResize();
529 mActionInitiated =
true;
534 MonthCell *
const currentCell = getCellFromPos(pos);
535 if (currentCell && currentCell != mPreviousCell) {
537 if (mActionType == Move) {
539 mActionItem->moveTo(currentCell->date());
540 mActionItem->updateGeometry();
542 mActionItem->moveTo(QDate());
543 mActionItem->updateGeometry();
544 mActionItem->endMove();
545 mActionItem =
nullptr;
547 mStartCell =
nullptr;
549 }
else if (mActionType == Resize) {
550 ok = mActionItem->resizeBy(mPreviousCell->date().daysTo(currentCell->date()));
551 mActionItem->updateGeometry();
555 mPreviousCell = currentCell;
563void MonthScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
565 QPointF pos = mouseEvent->
scenePos();
567 mClickedItem =
nullptr;
568 mCurrentIndicator =
nullptr;
570 MonthGraphicsItem *iItem =
dynamic_cast<MonthGraphicsItem *
>(
itemAt(pos, {}));
574 selectItem(mClickedItem);
578 Q_EMIT showIncidencePopupSignal(tmp->calendar(), tmp->akonadiItem(), tmp->realStartDate());
584 mActionItem = mClickedItem;
585 mStartCell = getCellFromPos(pos);
586 mPreviousCell = mStartCell;
587 mActionInitiated =
false;
591 mActionType = Resize;
592 mResizeType = ResizeLeft;
594 mActionType = Resize;
595 mResizeType = ResizeRight;
601 }
else if (ScrollIndicator *scrollItem =
dynamic_cast<ScrollIndicator *
>(
itemAt(pos, {}))) {
602 clickOnScrollIndicator(scrollItem);
603 mCurrentIndicator = scrollItem;
604 repeatTimer.start(AUTO_REPEAT_DELAY,
this);
609 MonthCell *cell = getCellFromPos(pos);
611 mSelectedCellDate = cell->date();
614 Q_EMIT showNewEventPopupSignal();
621void MonthScene::timerEvent(QTimerEvent *e)
623 if (e->
timerId() == repeatTimer.timerId()) {
624 if (mCurrentIndicator->isVisible()) {
625 clickOnScrollIndicator(mCurrentIndicator);
626 repeatTimer.start(AUTO_REPEAT_DELAY,
this);
628 mCurrentIndicator =
nullptr;
634void MonthScene::helpEvent(QGraphicsSceneHelpEvent *helpEvent)
637 const QPointF pos = helpEvent->scenePos();
638 MonthGraphicsItem *toolTipItem =
dynamic_cast<MonthGraphicsItem *
>(
itemAt(pos, {}));
644 text = toolTipItem->getToolTip();
645 point = helpEvent->screenPos();
648 helpEvent->setAccepted(!text.
isEmpty());
651void MonthScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
653 QPointF pos = mouseEvent->
scenePos();
655 static_cast<MonthGraphicsView *
>(
views().at(0))->setActionCursor(None);
658 mCurrentIndicator =
nullptr;
661 MonthCell *currentCell = getCellFromPos(pos);
663 const bool somethingChanged = currentCell && currentCell != mStartCell;
665 if (somethingChanged) {
666 if (mActionType == Resize) {
667 mActionItem->endResize();
668 }
else if (mActionType == Move) {
669 mActionItem->endMove();
673 mActionItem =
nullptr;
675 mStartCell =
nullptr;
683bool MonthScene::isInMonthGrid(
int x,
int y)
const
685 return x >= 0 && y >= 0 && x <= availableWidth() && y <= availableHeight();
690MonthCell *MonthScene::getCellFromPos(QPointF pos)
692 int y = sceneYToMonthGridY(
static_cast<int>(pos.
y()));
693 int x = sceneXToMonthGridX(
static_cast<int>(pos.
x()));
694 if (!isInMonthGrid(x, y)) {
697 int id = (int)(y / rowHeight()) * 7 + (int)(x / columnWidth());
699 return mMonthCellMap.value(mMonthView->actualStartDateTime().date().addDays(
id));
702void MonthScene::selectItem(
MonthItem *item)
717 mSelectedItem =
nullptr;
718 Q_EMIT incidenceSelected(Akonadi::Item(), QDate());
722 mSelectedItem = item;
723 Q_ASSERT(CalendarSupport::hasIncidence(tmp->akonadiItem()));
725 if (mMonthView->selectedIncidenceDates().isEmpty()) {
726 Q_EMIT incidenceSelected(tmp->akonadiItem(), QDate());
728 Q_EMIT incidenceSelected(tmp->akonadiItem(), mMonthView->selectedIncidenceDates().at(0));
733void MonthScene::removeIncidence(
const QString &uid)
735 for (MonthItem *manager : std::as_const(mManagerList)) {
746 const auto lst = imi->monthGraphicsItems();
747 for (MonthGraphicsItem *gitem : lst) {
755MonthGraphicsView::MonthGraphicsView(
MonthView *parent)
756 : QGraphicsView(parent)
764 switch (actionType) {
765 case MonthScene::Move:
770 case MonthScene::Resize:
782void MonthGraphicsView::setScene(MonthScene *scene)
791 mScene->updateGeometry();
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.
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.
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,...
const QColor & color() const const
QColor darker(int factor) const const
QDate addDays(qint64 ndays) const const
bool isValid(int year, int month, int day)
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
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
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
bool isNull() const const
qreal height() const const
qreal width() const const
bool isEmpty() const const
QString number(double n, char format, int precision)
int timerId() const const
void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime)