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

source code of kwidgetsaddons/src/kdatetable.cpp