File indexing completed on 2024-04-28 03:59:03

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     SPDX-FileCopyrightText: 2022 g10 Code GmbH
0007     SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
0008 
0009     SPDX-License-Identifier: LGPL-2.0-or-later
0010 */
0011 
0012 #include "kdatepicker.h"
0013 #include "kdatepicker_p.h"
0014 
0015 #include "common_helpers_p.h"
0016 #include "kdatetable_p.h"
0017 #include <kpopupframe.h>
0018 
0019 #include <QApplication>
0020 #include <QComboBox>
0021 #include <QFont>
0022 #include <QFontDatabase>
0023 #include <QKeyEvent>
0024 #include <QLayout>
0025 #include <QMenu>
0026 #include <QStyle>
0027 #include <QToolButton>
0028 
0029 #include "loggingcategory.h"
0030 #include "moc_kdatepicker.cpp"
0031 #include "moc_kdatepicker_p.cpp"
0032 
0033 class DatePickerValidator : public QValidator
0034 {
0035     Q_OBJECT
0036 public:
0037     explicit DatePickerValidator(KDatePicker *parent)
0038         : QValidator(parent)
0039         , picker(parent)
0040     {
0041     }
0042 
0043     State validate(QString &text, int &) const override
0044     {
0045         return toDate(text).isValid() ? QValidator::Acceptable : QValidator::Intermediate;
0046     }
0047 
0048     QDate toDate(const QString &text) const
0049     {
0050         QLocale locale = picker->locale();
0051         const QList<QString> formats{
0052             locale.dateFormat(QLocale::LongFormat),
0053             locale.dateFormat(QLocale::ShortFormat),
0054             locale.dateFormat(QLocale::NarrowFormat),
0055             dateFormatWith4DigitYear(locale, QLocale::ShortFormat),
0056             QStringLiteral("yyyy-MM-dd"),
0057         };
0058 
0059         QDate date;
0060         for (const auto &format : formats) {
0061             date = locale.toDate(text, format);
0062             if (date.isValid()) {
0063                 break;
0064             }
0065         }
0066         if (!date.isValid()) {
0067             qCDebug(KWidgetsAddonsLog) << "Could not parse text as date:" << text;
0068         }
0069         return date;
0070     }
0071 
0072 private:
0073     KDatePicker *const picker;
0074 };
0075 
0076 // Week numbers are defined by ISO 8601
0077 // See http://www.merlyn.demon.co.uk/weekinfo.htm for details
0078 
0079 KDatePickerPrivateYearSelector::KDatePickerPrivateYearSelector(const QDate &currentDate, QWidget *parent)
0080     : QLineEdit(parent)
0081     , val(new QIntValidator(this))
0082     , result(0)
0083     , oldDate{currentDate}
0084 {
0085     setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont));
0086 
0087     setFrame(false);
0088 
0089     // TODO: Find a way to get that from QLocale
0090     // val->setRange( calendar->year( calendar->earliestValidDate() ),
0091     //               calendar->year( calendar->latestValidDate() ) );
0092     setValidator(val);
0093 
0094     connect(this, &QLineEdit::returnPressed, this, &KDatePickerPrivateYearSelector::yearEnteredSlot);
0095 }
0096 
0097 void KDatePickerPrivateYearSelector::yearEnteredSlot()
0098 {
0099     bool ok;
0100     int newYear;
0101 
0102     // check if entered value is a number
0103     newYear = text().toInt(&ok);
0104     if (!ok) {
0105         QApplication::beep();
0106         return;
0107     }
0108 
0109     // check if new year will lead to a valid date
0110     if (QDate(newYear, oldDate.month(), oldDate.day()).isValid()) {
0111         result = newYear;
0112         Q_EMIT closeMe(1);
0113     } else {
0114         QApplication::beep();
0115     }
0116 }
0117 
0118 int KDatePickerPrivateYearSelector::year()
0119 {
0120     return result;
0121 }
0122 
0123 void KDatePickerPrivateYearSelector::setYear(const QDate &year)
0124 {
0125     setText(locale().toString(year, QStringLiteral("yyyy")).rightJustified(4, QLatin1Char('0')));
0126 }
0127 
0128 class KDatePickerPrivate
0129 {
0130     Q_DECLARE_TR_FUNCTIONS(KDatePicker)
0131 
0132 public:
0133     explicit KDatePickerPrivate(KDatePicker *qq)
0134         : q(qq)
0135     {
0136     }
0137 
0138     void fillWeeksCombo();
0139     QDate validDateInYearMonth(int year, int month);
0140 
0141     /// the date table
0142     KDatePicker *q;
0143 
0144     QToolButton *closeButton = nullptr;
0145     QComboBox *selectWeek = nullptr;
0146     QToolButton *todayButton = nullptr;
0147     QBoxLayout *navigationLayout = nullptr;
0148 
0149     /// the year forward button
0150     QToolButton *yearForward = nullptr;
0151     /// the year backward button
0152     QToolButton *yearBackward = nullptr;
0153     /// the month forward button
0154     QToolButton *monthForward = nullptr;
0155     /// the month backward button
0156     QToolButton *monthBackward = nullptr;
0157     /// the button for selecting the month directly
0158     QToolButton *selectMonth = nullptr;
0159     /// the button for selecting the year directly
0160     QToolButton *selectYear = nullptr;
0161     /// the line edit to enter the date directly
0162     QLineEdit *line = nullptr;
0163     /// the validator for the line edit:
0164     DatePickerValidator *val = nullptr;
0165     /// the date table
0166     KDateTable *table = nullptr;
0167     /// the widest month string in pixels:
0168     QSize maxMonthRect;
0169 
0170     /// the font size for the widget
0171     int fontsize = -1;
0172 };
0173 
0174 void KDatePickerPrivate::fillWeeksCombo()
0175 {
0176     // every year can have a different number of weeks
0177     // it could be that we had 53,1..52 and now 1..53 which is the same number but different
0178     // so always fill with new values
0179     // We show all week numbers for all weeks between first day of year to last day of year
0180     // This of course can be a list like 53,1,2..52
0181 
0182     const QDate thisDate = q->date();
0183     const int thisYear = thisDate.year();
0184     QDate day(thisDate.year(), 1, 1);
0185     const QDate lastDayOfYear = QDate(thisDate.year() + 1, 1, 1).addDays(-1);
0186 
0187     selectWeek->clear();
0188 
0189     // Starting from the first day in the year, loop through the year a week at a time
0190     // adding an entry to the week combo for each week in the year
0191 
0192     for (; day.isValid() && day <= lastDayOfYear; day = day.addDays(7)) {
0193         // Get the ISO week number for the current day and what year that week is in
0194         // e.g. 1st day of this year may fall in week 53 of previous year
0195         int weekYear = thisYear;
0196         const int week = day.weekNumber(&weekYear);
0197         QString weekString = tr("Week %1").arg(q->locale().toString(week));
0198 
0199         // show that this is a week from a different year
0200         if (weekYear != thisYear) {
0201             weekString += QLatin1Char('*');
0202         }
0203 
0204         // when the week is selected, go to the same weekday as the one
0205         // that is currently selected in the date table
0206         QDate targetDate = day.addDays(thisDate.dayOfWeek() - day.dayOfWeek());
0207         selectWeek->addItem(weekString, targetDate);
0208 
0209         // make sure that the week of the lastDayOfYear is always inserted: in Chinese calendar
0210         // system, this is not always the case
0211         if (day < lastDayOfYear //
0212             && day.daysTo(lastDayOfYear) < 7 //
0213             && lastDayOfYear.weekNumber() != day.weekNumber()) {
0214             day = lastDayOfYear.addDays(-7);
0215         }
0216     }
0217 }
0218 
0219 QDate KDatePickerPrivate::validDateInYearMonth(int year, int month)
0220 {
0221     QDate newDate;
0222 
0223     // Try to create a valid date in this year and month
0224     // First try the first of the month, then try last of month
0225     if (QDate(year, month, 1).isValid()) {
0226         newDate = QDate(year, month, 1);
0227     } else if (QDate(year, month + 1, 1).isValid()) {
0228         newDate = QDate(year, month + 1, 1).addDays(-1);
0229     } else {
0230         newDate = QDate::fromJulianDay(0);
0231     }
0232 
0233     return newDate;
0234 }
0235 
0236 KDatePicker::KDatePicker(QWidget *parent)
0237     : QFrame(parent)
0238     , d(new KDatePickerPrivate(this))
0239 {
0240     initWidget(QDate::currentDate());
0241 }
0242 
0243 KDatePicker::KDatePicker(const QDate &date_, QWidget *parent)
0244     : QFrame(parent)
0245     , d(new KDatePickerPrivate(this))
0246 {
0247     initWidget(date_);
0248 }
0249 
0250 void KDatePicker::initWidget(const QDate &date_)
0251 {
0252     const int horizontalSpacing = style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
0253 
0254     QBoxLayout *topLayout = new QVBoxLayout(this);
0255     topLayout->setSpacing(0);
0256     topLayout->setContentsMargins(0, 0, 0, 0);
0257 
0258     d->navigationLayout = new QHBoxLayout();
0259     d->navigationLayout->setSpacing(0);
0260     d->navigationLayout->setContentsMargins(0, 0, 0, 0);
0261     topLayout->addLayout(d->navigationLayout);
0262     d->navigationLayout->addStretch();
0263     d->yearBackward = new QToolButton(this);
0264     d->yearBackward->setAutoRaise(true);
0265     d->navigationLayout->addWidget(d->yearBackward);
0266     d->monthBackward = new QToolButton(this);
0267     d->monthBackward->setAutoRaise(true);
0268     d->navigationLayout->addWidget(d->monthBackward);
0269     d->navigationLayout->addSpacing(horizontalSpacing);
0270 
0271     d->selectMonth = new QToolButton(this);
0272     d->selectMonth->setAutoRaise(true);
0273     d->navigationLayout->addWidget(d->selectMonth);
0274     d->selectYear = new QToolButton(this);
0275     d->selectYear->setCheckable(true);
0276     d->selectYear->setAutoRaise(true);
0277     d->navigationLayout->addWidget(d->selectYear);
0278     d->navigationLayout->addSpacing(horizontalSpacing);
0279 
0280     d->monthForward = new QToolButton(this);
0281     d->monthForward->setAutoRaise(true);
0282     d->navigationLayout->addWidget(d->monthForward);
0283     d->yearForward = new QToolButton(this);
0284     d->yearForward->setAutoRaise(true);
0285     d->navigationLayout->addWidget(d->yearForward);
0286     d->navigationLayout->addStretch();
0287 
0288     d->line = new QLineEdit(this);
0289     d->val = new DatePickerValidator(this);
0290     d->table = new KDateTable(this);
0291     setFocusProxy(d->table);
0292 
0293     d->fontsize = QFontDatabase::systemFont(QFontDatabase::GeneralFont).pointSize();
0294     if (d->fontsize == -1) {
0295         d->fontsize = QFontInfo(QFontDatabase::systemFont(QFontDatabase::GeneralFont)).pointSize();
0296     }
0297 
0298     d->fontsize++; // Make a little bigger
0299 
0300     d->selectWeek = new QComboBox(this); // read only week selection
0301     d->selectWeek->setFocusPolicy(Qt::NoFocus);
0302     d->todayButton = new QToolButton(this);
0303     d->todayButton->setIcon(QIcon::fromTheme(QStringLiteral("go-jump-today")));
0304 
0305     d->yearForward->setToolTip(tr("Next year", "@info:tooltip"));
0306     d->yearBackward->setToolTip(tr("Previous year", "@info:tooltip"));
0307     d->monthForward->setToolTip(tr("Next month", "@info:tooltip"));
0308     d->monthBackward->setToolTip(tr("Previous month", "@info:tooltip"));
0309     d->selectWeek->setToolTip(tr("Select a week", "@info:tooltip"));
0310     d->selectMonth->setToolTip(tr("Select a month", "@info:tooltip"));
0311     d->selectYear->setToolTip(tr("Select a year", "@info:tooltip"));
0312     d->todayButton->setToolTip(tr("Select the current day", "@info:tooltip"));
0313 
0314     // -----
0315     setFontSize(d->fontsize);
0316     d->line->setValidator(d->val);
0317     d->line->installEventFilter(this);
0318     if (QApplication::isRightToLeft()) {
0319         d->yearForward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left-double")));
0320         d->yearBackward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right-double")));
0321         d->monthForward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left")));
0322         d->monthBackward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right")));
0323     } else {
0324         d->yearForward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right-double")));
0325         d->yearBackward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left-double")));
0326         d->monthForward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right")));
0327         d->monthBackward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left")));
0328     }
0329 
0330     connect(d->table, &KDateTable::dateChanged, this, &KDatePicker::dateChangedSlot);
0331     connect(d->table, &KDateTable::tableClicked, this, &KDatePicker::tableClickedSlot);
0332     connect(d->monthForward, &QAbstractButton::clicked, this, &KDatePicker::monthForwardClicked);
0333     connect(d->monthBackward, &QAbstractButton::clicked, this, &KDatePicker::monthBackwardClicked);
0334     connect(d->yearForward, &QAbstractButton::clicked, this, &KDatePicker::yearForwardClicked);
0335     connect(d->yearBackward, &QAbstractButton::clicked, this, &KDatePicker::yearBackwardClicked);
0336     connect(d->selectWeek, &QComboBox::activated, this, &KDatePicker::weekSelected);
0337     connect(d->todayButton, &QAbstractButton::clicked, this, &KDatePicker::todayButtonClicked);
0338     connect(d->selectMonth, &QAbstractButton::clicked, this, &KDatePicker::selectMonthClicked);
0339     connect(d->selectYear, &QAbstractButton::toggled, this, &KDatePicker::selectYearClicked);
0340     connect(d->line, &QLineEdit::returnPressed, this, &KDatePicker::lineEnterPressed);
0341 
0342     topLayout->addWidget(d->table);
0343 
0344     QBoxLayout *bottomLayout = new QHBoxLayout();
0345     bottomLayout->setContentsMargins(0, 0, 0, 0);
0346     bottomLayout->setSpacing(0);
0347     topLayout->addLayout(bottomLayout);
0348 
0349     bottomLayout->addWidget(d->todayButton);
0350     bottomLayout->addWidget(d->line);
0351     bottomLayout->addWidget(d->selectWeek);
0352 
0353     d->table->setDate(date_);
0354     dateChangedSlot(date_); // needed because table emits changed only when newDate != oldDate
0355 }
0356 
0357 KDatePicker::~KDatePicker() = default;
0358 
0359 bool KDatePicker::eventFilter(QObject *o, QEvent *e)
0360 {
0361     if (e->type() == QEvent::KeyPress) {
0362         QKeyEvent *k = (QKeyEvent *)e;
0363 
0364         if ((k->key() == Qt::Key_PageUp) //
0365             || (k->key() == Qt::Key_PageDown) //
0366             || (k->key() == Qt::Key_Up) //
0367             || (k->key() == Qt::Key_Down)) {
0368             QApplication::sendEvent(d->table, e);
0369             d->table->setFocus();
0370             return true; // eat event
0371         }
0372     }
0373     return QFrame::eventFilter(o, e);
0374 }
0375 
0376 void KDatePicker::resizeEvent(QResizeEvent *e)
0377 {
0378     QWidget::resizeEvent(e);
0379 }
0380 
0381 void KDatePicker::dateChangedSlot(const QDate &date_)
0382 {
0383     d->line->setText(locale().toString(date_, dateFormatWith4DigitYear(locale(), QLocale::ShortFormat)));
0384     d->selectMonth->setText(locale().standaloneMonthName(date_.month(), QLocale::LongFormat));
0385     d->fillWeeksCombo();
0386 
0387     // calculate the item num in the week combo box; normalize selected day so as if 1.1. is the first day of the week
0388     QDate firstDay(date_.year(), 1, 1);
0389     // If we cannot successfully create the 1st of the year, this can only mean that
0390     // the 1st is before the earliest valid date in the current calendar system, so use
0391     // the earliestValidDate as the first day.
0392     // In particular covers the case of Gregorian where 1/1/-4713 is not a valid QDate
0393     d->selectWeek->setCurrentIndex((date_.dayOfYear() + firstDay.dayOfWeek() - 2) / 7);
0394     d->selectYear->setText(locale().toString(date_, QStringLiteral("yyyy")).rightJustified(4, QLatin1Char('0')));
0395 
0396     Q_EMIT dateChanged(date_);
0397 }
0398 
0399 void KDatePicker::tableClickedSlot()
0400 {
0401     Q_EMIT dateSelected(date());
0402     Q_EMIT tableClicked();
0403 }
0404 
0405 // TODO KF6: remove the const & from the returned QDate
0406 const QDate &KDatePicker::date() const
0407 {
0408     return d->table->date();
0409 }
0410 
0411 bool KDatePicker::setDate(const QDate &date_)
0412 {
0413     // the table setDate does validity checking for us
0414     // this also emits dateChanged() which then calls our dateChangedSlot()
0415     return d->table->setDate(date_);
0416 }
0417 
0418 void KDatePicker::monthForwardClicked()
0419 {
0420     if (!setDate(date().addMonths(1))) {
0421         QApplication::beep();
0422     }
0423     d->table->setFocus();
0424 }
0425 
0426 void KDatePicker::monthBackwardClicked()
0427 {
0428     if (!setDate(date().addMonths(-1))) {
0429         QApplication::beep();
0430     }
0431     d->table->setFocus();
0432 }
0433 
0434 void KDatePicker::yearForwardClicked()
0435 {
0436     if (!setDate(d->table->date().addYears(1))) {
0437         QApplication::beep();
0438     }
0439     d->table->setFocus();
0440 }
0441 
0442 void KDatePicker::yearBackwardClicked()
0443 {
0444     if (!setDate(d->table->date().addYears(-1))) {
0445         QApplication::beep();
0446     }
0447     d->table->setFocus();
0448 }
0449 
0450 void KDatePicker::weekSelected(int index)
0451 {
0452     QDate targetDay = d->selectWeek->itemData(index).toDateTime().date();
0453 
0454     if (!setDate(targetDay)) {
0455         QApplication::beep();
0456     }
0457     d->table->setFocus();
0458 }
0459 
0460 void KDatePicker::selectMonthClicked()
0461 {
0462     QDate thisDate(date());
0463     d->table->setFocus();
0464 
0465     QMenu popup(d->selectMonth);
0466     // Populate the pick list with all the month names, this may change by year
0467     // JPL do we need to do something here for months that fall outside valid range?
0468     const int monthsInYear = QDate(thisDate.year() + 1, 1, 1).addDays(-1).month();
0469     for (int m = 1; m <= monthsInYear; m++) {
0470         popup.addAction(locale().standaloneMonthName(m))->setData(m);
0471     }
0472 
0473     QAction *item = popup.actions()[thisDate.month() - 1];
0474     // if this happens the above should already given an assertion
0475     if (item) {
0476         popup.setActiveAction(item);
0477     }
0478 
0479     // cancelled
0480     if ((item = popup.exec(d->selectMonth->mapToGlobal(QPoint(0, 0)), item)) == nullptr) {
0481         return;
0482     }
0483 
0484     // We need to create a valid date in the month selected so we can find out how many days are
0485     // in the month.
0486     QDate newDate(thisDate.year(), item->data().toInt(), 1);
0487 
0488     // If we have succeeded in creating a date in the new month, then try to create the new date,
0489     // checking we don't set a day after the last day of the month
0490     newDate.setDate(newDate.year(), newDate.month(), qMin(thisDate.day(), newDate.daysInMonth()));
0491 
0492     // Set the date, if it's invalid in any way then alert user and don't update
0493     if (!setDate(newDate)) {
0494         QApplication::beep();
0495     }
0496 }
0497 
0498 void KDatePicker::selectYearClicked()
0499 {
0500     if (!d->selectYear->isChecked()) {
0501         return;
0502     }
0503 
0504     QDate thisDate(date());
0505 
0506     KPopupFrame *popup = new KPopupFrame(this);
0507     KDatePickerPrivateYearSelector *picker = new KDatePickerPrivateYearSelector(date(), popup);
0508     picker->resize(picker->sizeHint());
0509     picker->setYear(thisDate);
0510     picker->selectAll();
0511     popup->setMainWidget(picker);
0512     connect(picker, &KDatePickerPrivateYearSelector::closeMe, popup, &KPopupFrame::close);
0513     picker->setFocus();
0514 
0515     if (popup->exec(d->selectYear->mapToGlobal(QPoint(0, d->selectMonth->height())))) {
0516         // We need to create a valid date in the year/month selected so we can find out how many
0517         // days are in the month.
0518         QDate newDate(picker->year(), thisDate.month(), 1);
0519 
0520         // If we have succeeded in creating a date in the new month, then try to create the new
0521         // date, checking we don't set a day after the last day of the month
0522         newDate = QDate(newDate.year(), newDate.month(), qMin(thisDate.day(), newDate.daysInMonth()));
0523 
0524         // Set the date, if it's invalid in any way then alert user and don't update
0525         if (!setDate(newDate)) {
0526             QApplication::beep();
0527         }
0528     }
0529     delete popup;
0530 
0531     d->selectYear->setChecked(false);
0532 }
0533 
0534 void KDatePicker::uncheckYearSelector()
0535 {
0536     d->selectYear->setChecked(false);
0537     d->selectYear->update();
0538 }
0539 
0540 void KDatePicker::changeEvent(QEvent *event)
0541 {
0542     if (event && event->type() == QEvent::EnabledChange) {
0543         if (isEnabled()) {
0544             d->table->setFocus();
0545         }
0546     }
0547 }
0548 
0549 KDateTable *KDatePicker::dateTable() const
0550 {
0551     return d->table;
0552 }
0553 
0554 void KDatePicker::lineEnterPressed()
0555 {
0556     const QDate newDate = d->val->toDate(d->line->text());
0557 
0558     if (newDate.isValid()) {
0559         Q_EMIT dateEntered(newDate);
0560         setDate(newDate);
0561         d->table->setFocus();
0562     } else {
0563         QApplication::beep();
0564     }
0565 }
0566 
0567 void KDatePicker::todayButtonClicked()
0568 {
0569     setDate(QDate::currentDate());
0570     d->table->setFocus();
0571 }
0572 
0573 QSize KDatePicker::sizeHint() const
0574 {
0575     return QWidget::sizeHint();
0576 }
0577 
0578 void KDatePicker::setFontSize(int s)
0579 {
0580     QWidget *const buttons[] = {
0581         d->selectMonth,
0582         d->selectYear,
0583     };
0584     QFont font;
0585     QRect r;
0586     // -----
0587     d->fontsize = s;
0588     for (QWidget *button : buttons) {
0589         font = button->font();
0590         font.setPointSize(s);
0591         button->setFont(font);
0592     }
0593     d->table->setFontSize(s);
0594 
0595     QFontMetrics metrics(d->selectMonth->fontMetrics());
0596     QString longestMonth;
0597 
0598     for (int i = 1;; ++i) {
0599         QString str = locale().standaloneMonthName(i, QLocale::LongFormat);
0600         if (str.isNull()) {
0601             break;
0602         }
0603         r = metrics.boundingRect(str);
0604 
0605         if (r.width() > d->maxMonthRect.width()) {
0606             d->maxMonthRect.setWidth(r.width());
0607             longestMonth = str;
0608         }
0609         if (r.height() > d->maxMonthRect.height()) {
0610             d->maxMonthRect.setHeight(r.height());
0611         }
0612     }
0613 
0614     QStyleOptionToolButton opt;
0615     opt.initFrom(d->selectMonth);
0616     opt.text = longestMonth;
0617 
0618     // stolen from QToolButton
0619     QSize textSize = metrics.size(Qt::TextShowMnemonic, longestMonth);
0620     textSize.setWidth(textSize.width() + metrics.horizontalAdvance(QLatin1Char(' ')) * 2);
0621     int w = textSize.width();
0622     int h = textSize.height();
0623     opt.rect.setHeight(h); // PM_MenuButtonIndicator depends on the height
0624 
0625     QSize metricBound = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), d->selectMonth);
0626 
0627     d->selectMonth->setMinimumSize(metricBound);
0628 }
0629 
0630 int KDatePicker::fontSize() const
0631 {
0632     return d->fontsize;
0633 }
0634 
0635 void KDatePicker::setCloseButton(bool enable)
0636 {
0637     if (enable == (d->closeButton != nullptr)) {
0638         return;
0639     }
0640 
0641     if (enable) {
0642         d->closeButton = new QToolButton(this);
0643         d->closeButton->setAutoRaise(true);
0644         const int horizontalSpacing = style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
0645         d->navigationLayout->addSpacing(horizontalSpacing);
0646         d->navigationLayout->addWidget(d->closeButton);
0647         d->closeButton->setToolTip(tr("Close", "@action:button"));
0648         d->closeButton->setIcon(QIcon::fromTheme(QStringLiteral("window-close")));
0649         connect(d->closeButton, &QAbstractButton::clicked, topLevelWidget(), &QWidget::close);
0650     } else {
0651         delete d->closeButton;
0652         d->closeButton = nullptr;
0653     }
0654 
0655     updateGeometry();
0656 }
0657 
0658 bool KDatePicker::hasCloseButton() const
0659 {
0660     return (d->closeButton);
0661 }
0662 
0663 #include "kdatepicker.moc"