1/* -*- C++ -*-
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1997 Tim D. Gilman <tdgilman@best.org>
4 SPDX-FileCopyrightText: 1998-2001 Mirko Boehm <mirko@kde.org>
5 SPDX-FileCopyrightText: 2007 John Layt <john@layt.net>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "kdatetable_p.h"
11
12#include <QAction>
13#include <QActionEvent>
14#include <QApplication>
15#include <QDate>
16#include <QFontDatabase>
17#include <QMenu>
18#include <QPainter>
19#include <QStyle>
20#include <QStyleOptionViewItem>
21
22#include <cmath>
23
24#include "kdaterangecontrol_p.h"
25
26class KDateTable::KDateTablePrivate : public KDateRangeControlPrivate
27{
28public:
29 KDateTablePrivate(KDateTable *qq)
30 : q(qq)
31 {
32 m_popupMenuEnabled = false;
33 m_useCustomColors = false;
34 m_hoveredPos = -1;
35 setDate(QDate::currentDate());
36 }
37
38 ~KDateTablePrivate()
39 {
40 }
41
42 void setDate(const QDate &date);
43 void nextMonth();
44 void previousMonth();
45 void beginningOfMonth();
46 void endOfMonth();
47 void beginningOfWeek();
48 void endOfWeek();
49
50 KDateTable *q;
51
52 /*
53 * The currently selected date.
54 */
55 QDate m_date;
56
57 /*
58 * The weekday number of the first day in the month [1..daysInWeek()].
59 */
60 int m_weekDayFirstOfMonth;
61
62 /*
63 * The number of days in the current month.
64 */
65 int m_numDaysThisMonth;
66
67 /*
68 * Save the size of the largest used cell content.
69 */
70 QRectF m_maxCell;
71
72 /*
73 * How many week rows we are to draw.
74 */
75 int m_numWeekRows;
76
77 /*
78 * How many day columns we are to draw, i.e. days in a week.
79 */
80 int m_numDayColumns;
81
82 /*
83 * The font size of the displayed text.
84 */
85 int fontsize;
86
87 bool m_popupMenuEnabled;
88 bool m_useCustomColors;
89
90 struct DatePaintingMode {
91 QColor fgColor;
92 QColor bgColor;
93 BackgroundMode bgMode;
94 };
95 QHash<int, DatePaintingMode> m_customPaintingModes;
96
97 int m_hoveredPos;
98};
99
100KDateTable::KDateTable(const QDate &date, QWidget *parent)
101 : QWidget(parent)
102 , d(new KDateTablePrivate(this))
103{
104 initWidget(date);
105}
106
107KDateTable::KDateTable(QWidget *parent)
108 : QWidget(parent)
109 , d(std::make_unique<KDateTablePrivate>(args: this))
110{
111 initWidget(date: QDate::currentDate());
112}
113
114KDateTable::~KDateTable()
115{
116}
117
118void KDateTable::initWidget(const QDate &date)
119{
120 d->m_numWeekRows = 7;
121
122 setFontSize(10);
123 setFocusPolicy(Qt::StrongFocus);
124 setBackgroundRole(QPalette::Base);
125 setAutoFillBackground(true);
126 initAccels();
127 setAttribute(Qt::WA_Hover, on: true);
128
129 setDate(date);
130}
131
132void KDateTable::initAccels()
133{
134 QAction *next = new QAction(this);
135 next->setObjectName(QStringLiteral("next"));
136 next->setShortcuts(QKeySequence::keyBindings(key: QKeySequence::Forward));
137 next->setShortcutContext(Qt::WidgetWithChildrenShortcut);
138 connect(sender: next, signal: &QAction::triggered, context: this, slot: [this]() {
139 d->nextMonth();
140 });
141
142 QAction *prior = new QAction(this);
143 prior->setObjectName(QStringLiteral("prior"));
144 prior->setShortcuts(QKeySequence::keyBindings(key: QKeySequence::Back));
145 prior->setShortcutContext(Qt::WidgetWithChildrenShortcut);
146 connect(sender: prior, signal: &QAction::triggered, context: this, slot: [this]() {
147 d->previousMonth();
148 });
149
150 QAction *beginMonth = new QAction(this);
151 beginMonth->setObjectName(QStringLiteral("beginMonth"));
152 beginMonth->setShortcuts(QKeySequence::keyBindings(key: QKeySequence::MoveToStartOfDocument));
153 beginMonth->setShortcutContext(Qt::WidgetWithChildrenShortcut);
154 connect(sender: beginMonth, signal: &QAction::triggered, context: this, slot: [this]() {
155 d->beginningOfMonth();
156 });
157
158 QAction *endMonth = new QAction(this);
159 endMonth->setObjectName(QStringLiteral("endMonth"));
160 endMonth->setShortcuts(QKeySequence::keyBindings(key: QKeySequence::MoveToEndOfDocument));
161 endMonth->setShortcutContext(Qt::WidgetWithChildrenShortcut);
162 connect(sender: endMonth, signal: &QAction::triggered, context: this, slot: [this]() {
163 d->endOfMonth();
164 });
165
166 QAction *beginWeek = new QAction(this);
167 beginWeek->setObjectName(QStringLiteral("beginWeek"));
168 beginWeek->setShortcuts(QKeySequence::keyBindings(key: QKeySequence::MoveToStartOfLine));
169 beginWeek->setShortcutContext(Qt::WidgetWithChildrenShortcut);
170 connect(sender: beginWeek, signal: &QAction::triggered, context: this, slot: [this]() {
171 d->beginningOfWeek();
172 });
173
174 QAction *endWeek = new QAction(this);
175 endWeek->setObjectName(QStringLiteral("endWeek"));
176 endWeek->setShortcuts(QKeySequence::keyBindings(key: QKeySequence::MoveToEndOfLine));
177 endWeek->setShortcutContext(Qt::WidgetWithChildrenShortcut);
178 connect(sender: endWeek, signal: &QAction::triggered, context: this, slot: [this]() {
179 d->endOfWeek();
180 });
181}
182
183int KDateTable::posFromDate(const QDate &date)
184{
185 int initialPosition = date.day();
186 int offset = (d->m_weekDayFirstOfMonth - locale().firstDayOfWeek() + d->m_numDayColumns) % d->m_numDayColumns;
187
188 // make sure at least one day of the previous month is visible.
189 // adjust this < 1 if more days should be forced visible:
190 if (offset < 1) {
191 offset += d->m_numDayColumns;
192 }
193
194 return initialPosition + offset;
195}
196
197QDate KDateTable::dateFromPos(int position)
198{
199 int offset = (d->m_weekDayFirstOfMonth - locale().firstDayOfWeek() + d->m_numDayColumns) % d->m_numDayColumns;
200
201 // make sure at least one day of the previous month is visible.
202 // adjust this < 1 if more days should be forced visible:
203 if (offset < 1) {
204 offset += d->m_numDayColumns;
205 }
206
207 return QDate(d->m_date.year(), d->m_date.month(), 1).addDays(days: position - offset);
208}
209
210void KDateTable::paintEvent(QPaintEvent *e)
211{
212 QPainter p(this);
213 const QRect &rectToUpdate = e->rect();
214 double cellWidth = width() / (double)d->m_numDayColumns;
215 double cellHeight = height() / (double)d->m_numWeekRows;
216 int leftCol = (int)std::floor(x: rectToUpdate.left() / cellWidth);
217 int topRow = (int)std::floor(x: rectToUpdate.top() / cellHeight);
218 int rightCol = (int)std::ceil(x: rectToUpdate.right() / cellWidth);
219 int bottomRow = (int)std::ceil(x: rectToUpdate.bottom() / cellHeight);
220 bottomRow = qMin(a: bottomRow, b: d->m_numWeekRows - 1);
221 rightCol = qMin(a: rightCol, b: d->m_numDayColumns - 1);
222 if (layoutDirection() == Qt::RightToLeft) {
223 p.translate(dx: (d->m_numDayColumns - leftCol - 1) * cellWidth, dy: topRow * cellHeight);
224 } else {
225 p.translate(dx: leftCol * cellWidth, dy: topRow * cellHeight);
226 }
227 for (int i = leftCol; i <= rightCol; ++i) {
228 for (int j = topRow; j <= bottomRow; ++j) {
229 paintCell(painter: &p, row: j, col: i);
230 p.translate(dx: 0, dy: cellHeight);
231 }
232 if (layoutDirection() == Qt::RightToLeft) {
233 p.translate(dx: -cellWidth, dy: 0);
234 } else {
235 p.translate(dx: cellWidth, dy: 0);
236 }
237 p.translate(dx: 0, dy: -cellHeight * (bottomRow - topRow + 1));
238 }
239}
240
241void KDateTable::paintCell(QPainter *painter, int row, int col)
242{
243 double w = (width() / (double)d->m_numDayColumns) - 1;
244 double h = (height() / (double)d->m_numWeekRows) - 1;
245 QRectF cell = QRectF(0, 0, w, h);
246 QString cellText;
247 QColor cellBackgroundColor;
248 QColor cellTextColor;
249 QFont cellFont = QFontDatabase::systemFont(type: QFontDatabase::GeneralFont);
250 bool workingDay = false;
251 int cellWeekDay;
252 int pos;
253
254 // Calculate the position of the cell in the grid
255 pos = d->m_numDayColumns * (row - 1) + col;
256
257 // Calculate what day of the week the cell is
258 if (col + locale().firstDayOfWeek() <= d->m_numDayColumns) {
259 cellWeekDay = col + locale().firstDayOfWeek();
260 } else {
261 cellWeekDay = col + locale().firstDayOfWeek() - d->m_numDayColumns;
262 }
263
264 // FIXME This is wrong if the widget is not using the global!
265 // See if cell day is normally a working day
266 if (locale().weekdays().first() <= locale().weekdays().last()) {
267 if (cellWeekDay >= locale().weekdays().first() && cellWeekDay <= locale().weekdays().last()) {
268 workingDay = true;
269 }
270 } else {
271 if (cellWeekDay >= locale().weekdays().first() //
272 || cellWeekDay <= locale().weekdays().last()) {
273 workingDay = true;
274 }
275 }
276
277 if (row == 0) {
278 // We are drawing a header cell
279
280 // If not a normal working day, then use "do not work today" color
281 if (workingDay) {
282 cellTextColor = palette().color(cr: QPalette::WindowText);
283 } else {
284 cellTextColor = Qt::darkRed;
285 }
286 cellBackgroundColor = palette().color(cr: QPalette::Window);
287
288 // Set the text to the short day name and bold it
289 cellFont.setBold(true);
290 cellText = locale().dayName(cellWeekDay, format: QLocale::ShortFormat);
291
292 } else {
293 // We are drawing a day cell
294
295 // Calculate the date the cell represents
296 QDate cellDate = dateFromPos(position: pos);
297
298 bool validDay = cellDate.isValid();
299
300 // Draw the day number in the cell, if the date is not valid then we don't want to show it
301 if (validDay) {
302 cellText = locale().toString(i: cellDate.day());
303 } else {
304 cellText = QString();
305 }
306
307 if (!validDay || cellDate.month() != d->m_date.month()) {
308 // we are either
309 // ° painting an invalid day
310 // ° painting a day of the previous month or
311 // ° painting a day of the following month or
312 cellBackgroundColor = palette().color(cr: backgroundRole());
313 cellTextColor = palette().color(cg: QPalette::Disabled, cr: QPalette::Text);
314 } else {
315 // Paint a day of the current month
316
317 // Background Colour priorities will be (high-to-low):
318 // * Selected Day Background Colour
319 // * Customized Day Background Colour
320 // * Normal Day Background Colour
321
322 // Background Shape priorities will be (high-to-low):
323 // * Customized Day Shape
324 // * Normal Day Shape
325
326 // Text Colour priorities will be (high-to-low):
327 // * Customized Day Colour
328 // * Day of Pray Colour (Red letter)
329 // * Selected Day Colour
330 // * Normal Day Colour
331
332 // Determine various characteristics of the cell date
333 bool selectedDay = (cellDate == date());
334 bool currentDay = (cellDate == QDate::currentDate());
335 bool dayOfPray = (cellDate.dayOfWeek() == Qt::Sunday);
336 // TODO: Uncomment if QLocale ever gets the feature...
337 // bool dayOfPray = ( cellDate.dayOfWeek() == locale().dayOfPray() );
338 bool customDay = (d->m_useCustomColors && d->m_customPaintingModes.contains(key: cellDate.toJulianDay()));
339
340 // Default values for a normal cell
341 cellBackgroundColor = palette().color(cr: backgroundRole());
342 cellTextColor = palette().color(cr: foregroundRole());
343
344 // If we are drawing the current date, then draw it bold and active
345 if (currentDay) {
346 cellFont.setBold(true);
347 cellTextColor = palette().color(cr: QPalette::LinkVisited);
348 }
349
350 // if we are drawing the day cell currently selected in the table
351 if (selectedDay) {
352 // set the background to highlighted
353 cellBackgroundColor = palette().color(cr: QPalette::Highlight);
354 cellTextColor = palette().color(cr: QPalette::HighlightedText);
355 }
356
357 // If custom colors or shape are required for this date
358 if (customDay) {
359 KDateTablePrivate::DatePaintingMode mode = d->m_customPaintingModes[cellDate.toJulianDay()];
360 if (mode.bgMode != NoBgMode) {
361 if (!selectedDay) {
362 cellBackgroundColor = mode.bgColor;
363 }
364 }
365 cellTextColor = mode.fgColor;
366 }
367
368 // If the cell day is the day of religious observance, then always color text red unless Custom overrides
369 if (!customDay && dayOfPray) {
370 cellTextColor = Qt::darkRed;
371 }
372 }
373
374 // If the cell day is out of the allowed range, paint it as disabled
375 if (!d->isInDateRange(date: cellDate)) {
376 cellBackgroundColor = palette().color(cg: QPalette::Disabled, cr: backgroundRole());
377 }
378 }
379
380 // Draw the background
381 if (row == 0) {
382 painter->setPen(cellBackgroundColor);
383 painter->setBrush(cellBackgroundColor);
384 painter->drawRect(rect: cell);
385 } else if (cellBackgroundColor != palette().color(cr: backgroundRole()) || pos == d->m_hoveredPos) {
386 QStyleOptionViewItem opt;
387 opt.initFrom(w: this);
388 opt.rect = cell.toRect();
389 if (cellBackgroundColor != palette().color(cr: backgroundRole())) {
390 opt.palette.setBrush(acr: QPalette::Highlight, abrush: cellBackgroundColor);
391 opt.state |= QStyle::State_Selected;
392 }
393 if (pos == d->m_hoveredPos && opt.state & QStyle::State_Enabled) {
394 opt.state |= QStyle::State_MouseOver;
395 } else {
396 opt.state &= ~QStyle::State_MouseOver;
397 }
398 opt.showDecorationSelected = true;
399 opt.viewItemPosition = QStyleOptionViewItem::OnlyOne;
400 style()->drawPrimitive(pe: QStyle::PE_PanelItemViewItem, opt: &opt, p: painter, w: this);
401 }
402
403 // Draw the text
404 painter->setPen(cellTextColor);
405 painter->setFont(cellFont);
406 painter->drawText(r: cell, flags: Qt::AlignCenter, text: cellText, br: &cell);
407
408 // Draw the base line
409 if (row == 0) {
410 painter->setPen(palette().color(cr: foregroundRole()));
411 painter->drawLine(p1: QPointF(0, h), p2: QPointF(w, h));
412 }
413
414 // If the day cell we just drew is bigger than the current max cell sizes,
415 // then adjust the max to the current cell
416 if (cell.width() > d->m_maxCell.width()) {
417 d->m_maxCell.setWidth(cell.width());
418 }
419 if (cell.height() > d->m_maxCell.height()) {
420 d->m_maxCell.setHeight(cell.height());
421 }
422}
423
424void KDateTable::KDateTablePrivate::nextMonth()
425{
426 // setDate does validity checking for us
427 q->setDate(m_date.addMonths(months: 1));
428}
429
430void KDateTable::KDateTablePrivate::previousMonth()
431{
432 // setDate does validity checking for us
433 q->setDate(m_date.addMonths(months: -1));
434}
435
436void KDateTable::KDateTablePrivate::beginningOfMonth()
437{
438 // setDate does validity checking for us
439 q->setDate(QDate(m_date.year(), m_date.month(), 1));
440}
441
442void KDateTable::KDateTablePrivate::endOfMonth()
443{
444 // setDate does validity checking for us
445 q->setDate(QDate(m_date.year(), m_date.month() + 1, 0));
446}
447
448// JPL Do these make the assumption that first day of week is weekday 1? As it may not be.
449void KDateTable::KDateTablePrivate::beginningOfWeek()
450{
451 // setDate does validity checking for us
452 q->setDate(m_date.addDays(days: 1 - m_date.dayOfWeek()));
453}
454
455// JPL Do these make the assumption that first day of week is weekday 1? As it may not be.
456void KDateTable::KDateTablePrivate::endOfWeek()
457{
458 // setDate does validity checking for us
459 q->setDate(m_date.addDays(days: 7 - m_date.dayOfWeek()));
460}
461
462void KDateTable::keyPressEvent(QKeyEvent *e)
463{
464 switch (e->key()) {
465 case Qt::Key_Up:
466 // setDate does validity checking for us
467 setDate(d->m_date.addDays(days: -d->m_numDayColumns));
468 break;
469 case Qt::Key_Down:
470 // setDate does validity checking for us
471 setDate(d->m_date.addDays(days: d->m_numDayColumns));
472 break;
473 case Qt::Key_Left:
474 // setDate does validity checking for us
475 setDate(d->m_date.addDays(days: -1));
476 break;
477 case Qt::Key_Right:
478 // setDate does validity checking for us
479 setDate(d->m_date.addDays(days: 1));
480 break;
481 case Qt::Key_Minus:
482 // setDate does validity checking for us
483 setDate(d->m_date.addDays(days: -1));
484 break;
485 case Qt::Key_Plus:
486 // setDate does validity checking for us
487 setDate(d->m_date.addDays(days: 1));
488 break;
489 case Qt::Key_N:
490 // setDate does validity checking for us
491 setDate(QDate::currentDate());
492 break;
493 case Qt::Key_Return:
494 case Qt::Key_Enter:
495 Q_EMIT tableClicked();
496 break;
497 case Qt::Key_Control:
498 case Qt::Key_Alt:
499 case Qt::Key_Meta:
500 case Qt::Key_Shift:
501 // Don't beep for modifiers
502 break;
503 default:
504 if (!e->modifiers()) { // hm
505 QApplication::beep();
506 }
507 }
508}
509
510void KDateTable::setFontSize(int size)
511{
512 QFontMetricsF metrics(fontMetrics());
513 QRectF rect;
514 // ----- store rectangles:
515 d->fontsize = size;
516 // ----- find largest day name:
517 d->m_maxCell.setWidth(0);
518 d->m_maxCell.setHeight(0);
519 for (int weekday = 1; weekday <= 7; ++weekday) {
520 rect = metrics.boundingRect(string: locale().dayName(weekday, format: QLocale::ShortFormat));
521 d->m_maxCell.setWidth(qMax(a: d->m_maxCell.width(), b: rect.width()));
522 d->m_maxCell.setHeight(qMax(a: d->m_maxCell.height(), b: rect.height()));
523 }
524 // ----- compare with a real wide number and add some space:
525 rect = metrics.boundingRect(QStringLiteral("88"));
526 d->m_maxCell.setWidth(qMax(a: d->m_maxCell.width() + 2, b: rect.width()));
527 d->m_maxCell.setHeight(qMax(a: d->m_maxCell.height() + 4, b: rect.height()));
528}
529
530void KDateTable::wheelEvent(QWheelEvent *e)
531{
532 setDate(d->m_date.addMonths(months: -(int)(e->angleDelta().y() / 120)));
533 e->accept();
534}
535
536bool KDateTable::event(QEvent *ev)
537{
538 switch (ev->type()) {
539 case QEvent::HoverMove: {
540 QHoverEvent *e = static_cast<QHoverEvent *>(ev);
541 const int row = e->position().y() * d->m_numWeekRows / height();
542 int col;
543 if (layoutDirection() == Qt::RightToLeft) {
544 col = d->m_numDayColumns - (e->position().x() * d->m_numDayColumns / width()) - 1;
545 } else {
546 col = e->position().x() * d->m_numDayColumns / width();
547 }
548
549 const int pos = row < 1 ? -1 : (d->m_numDayColumns * (row - 1)) + col;
550
551 if (pos != d->m_hoveredPos) {
552 d->m_hoveredPos = pos;
553 update();
554 }
555 break;
556 }
557 case QEvent::HoverLeave:
558 if (d->m_hoveredPos != -1) {
559 d->m_hoveredPos = -1;
560 update();
561 }
562 break;
563 default:
564 break;
565 }
566 return QWidget::event(event: ev);
567}
568
569void KDateTable::mousePressEvent(QMouseEvent *e)
570{
571 if (e->type() != QEvent::MouseButtonPress) { // the KDatePicker only reacts on mouse press events:
572 return;
573 }
574
575 if (!isEnabled()) {
576 QApplication::beep();
577 return;
578 }
579
580 int row;
581 int col;
582 int pos;
583
584 QPoint mouseCoord = e->pos();
585 row = mouseCoord.y() * d->m_numWeekRows / height();
586 if (layoutDirection() == Qt::RightToLeft) {
587 col = d->m_numDayColumns - (mouseCoord.x() * d->m_numDayColumns / width()) - 1;
588 } else {
589 col = mouseCoord.x() * d->m_numDayColumns / width();
590 }
591
592 if (row < 1 || col < 0) { // the user clicked on the frame of the table
593 return;
594 }
595
596 // Rows and columns are zero indexed. The (row - 1) below is to avoid counting
597 // the row with the days of the week in the calculation.
598
599 // new position and date
600 pos = (d->m_numDayColumns * (row - 1)) + col;
601 QDate clickedDate = dateFromPos(position: pos);
602
603 if (!d->isInDateRange(date: clickedDate)) {
604 return;
605 }
606
607 // set the new date. If it is in the previous or next month, the month will
608 // automatically be changed, no need to do that manually...
609 // validity checking done inside setDate
610 setDate(clickedDate);
611
612 // This could be optimized to only call update over the regions
613 // of old and new cell, but 99% of times there is also a call to
614 // setDate that already calls update() so no need to optimize that
615 // much here
616 update();
617
618 Q_EMIT tableClicked();
619
620 if (e->button() == Qt::RightButton && d->m_popupMenuEnabled) {
621 QMenu *menu = new QMenu();
622 menu->addSection(text: locale().toString(date: d->m_date));
623 Q_EMIT aboutToShowContextMenu(menu, date: clickedDate);
624 menu->popup(pos: e->globalPosition().toPoint());
625 }
626}
627
628void KDateTable::KDateTablePrivate::setDate(const QDate &date)
629{
630 m_date = date;
631 m_weekDayFirstOfMonth = QDate(date.year(), date.month(), 1).dayOfWeek();
632 m_numDaysThisMonth = m_date.daysInMonth();
633 m_numDayColumns = 7;
634}
635
636bool KDateTable::setDate(const QDate &toDate)
637{
638 if (!toDate.isValid()) {
639 return false;
640 }
641
642 if (toDate == date()) {
643 return true;
644 }
645
646 if (!d->isInDateRange(date: toDate)) {
647 return false;
648 }
649
650 d->setDate(toDate);
651 Q_EMIT dateChanged(date: date());
652 update();
653
654 return true;
655}
656
657const QDate &KDateTable::date() const
658{
659 return d->m_date;
660}
661
662void KDateTable::focusInEvent(QFocusEvent *e)
663{
664 QWidget::focusInEvent(event: e);
665}
666
667void KDateTable::focusOutEvent(QFocusEvent *e)
668{
669 QWidget::focusOutEvent(event: e);
670}
671
672QSize KDateTable::sizeHint() const
673{
674 if (d->m_maxCell.height() > 0 && d->m_maxCell.width() > 0) {
675 return QSize(qRound(d: d->m_maxCell.width() * d->m_numDayColumns), (qRound(d: d->m_maxCell.height() + 2) * d->m_numWeekRows));
676 } else {
677 // qCDebug(KWidgetsAddonsLog) << "KDateTable::sizeHint: obscure failure - " << endl;
678 return QSize(-1, -1);
679 }
680}
681
682void KDateTable::setPopupMenuEnabled(bool enable)
683{
684 d->m_popupMenuEnabled = enable;
685}
686
687bool KDateTable::popupMenuEnabled() const
688{
689 return d->m_popupMenuEnabled;
690}
691
692void KDateTable::setCustomDatePainting(const QDate &date, const QColor &fgColor, BackgroundMode bgMode, const QColor &bgColor)
693{
694 if (!fgColor.isValid()) {
695 unsetCustomDatePainting(date);
696 return;
697 }
698
699 KDateTablePrivate::DatePaintingMode mode;
700 mode.bgMode = bgMode;
701 mode.fgColor = fgColor;
702 mode.bgColor = bgColor;
703
704 d->m_customPaintingModes.insert(key: date.toJulianDay(), value: mode);
705 d->m_useCustomColors = true;
706 update();
707}
708
709void KDateTable::unsetCustomDatePainting(const QDate &date)
710{
711 d->m_customPaintingModes.remove(key: date.toJulianDay());
712 if (d->m_customPaintingModes.isEmpty()) {
713 d->m_useCustomColors = false;
714 }
715 update();
716}
717
718void KDateTable::setDateRange(const QDate &minDate, const QDate &maxDate)
719{
720 d->setDateRange(minDate, maxDate);
721}
722
723#include "moc_kdatetable_p.cpp"
724

source code of kwidgetsaddons/src/kdatetable.cpp