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 , mClickedItem(nullptr)
32 , mActionItem(nullptr)
33 , mActionInitiated(false)
34 , mSelectedItem(nullptr)
36 , mPreviousCell(nullptr)
39 , mCurrentIndicator(nullptr)
49 setSceneRect(0, 0, parent->width(), parent->height());
52MonthScene::~MonthScene()
54 qDeleteAll(mMonthCellMap);
55 qDeleteAll(mManagerList);
58MonthCell *MonthScene::selectedCell()
const
60 return mMonthCellMap.value(mSelectedCellDate);
63MonthCell *MonthScene::previousCell()
const
68int MonthScene::getRightSpan(QDate date)
const
70 MonthCell *cell = mMonthCellMap.value(date);
75 return 7 - cell->x() - 1;
78int MonthScene::getLeftSpan(QDate date)
const
80 MonthCell *cell = mMonthCellMap.value(date);
88int MonthScene::maxRowCount()
90 return (rowHeight() - MonthCell::topMargin()) / itemHeightIncludingSpacing();
93int MonthScene::itemHeightIncludingSpacing()
95 return MonthCell::topMargin() + 2;
98int MonthScene::itemHeight()
100 return MonthCell::topMargin();
105 for (QDate d = manager->
startDate(); d <= manager->endDate(); d = d.
addDays(1)) {
106 MonthCell *monthCell = mMonthCellMap.value(d);
115void MonthScene::updateGeometry()
117 for (MonthItem *manager : std::as_const(mManagerList)) {
122int MonthScene::availableWidth()
const
124 return static_cast<int>(
sceneRect().width());
127int MonthScene::availableHeight()
const
129 return static_cast<int>(
sceneRect().height() - headerHeight());
132int MonthScene::columnWidth()
const
134 return static_cast<int>((availableWidth() - 1) / 7.);
137int MonthScene::rowHeight()
const
139 return static_cast<int>((availableHeight() - 1) / 6.);
142int MonthScene::headerHeight()
const
147int MonthScene::cellVerticalPos(
const MonthCell *cell)
const
149 return headerHeight() + cell->y() * rowHeight();
152int MonthScene::cellHorizontalPos(
const MonthCell *cell)
const
154 return cell->x() * columnWidth();
157int MonthScene::sceneYToMonthGridY(
int yScene)
159 return yScene - headerHeight();
162int MonthScene::sceneXToMonthGridX(
int xScene)
171 PrefsPtr prefs = mScene->monthView()->preferences();
172 p->
setFont(prefs->monthViewFont());
180 font.setPointSize(15);
182 const int dayLabelsHeight = 20;
183 const auto dayInMonth = mMonthView->averageDate();
186 static_cast<int>(mScene->sceneRect().width()),
187 static_cast<int>(mScene->headerHeight() - dayLabelsHeight)),
191 font.setPointSize(dayLabelsHeight - 10);
194 const QDate start = mMonthView->actualStartDateTime().date();
195 const QDate end = mMonthView->actualEndDateTime().date();
198 const MonthCell *
const cell = mScene->mMonthCellMap.value(d);
206 p->
drawText(
QRect(mScene->cellHorizontalPos(cell), mScene->cellVerticalPos(cell) - 15, mScene->columnWidth(), 15),
214 int columnWidth = mScene->columnWidth();
215 int rowHeight = mScene->rowHeight();
218 const QList<QDate> workDays = CalendarSupport::workDays(mMonthView->actualStartDateTime().date(), mMonthView->actualEndDateTime().date());
223 if (mMonthView->preferences()->useSystemColor()) {
227 workdayBg = mMonthView->preferences()->monthGridWorkHoursBackgroundColor();
228 holidayBg = mMonthView->preferences()->monthGridBackgroundColor();
231 for (
QDate d =
start; d <= end; d = d.addDays(1)) {
232 const MonthCell *
const cell = mScene->mMonthCellMap.value(d);
240 const QRect cellRect(mScene->cellHorizontalPos(cell), mScene->cellVerticalPos(cell), columnWidth, rowHeight);
241 if (cell == mScene->selectedCell()) {
242 selectedRect = cellRect;
244 if (cell->date() == todayDate) {
245 todayRect = cellRect;
249 p->
setPen(mMonthView->preferences()->monthGridBackgroundColor().darker(150));
252 if (mMonthView->isBusyDay(d)) {
253 QColor busyColor = mMonthView->preferences()->viewBgBusyColor();
254 busyColor.
setAlpha(EventViews::BUSY_BACKGROUND_ALPHA);
259 if (!todayRect.
isNull()) {
265 if (!selectedRect.
isNull()) {
267 auto color = scheme.
background(KColorScheme::BackgroundRole::NormalBackground).
color();
269 color.setAlpha(EventViews::BUSY_BACKGROUND_ALPHA);
278 font = mMonthView->preferences()->monthViewFont();
279 font.setPixelSize(MonthCell::topMargin() - 4);
283 if (mMonthView->preferences()->useSystemColor()) {
286 oldPen = mMonthView->preferences()->monthGridBackgroundColor().darker(150);
289 for (
QDate d = mMonthView->actualStartDateTime().date(); d <= mMonthView->actualEndDateTime().date(); d = d.
addDays(1)) {
290 MonthCell *
const cell = mScene->mMonthCellMap.value(d);
293 int cellHeaderX = mScene->cellHorizontalPos(cell) + 1;
294 int cellHeaderY = mScene->cellVerticalPos(cell) + 1;
295 int cellHeaderWidth = columnWidth - 2;
296 int cellHeaderHeight = cell->topMargin() - 2;
300 p->
drawRect(
QRect(cellHeaderX, cellHeaderY, cellHeaderWidth, cellHeaderHeight));
303 font.setBold(cell->date() == todayDate);
306 if (d.month() == mMonthView->currentMonth()) {
315 d.addDays(1).day() == 1) {
321 mScene->cellVerticalPos(cell),
322 mScene->columnWidth() - 2,
332 if (mScene->startHeight() != 0 && cell->hasEventBelow(mScene->startHeight())) {
333 cell->upArrow()->
setPos(mScene->cellHorizontalPos(cell) + columnWidth / 2,
334 mScene->cellVerticalPos(cell) + cell->upArrow()->boundingRect().
height() / 2 + 2);
335 cell->upArrow()->
show();
337 cell->upArrow()->
hide();
341 if (!mScene->lastItemFit(cell)) {
342 cell->downArrow()->
setPos(mScene->cellHorizontalPos(cell) + columnWidth / 2,
343 mScene->cellVerticalPos(cell) + rowHeight - cell->downArrow()->boundingRect().
height() / 2 - 2);
344 cell->downArrow()->
show();
346 cell->downArrow()->
hide();
351void MonthScene::resetAll()
353 qDeleteAll(mMonthCellMap);
354 mMonthCellMap.clear();
356 qDeleteAll(mManagerList);
357 mManagerList.clear();
359 mSelectedItem =
nullptr;
360 mActionItem =
nullptr;
361 mClickedItem =
nullptr;
364Akonadi::IncidenceChanger *MonthScene::incidenceChanger()
const
366 return mMonthView->changer();
369QDate MonthScene::firstDateOnRow(
int row)
const
371 return mMonthView->actualStartDateTime().date().addDays(7 * row);
374bool MonthScene::lastItemFit(
MonthCell *cell)
376 if (cell->firstFreeSpace() > maxRowCount() + startHeight()) {
383int MonthScene::totalHeight()
386 for (QDate d = mMonthView->actualStartDateTime().date(); d <= mMonthView->actualEndDateTime().date(); d = d.
addDays(1)) {
387 int c = mMonthCellMap[d]->firstFreeSpace();
396void MonthScene::wheelEvent(QGraphicsSceneWheelEvent *event)
442void MonthScene::scrollCellsDown()
444 int newHeight = startHeight() + 1;
445 setStartHeight(newHeight);
447 for (MonthItem *manager : std::as_const(mManagerList)) {
454void MonthScene::scrollCellsUp()
456 int newHeight = startHeight() - 1;
457 setStartHeight(newHeight);
459 for (MonthItem *manager : std::as_const(mManagerList)) {
468 if (scrollItem->direction() == ScrollIndicator::UpArrow) {
470 }
else if (scrollItem->direction() == ScrollIndicator::DownArrow) {
475void MonthScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
477 QPointF pos = mouseEvent->
scenePos();
479 MonthGraphicsItem *iItem =
dynamic_cast<MonthGraphicsItem *
>(
itemAt(pos, {}));
485 mMonthView->defaultAction(tmp->akonadiItem());
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
QPainterPath mapFromScene(const QPainterPath &path) const const
void setPos(const QPointF &pos)
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
virtual bool event(QEvent *e)
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)