12#include "kdatepicker.h"
13#include "kdatepicker_p.h"
15#include "common_helpers_p.h"
16#include "kdatetable_p.h"
17#include <kpopupframe.h>
19#include <QApplication>
22#include <QFontDatabase>
29#include "loggingcategory.h"
30#include "moc_kdatepicker.cpp"
31#include "moc_kdatepicker_p.cpp"
37 explicit DatePickerValidator(KDatePicker *
parent)
43 State validate(QString &text,
int &)
const override
48 QDate toDate(
const QString &text)
const
50 QLocale
locale = picker->locale();
51 const QList<QString> formats{
56 QStringLiteral(
"yyyy-MM-dd"),
60 for (
const auto &format : formats) {
61 date =
locale.toDate(text, format);
67 qCDebug(KWidgetsAddonsLog) <<
"Could not parse text as date:" << text;
73 KDatePicker *
const picker;
79KDatePickerPrivateYearSelector::KDatePickerPrivateYearSelector(
const QDate ¤tDate,
QWidget *parent)
83 , oldDate{currentDate}
97void KDatePickerPrivateYearSelector::yearEnteredSlot()
103 newYear = text().
toInt(&ok);
110 if (
QDate(newYear, oldDate.month(), oldDate.day()).
isValid()) {
118int KDatePickerPrivateYearSelector::year()
123void KDatePickerPrivateYearSelector::setYear(
const QDate &year)
125 setText(locale().
toString(year, QStringLiteral(
"yyyy")).rightJustified(4,
QLatin1Char(
'0')));
128class KDatePickerPrivate
130 Q_DECLARE_TR_FUNCTIONS(KDatePicker)
133 explicit KDatePickerPrivate(KDatePicker *qq)
138 void fillWeeksCombo();
139 QDate validDateInYearMonth(
int year,
int month);
144 QToolButton *closeButton =
nullptr;
145 QComboBox *selectWeek =
nullptr;
146 QToolButton *todayButton =
nullptr;
147 QBoxLayout *navigationLayout =
nullptr;
150 QToolButton *yearForward =
nullptr;
152 QToolButton *yearBackward =
nullptr;
154 QToolButton *monthForward =
nullptr;
156 QToolButton *monthBackward =
nullptr;
158 QToolButton *selectMonth =
nullptr;
160 QToolButton *selectYear =
nullptr;
162 QLineEdit *line =
nullptr;
164 DatePickerValidator *val =
nullptr;
166 KDateTable *table =
nullptr;
174void KDatePickerPrivate::fillWeeksCombo()
182 const QDate thisDate = q->date();
183 const int thisYear = thisDate.
year();
184 QDate day(thisDate.
year(), 1, 1);
185 const QDate lastDayOfYear = QDate(thisDate.
year() + 1, 1, 1).addDays(-1);
192 for (; day.isValid() && day <= lastDayOfYear; day = day.addDays(7)) {
195 int weekYear = thisYear;
196 const int week = day.weekNumber(&weekYear);
197 QString weekString = tr(
"Week %1").arg(q->locale().toString(week));
200 if (weekYear != thisYear) {
201 weekString += QLatin1Char(
'*');
206 QDate targetDate = day.addDays(thisDate.
dayOfWeek() - day.dayOfWeek());
207 selectWeek->addItem(weekString, targetDate);
211 if (day < lastDayOfYear
212 && day.daysTo(lastDayOfYear) < 7
213 && lastDayOfYear.
weekNumber() != day.weekNumber()) {
214 day = lastDayOfYear.
addDays(-7);
219QDate KDatePickerPrivate::validDateInYearMonth(
int year,
int month)
225 if (QDate(year, month, 1).
isValid()) {
226 newDate = QDate(year, month, 1);
227 }
else if (QDate(year, month + 1, 1).
isValid()) {
228 newDate = QDate(year, month + 1, 1).
addDays(-1);
238 , d(new KDatePickerPrivate(this))
245 , d(new KDatePickerPrivate(this))
250void KDatePicker::initWidget(
const QDate &date_)
259 d->navigationLayout->setSpacing(0);
260 d->navigationLayout->setContentsMargins(0, 0, 0, 0);
261 topLayout->
addLayout(d->navigationLayout);
262 d->navigationLayout->addStretch();
264 d->yearBackward->setAutoRaise(
true);
265 d->navigationLayout->addWidget(d->yearBackward);
267 d->monthBackward->setAutoRaise(
true);
268 d->navigationLayout->addWidget(d->monthBackward);
269 d->navigationLayout->addSpacing(horizontalSpacing);
272 d->selectMonth->setAutoRaise(
true);
273 d->navigationLayout->addWidget(d->selectMonth);
275 d->selectYear->setCheckable(
true);
276 d->selectYear->setAutoRaise(
true);
277 d->navigationLayout->addWidget(d->selectYear);
278 d->navigationLayout->addSpacing(horizontalSpacing);
281 d->monthForward->setAutoRaise(
true);
282 d->navigationLayout->addWidget(d->monthForward);
284 d->yearForward->setAutoRaise(
true);
285 d->navigationLayout->addWidget(d->yearForward);
286 d->navigationLayout->addStretch();
289 d->val =
new DatePickerValidator(
this);
290 d->table =
new KDateTable(
this);
294 if (d->fontsize == -1) {
300 d->selectWeek =
new QComboBox(
this);
302 d->todayButton =
new QToolButton(
this);
305 d->yearForward->setToolTip(
tr(
"Next year",
"@info:tooltip"));
306 d->yearBackward->setToolTip(
tr(
"Previous year",
"@info:tooltip"));
307 d->monthForward->setToolTip(
tr(
"Next month",
"@info:tooltip"));
308 d->monthBackward->setToolTip(
tr(
"Previous month",
"@info:tooltip"));
309 d->selectWeek->setToolTip(
tr(
"Select a week",
"@info:tooltip"));
310 d->selectMonth->setToolTip(
tr(
"Select a month",
"@info:tooltip"));
311 d->selectYear->setToolTip(
tr(
"Select a year",
"@info:tooltip"));
312 d->todayButton->setToolTip(
tr(
"Select the current day",
"@info:tooltip"));
316 d->line->setValidator(d->val);
317 d->line->installEventFilter(
this);
319 d->yearForward->setIcon(
QIcon::fromTheme(QStringLiteral(
"arrow-left-double")));
320 d->yearBackward->setIcon(
QIcon::fromTheme(QStringLiteral(
"arrow-right-double")));
324 d->yearForward->setIcon(
QIcon::fromTheme(QStringLiteral(
"arrow-right-double")));
325 d->yearBackward->setIcon(
QIcon::fromTheme(QStringLiteral(
"arrow-left-double")));
330 connect(d->table, &KDateTable::dateChanged,
this, &KDatePicker::dateChangedSlot);
331 connect(d->table, &KDateTable::tableClicked,
this, &KDatePicker::tableClickedSlot);
344 QBoxLayout *bottomLayout =
new QHBoxLayout();
353 d->table->setDate(date_);
354 dateChangedSlot(date_);
369 d->table->setFocus();
381void KDatePicker::dateChangedSlot(
const QDate &date_)
393 d->selectWeek->setCurrentIndex((date_.
dayOfYear() + firstDay.dayOfWeek() - 2) / 7);
394 d->selectYear->setText(
locale().toString(date_, QStringLiteral(
"yyyy")).rightJustified(4,
QLatin1Char(
'0')));
399void KDatePicker::tableClickedSlot()
406const QDate &KDatePicker::date()
const
408 return d->table->date();
415 return d->table->setDate(date_);
418void KDatePicker::monthForwardClicked()
420 if (!
setDate(date().addMonths(1))) {
423 d->table->setFocus();
426void KDatePicker::monthBackwardClicked()
428 if (!
setDate(date().addMonths(-1))) {
431 d->table->setFocus();
434void KDatePicker::yearForwardClicked()
436 if (!
setDate(d->table->date().addYears(1))) {
439 d->table->setFocus();
442void KDatePicker::yearBackwardClicked()
444 if (!
setDate(d->table->date().addYears(-1))) {
447 d->table->setFocus();
450void KDatePicker::weekSelected(
int index)
452 QDate targetDay = d->selectWeek->itemData(index).toDateTime().date();
457 d->table->setFocus();
460void KDatePicker::selectMonthClicked()
462 QDate thisDate(date());
463 d->table->setFocus();
465 QMenu popup(d->selectMonth);
468 const int monthsInYear = QDate(thisDate.
year() + 1, 1, 1).addDays(-1).month();
469 for (
int m = 1; m <= monthsInYear; m++) {
470 popup.addAction(
locale().standaloneMonthName(m))->setData(m);
473 QAction *item = popup.actions()[thisDate.
month() - 1];
476 popup.setActiveAction(item);
480 if ((item = popup.exec(d->selectMonth->mapToGlobal(QPoint(0, 0)), item)) ==
nullptr) {
498void KDatePicker::selectYearClicked()
500 if (!d->selectYear->isChecked()) {
504 QDate thisDate(date());
506 KPopupFrame *popup =
new KPopupFrame(
this);
507 KDatePickerPrivateYearSelector *picker =
new KDatePickerPrivateYearSelector(date(), popup);
508 picker->resize(picker->sizeHint());
509 picker->setYear(thisDate);
515 if (popup->
exec(d->selectYear->mapToGlobal(QPoint(0, d->selectMonth->height())))) {
518 QDate newDate(picker->year(), thisDate.
month(), 1);
531 d->selectYear->setChecked(
false);
534void KDatePicker::uncheckYearSelector()
536 d->selectYear->setChecked(
false);
540void KDatePicker::changeEvent(
QEvent *event)
544 d->table->setFocus();
549KDateTable *KDatePicker::dateTable()
const
554void KDatePicker::lineEnterPressed()
556 const QDate newDate = d->val->toDate(d->line->text());
561 d->table->setFocus();
567void KDatePicker::todayButtonClicked()
570 d->table->setFocus();
588 for (
QWidget *button : buttons) {
589 font = button->font();
590 font.setPointSize(s);
591 button->setFont(
font);
593 d->table->setFontSize(s);
598 for (
int i = 1;; ++i) {
605 if (r.
width() > d->maxMonthRect.width()) {
606 d->maxMonthRect.setWidth(r.
width());
609 if (r.
height() > d->maxMonthRect.height()) {
610 d->maxMonthRect.setHeight(r.
height());
616 opt.text = longestMonth;
621 int w = textSize.
width();
622 int h = textSize.
height();
623 opt.rect.setHeight(h);
627 d->selectMonth->setMinimumSize(metricBound);
630int KDatePicker::fontSize()
const
637 if (enable == (d->closeButton !=
nullptr)) {
643 d->closeButton->setAutoRaise(
true);
645 d->navigationLayout->addSpacing(horizontalSpacing);
646 d->navigationLayout->addWidget(d->closeButton);
647 d->closeButton->setToolTip(
tr(
"Close",
"@action:button"));
651 delete d->closeButton;
652 d->closeButton =
nullptr;
660 return (d->closeButton);
663#include "kdatepicker.moc"
KDatePicker(QWidget *parent=nullptr)
The constructor.
bool setDate(const QDate &date)
Sets the date.
void dateEntered(const QDate &date)
This signal is emitted when enter is pressed and a VALID date has been entered before into the line e...
bool eventFilter(QObject *o, QEvent *e) override
to catch move keyEvents when QLineEdit has keyFocus
bool hasCloseButton() const
void dateSelected(const QDate &date)
This signal is emitted each time a day has been selected by clicking on the table (hitting a day in t...
void setFontSize(int)
Sets the font size of the widgets elements.
QSize sizeHint() const override
The size hint for date pickers.
~KDatePicker() override
The destructor.
void dateChanged(const QDate &date)
This signal is emitted each time the selected date is changed.
void setCloseButton(bool enable)
By calling this method with enable = true, KDatePicker will show a little close-button in the upper b...
void resizeEvent(QResizeEvent *) override
the resize event
void tableClicked()
This signal is emitted when the day has been selected by clicking on it in the table.
char * toString(const EngineQuery &query)
bool isValid(QStringView ifopt)
KGuiItem ok()
Returns the 'Ok' gui item.
QVariant data() const const
void addLayout(QLayout *layout, int stretch)
virtual void setSpacing(int spacing) override
void activated(int index)
bool sendEvent(QObject *receiver, QEvent *event)
QDate addDays(qint64 ndays) const const
int dayOfWeek() const const
int dayOfYear() const const
int daysInMonth() const const
QDate fromJulianDay(qint64 jd)
bool isValid(int year, int month, int day)
bool setDate(int year, int month, int day)
int weekNumber(int *yearNumber) const const
int pointSize() const const
QFont systemFont(SystemFont type)
int pointSize() const const
QRect boundingRect(QChar ch) const const
int horizontalAdvance(QChar ch) const const
QSize size(int flags, const QString &text, int tabStops, int *tabArray) const const
QFrame(QWidget *parent, Qt::WindowFlags f)
QIcon fromTheme(const QString &name)
void setContentsMargins(const QMargins &margins)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual bool event(QEvent *e)
virtual bool eventFilter(QObject *watched, QEvent *event)
QObject * parent() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
bool isNull() const const
int toInt(bool *ok, int base) const const
PM_LayoutHorizontalSpacing
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
virtual QSize sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const const=0
void initFrom(const QWidget *widget)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QValidator(QObject *parent)
QLocale locale() const const
int toInt(bool *ok) const const