File indexing completed on 2024-04-28 15:32:01

0001 /*  -*- C++ -*-
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 1997 Tim D. Gilman <tdgilman@best.org>
0004     SPDX-FileCopyrightText: 1998-2001 Mirko Boehm <mirko@kde.org>
0005     SPDX-FileCopyrightText: 2007 John Layt <john@layt.net>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "kdatetable_p.h"
0011 
0012 #include <QAction>
0013 #include <QActionEvent>
0014 #include <QApplication>
0015 #include <QDate>
0016 #include <QFontDatabase>
0017 #include <QMenu>
0018 #include <QPainter>
0019 #include <QStyle>
0020 #include <QStyleOptionViewItem>
0021 
0022 #include <cmath>
0023 
0024 class KDateTable::KDateTablePrivate
0025 {
0026 public:
0027     KDateTablePrivate(KDateTable *qq)
0028         : q(qq)
0029     {
0030         m_popupMenuEnabled = false;
0031         m_useCustomColors = false;
0032         m_hoveredPos = -1;
0033         setDate(QDate::currentDate());
0034     }
0035 
0036     ~KDateTablePrivate()
0037     {
0038     }
0039 
0040     void setDate(const QDate &date);
0041     void nextMonth();
0042     void previousMonth();
0043     void beginningOfMonth();
0044     void endOfMonth();
0045     void beginningOfWeek();
0046     void endOfWeek();
0047 
0048     KDateTable *q;
0049 
0050     /**
0051      * The currently selected date.
0052      */
0053     QDate m_date;
0054 
0055     /**
0056      * The weekday number of the first day in the month [1..daysInWeek()].
0057      */
0058     int m_weekDayFirstOfMonth;
0059 
0060     /**
0061      * The number of days in the current month.
0062      */
0063     int m_numDaysThisMonth;
0064 
0065     /**
0066      * Save the size of the largest used cell content.
0067      */
0068     QRectF m_maxCell;
0069 
0070     /**
0071      * How many week rows we are to draw.
0072      */
0073     int m_numWeekRows;
0074 
0075     /**
0076      * How many day columns we are to draw, i.e. days in a week.
0077      */
0078     int m_numDayColumns;
0079 
0080     /**
0081      * The font size of the displayed text.
0082      */
0083     int fontsize;
0084 
0085     bool m_popupMenuEnabled;
0086     bool m_useCustomColors;
0087 
0088     struct DatePaintingMode {
0089         QColor fgColor;
0090         QColor bgColor;
0091         BackgroundMode bgMode;
0092     };
0093     QHash<int, DatePaintingMode> m_customPaintingModes;
0094 
0095     int m_hoveredPos;
0096 };
0097 
0098 KDateTable::KDateTable(const QDate &date, QWidget *parent)
0099     : QWidget(parent)
0100     , d(new KDateTablePrivate(this))
0101 {
0102     initWidget(date);
0103 }
0104 
0105 KDateTable::KDateTable(QWidget *parent)
0106     : QWidget(parent)
0107     , d(new KDateTablePrivate(this))
0108 {
0109     initWidget(QDate::currentDate());
0110 }
0111 
0112 KDateTable::~KDateTable()
0113 {
0114     delete d;
0115 }
0116 
0117 void KDateTable::initWidget(const QDate &date)
0118 {
0119     d->m_numWeekRows = 7;
0120 
0121     setFontSize(10);
0122     setFocusPolicy(Qt::StrongFocus);
0123     setBackgroundRole(QPalette::Base);
0124     setAutoFillBackground(true);
0125     initAccels();
0126     setAttribute(Qt::WA_Hover, true);
0127 
0128     setDate(date);
0129 }
0130 
0131 void KDateTable::initAccels()
0132 {
0133     QAction *next = new QAction(this);
0134     next->setObjectName(QStringLiteral("next"));
0135     next->setShortcuts(QKeySequence::keyBindings(QKeySequence::Forward));
0136     next->setShortcutContext(Qt::WidgetWithChildrenShortcut);
0137     connect(next, &QAction::triggered, this, [this]() {
0138         d->nextMonth();
0139     });
0140 
0141     QAction *prior = new QAction(this);
0142     prior->setObjectName(QStringLiteral("prior"));
0143     prior->setShortcuts(QKeySequence::keyBindings(QKeySequence::Back));
0144     prior->setShortcutContext(Qt::WidgetWithChildrenShortcut);
0145     connect(prior, &QAction::triggered, this, [this]() {
0146         d->previousMonth();
0147     });
0148 
0149     QAction *beginMonth = new QAction(this);
0150     beginMonth->setObjectName(QStringLiteral("beginMonth"));
0151     beginMonth->setShortcuts(QKeySequence::keyBindings(QKeySequence::MoveToStartOfDocument));
0152     beginMonth->setShortcutContext(Qt::WidgetWithChildrenShortcut);
0153     connect(beginMonth, &QAction::triggered, this, [this]() {
0154         d->beginningOfMonth();
0155     });
0156 
0157     QAction *endMonth = new QAction(this);
0158     endMonth->setObjectName(QStringLiteral("endMonth"));
0159     endMonth->setShortcuts(QKeySequence::keyBindings(QKeySequence::MoveToEndOfDocument));
0160     endMonth->setShortcutContext(Qt::WidgetWithChildrenShortcut);
0161     connect(endMonth, &QAction::triggered, this, [this]() {
0162         d->endOfMonth();
0163     });
0164 
0165     QAction *beginWeek = new QAction(this);
0166     beginWeek->setObjectName(QStringLiteral("beginWeek"));
0167     beginWeek->setShortcuts(QKeySequence::keyBindings(QKeySequence::MoveToStartOfLine));
0168     beginWeek->setShortcutContext(Qt::WidgetWithChildrenShortcut);
0169     connect(beginWeek, &QAction::triggered, this, [this]() {
0170         d->beginningOfWeek();
0171     });
0172 
0173     QAction *endWeek = new QAction(this);
0174     endWeek->setObjectName(QStringLiteral("endWeek"));
0175     endWeek->setShortcuts(QKeySequence::keyBindings(QKeySequence::MoveToEndOfLine));
0176     endWeek->setShortcutContext(Qt::WidgetWithChildrenShortcut);
0177     connect(endWeek, &QAction::triggered, this, [this]() {
0178         d->endOfWeek();
0179     });
0180 }
0181 
0182 int KDateTable::posFromDate(const QDate &date)
0183 {
0184     int initialPosition = date.day();
0185     int offset = (d->m_weekDayFirstOfMonth - locale().firstDayOfWeek() + d->m_numDayColumns) % d->m_numDayColumns;
0186 
0187     // make sure at least one day of the previous month is visible.
0188     // adjust this < 1 if more days should be forced visible:
0189     if (offset < 1) {
0190         offset += d->m_numDayColumns;
0191     }
0192 
0193     return initialPosition + offset;
0194 }
0195 
0196 QDate KDateTable::dateFromPos(int position)
0197 {
0198     int offset = (d->m_weekDayFirstOfMonth - locale().firstDayOfWeek() + d->m_numDayColumns) % d->m_numDayColumns;
0199 
0200     // make sure at least one day of the previous month is visible.
0201     // adjust this < 1 if more days should be forced visible:
0202     if (offset < 1) {
0203         offset += d->m_numDayColumns;
0204     }
0205 
0206     return QDate(d->m_date.year(), d->m_date.month(), 1).addDays(position - offset);
0207 }
0208 
0209 void KDateTable::paintEvent(QPaintEvent *e)
0210 {
0211     QPainter p(this);
0212     const QRect &rectToUpdate = e->rect();
0213     double cellWidth = width() / (double)d->m_numDayColumns;
0214     double cellHeight = height() / (double)d->m_numWeekRows;
0215     int leftCol = (int)std::floor(rectToUpdate.left() / cellWidth);
0216     int topRow = (int)std::floor(rectToUpdate.top() / cellHeight);
0217     int rightCol = (int)std::ceil(rectToUpdate.right() / cellWidth);
0218     int bottomRow = (int)std::ceil(rectToUpdate.bottom() / cellHeight);
0219     bottomRow = qMin(bottomRow, d->m_numWeekRows - 1);
0220     rightCol = qMin(rightCol, d->m_numDayColumns - 1);
0221     if (layoutDirection() == Qt::RightToLeft) {
0222         p.translate((d->m_numDayColumns - leftCol - 1) * cellWidth, topRow * cellHeight);
0223     } else {
0224         p.translate(leftCol * cellWidth, topRow * cellHeight);
0225     }
0226     for (int i = leftCol; i <= rightCol; ++i) {
0227         for (int j = topRow; j <= bottomRow; ++j) {
0228             paintCell(&p, j, i);
0229             p.translate(0, cellHeight);
0230         }
0231         if (layoutDirection() == Qt::RightToLeft) {
0232             p.translate(-cellWidth, 0);
0233         } else {
0234             p.translate(cellWidth, 0);
0235         }
0236         p.translate(0, -cellHeight * (bottomRow - topRow + 1));
0237     }
0238 }
0239 
0240 void KDateTable::paintCell(QPainter *painter, int row, int col)
0241 {
0242     double w = (width() / (double)d->m_numDayColumns) - 1;
0243     double h = (height() / (double)d->m_numWeekRows) - 1;
0244     QRectF cell = QRectF(0, 0, w, h);
0245     QString cellText;
0246     QColor cellBackgroundColor;
0247     QColor cellTextColor;
0248     QFont cellFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont);
0249     bool workingDay = false;
0250     int cellWeekDay;
0251     int pos;
0252 
0253     // Calculate the position of the cell in the grid
0254     pos = d->m_numDayColumns * (row - 1) + col;
0255 
0256     // Calculate what day of the week the cell is
0257     if (col + locale().firstDayOfWeek() <= d->m_numDayColumns) {
0258         cellWeekDay = col + locale().firstDayOfWeek();
0259     } else {
0260         cellWeekDay = col + locale().firstDayOfWeek() - d->m_numDayColumns;
0261     }
0262 
0263     // FIXME This is wrong if the widget is not using the global!
0264     // See if cell day is normally a working day
0265     if (locale().weekdays().first() <= locale().weekdays().last()) {
0266         if (cellWeekDay >= locale().weekdays().first() && cellWeekDay <= locale().weekdays().last()) {
0267             workingDay = true;
0268         }
0269     } else {
0270         if (cellWeekDay >= locale().weekdays().first() //
0271             || cellWeekDay <= locale().weekdays().last()) {
0272             workingDay = true;
0273         }
0274     }
0275 
0276     if (row == 0) {
0277         // We are drawing a header cell
0278 
0279         // If not a normal working day, then use "do not work today" color
0280         if (workingDay) {
0281             cellTextColor = palette().color(QPalette::WindowText);
0282         } else {
0283             cellTextColor = Qt::darkRed;
0284         }
0285         cellBackgroundColor = palette().color(QPalette::Window);
0286 
0287         // Set the text to the short day name and bold it
0288         cellFont.setBold(true);
0289         cellText = locale().dayName(cellWeekDay, QLocale::ShortFormat);
0290 
0291     } else {
0292         // We are drawing a day cell
0293 
0294         // Calculate the date the cell represents
0295         QDate cellDate = dateFromPos(pos);
0296 
0297         bool validDay = cellDate.isValid();
0298 
0299         // Draw the day number in the cell, if the date is not valid then we don't want to show it
0300         if (validDay) {
0301             cellText = locale().toString(cellDate.day());
0302         } else {
0303             cellText = QString();
0304         }
0305 
0306         if (!validDay || cellDate.month() != d->m_date.month()) {
0307             // we are either
0308             // ° painting an invalid day
0309             // ° painting a day of the previous month or
0310             // ° painting a day of the following month or
0311             cellBackgroundColor = palette().color(backgroundRole());
0312             cellTextColor = palette().color(QPalette::Disabled, QPalette::Text);
0313         } else {
0314             // Paint a day of the current month
0315 
0316             // Background Colour priorities will be (high-to-low):
0317             // * Selected Day Background Colour
0318             // * Customized Day Background Colour
0319             // * Normal Day Background Colour
0320 
0321             // Background Shape priorities will be (high-to-low):
0322             // * Customized Day Shape
0323             // * Normal Day Shape
0324 
0325             // Text Colour priorities will be (high-to-low):
0326             // * Customized Day Colour
0327             // * Day of Pray Colour (Red letter)
0328             // * Selected Day Colour
0329             // * Normal Day Colour
0330 
0331             // Determine various characteristics of the cell date
0332             bool selectedDay = (cellDate == date());
0333             bool currentDay = (cellDate == QDate::currentDate());
0334             bool dayOfPray = (cellDate.dayOfWeek() == Qt::Sunday);
0335             // TODO: Uncomment if QLocale ever gets the feature...
0336             // bool dayOfPray = ( cellDate.dayOfWeek() == locale().dayOfPray() );
0337             bool customDay = (d->m_useCustomColors && d->m_customPaintingModes.contains(cellDate.toJulianDay()));
0338 
0339             // Default values for a normal cell
0340             cellBackgroundColor = palette().color(backgroundRole());
0341             cellTextColor = palette().color(foregroundRole());
0342 
0343             // If we are drawing the current date, then draw it bold and active
0344             if (currentDay) {
0345                 cellFont.setBold(true);
0346                 cellTextColor = palette().color(QPalette::LinkVisited);
0347             }
0348 
0349             // if we are drawing the day cell currently selected in the table
0350             if (selectedDay) {
0351                 // set the background to highlighted
0352                 cellBackgroundColor = palette().color(QPalette::Highlight);
0353                 cellTextColor = palette().color(QPalette::HighlightedText);
0354             }
0355 
0356             // If custom colors or shape are required for this date
0357             if (customDay) {
0358                 KDateTablePrivate::DatePaintingMode mode = d->m_customPaintingModes[cellDate.toJulianDay()];
0359                 if (mode.bgMode != NoBgMode) {
0360                     if (!selectedDay) {
0361                         cellBackgroundColor = mode.bgColor;
0362                     }
0363                 }
0364                 cellTextColor = mode.fgColor;
0365             }
0366 
0367             // If the cell day is the day of religious observance, then always color text red unless Custom overrides
0368             if (!customDay && dayOfPray) {
0369                 cellTextColor = Qt::darkRed;
0370             }
0371         }
0372     }
0373 
0374     // Draw the background
0375     if (row == 0) {
0376         painter->setPen(cellBackgroundColor);
0377         painter->setBrush(cellBackgroundColor);
0378         painter->drawRect(cell);
0379     } else if (cellBackgroundColor != palette().color(backgroundRole()) || pos == d->m_hoveredPos) {
0380         QStyleOptionViewItem opt;
0381         opt.initFrom(this);
0382         opt.rect = cell.toRect();
0383         if (cellBackgroundColor != palette().color(backgroundRole())) {
0384             opt.palette.setBrush(QPalette::Highlight, cellBackgroundColor);
0385             opt.state |= QStyle::State_Selected;
0386         }
0387         if (pos == d->m_hoveredPos && opt.state & QStyle::State_Enabled) {
0388             opt.state |= QStyle::State_MouseOver;
0389         } else {
0390             opt.state &= ~QStyle::State_MouseOver;
0391         }
0392         opt.showDecorationSelected = true;
0393         opt.viewItemPosition = QStyleOptionViewItem::OnlyOne;
0394         style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, this);
0395     }
0396 
0397     // Draw the text
0398     painter->setPen(cellTextColor);
0399     painter->setFont(cellFont);
0400     painter->drawText(cell, Qt::AlignCenter, cellText, &cell);
0401 
0402     // Draw the base line
0403     if (row == 0) {
0404         painter->setPen(palette().color(foregroundRole()));
0405         painter->drawLine(QPointF(0, h), QPointF(w, h));
0406     }
0407 
0408     // If the day cell we just drew is bigger than the current max cell sizes,
0409     // then adjust the max to the current cell
0410     if (cell.width() > d->m_maxCell.width()) {
0411         d->m_maxCell.setWidth(cell.width());
0412     }
0413     if (cell.height() > d->m_maxCell.height()) {
0414         d->m_maxCell.setHeight(cell.height());
0415     }
0416 }
0417 
0418 void KDateTable::KDateTablePrivate::nextMonth()
0419 {
0420     // setDate does validity checking for us
0421     q->setDate(m_date.addMonths(1));
0422 }
0423 
0424 void KDateTable::KDateTablePrivate::previousMonth()
0425 {
0426     // setDate does validity checking for us
0427     q->setDate(m_date.addMonths(-1));
0428 }
0429 
0430 void KDateTable::KDateTablePrivate::beginningOfMonth()
0431 {
0432     // setDate does validity checking for us
0433     q->setDate(QDate(m_date.year(), m_date.month(), 1));
0434 }
0435 
0436 void KDateTable::KDateTablePrivate::endOfMonth()
0437 {
0438     // setDate does validity checking for us
0439     q->setDate(QDate(m_date.year(), m_date.month() + 1, 0));
0440 }
0441 
0442 // JPL Do these make the assumption that first day of week is weekday 1? As it may not be.
0443 void KDateTable::KDateTablePrivate::beginningOfWeek()
0444 {
0445     // setDate does validity checking for us
0446     q->setDate(m_date.addDays(1 - m_date.dayOfWeek()));
0447 }
0448 
0449 // JPL Do these make the assumption that first day of week is weekday 1? As it may not be.
0450 void KDateTable::KDateTablePrivate::endOfWeek()
0451 {
0452     // setDate does validity checking for us
0453     q->setDate(m_date.addDays(7 - m_date.dayOfWeek()));
0454 }
0455 
0456 void KDateTable::keyPressEvent(QKeyEvent *e)
0457 {
0458     switch (e->key()) {
0459     case Qt::Key_Up:
0460         // setDate does validity checking for us
0461         setDate(d->m_date.addDays(-d->m_numDayColumns));
0462         break;
0463     case Qt::Key_Down:
0464         // setDate does validity checking for us
0465         setDate(d->m_date.addDays(d->m_numDayColumns));
0466         break;
0467     case Qt::Key_Left:
0468         // setDate does validity checking for us
0469         setDate(d->m_date.addDays(-1));
0470         break;
0471     case Qt::Key_Right:
0472         // setDate does validity checking for us
0473         setDate(d->m_date.addDays(1));
0474         break;
0475     case Qt::Key_Minus:
0476         // setDate does validity checking for us
0477         setDate(d->m_date.addDays(-1));
0478         break;
0479     case Qt::Key_Plus:
0480         // setDate does validity checking for us
0481         setDate(d->m_date.addDays(1));
0482         break;
0483     case Qt::Key_N:
0484         // setDate does validity checking for us
0485         setDate(QDate::currentDate());
0486         break;
0487     case Qt::Key_Return:
0488     case Qt::Key_Enter:
0489         Q_EMIT tableClicked();
0490         break;
0491     case Qt::Key_Control:
0492     case Qt::Key_Alt:
0493     case Qt::Key_Meta:
0494     case Qt::Key_Shift:
0495         // Don't beep for modifiers
0496         break;
0497     default:
0498         if (!e->modifiers()) { // hm
0499             QApplication::beep();
0500         }
0501     }
0502 }
0503 
0504 void KDateTable::setFontSize(int size)
0505 {
0506     QFontMetricsF metrics(fontMetrics());
0507     QRectF rect;
0508     // ----- store rectangles:
0509     d->fontsize = size;
0510     // ----- find largest day name:
0511     d->m_maxCell.setWidth(0);
0512     d->m_maxCell.setHeight(0);
0513     for (int weekday = 1; weekday <= 7; ++weekday) {
0514         rect = metrics.boundingRect(locale().dayName(weekday, QLocale::ShortFormat));
0515         d->m_maxCell.setWidth(qMax(d->m_maxCell.width(), rect.width()));
0516         d->m_maxCell.setHeight(qMax(d->m_maxCell.height(), rect.height()));
0517     }
0518     // ----- compare with a real wide number and add some space:
0519     rect = metrics.boundingRect(QStringLiteral("88"));
0520     d->m_maxCell.setWidth(qMax(d->m_maxCell.width() + 2, rect.width()));
0521     d->m_maxCell.setHeight(qMax(d->m_maxCell.height() + 4, rect.height()));
0522 }
0523 
0524 void KDateTable::wheelEvent(QWheelEvent *e)
0525 {
0526     setDate(d->m_date.addMonths(-(int)(e->angleDelta().y() / 120)));
0527     e->accept();
0528 }
0529 
0530 bool KDateTable::event(QEvent *ev)
0531 {
0532     switch (ev->type()) {
0533     case QEvent::HoverMove: {
0534         QHoverEvent *e = static_cast<QHoverEvent *>(ev);
0535         const int row = e->pos().y() * d->m_numWeekRows / height();
0536         int col;
0537         if (layoutDirection() == Qt::RightToLeft) {
0538             col = d->m_numDayColumns - (e->pos().x() * d->m_numDayColumns / width()) - 1;
0539         } else {
0540             col = e->pos().x() * d->m_numDayColumns / width();
0541         }
0542 
0543         const int pos = row < 1 ? -1 : (d->m_numDayColumns * (row - 1)) + col;
0544 
0545         if (pos != d->m_hoveredPos) {
0546             d->m_hoveredPos = pos;
0547             update();
0548         }
0549         break;
0550     }
0551     case QEvent::HoverLeave:
0552         if (d->m_hoveredPos != -1) {
0553             d->m_hoveredPos = -1;
0554             update();
0555         }
0556         break;
0557     default:
0558         break;
0559     }
0560     return QWidget::event(ev);
0561 }
0562 
0563 void KDateTable::mousePressEvent(QMouseEvent *e)
0564 {
0565     if (e->type() != QEvent::MouseButtonPress) { // the KDatePicker only reacts on mouse press events:
0566         return;
0567     }
0568 
0569     if (!isEnabled()) {
0570         QApplication::beep();
0571         return;
0572     }
0573 
0574     int row;
0575     int col;
0576     int pos;
0577 
0578     QPoint mouseCoord = e->pos();
0579     row = mouseCoord.y() * d->m_numWeekRows / height();
0580     if (layoutDirection() == Qt::RightToLeft) {
0581         col = d->m_numDayColumns - (mouseCoord.x() * d->m_numDayColumns / width()) - 1;
0582     } else {
0583         col = mouseCoord.x() * d->m_numDayColumns / width();
0584     }
0585 
0586     if (row < 1 || col < 0) { // the user clicked on the frame of the table
0587         return;
0588     }
0589 
0590     // Rows and columns are zero indexed.  The (row - 1) below is to avoid counting
0591     // the row with the days of the week in the calculation.
0592 
0593     // new position and date
0594     pos = (d->m_numDayColumns * (row - 1)) + col;
0595     QDate clickedDate = dateFromPos(pos);
0596 
0597     // set the new date. If it is in the previous or next month, the month will
0598     // automatically be changed, no need to do that manually...
0599     // validity checking done inside setDate
0600     setDate(clickedDate);
0601 
0602     // This could be optimized to only call update over the regions
0603     // of old and new cell, but 99% of times there is also a call to
0604     // setDate that already calls update() so no need to optimize that
0605     // much here
0606     update();
0607 
0608     Q_EMIT tableClicked();
0609 
0610     if (e->button() == Qt::RightButton && d->m_popupMenuEnabled) {
0611         QMenu *menu = new QMenu();
0612         menu->addSection(locale().toString(d->m_date));
0613         Q_EMIT aboutToShowContextMenu(menu, clickedDate);
0614         menu->popup(e->globalPos());
0615     }
0616 }
0617 
0618 void KDateTable::KDateTablePrivate::setDate(const QDate &date)
0619 {
0620     m_date = date;
0621     m_weekDayFirstOfMonth = QDate(date.year(), date.month(), 1).dayOfWeek();
0622     m_numDaysThisMonth = m_date.daysInMonth();
0623     m_numDayColumns = 7;
0624 }
0625 
0626 bool KDateTable::setDate(const QDate &toDate)
0627 {
0628     if (!toDate.isValid()) {
0629         return false;
0630     }
0631 
0632     if (toDate == date()) {
0633         return true;
0634     }
0635 
0636     d->setDate(toDate);
0637     Q_EMIT dateChanged(date());
0638     update();
0639 
0640     return true;
0641 }
0642 
0643 const QDate &KDateTable::date() const
0644 {
0645     return d->m_date;
0646 }
0647 
0648 void KDateTable::focusInEvent(QFocusEvent *e)
0649 {
0650     QWidget::focusInEvent(e);
0651 }
0652 
0653 void KDateTable::focusOutEvent(QFocusEvent *e)
0654 {
0655     QWidget::focusOutEvent(e);
0656 }
0657 
0658 QSize KDateTable::sizeHint() const
0659 {
0660     if (d->m_maxCell.height() > 0 && d->m_maxCell.width() > 0) {
0661         return QSize(qRound(d->m_maxCell.width() * d->m_numDayColumns), (qRound(d->m_maxCell.height() + 2) * d->m_numWeekRows));
0662     } else {
0663         // qCDebug(KWidgetsAddonsLog) << "KDateTable::sizeHint: obscure failure - " << endl;
0664         return QSize(-1, -1);
0665     }
0666 }
0667 
0668 void KDateTable::setPopupMenuEnabled(bool enable)
0669 {
0670     d->m_popupMenuEnabled = enable;
0671 }
0672 
0673 bool KDateTable::popupMenuEnabled() const
0674 {
0675     return d->m_popupMenuEnabled;
0676 }
0677 
0678 void KDateTable::setCustomDatePainting(const QDate &date, const QColor &fgColor, BackgroundMode bgMode, const QColor &bgColor)
0679 {
0680     if (!fgColor.isValid()) {
0681         unsetCustomDatePainting(date);
0682         return;
0683     }
0684 
0685     KDateTablePrivate::DatePaintingMode mode;
0686     mode.bgMode = bgMode;
0687     mode.fgColor = fgColor;
0688     mode.bgColor = bgColor;
0689 
0690     d->m_customPaintingModes.insert(date.toJulianDay(), mode);
0691     d->m_useCustomColors = true;
0692     update();
0693 }
0694 
0695 void KDateTable::unsetCustomDatePainting(const QDate &date)
0696 {
0697     d->m_customPaintingModes.remove(date.toJulianDay());
0698     if (d->m_customPaintingModes.isEmpty()) {
0699         d->m_useCustomColors = false;
0700     }
0701     update();
0702 }
0703 
0704 #include "moc_kdatetable_p.cpp"