Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qcalendarwidget.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
6
7#include <qabstractitemmodel.h>
8#include <qstyleditemdelegate.h>
9#include <qdatetime.h>
10#include <qtableview.h>
11#include <qlayout.h>
12#include <qevent.h>
13#include <qtextformat.h>
14#include <qheaderview.h>
15#include <private/qwidget_p.h>
16#include <qpushbutton.h>
17#include <qtoolbutton.h>
18#include <qlabel.h>
19#include <qspinbox.h>
20#include <qmenu.h>
21#include <qapplication.h>
22#include <private/qapplication_p.h>
23#include <qbasictimer.h>
24#include <qstylepainter.h>
25#include <qcalendar.h>
26
27#include <vector>
28
29QT_BEGIN_NAMESPACE
30
31using namespace Qt::StringLiterals;
32
33enum {
39};
40
41static QString formatNumber(int number, int fieldWidth)
42{
43 return QString::number(number).rightJustified(fieldWidth, u'0');
44}
45
46namespace QtPrivate {
47
49{
50public:
51
57
60 virtual Section handleKey(int key) = 0;
61 virtual QDate applyToDate(QDate date, QCalendar cal = QCalendar()) const = 0;
62 virtual void setDate(QDate date, QCalendar cal = QCalendar()) = 0;
63 virtual QString text() const = 0;
64 virtual QString text(QDate date, QCalendar cal, int repeat) const = 0;
65
66 QLocale m_locale;
67
68protected:
69 static QString highlightString(const QString &str, int pos);
70};
71
72QString QCalendarDateSectionValidator::highlightString(const QString &str, int pos)
73{
74 if (pos == 0)
75 return "<b>"_L1 + str + "</b>"_L1;
76 int startPos = str.size() - pos;
77 return QStringView{str}.mid(0, startPos) + "<b>"_L1 + QStringView{str}.mid(startPos, pos) + "</b>"_L1;
78
79}
80
82{
83
84public:
86 virtual Section handleKey(int key) override;
87 virtual QDate applyToDate(QDate date, QCalendar cal) const override;
88 virtual void setDate(QDate date, QCalendar cal) override;
89 virtual QString text() const override;
90 virtual QString text(QDate date, QCalendar cal, int repeat) const override;
91private:
92 int m_pos;
93 int m_day;
94 int m_oldDay;
95};
96
98 : QCalendarDateSectionValidator(), m_pos(0), m_day(1), m_oldDay(1)
99{
100}
101
103{
104 if (key == Qt::Key_Right || key == Qt::Key_Left) {
105 m_pos = 0;
107 } else if (key == Qt::Key_Up) {
108 m_pos = 0;
109 ++m_day;
110 if (m_day > 31)
111 m_day = 1;
113 } else if (key == Qt::Key_Down) {
114 m_pos = 0;
115 --m_day;
116 if (m_day < 1)
117 m_day = 31;
119 } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
120 --m_pos;
121 if (m_pos < 0)
122 m_pos = 1;
123
124 if (m_pos == 0)
125 m_day = m_oldDay;
126 else
127 m_day = m_day / 10;
128 //m_day = m_oldDay / 10 * 10 + m_day / 10;
129
130 if (m_pos == 0)
133 }
134 if (key < Qt::Key_0 || key > Qt::Key_9)
136 int pressedKey = key - Qt::Key_0;
137 if (m_pos == 0)
138 m_day = pressedKey;
139 else
140 m_day = m_day % 10 * 10 + pressedKey;
141 if (m_day > 31)
142 m_day = 31;
143 ++m_pos;
144 if (m_pos > 1) {
145 m_pos = 0;
147 }
149}
150
151QDate QCalendarDayValidator::applyToDate(QDate date, QCalendar cal) const
152{
153 auto parts = cal.partsFromDate(date);
154 if (!parts.isValid())
155 return QDate();
156 parts.day = qMin(qMax(1, m_day), cal.daysInMonth(parts.month, parts.year));
157 return cal.dateFromParts(parts);
158}
159
160void QCalendarDayValidator::setDate(QDate date, QCalendar cal)
161{
162 m_day = m_oldDay = date.day(cal);
163 m_pos = 0;
164}
165
167{
168 return highlightString(formatNumber(m_day, 2), m_pos);
169}
170
171QString QCalendarDayValidator::text(QDate date, QCalendar cal, int repeat) const
172{
173 if (repeat <= 1) {
174 return QString::number(date.day(cal));
175 } else if (repeat == 2) {
176 return formatNumber(date.day(cal), 2);
177 } else if (repeat == 3) {
178 return m_locale.dayName(date.dayOfWeek(cal), QLocale::ShortFormat);
179 } else /* repeat >= 4 */ {
180 return m_locale.dayName(date.dayOfWeek(cal), QLocale::LongFormat);
181 }
182}
183
184//////////////////////////////////
185
187{
188
189public:
191 virtual Section handleKey(int key) override;
192 virtual QDate applyToDate(QDate date, QCalendar cal) const override;
193 virtual void setDate(QDate date, QCalendar cal) override;
194 virtual QString text() const override;
195 virtual QString text(QDate date, QCalendar cal, int repeat) const override;
196private:
197 int m_pos;
198 int m_month;
199 int m_oldMonth;
200};
201
203 : QCalendarDateSectionValidator(), m_pos(0), m_month(1), m_oldMonth(1)
204{
205}
206
208{
209 if (key == Qt::Key_Right || key == Qt::Key_Left) {
210 m_pos = 0;
212 } else if (key == Qt::Key_Up) {
213 m_pos = 0;
214 ++m_month;
215 if (m_month > 12)
216 m_month = 1;
218 } else if (key == Qt::Key_Down) {
219 m_pos = 0;
220 --m_month;
221 if (m_month < 1)
222 m_month = 12;
224 } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
225 --m_pos;
226 if (m_pos < 0)
227 m_pos = 1;
228
229 if (m_pos == 0)
230 m_month = m_oldMonth;
231 else
232 m_month = m_month / 10;
233 //m_month = m_oldMonth / 10 * 10 + m_month / 10;
234
235 if (m_pos == 0)
238 }
239 if (key < Qt::Key_0 || key > Qt::Key_9)
241 int pressedKey = key - Qt::Key_0;
242 if (m_pos == 0)
243 m_month = pressedKey;
244 else
245 m_month = m_month % 10 * 10 + pressedKey;
246 if (m_month > 12)
247 m_month = 12;
248 ++m_pos;
249 if (m_pos > 1) {
250 m_pos = 0;
252 }
254}
255
256QDate QCalendarMonthValidator::applyToDate(QDate date, QCalendar cal) const
257{
258 auto parts = cal.partsFromDate(date);
259 if (!parts.isValid())
260 return QDate();
261 parts.month = qMin(qMax(1, m_month), cal.monthsInYear(parts.year));
262 parts.day = qMin(parts.day, cal.daysInMonth(parts.month, parts.year));
263 return cal.dateFromParts(parts);
264}
265
266void QCalendarMonthValidator::setDate(QDate date, QCalendar cal)
267{
268 m_month = m_oldMonth = date.month(cal);
269 m_pos = 0;
270}
271
273{
274 return highlightString(formatNumber(m_month, 2), m_pos);
275}
276
277QString QCalendarMonthValidator::text(QDate date, QCalendar cal, int repeat) const
278{
279 const auto parts = cal.partsFromDate(date);
280 // Numeric forms:
281 if (repeat <= 1)
282 return QString::number(parts.month);
283 if (repeat == 2)
284 return formatNumber(parts.month, 2);
285 // Text forms:
286 if (repeat == 3)
287 return cal.standaloneMonthName(m_locale, parts.month, parts.year, QLocale::ShortFormat);
288 /* repeat >= 4 */
289 return cal.standaloneMonthName(m_locale, parts.month, parts.year, QLocale::LongFormat);
290}
291
292//////////////////////////////////
293
295{
296
297public:
299 virtual Section handleKey(int key) override;
300 virtual QDate applyToDate(QDate date, QCalendar cal) const override;
301 virtual void setDate(QDate date, QCalendar cal) override;
302 virtual QString text() const override;
303 virtual QString text(QDate date, QCalendar cal, int repeat) const override;
304private:
305 int pow10(int n);
306 int m_pos;
307 int m_year;
308 int m_oldYear;
309};
310
312 : QCalendarDateSectionValidator(), m_pos(0), m_year(2000), m_oldYear(2000)
313{
314 // TODO: What to use (for non-Gregorian calendars) as default year?
315 // Maybe 1360 for Jalali, 1420 for Islamic, etc.
316}
317
318int QCalendarYearValidator::pow10(int n)
319{
320 int power = 1;
321 for (int i = 0; i < n; i++)
322 power *= 10;
323 return power;
324}
325
327{
328 if (key == Qt::Key_Right || key == Qt::Key_Left) {
329 m_pos = 0;
331 } else if (key == Qt::Key_Up) {
332 m_pos = 0;
333 ++m_year;
335 } else if (key == Qt::Key_Down) {
336 m_pos = 0;
337 --m_year;
339 } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
340 --m_pos;
341 if (m_pos < 0)
342 m_pos = 3;
343
344 int pow = pow10(m_pos);
345 m_year = m_oldYear / pow * pow + m_year % (pow * 10) / 10;
346
347 if (m_pos == 0)
350 }
351 if (key < Qt::Key_0 || key > Qt::Key_9)
353 int pressedKey = key - Qt::Key_0;
354 int pow = pow10(m_pos);
355 m_year = m_year / (pow * 10) * (pow * 10) + m_year % pow * 10 + pressedKey;
356 ++m_pos;
357 if (m_pos > 3) {
358 m_pos = 0;
360 }
362}
363
364QDate QCalendarYearValidator::applyToDate(QDate date, QCalendar cal) const
365{
366 auto parts = cal.partsFromDate(date);
367 if (!parts.isValid())
368 return QDate();
369 // This widget does not support negative years (some calendars may support)
370 parts.year = qMax(1, m_year);
371 parts.day = qMin(parts.day, cal.daysInMonth(parts.month, parts.year));
372 return cal.dateFromParts(parts);
373}
374
375void QCalendarYearValidator::setDate(QDate date, QCalendar cal)
376{
377 m_year = m_oldYear = date.year(cal);
378 m_pos = 0;
379}
380
382{
383 return highlightString(formatNumber(m_year, 4), m_pos);
384}
385
386QString QCalendarYearValidator::text(QDate date, QCalendar cal, int repeat) const
387{
388 if (repeat < 4)
389 return formatNumber(date.year(cal) % 100, 2);
390 return QString::number(date.year(cal));
391}
392
393///////////////////////////////////
394
402} // namespace QtPrivate
403
405
406namespace QtPrivate {
407
409{
410public:
413
414 void handleKeyEvent(QKeyEvent *keyEvent, QCalendar cal);
415 QString currentText(QCalendar cal) const;
416 QDate currentDate() const { return m_currentDate; }
417 void setFormat(const QString &format);
418 void setInitialDate(QDate date, QCalendar cal);
419
420 void setLocale(const QLocale &locale);
421
422private:
423 void toNextToken();
424 void toPreviousToken();
425 void applyToDate(QCalendar cal);
426
427 int countRepeat(const QString &str, int index) const;
428 void clear();
429
430 QStringList m_separators;
431 std::vector<SectionToken> m_tokens;
432 QCalendarYearValidator m_yearValidator;
433 QCalendarMonthValidator m_monthValidator;
434 QCalendarDayValidator m_dayValidator;
435
436 int m_currentToken;
437
438 QDate m_initialDate;
439 QDate m_currentDate;
440
441 QCalendarDateSectionValidator::Section m_lastSectionMove;
442};
443
451
452void QCalendarDateValidator::setLocale(const QLocale &locale)
453{
454 m_yearValidator.m_locale = locale;
455 m_monthValidator.m_locale = locale;
456 m_dayValidator.m_locale = locale;
457}
458
463
464// from qdatetime.cpp
465int QCalendarDateValidator::countRepeat(const QString &str, int index) const
466{
467 Q_ASSERT(index >= 0 && index < str.size());
468 int count = 1;
469 const QChar ch = str.at(index);
470 while (index + count < str.size() && str.at(index + count) == ch)
471 ++count;
472 return count;
473}
474
475void QCalendarDateValidator::setInitialDate(QDate date, QCalendar cal)
476{
477 m_yearValidator.setDate(date, cal);
478 m_monthValidator.setDate(date, cal);
479 m_dayValidator.setDate(date, cal);
480 m_initialDate = date;
481 m_currentDate = date;
483}
484
485QString QCalendarDateValidator::currentText(QCalendar cal) const
486{
487 QString str;
488 const int numSeps = m_separators.size();
489 const int numTokens = int(m_tokens.size());
490 for (int i = 0; i < numSeps; ++i) {
491 str += m_separators.at(i);
492 if (i < numTokens) {
493 const SectionToken &token = m_tokens[i];
494 if (i == m_currentToken)
495 str += token.validator->text();
496 else
497 str += token.validator->text(m_currentDate, cal, token.repeat);
498 }
499 }
500 return str;
501}
502
503void QCalendarDateValidator::clear()
504{
505 m_tokens.clear();
506 m_separators.clear();
507
508 m_currentToken = -1;
509}
510
511void QCalendarDateValidator::setFormat(const QString &format)
512{
513 clear();
514
515 int pos = 0;
516 const auto quote = u'\'';
517 bool quoting = false;
518 QString separator;
519 while (pos < format.size()) {
520 const QStringView mid = QStringView{format}.mid(pos);
521 int offset = 1;
522
523 if (mid.startsWith(quote)) {
524 quoting = !quoting;
525 } else {
526 const QChar nextChar = format.at(pos);
527 if (quoting) {
528 separator += nextChar;
529 quoting = false;
530 } else {
531 QCalendarDateSectionValidator *validator = nullptr;
532 if (nextChar == u'd') {
533 offset = qMin(4, countRepeat(format, pos));
534 validator = &m_dayValidator;
535 } else if (nextChar == u'M') {
536 offset = qMin(4, countRepeat(format, pos));
537 validator = &m_monthValidator;
538 } else if (nextChar == u'y') {
539 offset = qMin(4, countRepeat(format, pos));
540 validator = &m_yearValidator;
541 } else {
542 separator += nextChar;
543 }
544 if (validator) {
545 m_tokens.push_back(SectionToken(validator, offset));
546 m_separators.append(separator);
547 separator = QString();
548 if (m_currentToken < 0)
549 m_currentToken = int(m_tokens.size()) - 1;
550
551 }
552 }
553 }
554 pos += offset;
555 }
556 m_separators += separator;
557}
558
559void QCalendarDateValidator::applyToDate(QCalendar cal)
560{
561 m_currentDate = m_yearValidator.applyToDate(m_currentDate, cal);
562 m_currentDate = m_monthValidator.applyToDate(m_currentDate, cal);
563 m_currentDate = m_dayValidator.applyToDate(m_currentDate, cal);
564}
565
566void QCalendarDateValidator::toNextToken()
567{
568 if (m_currentToken < 0)
569 return;
570 ++m_currentToken;
571 m_currentToken %= m_tokens.size();
572}
573
574void QCalendarDateValidator::toPreviousToken()
575{
576 if (m_currentToken < 0)
577 return;
578 --m_currentToken;
579 m_currentToken %= m_tokens.size();
580}
581
605
606//////////////////////////////////
607
609{
611public:
613 : QObject(parent), m_dateText(nullptr), m_dateFrame(nullptr), m_dateValidator(nullptr),
614 m_widget(nullptr), m_editDelay(1500), m_date(QDate::currentDate()) {}
615
616 QWidget *widget() const;
617 void setWidget(QWidget *widget);
618
620 void setDateEditAcceptDelay(int delay);
621
622 void setDate(QDate date);
623
624 bool eventFilter(QObject *o, QEvent *e) override;
625 void timerEvent(QTimerEvent *e) override;
626
627signals:
630
631private:
632 void applyDate();
633 void updateDateLabel();
634 void createDateLabel();
635 void removeDateLabel();
636
637 QLabel *m_dateText;
638 QFrame *m_dateFrame;
639 QBasicTimer m_acceptTimer;
640 QCalendarDateValidator *m_dateValidator;
641 QWidget *m_widget;
642 int m_editDelay;
643
644 QDate m_date;
645 const QCalendar m_calendar;
646};
647
648QWidget *QCalendarTextNavigator::widget() const
649{
650 return m_widget;
651}
652
653void QCalendarTextNavigator::setWidget(QWidget *widget)
654{
655 m_widget = widget;
656}
657
659{
660 m_date = date;
661}
662
663void QCalendarTextNavigator::updateDateLabel()
664{
665 if (!m_widget)
666 return;
667
668 m_acceptTimer.start(m_editDelay, this);
669
670 m_dateText->setText(m_dateValidator->currentText(m_calendar));
671
672 QSize s = m_dateFrame->sizeHint();
673 QRect r = m_widget->geometry(); // later, just the table section
674 QRect newRect((r.width() - s.width()) / 2, (r.height() - s.height()) / 2, s.width(), s.height());
675 m_dateFrame->setGeometry(newRect);
676 // need to set palette after geometry update as phonestyle sets transparency
677 // effect in move event.
678 QPalette p = m_dateFrame->palette();
679 p.setBrush(QPalette::Window, m_dateFrame->window()->palette().brush(QPalette::Window));
680 m_dateFrame->setPalette(p);
681
682 m_dateFrame->raise();
683 m_dateFrame->show();
684}
685
686void QCalendarTextNavigator::applyDate()
687{
688 QDate date = m_dateValidator->currentDate();
689 if (m_date == date)
690 return;
691
692 m_date = date;
693 emit dateChanged(date);
694}
695
696void QCalendarTextNavigator::createDateLabel()
697{
698 if (m_dateFrame)
699 return;
700 m_dateFrame = new QFrame(m_widget);
701 QVBoxLayout *vl = new QVBoxLayout;
702 m_dateText = new QLabel;
703 vl->addWidget(m_dateText);
704 m_dateFrame->setLayout(vl);
705 m_dateFrame->setFrameShadow(QFrame::Plain);
706 m_dateFrame->setFrameShape(QFrame::Box);
707 m_dateValidator = new QCalendarDateValidator();
708 m_dateValidator->setLocale(m_widget->locale());
709 m_dateValidator->setFormat(m_widget->locale().dateFormat(QLocale::ShortFormat));
710 m_dateValidator->setInitialDate(m_date, m_calendar);
711
712 m_dateFrame->setAutoFillBackground(true);
713 m_dateFrame->setBackgroundRole(QPalette::Window);
714}
715
716void QCalendarTextNavigator::removeDateLabel()
717{
718 if (!m_dateFrame)
719 return;
720 m_acceptTimer.stop();
721 m_dateFrame->hide();
722 m_dateFrame->deleteLater();
723 delete m_dateValidator;
724 m_dateFrame = nullptr;
725 m_dateText = nullptr;
726 m_dateValidator = nullptr;
727}
728
729bool QCalendarTextNavigator::eventFilter(QObject *o, QEvent *e)
730{
731 if (m_widget) {
732 if (e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease) {
733 QKeyEvent *ke = static_cast<QKeyEvent *>(e);
734 if ((ke->text().size() > 0 && ke->text().at(0).isPrint()) || m_dateFrame) {
735 if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Select) {
736 if (!m_dateFrame)
737 return false; // No date editing in progress, let the view handle the key
738 applyDate();
739 emit editingFinished();
740 removeDateLabel();
741#if QT_CONFIG(shortcut)
742 } else if (ke->matches(QKeySequence::Cancel)) {
743 removeDateLabel();
744#endif
745 } else if (e->type() == QEvent::KeyPress) {
746 createDateLabel();
747 m_dateValidator->handleKeyEvent(ke, m_calendar);
748 updateDateLabel();
749 }
750 ke->accept();
751 return true;
752 }
753 // If we are navigating let the user finish his date in old locate.
754 // If we change our mind and want it to update immediately simply uncomment below
755 /*
756 } else if (e->type() == QEvent::LocaleChange) {
757 if (m_dateValidator) {
758 m_dateValidator->setLocale(m_widget->locale());
759 m_dateValidator->setFormat(m_widget->locale().dateFormat(QLocale::ShortFormat));
760 updateDateLabel();
761 }
762 */
763 }
764 }
765 return QObject::eventFilter(o,e);
766}
767
769{
770 if (e->timerId() == m_acceptTimer.timerId()) {
771 applyDate();
772 removeDateLabel();
773 }
774}
775
777{
778 return m_editDelay;
779}
780
782{
783 m_editDelay = delay;
784}
785
786class QCalendarView;
787
788// a small helper class that replaces a QMap<Qt::DayOfWeek, T>,
789// but requires T to have a member-swap and a default constructor
790// which should be cheap (no memory allocations)
791
792QT_WARNING_PUSH
793QT_WARNING_DISABLE_MSVC(4351) // "new behavior: elements of array ... will be default initialized"
794
795template <typename T>
797 bool contained[7];
798 T data[7];
799
800 static constexpr int day2idx(Qt::DayOfWeek day) noexcept { return int(day) - 1; } // alt: day % 7
801public:
802 constexpr StaticDayOfWeekAssociativeArray() noexcept(noexcept(T()))
803 : contained{}, data{} // arrays require uniform initialization
804 {}
805
806 constexpr bool contains(Qt::DayOfWeek day) const noexcept { return contained[day2idx(day)]; }
807 constexpr const T &value(Qt::DayOfWeek day) const noexcept { return data[day2idx(day)]; }
808
809 constexpr T &operator[](Qt::DayOfWeek day) noexcept
810 {
811 const int idx = day2idx(day);
812 contained[idx] = true;
813 return data[idx];
814 }
815
816 constexpr void insert(Qt::DayOfWeek day, T v) noexcept
817 {
818 operator[](day).swap(v);
819 }
820};
821
823
825{
827public:
829
830 int rowCount(const QModelIndex &parent) const override
831 {
832 if (parent.isValid())
833 return 0;
834 return RowCount + m_firstRow;
835 }
836
837 int columnCount(const QModelIndex &parent) const override
838 {
839 if (parent.isValid())
840 return 0;
841 return ColumnCount + m_firstColumn;
842 }
843
844 QVariant data(const QModelIndex &index, int role) const override;
845 Qt::ItemFlags flags(const QModelIndex &index) const override;
846
847 void showMonth(int year, int month);
848 void setDate(QDate d);
849
850 void setCalendar(QCalendar c);
852
853 void setMinimumDate(QDate date);
854 void setMaximumDate(QDate date);
855
856 void setRange(QDate min, QDate max);
857
858 void setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format);
859
860 void setFirstColumnDay(Qt::DayOfWeek dayOfWeek);
862
863 bool weekNumbersShown() const;
864 void setWeekNumbersShown(bool show);
865
866 QTextCharFormat formatForCell(int row, int col) const;
867 Qt::DayOfWeek dayOfWeekForColumn(int section) const;
868 int columnForDayOfWeek(Qt::DayOfWeek day) const;
869 QDate dateForCell(int row, int column) const;
870 void cellForDate(QDate date, int *row, int *column) const;
871 QString dayName(Qt::DayOfWeek day) const;
872
874 { m_view = view; }
875
877 QDate referenceDate() const;
878 int columnForFirstOfMonth(QDate date) const;
879
880 QString monthName(const QLocale &locale, int month)
881 {
882 return m_calendar.standaloneMonthName(locale, month, m_shownYear, QLocale::LongFormat);
883 }
884
888 QDate m_date;
897 QMap<QDate, QTextCharFormat> m_dateFormats;
898 QTextCharFormat m_headerFormat;
900};
901
903{
905public:
907
908 void internalUpdate() { updateGeometries(); }
909 void setReadOnly(bool enable);
910 virtual void keyboardSearch(const QString &) override {}
911
912signals:
914 void changeDate(QDate date, bool changeMonth);
915 void dateClicked(QDate date);
917protected:
918 QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;
919 void mouseDoubleClickEvent(QMouseEvent *event) override;
920 void mousePressEvent(QMouseEvent *event) override;
921 void mouseMoveEvent(QMouseEvent *event) override;
922 void mouseReleaseEvent(QMouseEvent *event) override;
923#if QT_CONFIG(wheelevent)
925#endif
926 void keyPressEvent(QKeyEvent *event) override;
927 bool event(QEvent *event) override;
928
929 QDate handleMouseEvent(QMouseEvent *event);
930public:
932private:
933 bool validDateClicked;
934};
935
936QCalendarModel::QCalendarModel(QObject *parent)
937 : QAbstractTableModel(parent),
938 m_firstColumn(1),
939 m_firstRow(1),
940 m_date(QDate::currentDate()),
941 m_minimumDate(QDate::fromJulianDay(1)),
942 m_maximumDate(9999, 12, 31),
943 m_shownYear(m_date.year(m_calendar)),
944 m_shownMonth(m_date.month(m_calendar)),
945 m_firstDay(QLocale().firstDayOfWeek()),
946 m_horizontalHeaderFormat(QCalendarWidget::ShortDayNames),
947 m_weekNumbersShown(true),
948 m_view(nullptr)
949{
950}
951
953{
954 int col = column - m_firstColumn;
955 if (col < 0 || col > 6)
956 return Qt::Sunday;
957 int day = m_firstDay + col;
958 if (day > 7)
959 day -= 7;
960 return Qt::DayOfWeek(day);
961}
962
963int QCalendarModel::columnForDayOfWeek(Qt::DayOfWeek day) const
964{
965 if (day < 1 || unsigned(day) > unsigned(7))
966 return -1;
967 int column = (int)day - (int)m_firstDay;
968 if (column < 0)
969 column += 7;
970 return column + m_firstColumn;
971}
972
973/*
974This simple algorithm tries to generate a valid date from the month shown.
975Some months don't contain a first day (e.g. Jan of -4713 year,
976so QDate (-4713, 1, 1) would be invalid). In that case we try to generate
977another valid date for that month. Later, returned date's day is the number of cells
978calendar widget will reserve for days before referenceDate. (E.g. if returned date's
979day is 16, that day will be placed in 3rd or 4th row, not in the 1st or 2nd row).
980Depending on referenceData we can change behaviour of Oct 1582. If referenceDate is 1st
981of Oct we render 1 Oct in 1st or 2nd row. If referenceDate is 17 of Oct we show always 16
982dates before 17 of Oct, and since this month contains the hole 5-14 Oct, the first of Oct
983will be rendered in 2nd or 3rd row, showing more dates from previous month.
984*/
986{
987 // TODO: Check this
988 int refDay = 1;
989 while (refDay <= 31) {
990 QDate refDate(m_shownYear, m_shownMonth, refDay, m_calendar);
991 if (refDate.isValid())
992 return refDate;
993 refDay += 1;
994 }
995 return QDate();
996}
997
999{
1000 return (columnForDayOfWeek(static_cast<Qt::DayOfWeek>(m_calendar.dayOfWeek(date)))
1001 - (date.day(m_calendar) % 7) + 8) % 7;
1002}
1003
1004QDate QCalendarModel::dateForCell(int row, int column) const
1005{
1006 if (row < m_firstRow || row > m_firstRow + RowCount - 1 ||
1007 column < m_firstColumn || column > m_firstColumn + ColumnCount - 1)
1008 return QDate();
1009 const QDate refDate = referenceDate();
1010 if (!refDate.isValid())
1011 return QDate();
1012
1013 const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
1014 if (columnForFirstOfShownMonth - m_firstColumn < MinimumDayOffset)
1015 row -= 1;
1016
1017 const int requestedDay =
1018 7 * (row - m_firstRow) + column - columnForFirstOfShownMonth - refDate.day(m_calendar) + 1;
1019 return refDate.addDays(requestedDay);
1020}
1021
1022void QCalendarModel::cellForDate(QDate date, int *row, int *column) const
1023{
1024 if (!row && !column)
1025 return;
1026
1027 if (row)
1028 *row = -1;
1029 if (column)
1030 *column = -1;
1031
1032 const QDate refDate = referenceDate();
1033 if (!refDate.isValid())
1034 return;
1035
1036 const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
1037 const int requestedPosition = (refDate.daysTo(date) - m_firstColumn +
1038 columnForFirstOfShownMonth + refDate.day(m_calendar) - 1);
1039
1040 int c = requestedPosition % 7;
1041 int r = requestedPosition / 7;
1042 if (c < 0) {
1043 c += 7;
1044 r -= 1;
1045 }
1046
1047 if (columnForFirstOfShownMonth - m_firstColumn < MinimumDayOffset)
1048 r += 1;
1049
1050 if (r < 0 || r > RowCount - 1 || c < 0 || c > ColumnCount - 1)
1051 return;
1052
1053 if (row)
1054 *row = r + m_firstRow;
1055 if (column)
1056 *column = c + m_firstColumn;
1057}
1058
1059QString QCalendarModel::dayName(Qt::DayOfWeek day) const
1060{
1061 switch (m_horizontalHeaderFormat) {
1062 case QCalendarWidget::SingleLetterDayNames: {
1063 QString standaloneDayName = m_view->locale().standaloneDayName(day, QLocale::NarrowFormat);
1064 if (standaloneDayName == m_view->locale().dayName(day, QLocale::NarrowFormat))
1065 return standaloneDayName.left(1);
1066 return standaloneDayName;
1067 }
1068 case QCalendarWidget::ShortDayNames:
1069 return m_view->locale().dayName(day, QLocale::ShortFormat);
1070 case QCalendarWidget::LongDayNames:
1071 return m_view->locale().dayName(day, QLocale::LongFormat);
1072 default:
1073 break;
1074 }
1075 return QString();
1076}
1077
1078QTextCharFormat QCalendarModel::formatForCell(int row, int col) const
1079{
1080 QPalette pal;
1081 QPalette::ColorGroup cg = QPalette::Active;
1082 QTextCharFormat format;
1083
1084 if (m_view) {
1085 pal = m_view->palette();
1086 if (!m_view->isEnabled())
1087 cg = QPalette::Disabled;
1088 else if (!m_view->isActiveWindow())
1089 cg = QPalette::Inactive;
1090 format.setFont(m_view->font());
1091 }
1092
1093 bool header = (m_weekNumbersShown && col == HeaderColumn)
1094 || (m_horizontalHeaderFormat != QCalendarWidget::NoHorizontalHeader && row == HeaderRow);
1095 format.setBackground(pal.brush(cg, header ? QPalette::AlternateBase : QPalette::Base));
1096 format.setForeground(pal.brush(cg, QPalette::Text));
1097 if (header) {
1098 format.merge(m_headerFormat);
1099 }
1100
1101 if (col >= m_firstColumn && col < m_firstColumn + ColumnCount) {
1102 Qt::DayOfWeek dayOfWeek = dayOfWeekForColumn(col);
1103 if (m_dayFormats.contains(dayOfWeek))
1104 format.merge(m_dayFormats.value(dayOfWeek));
1105 }
1106
1107 if (!header) {
1108 QDate date = dateForCell(row, col);
1109 format.merge(m_dateFormats.value(date));
1110 if (date < m_minimumDate || date > m_maximumDate)
1111 format.setBackground(pal.brush(cg, QPalette::Window));
1112 if (m_shownMonth != date.month(m_calendar))
1113 format.setForeground(pal.brush(QPalette::Disabled, QPalette::Text));
1114 }
1115 return format;
1116}
1117
1118QVariant QCalendarModel::data(const QModelIndex &index, int role) const
1119{
1120 if (role == Qt::TextAlignmentRole)
1121 return (int) Qt::AlignCenter;
1122
1123 int row = index.row();
1124 int column = index.column();
1125
1126 if (role == Qt::DisplayRole) {
1127 if (m_weekNumbersShown && column == HeaderColumn
1128 && row >= m_firstRow && row < m_firstRow + RowCount) {
1129 QDate date = dateForCell(row, columnForDayOfWeek(Qt::Monday));
1130 if (date.isValid())
1131 return date.weekNumber();
1132 }
1133 if (m_horizontalHeaderFormat != QCalendarWidget::NoHorizontalHeader && row == HeaderRow
1134 && column >= m_firstColumn && column < m_firstColumn + ColumnCount)
1135 return dayName(dayOfWeekForColumn(column));
1136 QDate date = dateForCell(row, column);
1137 if (date.isValid())
1138 return date.day(m_calendar);
1139 return QString();
1140 }
1141
1142 QTextCharFormat fmt = formatForCell(row, column);
1143 if (role == Qt::BackgroundRole)
1144 return fmt.background().color();
1145 if (role == Qt::ForegroundRole)
1146 return fmt.foreground().color();
1147 if (role == Qt::FontRole)
1148 return fmt.font();
1149 if (role == Qt::ToolTipRole)
1150 return fmt.toolTip();
1151 return QVariant();
1152}
1153
1155{
1156 QDate date = dateForCell(index.row(), index.column());
1157 if (!date.isValid())
1158 return QAbstractTableModel::flags(index);
1159 if (date < m_minimumDate)
1160 return { };
1161 if (date > m_maximumDate)
1162 return { };
1163 return QAbstractTableModel::flags(index);
1164}
1165
1167{
1168 m_date = d;
1169 if (m_date < m_minimumDate)
1170 m_date = m_minimumDate;
1171 else if (m_date > m_maximumDate)
1172 m_date = m_maximumDate;
1173}
1174
1175void QCalendarModel::setCalendar(QCalendar c)
1176{
1177 m_calendar = c;
1178 m_shownYear = m_date.year(c);
1179 m_shownMonth = m_date.month(c);
1182}
1183
1185{
1186 return m_calendar;
1187}
1188
1189void QCalendarModel::showMonth(int year, int month)
1190{
1191 if (m_shownYear == year && m_shownMonth == month)
1192 return;
1193
1194 m_shownYear = year;
1195 m_shownMonth = month;
1196
1198}
1199
1201{
1202 if (!d.isValid() || d == m_minimumDate)
1203 return;
1204
1205 m_minimumDate = d;
1206 if (m_maximumDate < m_minimumDate)
1207 m_maximumDate = m_minimumDate;
1208 if (m_date < m_minimumDate)
1209 m_date = m_minimumDate;
1211}
1212
1214{
1215 if (!d.isValid() || d == m_maximumDate)
1216 return;
1217
1218 m_maximumDate = d;
1219 if (m_minimumDate > m_maximumDate)
1220 m_minimumDate = m_maximumDate;
1221 if (m_date > m_maximumDate)
1222 m_date = m_maximumDate;
1224}
1225
1226void QCalendarModel::setRange(QDate min, QDate max)
1227{
1228 m_minimumDate = min;
1229 m_maximumDate = max;
1230 if (m_minimumDate > m_maximumDate)
1231 qSwap(m_minimumDate, m_maximumDate);
1232 if (m_date < m_minimumDate)
1233 m_date = m_minimumDate;
1234 if (m_date > m_maximumDate)
1235 m_date = m_maximumDate;
1237}
1238
1240{
1241 QModelIndex begin = index(0, 0);
1242 QModelIndex end = index(m_firstRow + RowCount - 1, m_firstColumn + ColumnCount - 1);
1243 emit dataChanged(begin, end);
1244 emit headerDataChanged(Qt::Vertical, 0, m_firstRow + RowCount - 1);
1245 emit headerDataChanged(Qt::Horizontal, 0, m_firstColumn + ColumnCount - 1);
1246}
1247
1248void QCalendarModel::setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format)
1249{
1250 if (m_horizontalHeaderFormat == format)
1251 return;
1252
1253 int oldFormat = m_horizontalHeaderFormat;
1254 m_horizontalHeaderFormat = format;
1255 if (oldFormat == QCalendarWidget::NoHorizontalHeader) {
1256 beginInsertRows(QModelIndex(), 0, 0);
1257 m_firstRow = 1;
1258 endInsertRows();
1259 } else if (m_horizontalHeaderFormat == QCalendarWidget::NoHorizontalHeader) {
1260 beginRemoveRows(QModelIndex(), 0, 0);
1261 m_firstRow = 0;
1262 endRemoveRows();
1263 }
1265}
1266
1267void QCalendarModel::setFirstColumnDay(Qt::DayOfWeek dayOfWeek)
1268{
1269 if (m_firstDay == dayOfWeek)
1270 return;
1271
1272 m_firstDay = dayOfWeek;
1274}
1275
1277{
1278 return m_firstDay;
1279}
1280
1282{
1283 return m_weekNumbersShown;
1284}
1285
1287{
1288 if (m_weekNumbersShown == show)
1289 return;
1290
1291 m_weekNumbersShown = show;
1292 if (show) {
1293 beginInsertColumns(QModelIndex(), 0, 0);
1294 m_firstColumn = 1;
1295 endInsertColumns();
1296 } else {
1297 beginRemoveColumns(QModelIndex(), 0, 0);
1298 m_firstColumn = 0;
1299 endRemoveColumns();
1300 }
1302}
1303
1304QCalendarView::QCalendarView(QWidget *parent)
1305 : QTableView(parent),
1306 readOnly(false),
1307 validDateClicked(false)
1308{
1309 setTabKeyNavigation(false);
1310 setShowGrid(false);
1311 verticalHeader()->setVisible(false);
1312 horizontalHeader()->setVisible(false);
1313 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1314 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1315}
1316
1317QModelIndex QCalendarView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
1318{
1319 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1320 if (!calendarModel)
1321 return QTableView::moveCursor(cursorAction, modifiers);
1322
1323 QCalendar cal = calendarModel->calendar();
1324
1325 if (readOnly)
1326 return currentIndex();
1327
1328 QModelIndex index = currentIndex();
1329 QDate currentDate = static_cast<QCalendarModel*>(model())->dateForCell(index.row(), index.column());
1330 switch (cursorAction) {
1331 case QAbstractItemView::MoveUp:
1332 currentDate = currentDate.addDays(-7);
1333 break;
1334 case QAbstractItemView::MoveDown:
1335 currentDate = currentDate.addDays(7);
1336 break;
1337 case QAbstractItemView::MoveLeft:
1338 currentDate = currentDate.addDays(isRightToLeft() ? 1 : -1);
1339 break;
1340 case QAbstractItemView::MoveRight:
1341 currentDate = currentDate.addDays(isRightToLeft() ? -1 : 1);
1342 break;
1343 case QAbstractItemView::MoveHome: {
1344 auto parts = cal.partsFromDate(currentDate);
1345 if (parts.isValid()) {
1346 parts.day = 1;
1347 currentDate = cal.dateFromParts(parts);
1348 }
1349 }
1350 break;
1351 case QAbstractItemView::MoveEnd: {
1352 auto parts = cal.partsFromDate(currentDate);
1353 if (parts.isValid()) {
1354 parts.day = cal.daysInMonth(parts.month, parts.year);
1355 currentDate = cal.dateFromParts(parts);
1356 }
1357 }
1358 break;
1359 case QAbstractItemView::MovePageUp:
1360 currentDate = currentDate.addMonths(-1, cal);
1361 break;
1362 case QAbstractItemView::MovePageDown:
1363 currentDate = currentDate.addMonths(1, cal);
1364 break;
1365 case QAbstractItemView::MoveNext:
1366 case QAbstractItemView::MovePrevious:
1367 return currentIndex();
1368 default:
1369 break;
1370 }
1371 emit changeDate(currentDate, true);
1372 return currentIndex();
1373}
1374
1375void QCalendarView::keyPressEvent(QKeyEvent *event)
1376{
1377 if (!readOnly) {
1378 switch (event->key()) {
1379 case Qt::Key_Return:
1380 case Qt::Key_Enter:
1381 case Qt::Key_Select:
1383 return;
1384 default:
1385 break;
1386 }
1387 }
1389}
1390
1391#if QT_CONFIG(wheelevent)
1393{
1394 const int numDegrees = event->angleDelta().y() / 8;
1395 const int numSteps = numDegrees / 15;
1396 const QModelIndex index = currentIndex();
1401}
1402#endif
1403
1404bool QCalendarView::event(QEvent *event)
1405{
1406 return QTableView::event(event);
1407}
1408
1409QDate QCalendarView::handleMouseEvent(QMouseEvent *event)
1410{
1411 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1412 if (!calendarModel)
1413 return QDate();
1414
1415 QPoint pos = event->position().toPoint();
1416 QModelIndex index = indexAt(pos);
1417 QDate date = calendarModel->dateForCell(index.row(), index.column());
1418 if (date.isValid() && date >= calendarModel->m_minimumDate
1419 && date <= calendarModel->m_maximumDate) {
1420 return date;
1421 }
1422 return QDate();
1423}
1424
1425void QCalendarView::mouseDoubleClickEvent(QMouseEvent *event)
1426{
1427 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1428 if (!calendarModel) {
1429 QTableView::mouseDoubleClickEvent(event);
1430 return;
1431 }
1432
1433 if (readOnly)
1434 return;
1435
1436 QDate date = handleMouseEvent(event);
1437 validDateClicked = false;
1438 if (date == calendarModel->m_date &&
1439 !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this)) {
1440 emit editingFinished();
1441 }
1442}
1443
1444void QCalendarView::mousePressEvent(QMouseEvent *event)
1445{
1446 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1447 if (!calendarModel) {
1448 QTableView::mousePressEvent(event);
1449 return;
1450 }
1451
1452 if (readOnly)
1453 return;
1454
1455 if (event->button() != Qt::LeftButton)
1456 return;
1457
1458 QDate date = handleMouseEvent(event);
1459 if (date.isValid()) {
1460 validDateClicked = true;
1461 int row = -1, col = -1;
1462 static_cast<QCalendarModel *>(model())->cellForDate(date, &row, &col);
1463 if (row != -1 && col != -1) {
1464 selectionModel()->setCurrentIndex(model()->index(row, col), QItemSelectionModel::NoUpdate);
1465 }
1466 } else {
1467 validDateClicked = false;
1468 event->ignore();
1469 }
1470}
1471
1472void QCalendarView::mouseMoveEvent(QMouseEvent *event)
1473{
1474 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1475 if (!calendarModel) {
1476 QTableView::mouseMoveEvent(event);
1477 return;
1478 }
1479
1480 if (readOnly)
1481 return;
1482
1483 if (validDateClicked) {
1484 QDate date = handleMouseEvent(event);
1485 if (date.isValid()) {
1486 int row = -1, col = -1;
1487 static_cast<QCalendarModel *>(model())->cellForDate(date, &row, &col);
1488 if (row != -1 && col != -1) {
1489 selectionModel()->setCurrentIndex(model()->index(row, col), QItemSelectionModel::NoUpdate);
1490 }
1491 }
1492 } else {
1493 event->ignore();
1494 }
1495}
1496
1497void QCalendarView::mouseReleaseEvent(QMouseEvent *event)
1498{
1499 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1500 if (!calendarModel) {
1501 QTableView::mouseReleaseEvent(event);
1502 return;
1503 }
1504
1505 if (event->button() != Qt::LeftButton)
1506 return;
1507
1508 if (readOnly)
1509 return;
1510
1511 if (validDateClicked) {
1512 QDate date = handleMouseEvent(event);
1513 if (date.isValid()) {
1514 emit changeDate(date, true);
1515 emit dateClicked(date);
1516 if (style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this))
1517 emit editingFinished();
1518 }
1519 validDateClicked = false;
1520 } else {
1521 event->ignore();
1522 }
1523}
1524
1526{
1527 Q_OBJECT
1528public:
1533 const QModelIndex &index) const override;
1534 void paintCell(QPainter *painter, const QRect &rect, QDate date) const;
1535
1536private:
1537 QCalendarWidgetPrivate *calendarWidgetPrivate;
1538 mutable QStyleOptionViewItem storedOption;
1539};
1540
1541//Private tool button class
1543{
1544public:
1545 QCalToolButton(QWidget * parent)
1547 { }
1548protected:
1549 void paintEvent(QPaintEvent *e) override
1550 {
1551 Q_UNUSED(e);
1552
1553 QStylePainter painter(this);
1554 QStyleOptionToolButton opt;
1555 initStyleOption(&opt);
1556
1557 // set the highlight color for button text so it remains legible on top of navBarBackground
1558 if (!opt.state.testFlag(QStyle::State_MouseOver) || isDown())
1559 opt.palette.setColor(QPalette::ButtonText, opt.palette.color(QPalette::HighlightedText));
1560
1561 painter.drawComplexControl(QStyle::CC_ToolButton, opt);
1562 }
1563};
1564
1579
1580} // namespace QtPrivate
1581
1594
1596{
1597 Q_DECLARE_PUBLIC(QCalendarWidget)
1598public:
1600
1601 void showMonth(int year, int month);
1602 void update();
1603 void paintCell(QPainter *painter, const QRect &rect, QDate date) const;
1604
1605 void _q_slotShowDate(QDate date);
1606 void _q_slotChangeDate(QDate date);
1607 void _q_slotChangeDate(QDate date, bool changeMonth);
1609 void _q_monthChanged(QAction*);
1614
1615 void createNavigationBar(QWidget *widget);
1620 void updateCurrentPage(QDate newDate);
1621 inline QDate getCurrentDate();
1622 void setNavigatorEnabled(bool enable);
1623
1630
1635 QMap<int, QAction *> monthToAction;
1640
1642 mutable QSize cachedSizeHint;
1644};
1645
1646void QCalendarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
1647 const QModelIndex &index) const
1648{
1649 QDate date = calendarWidgetPrivate->m_model->dateForCell(index.row(), index.column());
1650 if (date.isValid()) {
1651 storedOption = option;
1652 QRect rect = option.rect;
1653 calendarWidgetPrivate->paintCell(painter, rect, date);
1654 } else {
1655 QStyledItemDelegate::paint(painter, option, index);
1656 }
1657}
1658
1659void QCalendarDelegate::paintCell(QPainter *painter, const QRect &rect, QDate date) const
1660{
1661 storedOption.rect = rect;
1662 int row = -1;
1663 int col = -1;
1664 calendarWidgetPrivate->m_model->cellForDate(date, &row, &col);
1665 QModelIndex idx = calendarWidgetPrivate->m_model->index(row, col);
1666 QStyledItemDelegate::paint(painter, storedOption, idx);
1667}
1668
1669QCalendarWidgetPrivate::QCalendarWidgetPrivate()
1670 : QWidgetPrivate()
1671{
1672 m_model = nullptr;
1673 m_view = nullptr;
1674 m_delegate = nullptr;
1675 m_selection = nullptr;
1676 m_navigator = nullptr;
1677 m_dateEditEnabled = false;
1678 navBarVisible = true;
1679 oldFocusPolicy = Qt::StrongFocus;
1680}
1681
1683{
1684 Q_Q(QCalendarWidget);
1685
1686 bool navigatorEnabled = (m_navigator->widget() != nullptr);
1687 if (enable == navigatorEnabled)
1688 return;
1689
1690 if (enable) {
1691 m_navigator->setWidget(q);
1692 q->connect(m_navigator, SIGNAL(dateChanged(QDate)),
1693 q, SLOT(_q_slotChangeDate(QDate)));
1694 q->connect(m_navigator, SIGNAL(editingFinished()),
1695 q, SLOT(_q_editingFinished()));
1696 m_view->installEventFilter(m_navigator);
1697 } else {
1698 m_navigator->setWidget(nullptr);
1699 q->disconnect(m_navigator, SIGNAL(dateChanged(QDate)),
1700 q, SLOT(_q_slotChangeDate(QDate)));
1701 q->disconnect(m_navigator, SIGNAL(editingFinished()),
1702 q, SLOT(_q_editingFinished()));
1703 m_view->removeEventFilter(m_navigator);
1704 }
1705}
1706
1708{
1709 Q_Q(QCalendarWidget);
1710 navBarBackground = new QWidget(widget);
1711 navBarBackground->setObjectName("qt_calendar_navigationbar"_L1);
1712 navBarBackground->setAutoFillBackground(true);
1713 navBarBackground->setBackgroundRole(QPalette::Highlight);
1714
1715 prevMonth = new QPrevNextCalButton(navBarBackground);
1716 nextMonth = new QPrevNextCalButton(navBarBackground);
1717 prevMonth->setAutoRaise(true);
1718 nextMonth->setAutoRaise(true);
1719 prevMonth->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1720 nextMonth->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1721 nextMonth->setAutoRaise(true);
1723 prevMonth->setAutoRepeat(true);
1724 nextMonth->setAutoRepeat(true);
1725
1726 monthButton = new QCalToolButton(navBarBackground);
1727 monthButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1728 monthButton->setAutoRaise(true);
1729 monthButton->setPopupMode(QToolButton::InstantPopup);
1730 monthMenu = new QMenu(monthButton);
1731 for (int i = 1, e = m_model->m_calendar.maximumMonthsInYear(); i <= e; i++) {
1732 QString monthName(m_model->monthName(q->locale(), i));
1733 QAction *act = monthMenu->addAction(monthName);
1734 act->setData(i);
1735 monthToAction[i] = act;
1736 }
1737 monthButton->setMenu(monthMenu);
1738 yearButton = new QCalToolButton(navBarBackground);
1739 yearButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1740 yearButton->setAutoRaise(true);
1741 yearEdit = new QSpinBox(navBarBackground);
1742
1743 QFont font = q->font();
1744 font.setBold(true);
1745 monthButton->setFont(font);
1746 yearButton->setFont(font);
1747 yearEdit->setFrame(false);
1748 yearEdit->setMinimum(m_model->m_minimumDate.year(m_model->m_calendar));
1749 yearEdit->setMaximum(m_model->m_maximumDate.year(m_model->m_calendar));
1750 yearEdit->hide();
1751 spaceHolder = new QSpacerItem(0,0);
1752
1753 QHBoxLayout *headerLayout = new QHBoxLayout;
1754 headerLayout->setContentsMargins(QMargins());
1755 headerLayout->setSpacing(0);
1756 headerLayout->addWidget(prevMonth);
1757 headerLayout->insertStretch(headerLayout->count());
1758 headerLayout->addWidget(monthButton);
1759 headerLayout->addItem(spaceHolder);
1760 headerLayout->addWidget(yearButton);
1761 headerLayout->insertStretch(headerLayout->count());
1762 headerLayout->addWidget(nextMonth);
1763 navBarBackground->setLayout(headerLayout);
1764
1765 yearEdit->setFocusPolicy(Qt::StrongFocus);
1766 prevMonth->setFocusPolicy(Qt::NoFocus);
1767 nextMonth->setFocusPolicy(Qt::NoFocus);
1768 yearButton->setFocusPolicy(Qt::NoFocus);
1769 monthButton->setFocusPolicy(Qt::NoFocus);
1770
1771 //set names for the header controls.
1772 prevMonth->setObjectName("qt_calendar_prevmonth"_L1);
1773 nextMonth->setObjectName("qt_calendar_nextmonth"_L1);
1774 monthButton->setObjectName("qt_calendar_monthbutton"_L1);
1775 yearButton->setObjectName("qt_calendar_yearbutton"_L1);
1776 yearEdit->setObjectName("qt_calendar_yearedit"_L1);
1777
1779 showMonth(m_model->m_date.year(m_model->m_calendar), m_model->m_date.month(m_model->m_calendar));
1780}
1781
1783{
1784 Q_Q(QCalendarWidget);
1785 prevMonth->setIcon(q->style()->standardIcon(q->isRightToLeft() ? QStyle::SP_ArrowRight : QStyle::SP_ArrowLeft, nullptr, q));
1786 nextMonth->setIcon(q->style()->standardIcon(q->isRightToLeft() ? QStyle::SP_ArrowLeft : QStyle::SP_ArrowRight, nullptr, q));
1787}
1788
1790{
1791 int maxMonths = m_model->m_calendar.monthsInYear(m_model->m_shownYear);
1792 int beg = 1, end = maxMonths;
1793 bool prevEnabled = true;
1794 bool nextEnabled = true;
1795 QCalendar cal = m_model->calendar();
1796 if (m_model->m_shownYear == m_model->m_minimumDate.year(cal)) {
1797 beg = m_model->m_minimumDate.month(cal);
1798 if (m_model->m_shownMonth == m_model->m_minimumDate.month(cal))
1799 prevEnabled = false;
1800 }
1801 if (m_model->m_shownYear == m_model->m_maximumDate.year(cal)) {
1802 end = m_model->m_maximumDate.month(cal);
1803 if (m_model->m_shownMonth == m_model->m_maximumDate.month(cal))
1804 nextEnabled = false;
1805 }
1806 prevMonth->setEnabled(prevEnabled);
1807 nextMonth->setEnabled(nextEnabled);
1808 for (int i = 1; i <= maxMonths; i++) {
1809 bool monthEnabled = true;
1810 if (i < beg || i > end)
1811 monthEnabled = false;
1812 monthToAction[i]->setEnabled(monthEnabled);
1813 }
1814}
1815
1817{
1818 Q_Q(QCalendarWidget);
1819
1820 for (int i = 1; i <= 12; i++) {
1821 QString monthName(m_model->monthName(q->locale(), i));
1822 monthToAction[i]->setText(monthName);
1823 }
1824}
1825
1827{
1828 Q_Q(QCalendarWidget);
1829 QCalendar cal = m_model->calendar();
1830
1831 QDate newDate = date;
1832 QDate minDate = q->minimumDate();
1833 QDate maxDate = q->maximumDate();
1834 if (minDate.isValid()&& minDate.daysTo(newDate) < 0)
1835 newDate = minDate;
1836 if (maxDate.isValid()&& maxDate.daysTo(newDate) > 0)
1837 newDate = maxDate;
1838 showMonth(newDate.year(cal), newDate.month(cal));
1839 int row = -1, col = -1;
1840 m_model->cellForDate(newDate, &row, &col);
1841 if (row != -1 && col != -1)
1842 {
1843 m_view->selectionModel()->setCurrentIndex(m_model->index(row, col),
1844 QItemSelectionModel::NoUpdate);
1845 }
1846}
1847
1849{
1850 monthButton->setText(act->text());
1851 QDate currentDate = getCurrentDate();
1852 QDate newDate = currentDate.addMonths(act->data().toInt() - currentDate.month(m_model->m_calendar), m_model->m_calendar);
1853 updateCurrentPage(newDate);
1854}
1855
1857{
1858 QModelIndex index = m_view->currentIndex();
1859 return m_model->dateForCell(index.row(), index.column());
1860}
1861
1863{
1864 QDate currentDate = getCurrentDate().addMonths(-1, m_model->m_calendar);
1865 updateCurrentPage(currentDate);
1866}
1867
1869{
1870 QDate currentDate = getCurrentDate().addMonths(1, m_model->m_calendar);
1871 updateCurrentPage(currentDate);
1872}
1873
1875{
1876 Q_Q(QCalendarWidget);
1877 yearEdit->hide();
1878 q->setFocusPolicy(oldFocusPolicy);
1879 qApp->removeEventFilter(q);
1880 spaceHolder->changeSize(0, 0);
1881 yearButton->show();
1882 QDate currentDate = getCurrentDate();
1883 int newYear = q->locale().toInt(yearEdit->text());
1884 currentDate = currentDate.addYears(newYear - currentDate.year(m_model->m_calendar), m_model->m_calendar);
1885 yearButton->setText(q->locale().toString(currentDate, u"yyyy", m_model->m_calendar));
1886 updateCurrentPage(currentDate);
1887}
1888
1890{
1891 Q_Q(QCalendarWidget);
1892 //show the spinbox on top of the button
1893 yearEdit->setGeometry(yearButton->x(), yearButton->y(),
1894 yearEdit->sizeHint().width(), yearButton->height());
1895 spaceHolder->changeSize(yearButton->width(), 0);
1896 yearButton->hide();
1897 oldFocusPolicy = q->focusPolicy();
1898 q->setFocusPolicy(Qt::NoFocus);
1899 yearEdit->show();
1900 qApp->installEventFilter(q);
1901 yearEdit->raise();
1902 yearEdit->selectAll();
1903 yearEdit->setFocus(Qt::MouseFocusReason);
1904}
1905
1906void QCalendarWidgetPrivate::showMonth(int year, int month)
1907{
1908 if (m_model->m_shownYear == year && m_model->m_shownMonth == month)
1909 return;
1910 Q_Q(QCalendarWidget);
1911 m_model->showMonth(year, month);
1913 emit q->currentPageChanged(year, month);
1915 cachedSizeHint = QSize();
1916 update();
1918}
1919
1921{
1922 Q_Q(QCalendarWidget);
1923
1924 QString monthName = m_model->monthName(q->locale(), m_model->m_shownMonth);
1925
1926 monthButton->setText(monthName);
1927 yearEdit->setValue(m_model->m_shownYear);
1928 yearButton->setText(yearEdit->text());
1929}
1930
1932{
1933 QDate currentDate = m_model->m_date;
1934 int row, column;
1935 m_model->cellForDate(currentDate, &row, &column);
1936 QModelIndex idx;
1937 m_selection->clear();
1938 if (row != -1 && column != -1) {
1939 idx = m_model->index(row, column);
1940 m_selection->setCurrentIndex(idx, QItemSelectionModel::SelectCurrent);
1941 }
1942}
1943
1944void QCalendarWidgetPrivate::paintCell(QPainter *painter, const QRect &rect, QDate date) const
1945{
1946 Q_Q(const QCalendarWidget);
1947 q->paintCell(painter, rect, date);
1948}
1949
1951{
1953}
1954
1956{
1957 _q_slotChangeDate(date, true);
1958}
1959
1960void QCalendarWidgetPrivate::_q_slotChangeDate(QDate date, bool changeMonth)
1961{
1962 QDate oldDate = m_model->m_date;
1964 QDate newDate = m_model->m_date;
1965 if (changeMonth)
1966 showMonth(newDate.year(m_model->m_calendar), newDate.month(m_model->m_calendar));
1967 if (oldDate != newDate) {
1968 update();
1969 Q_Q(QCalendarWidget);
1971 emit q->selectionChanged();
1972 }
1973}
1974
1976{
1977 Q_Q(QCalendarWidget);
1978 emit q->activated(m_model->m_date);
1979}
1980
1981/*!
1982 \class QCalendarWidget
1983 \brief The QCalendarWidget class provides a monthly based
1984 calendar widget allowing the user to select a date.
1985 \since 4.2
1986
1987 \ingroup advanced
1988 \inmodule QtWidgets
1989
1990 \image fusion-calendarwidget.png
1991 {Calendar widget showing the month, year, and a selected day}
1992
1993 The widget is initialized with the current month and year, but
1994 QCalendarWidget provides several public slots to change the year
1995 and month that is shown.
1996
1997 By default, today's date is selected, and the user can select a
1998 date using both mouse and keyboard. The currently selected date
1999 can be retrieved using the selectedDate() function. It is
2000 possible to constrain the user selection to a given date range by
2001 setting the minimumDate and maximumDate properties.
2002 Alternatively, both properties can be set in one go using the
2003 setDateRange() convenience slot. Set the \l selectionMode
2004 property to NoSelection to prohibit the user from selecting at
2005 all. Note that a date also can be selected programmatically using
2006 the setSelectedDate() slot.
2007
2008 The currently displayed month and year can be retrieved using the
2009 monthShown() and yearShown() functions, respectively.
2010
2011 A newly created calendar widget uses abbreviated day names, and
2012 both Saturdays and Sundays are marked in red. The calendar grid is
2013 not visible. The week numbers are displayed, and the first column
2014 day is the first day of the week for the calendar's locale.
2015
2016 The notation of the days can be altered to a single letter
2017 abbreviations ("M" for "Monday") by setting the
2018 horizontalHeaderFormat property to
2019 QCalendarWidget::SingleLetterDayNames. Setting the same property
2020 to QCalendarWidget::LongDayNames makes the header display the
2021 complete day names. The week numbers can be removed by setting
2022 the verticalHeaderFormat property to
2023 QCalendarWidget::NoVerticalHeader. The calendar grid can be
2024 turned on by setting the gridVisible property to true using the
2025 setGridVisible() function:
2026
2027 \table
2028 \row \li
2029 \image qcalendarwidget-grid.png
2030 {Calendar widget with a visible grid}
2031 \row \li
2032 \snippet code/src_gui_widgets_qcalendarwidget.cpp 0
2033 \endtable
2034
2035 Finally, the day in the first column can be altered using the
2036 setFirstDayOfWeek() function.
2037
2038 The QCalendarWidget class also provides three signals,
2039 selectionChanged(), activated() and currentPageChanged() making it
2040 possible to respond to user interaction.
2041
2042 The rendering of the headers, weekdays or single days can be
2043 largely customized by setting QTextCharFormat's for some special
2044 weekday, a special date or for the rendering of the headers.
2045
2046 Only a subset of the properties in QTextCharFormat are used by the
2047 calendar widget. Currently, the foreground, background and font
2048 properties are used to determine the rendering of individual cells
2049 in the widget.
2050
2051 \sa QDate, QDateEdit, QTextCharFormat
2052*/
2053
2054/*!
2055 \enum QCalendarWidget::SelectionMode
2056
2057 This enum describes the types of selection offered to the user for
2058 selecting dates in the calendar.
2059
2060 \value NoSelection Dates cannot be selected.
2061 \value SingleSelection Single dates can be selected.
2062
2063 \sa selectionMode
2064*/
2065
2066/*!
2067 Constructs a calendar widget with the given \a parent.
2068
2069 The widget is initialized with the current month and year, and the
2070 currently selected date is today.
2071
2072 \sa setCurrentPage()
2073*/
2074QCalendarWidget::QCalendarWidget(QWidget *parent)
2075 : QWidget(*new QCalendarWidgetPrivate, parent, { })
2076{
2077 Q_D(QCalendarWidget);
2078
2079 setAutoFillBackground(true);
2080 setBackgroundRole(QPalette::Window);
2081
2082 QVBoxLayout *layoutV = new QVBoxLayout(this);
2083 layoutV->setContentsMargins(QMargins());
2084 d->m_model = new QCalendarModel(this);
2085 QTextCharFormat fmt;
2086 fmt.setForeground(QBrush(Qt::red));
2087 d->m_model->m_dayFormats.insert(Qt::Saturday, fmt);
2088 d->m_model->m_dayFormats.insert(Qt::Sunday, fmt);
2089 d->m_view = new QCalendarView(this);
2090 d->m_view->setObjectName("qt_calendar_calendarview"_L1);
2091 d->m_view->setModel(d->m_model);
2092 d->m_model->setView(d->m_view);
2093 d->m_view->setSelectionBehavior(QAbstractItemView::SelectItems);
2094 d->m_view->setSelectionMode(QAbstractItemView::SingleSelection);
2095 d->m_view->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
2096 d->m_view->horizontalHeader()->setSectionsClickable(false);
2097 d->m_view->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
2098 d->m_view->verticalHeader()->setSectionsClickable(false);
2099 d->m_selection = d->m_view->selectionModel();
2100 d->createNavigationBar(this);
2101 d->m_view->setFrameStyle(QFrame::NoFrame);
2102 d->m_delegate = new QCalendarDelegate(d, this);
2103 d->m_view->setItemDelegate(d->m_delegate);
2104 d->update();
2105 d->updateNavigationBar();
2106 setFocusPolicy(Qt::StrongFocus);
2107 setFocusProxy(d->m_view);
2108 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
2109
2110 connect(d->m_view, SIGNAL(showDate(QDate)),
2111 this, SLOT(_q_slotShowDate(QDate)));
2112 connect(d->m_view, SIGNAL(changeDate(QDate,bool)),
2113 this, SLOT(_q_slotChangeDate(QDate,bool)));
2114 connect(d->m_view, SIGNAL(dateClicked(QDate)),
2115 this, SIGNAL(clicked(QDate)));
2116 connect(d->m_view, SIGNAL(editingFinished()),
2117 this, SLOT(_q_editingFinished()));
2118
2119 connect(d->prevMonth, SIGNAL(clicked(bool)),
2120 this, SLOT(_q_prevMonthClicked()));
2121 connect(d->nextMonth, SIGNAL(clicked(bool)),
2122 this, SLOT(_q_nextMonthClicked()));
2123 connect(d->yearButton, SIGNAL(clicked(bool)),
2124 this, SLOT(_q_yearClicked()));
2125 connect(d->monthMenu, SIGNAL(triggered(QAction*)),
2126 this, SLOT(_q_monthChanged(QAction*)));
2127 connect(d->yearEdit, SIGNAL(editingFinished()),
2128 this, SLOT(_q_yearEditingFinished()));
2129
2130 layoutV->setContentsMargins(QMargins());
2131 layoutV->setSpacing(0);
2132 layoutV->addWidget(d->navBarBackground);
2133 layoutV->addWidget(d->m_view);
2134
2135 d->m_navigator = new QCalendarTextNavigator(this);
2136 setDateEditEnabled(true);
2137}
2138
2139/*!
2140 Destroys the calendar widget.
2141*/
2142QCalendarWidget::~QCalendarWidget()
2143{
2144}
2145
2146/*!
2147 \reimp
2148*/
2149QSize QCalendarWidget::sizeHint() const
2150{
2151 return minimumSizeHint();
2152}
2153
2154/*!
2155 \reimp
2156*/
2157QSize QCalendarWidget::minimumSizeHint() const
2158{
2159 Q_D(const QCalendarWidget);
2160 if (d->cachedSizeHint.isValid())
2161 return d->cachedSizeHint;
2162
2163 ensurePolished();
2164
2165 int w = 0;
2166 int h = 0;
2167
2168 int end = 53;
2169 int rows = 7;
2170 int cols = 8;
2171
2172 QStyleOption option;
2173 option.initFrom(this);
2174 const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, this) + 1) * 2;
2175
2176 if (horizontalHeaderFormat() == QCalendarWidget::NoHorizontalHeader) {
2177 rows = 6;
2178 } else {
2179 for (int i = 1; i <= 7; i++) {
2180 QFontMetrics fm(d->m_model->formatForCell(0, i).font());
2181 w = qMax(w, fm.horizontalAdvance(d->m_model->dayName(d->m_model->dayOfWeekForColumn(i))) + marginH);
2182 h = qMax(h, fm.height());
2183 }
2184 }
2185
2186 if (verticalHeaderFormat() == QCalendarWidget::NoVerticalHeader) {
2187 cols = 7;
2188 } else {
2189 for (int i = 1; i <= 6; i++) {
2190 QFontMetrics fm(d->m_model->formatForCell(i, 0).font());
2191 for (int j = 1; j < end; j++)
2192 w = qMax(w, fm.horizontalAdvance(QString::number(j)) + marginH);
2193 h = qMax(h, fm.height());
2194 }
2195 }
2196
2197 QFontMetrics fm(d->m_model->formatForCell(1, 1).font());
2198 for (int i = 1; i <= end; i++) {
2199 w = qMax(w, fm.horizontalAdvance(QString::number(i)) + marginH);
2200 h = qMax(h, fm.height());
2201 }
2202
2203 if (d->m_view->showGrid()) {
2204 // hardcoded in tableview
2205 w += 1;
2206 h += 1;
2207 }
2208
2209 w += 1; // default column span
2210
2211 h = qMax(h, d->m_view->verticalHeader()->minimumSectionSize());
2212 w = qMax(w, d->m_view->horizontalHeader()->minimumSectionSize());
2213
2214 //add the size of the header.
2215 QSize headerSize(0, 0);
2216 if (d->navBarVisible) {
2217 int headerH = d->navBarBackground->sizeHint().height();
2218 int headerW = 0;
2219
2220 headerW += d->prevMonth->sizeHint().width();
2221 headerW += d->nextMonth->sizeHint().width();
2222
2223 QFontMetrics fm = d->monthButton->fontMetrics();
2224 int monthW = 0;
2225 for (int i = 1; i < 12; i++) {
2226 QString monthName = d->m_model->monthName(locale(), i);
2227 monthW = qMax(monthW, fm.boundingRect(monthName).width());
2228 }
2229 const int buttonDecoMargin = d->monthButton->sizeHint().width() - fm.boundingRect(d->monthButton->text()).width();
2230 headerW += monthW + buttonDecoMargin;
2231
2232 fm = d->yearButton->fontMetrics();
2233 headerW += fm.boundingRect("5555"_L1).width() + buttonDecoMargin;
2234
2235 headerSize = QSize(headerW, headerH);
2236 }
2237 w *= cols;
2238 w = qMax(headerSize.width(), w);
2239 h = (h * rows) + headerSize.height();
2240 QMargins cm = contentsMargins();
2241 w += cm.left() + cm.right();
2242 h += cm.top() + cm.bottom();
2243 d->cachedSizeHint = QSize(w, h);
2244 return d->cachedSizeHint;
2245}
2246
2247/*!
2248 Paints the cell specified by the given \a date, using the given \a painter and \a rect.
2249*/
2250
2251void QCalendarWidget::paintCell(QPainter *painter, const QRect &rect, QDate date) const
2252{
2253 Q_D(const QCalendarWidget);
2254 d->m_delegate->paintCell(painter, rect, date);
2255}
2256
2257/*!
2258 \property QCalendarWidget::selectedDate
2259 \brief the currently selected date.
2260
2261 The selected date must be within the date range specified by the
2262 minimumDate and maximumDate properties. By default, the selected
2263 date is the current date.
2264
2265 \sa setDateRange()
2266*/
2267
2268QDate QCalendarWidget::selectedDate() const
2269{
2270 Q_D(const QCalendarWidget);
2271 return d->m_model->m_date;
2272}
2273
2274void QCalendarWidget::setSelectedDate(QDate date)
2275{
2276 Q_D(QCalendarWidget);
2277 if (d->m_model->m_date == date && date == d->getCurrentDate())
2278 return;
2279
2280 if (!date.isValid())
2281 return;
2282
2283 d->m_model->setDate(date);
2284 d->update();
2285 QDate newDate = d->m_model->m_date;
2286 QCalendar cal = d->m_model->m_calendar;
2287 d->showMonth(newDate.year(cal), newDate.month(cal));
2288 emit selectionChanged();
2289}
2290
2291/*!
2292 Returns the year of the currently displayed month. Months are
2293 numbered from 1 to 12.
2294
2295 \sa monthShown(), setCurrentPage()
2296*/
2297
2298int QCalendarWidget::yearShown() const
2299{
2300 Q_D(const QCalendarWidget);
2301 return d->m_model->m_shownYear;
2302}
2303
2304/*!
2305 Returns the currently displayed month. Months are numbered from 1 to
2306 12.
2307
2308 \sa yearShown(), setCurrentPage()
2309*/
2310
2311int QCalendarWidget::monthShown() const
2312{
2313 Q_D(const QCalendarWidget);
2314 return d->m_model->m_shownMonth;
2315}
2316
2317/*!
2318 Displays the given \a month of the given \a year without changing
2319 the selected date. Use the setSelectedDate() function to alter the
2320 selected date.
2321
2322 The currently displayed month and year can be retrieved using the
2323 monthShown() and yearShown() functions respectively.
2324
2325 \sa yearShown(), monthShown(), showPreviousMonth(), showNextMonth(),
2326 showPreviousYear(), showNextYear()
2327*/
2328
2329void QCalendarWidget::setCurrentPage(int year, int month)
2330{
2331 Q_D(QCalendarWidget);
2332 QDate currentDate = d->getCurrentDate();
2333 QCalendar cal = d->m_model->m_calendar;
2334 int day = currentDate.day(cal);
2335 int daysInMonths = cal.daysInMonth(month, year);
2336 if (day > daysInMonths)
2337 day = daysInMonths;
2338
2339 d->showMonth(year, month);
2340
2341 QDate newDate(year, month, day, d->m_model->m_calendar);
2342 int row = -1, col = -1;
2343 d->m_model->cellForDate(newDate, &row, &col);
2344 if (row != -1 && col != -1) {
2345 d->m_view->selectionModel()->setCurrentIndex(d->m_model->index(row, col),
2346 QItemSelectionModel::NoUpdate);
2347 }
2348}
2349
2350/*!
2351 Shows the next month relative to the currently displayed
2352 month. Note that the selected date is not changed.
2353
2354 \sa showPreviousMonth(), setCurrentPage(), setSelectedDate()
2355*/
2356
2357void QCalendarWidget::showNextMonth()
2358{
2359 Q_D(const QCalendarWidget);
2360 int year = yearShown();
2361 int month = monthShown();
2362 if (month == d->m_model->m_calendar.maximumMonthsInYear()) {
2363 ++year;
2364 month = 1;
2365 } else {
2366 ++month;
2367 }
2368 setCurrentPage(year, month);
2369}
2370
2371/*!
2372 Shows the previous month relative to the currently displayed
2373 month. Note that the selected date is not changed.
2374
2375 \sa showNextMonth(), setCurrentPage(), setSelectedDate()
2376*/
2377
2378void QCalendarWidget::showPreviousMonth()
2379{
2380 Q_D(const QCalendarWidget);
2381
2382 int year = yearShown();
2383 int month = monthShown();
2384 if (month == 1) {
2385 --year;
2386 month = d->m_model->m_calendar.maximumMonthsInYear();
2387 } else {
2388 --month;
2389 }
2390 setCurrentPage(year, month);
2391}
2392
2393/*!
2394 Shows the currently displayed month in the \e next year relative
2395 to the currently displayed year. Note that the selected date is
2396 not changed.
2397
2398 \sa showPreviousYear(), setCurrentPage(), setSelectedDate()
2399*/
2400
2401void QCalendarWidget::showNextYear()
2402{
2403 int year = yearShown();
2404 int month = monthShown();
2405 ++year;
2406 setCurrentPage(year, month);
2407}
2408
2409/*!
2410 Shows the currently displayed month in the \e previous year
2411 relative to the currently displayed year. Note that the selected
2412 date is not changed.
2413
2414 \sa showNextYear(), setCurrentPage(), setSelectedDate()
2415*/
2416
2417void QCalendarWidget::showPreviousYear()
2418{
2419 int year = yearShown();
2420 int month = monthShown();
2421 --year;
2422 setCurrentPage(year, month);
2423}
2424
2425/*!
2426 Shows the month of the selected date.
2427
2428 \sa selectedDate(), setCurrentPage()
2429*/
2430void QCalendarWidget::showSelectedDate()
2431{
2432 Q_D(const QCalendarWidget);
2433
2434 QDate currentDate = selectedDate();
2435 setCurrentPage(currentDate.year(d->m_model->m_calendar), currentDate.month(d->m_model->m_calendar));
2436}
2437
2438/*!
2439 Shows the month of the today's date.
2440
2441 \sa selectedDate(), setCurrentPage()
2442*/
2443void QCalendarWidget::showToday()
2444{
2445 Q_D(const QCalendarWidget);
2446
2447 QDate currentDate = QDate::currentDate();
2448 setCurrentPage(currentDate.year(d->m_model->m_calendar), currentDate.month(d->m_model->m_calendar));
2449}
2450
2451/*!
2452 \property QCalendarWidget::minimumDate
2453 \brief the minimum date of the currently specified date range.
2454
2455 The user will not be able to select a date that is before the
2456 currently set minimum date.
2457
2458 \table
2459 \row
2460 \li \image qcalendarwidget-minimum.png
2461 {Calendar widget with the disabled dates before the minimum date}
2462 \row
2463 \li
2464 \snippet code/src_gui_widgets_qcalendarwidget.cpp 1
2465 \endtable
2466
2467 When setting a minimum date, the maximumDate and selectedDate
2468 properties are adjusted if the selection range becomes invalid. If
2469 the provided date is not a valid QDate object, the
2470 setMinimumDate() function does nothing.
2471
2472 The default minimum date is November 25, 4714 BCE.
2473 You can restore this default by calling clearMinimumDate() (since Qt 6.6).
2474
2475 \sa setDateRange()
2476*/
2477
2478QDate QCalendarWidget::minimumDate() const
2479{
2480 Q_D(const QCalendarWidget);
2481 return d->m_model->m_minimumDate;
2482}
2483
2484void QCalendarWidget::setMinimumDate(QDate date)
2485{
2486 Q_D(QCalendarWidget);
2487 if (!date.isValid() || d->m_model->m_minimumDate == date)
2488 return;
2489
2490 QDate oldDate = d->m_model->m_date;
2491 d->m_model->setMinimumDate(date);
2492 d->yearEdit->setMinimum(d->m_model->m_minimumDate.year(d->m_model->m_calendar));
2493 d->updateMonthMenu();
2494 QDate newDate = d->m_model->m_date;
2495 if (oldDate != newDate) {
2496 d->update();
2497 d->showMonth(newDate.year(d->m_model->m_calendar), newDate.month(d->m_model->m_calendar));
2498 d->m_navigator->setDate(newDate);
2499 emit selectionChanged();
2500 }
2501}
2502
2503void QCalendarWidget::clearMinimumDate()
2504{
2505 setMinimumDate(QDate::fromJulianDay(1));
2506}
2507
2508/*!
2509 \property QCalendarWidget::maximumDate
2510 \brief the maximum date of the currently specified date range.
2511
2512 The user will not be able to select a date which is after the
2513 currently set maximum date.
2514
2515 \table
2516 \row
2517 \li \image qcalendarwidget-maximum.png
2518 {Calendar widget with the disabled dates after the maximum date}
2519 \row
2520 \li
2521 \snippet code/src_gui_widgets_qcalendarwidget.cpp 2
2522 \endtable
2523
2524 When setting a maximum date, the minimumDate and selectedDate
2525 properties are adjusted if the selection range becomes invalid. If
2526 the provided date is not a valid QDate object, the
2527 setMaximumDate() function does nothing.
2528
2529 The default maximum date is December 31, 9999 CE.
2530 You can restore this default by calling clearMaximumDate() (since Qt 6.6).
2531
2532 \sa setDateRange()
2533*/
2534
2535QDate QCalendarWidget::maximumDate() const
2536{
2537 Q_D(const QCalendarWidget);
2538 return d->m_model->m_maximumDate;
2539}
2540
2541void QCalendarWidget::setMaximumDate(QDate date)
2542{
2543 Q_D(QCalendarWidget);
2544 if (!date.isValid() || d->m_model->m_maximumDate == date)
2545 return;
2546
2547 QDate oldDate = d->m_model->m_date;
2548 d->m_model->setMaximumDate(date);
2549 d->yearEdit->setMaximum(d->m_model->m_maximumDate.year(d->m_model->m_calendar));
2550 d->updateMonthMenu();
2551 QDate newDate = d->m_model->m_date;
2552 if (oldDate != newDate) {
2553 d->update();
2554 d->showMonth(newDate.year(d->m_model->m_calendar), newDate.month(d->m_model->m_calendar));
2555 d->m_navigator->setDate(newDate);
2556 emit selectionChanged();
2557 }
2558}
2559
2560void QCalendarWidget::clearMaximumDate()
2561{
2562 setMaximumDate(QDate(9999, 12, 31));
2563}
2564
2565/*!
2566 Defines a date range by setting the minimumDate and maximumDate
2567 properties.
2568
2569 The date range restricts the user selection, i.e. the user can
2570 only select dates within the specified date range. Note that
2571
2572 \snippet code/src_gui_widgets_qcalendarwidget.cpp 3
2573
2574 is analogous to
2575
2576 \snippet code/src_gui_widgets_qcalendarwidget.cpp 4
2577
2578 If either the \a min or \a max parameters are not valid QDate
2579 objects, this function does nothing.
2580
2581 \sa setMinimumDate(), setMaximumDate()
2582*/
2583
2584void QCalendarWidget::setDateRange(QDate min, QDate max)
2585{
2586 Q_D(QCalendarWidget);
2587 if (d->m_model->m_minimumDate == min && d->m_model->m_maximumDate == max)
2588 return;
2589 if (!min.isValid() || !max.isValid())
2590 return;
2591
2592 QDate oldDate = d->m_model->m_date;
2593 d->m_model->setRange(min, max);
2594 d->yearEdit->setMinimum(d->m_model->m_minimumDate.year(d->m_model->m_calendar));
2595 d->yearEdit->setMaximum(d->m_model->m_maximumDate.year(d->m_model->m_calendar));
2596 d->updateMonthMenu();
2597 QDate newDate = d->m_model->m_date;
2598 if (oldDate != newDate) {
2599 d->update();
2600 d->showMonth(newDate.year(d->m_model->m_calendar), newDate.month(d->m_model->m_calendar));
2601 d->m_navigator->setDate(newDate);
2602 emit selectionChanged();
2603 }
2604}
2605
2606
2607/*! \enum QCalendarWidget::HorizontalHeaderFormat
2608
2609 This enum type defines the various formats the horizontal header can display.
2610
2611 \value SingleLetterDayNames The header displays a single letter abbreviation for day names (e.g. M for Monday).
2612 \value ShortDayNames The header displays a short abbreviation for day names (e.g. Mon for Monday).
2613 \value LongDayNames The header displays complete day names (e.g. Monday).
2614 \value NoHorizontalHeader The header is hidden.
2615
2616 \sa horizontalHeaderFormat(), VerticalHeaderFormat
2617*/
2618
2619/*!
2620 \property QCalendarWidget::horizontalHeaderFormat
2621 \brief the format of the horizontal header.
2622
2623 The default value is QCalendarWidget::ShortDayNames.
2624*/
2625
2626void QCalendarWidget::setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format)
2627{
2628 Q_D(QCalendarWidget);
2629 if (d->m_model->m_horizontalHeaderFormat == format)
2630 return;
2631
2632 d->m_model->setHorizontalHeaderFormat(format);
2633 d->cachedSizeHint = QSize();
2634 d->m_view->viewport()->update();
2635 d->m_view->updateGeometry();
2636}
2637
2638QCalendarWidget::HorizontalHeaderFormat QCalendarWidget::horizontalHeaderFormat() const
2639{
2640 Q_D(const QCalendarWidget);
2641 return d->m_model->m_horizontalHeaderFormat;
2642}
2643
2644
2645/*!
2646 \enum QCalendarWidget::VerticalHeaderFormat
2647
2648 This enum type defines the various formats the vertical header can display.
2649
2650 \value ISOWeekNumbers The header displays ISO week numbers as described by \l QDate::weekNumber().
2651 \value NoVerticalHeader The header is hidden.
2652
2653 \sa verticalHeaderFormat(), HorizontalHeaderFormat
2654*/
2655
2656/*!
2657 \property QCalendarWidget::verticalHeaderFormat
2658 \brief the format of the vertical header.
2659
2660 The default value is QCalendarWidget::ISOWeekNumber.
2661*/
2662
2663QCalendarWidget::VerticalHeaderFormat QCalendarWidget::verticalHeaderFormat() const
2664{
2665 Q_D(const QCalendarWidget);
2666 bool shown = d->m_model->weekNumbersShown();
2667 if (shown)
2668 return QCalendarWidget::ISOWeekNumbers;
2669 return QCalendarWidget::NoVerticalHeader;
2670}
2671
2672void QCalendarWidget::setVerticalHeaderFormat(QCalendarWidget::VerticalHeaderFormat format)
2673{
2674 Q_D(QCalendarWidget);
2675 bool show = false;
2676 if (format == QCalendarWidget::ISOWeekNumbers)
2677 show = true;
2678 if (d->m_model->weekNumbersShown() == show)
2679 return;
2680 d->m_model->setWeekNumbersShown(show);
2681 d->cachedSizeHint = QSize();
2682 d->m_view->viewport()->update();
2683 d->m_view->updateGeometry();
2684}
2685
2686/*!
2687 \property QCalendarWidget::gridVisible
2688 \brief whether the table grid is displayed.
2689
2690 \table
2691 \row
2692 \li \inlineimage qcalendarwidget-grid.png
2693 {Calendar widget set to be visible}
2694 \row
2695 \li
2696 \snippet code/src_gui_widgets_qcalendarwidget.cpp 5
2697 \endtable
2698
2699 The default value is false.
2700*/
2701
2702bool QCalendarWidget::isGridVisible() const
2703{
2704 Q_D(const QCalendarWidget);
2705 return d->m_view->showGrid();
2706}
2707
2708/*!
2709 \since 5.14
2710 Report the calendar system in use by this widget.
2711
2712 \sa setCalendar()
2713*/
2714
2715QCalendar QCalendarWidget::calendar() const
2716{
2717 Q_D(const QCalendarWidget);
2718 return d->m_model->m_calendar;
2719}
2720
2721/*!
2722 \since 5.14
2723 Set \a c as the calendar system to be used by this widget.
2724
2725 The widget can use any supported calendar system.
2726 By default, it uses the Gregorian calendar.
2727
2728 \sa calendar()
2729*/
2730
2731void QCalendarWidget::setCalendar(QCalendar c)
2732{
2733 Q_D(QCalendarWidget);
2734 d->m_model->setCalendar(c);
2735 d->updateMonthMenuNames();
2736 d->yearEdit->setMinimum(d->m_model->m_minimumDate.year(d->m_model->m_calendar));
2737 d->yearEdit->setMaximum(d->m_model->m_maximumDate.year(d->m_model->m_calendar));
2738 d->updateNavigationBar();
2739}
2740
2741void QCalendarWidget::setGridVisible(bool show)
2742{
2743 Q_D(QCalendarWidget);
2744 d->m_view->setShowGrid(show);
2745 d->cachedSizeHint = QSize();
2746 d->m_view->viewport()->update();
2747 d->m_view->updateGeometry();
2748}
2749
2750/*!
2751 \property QCalendarWidget::selectionMode
2752 \brief the type of selection the user can make in the calendar
2753
2754 When this property is set to SingleSelection, the user can select a date
2755 within the minimum and maximum allowed dates, using either the mouse or
2756 the keyboard.
2757
2758 When the property is set to NoSelection, the user will be unable to select
2759 dates, but they can still be selected programmatically. Note that the date
2760 that is selected when the property is set to NoSelection will still be
2761 the selected date of the calendar.
2762
2763 The default value is SingleSelection.
2764*/
2765
2766QCalendarWidget::SelectionMode QCalendarWidget::selectionMode() const
2767{
2768 Q_D(const QCalendarWidget);
2769 return d->m_view->readOnly ? QCalendarWidget::NoSelection : QCalendarWidget::SingleSelection;
2770}
2771
2772void QCalendarWidget::setSelectionMode(SelectionMode mode)
2773{
2774 Q_D(QCalendarWidget);
2775 d->m_view->readOnly = (mode == QCalendarWidget::NoSelection);
2776 d->setNavigatorEnabled(isDateEditEnabled() && (selectionMode() != QCalendarWidget::NoSelection));
2777 d->update();
2778}
2779
2780/*!
2781 \property QCalendarWidget::firstDayOfWeek
2782 \brief a value identifying the day displayed in the first column.
2783
2784 By default, the day displayed in the first column
2785 is the first day of the week for the calendar's locale.
2786*/
2787
2788void QCalendarWidget::setFirstDayOfWeek(Qt::DayOfWeek dayOfWeek)
2789{
2790 Q_D(QCalendarWidget);
2791 if ((Qt::DayOfWeek)d->m_model->firstColumnDay() == dayOfWeek)
2792 return;
2793
2794 d->m_model->setFirstColumnDay(dayOfWeek);
2795 d->update();
2796}
2797
2798Qt::DayOfWeek QCalendarWidget::firstDayOfWeek() const
2799{
2800 Q_D(const QCalendarWidget);
2801 return (Qt::DayOfWeek)d->m_model->firstColumnDay();
2802}
2803
2804/*!
2805 Returns the text char format for rendering the header.
2806*/
2807QTextCharFormat QCalendarWidget::headerTextFormat() const
2808{
2809 Q_D(const QCalendarWidget);
2810 return d->m_model->m_headerFormat;
2811}
2812
2813/*!
2814 Sets the text char format for rendering the header to \a format.
2815 If you also set a weekday text format, this format's foreground and
2816 background color will take precedence over the header's format.
2817 The other formatting information will still be decided by
2818 the header's format.
2819*/
2820void QCalendarWidget::setHeaderTextFormat(const QTextCharFormat &format)
2821{
2822 Q_D(QCalendarWidget);
2823 d->m_model->m_headerFormat = format;
2824 d->cachedSizeHint = QSize();
2825 d->m_view->viewport()->update();
2826 d->m_view->updateGeometry();
2827}
2828
2829/*!
2830 Returns the text char format for rendering of day in the week \a dayOfWeek.
2831
2832 \sa headerTextFormat()
2833*/
2834QTextCharFormat QCalendarWidget::weekdayTextFormat(Qt::DayOfWeek dayOfWeek) const
2835{
2836 Q_D(const QCalendarWidget);
2837 return d->m_model->m_dayFormats.value(dayOfWeek);
2838}
2839
2840/*!
2841 Sets the text char format for rendering of day in the week \a dayOfWeek to \a format.
2842 The format will take precedence over the header format in case of foreground
2843 and background color. Other text formatting information is taken from the headers format.
2844
2845 \sa setHeaderTextFormat()
2846*/
2847void QCalendarWidget::setWeekdayTextFormat(Qt::DayOfWeek dayOfWeek, const QTextCharFormat &format)
2848{
2849 Q_D(QCalendarWidget);
2850 d->m_model->m_dayFormats[dayOfWeek] = format;
2851 d->cachedSizeHint = QSize();
2852 d->m_view->viewport()->update();
2853 d->m_view->updateGeometry();
2854}
2855
2856/*!
2857 Returns a QMap from QDate to QTextCharFormat showing all dates
2858 that use a special format that alters their rendering.
2859*/
2860QMap<QDate, QTextCharFormat> QCalendarWidget::dateTextFormat() const
2861{
2862 Q_D(const QCalendarWidget);
2863 return d->m_model->m_dateFormats;
2864}
2865
2866/*!
2867 Returns a QTextCharFormat for \a date. The char format can be
2868 empty if the date is not rendered specially.
2869*/
2870QTextCharFormat QCalendarWidget::dateTextFormat(QDate date) const
2871{
2872 Q_D(const QCalendarWidget);
2873 return d->m_model->m_dateFormats.value(date);
2874}
2875
2876/*!
2877 Sets the format used to render the given \a date to that specified by \a format.
2878
2879 If \a date is null, all date formats are cleared.
2880*/
2881void QCalendarWidget::setDateTextFormat(QDate date, const QTextCharFormat &format)
2882{
2883 Q_D(QCalendarWidget);
2884 if (date.isNull())
2885 d->m_model->m_dateFormats.clear();
2886 else
2887 d->m_model->m_dateFormats[date] = format;
2888 d->m_view->viewport()->update();
2889 d->m_view->updateGeometry();
2890}
2891
2892/*!
2893 \property QCalendarWidget::dateEditEnabled
2894 \brief whether the date edit popup is enabled
2895 \since 4.3
2896
2897 If this property is enabled, pressing a non-modifier key will cause a
2898 date edit to popup if the calendar widget has focus, allowing the user
2899 to specify a date in the form specified by the current locale.
2900
2901 By default, this property is enabled.
2902
2903 The date edit is simpler in appearance than QDateEdit, but allows the
2904 user to navigate between fields using the left and right cursor keys,
2905 increment and decrement individual fields using the up and down cursor
2906 keys, and enter values directly using the number keys.
2907
2908 \sa QCalendarWidget::dateEditAcceptDelay
2909*/
2910bool QCalendarWidget::isDateEditEnabled() const
2911{
2912 Q_D(const QCalendarWidget);
2913 return d->m_dateEditEnabled;
2914}
2915
2916void QCalendarWidget::setDateEditEnabled(bool enable)
2917{
2918 Q_D(QCalendarWidget);
2919 if (isDateEditEnabled() == enable)
2920 return;
2921
2922 d->m_dateEditEnabled = enable;
2923
2924 d->setNavigatorEnabled(enable && (selectionMode() != QCalendarWidget::NoSelection));
2925}
2926
2927/*!
2928 \property QCalendarWidget::dateEditAcceptDelay
2929 \brief the time an inactive date edit is shown before its contents are accepted
2930 \since 4.3
2931
2932 If the calendar widget's \l{dateEditEnabled}{date edit is enabled}, this
2933 property specifies the amount of time (in milliseconds) that the date edit
2934 remains open after the most recent user input. Once this time has elapsed,
2935 the date specified in the date edit is accepted and the popup is closed.
2936
2937 By default, the delay is defined to be 1500 milliseconds (1.5 seconds).
2938*/
2939int QCalendarWidget::dateEditAcceptDelay() const
2940{
2941 Q_D(const QCalendarWidget);
2942 return d->m_navigator->dateEditAcceptDelay();
2943}
2944
2945void QCalendarWidget::setDateEditAcceptDelay(int delay)
2946{
2947 Q_D(QCalendarWidget);
2948 d->m_navigator->setDateEditAcceptDelay(delay);
2949}
2950
2951/*!
2952 \since 4.4
2953
2954 Updates the cell specified by the given \a date unless updates
2955 are disabled or the cell is hidden.
2956
2957 \sa updateCells(), yearShown(), monthShown()
2958*/
2959void QCalendarWidget::updateCell(QDate date)
2960{
2961 if (Q_UNLIKELY(!date.isValid())) {
2962 qWarning("QCalendarWidget::updateCell: Invalid date");
2963 return;
2964 }
2965
2966 if (!isVisible())
2967 return;
2968
2969 Q_D(QCalendarWidget);
2970 int row, column;
2971 d->m_model->cellForDate(date, &row, &column);
2972 if (row == -1 || column == -1)
2973 return;
2974
2975 QModelIndex modelIndex = d->m_model->index(row, column);
2976 if (!modelIndex.isValid())
2977 return;
2978
2979 d->m_view->viewport()->update(d->m_view->visualRect(modelIndex));
2980}
2981
2982/*!
2983 \since 4.4
2984
2985 Updates all visible cells unless updates are disabled.
2986
2987 \sa updateCell()
2988*/
2989void QCalendarWidget::updateCells()
2990{
2991 Q_D(QCalendarWidget);
2992 if (isVisible())
2993 d->m_view->viewport()->update();
2994}
2995
2996/*!
2997 \fn void QCalendarWidget::selectionChanged()
2998
2999 This signal is emitted when the currently selected date is
3000 changed.
3001
3002 The currently selected date can be changed by the user using the
3003 mouse or keyboard, or by the programmer using setSelectedDate().
3004
3005 \sa selectedDate()
3006*/
3007
3008/*!
3009 \fn void QCalendarWidget::currentPageChanged(int year, int month)
3010
3011 This signal is emitted when the currently shown month is changed.
3012 The new \a year and \a month are passed as parameters.
3013
3014 \sa setCurrentPage()
3015*/
3016
3017/*!
3018 \fn void QCalendarWidget::activated(QDate date)
3019
3020 This signal is emitted whenever the user presses the Return or
3021 Enter key or double-clicks a \a date in the calendar
3022 widget.
3023*/
3024
3025/*!
3026 \fn void QCalendarWidget::clicked(QDate date)
3027
3028 This signal is emitted when a mouse button is clicked. The date
3029 the mouse was clicked on is specified by \a date. The signal is
3030 only emitted when clicked on a valid date, e.g., dates are not
3031 outside the minimumDate() and maximumDate(). If the selection mode
3032 is NoSelection, this signal will not be emitted.
3033
3034*/
3035
3036/*!
3037 \property QCalendarWidget::navigationBarVisible
3038 \brief whether the navigation bar is shown or not
3039
3040 \since 4.3
3041
3042 When this property is \c true (the default), the next month,
3043 previous month, month selection, year selection controls are
3044 shown on top.
3045
3046 When the property is set to false, these controls are hidden.
3047*/
3048
3049bool QCalendarWidget::isNavigationBarVisible() const
3050{
3051 Q_D(const QCalendarWidget);
3052 return d->navBarVisible;
3053}
3054
3055
3056void QCalendarWidget::setNavigationBarVisible(bool visible)
3057{
3058 Q_D(QCalendarWidget);
3059 d->navBarVisible = visible;
3060 d->cachedSizeHint = QSize();
3061 d->navBarBackground->setVisible(visible);
3062 updateGeometry();
3063}
3064
3065/*!
3066 \reimp
3067*/
3068bool QCalendarWidget::event(QEvent *event)
3069{
3070 Q_D(QCalendarWidget);
3071 switch (event->type()) {
3072 case QEvent::LayoutDirectionChange:
3073 d->updateButtonIcons();
3074 break;
3075 case QEvent::LocaleChange:
3076 d->m_model->setFirstColumnDay(locale().firstDayOfWeek());
3077 d->cachedSizeHint = QSize();
3078 d->updateMonthMenuNames();
3079 d->updateNavigationBar();
3080 d->m_view->updateGeometry();
3081 // TODO: fix this known bug of calendaring API:
3082 // Changing locale before calendar works, but reverse order causes
3083 // invalid month names (in C Locale apparently).
3084 break;
3085 case QEvent::FontChange:
3086 case QEvent::ApplicationFontChange:
3087 d->cachedSizeHint = QSize();
3088 d->m_view->updateGeometry();
3089 break;
3090 case QEvent::StyleChange:
3091 d->cachedSizeHint = QSize();
3092 d->m_view->updateGeometry();
3093 break;
3094 default:
3095 break;
3096 }
3097 return QWidget::event(event);
3098}
3099
3100/*!
3101 \reimp
3102*/
3103bool QCalendarWidget::eventFilter(QObject *watched, QEvent *event)
3104{
3105 Q_D(QCalendarWidget);
3106 if (event->type() == QEvent::MouseButtonPress && d->yearEdit->hasFocus()) {
3107 // We can get filtered press events that were intended for Qt Virtual Keyboard's
3108 // input panel (QQuickView), so we have to make sure that the window is indeed a QWidget - no static_cast.
3109 // In addition, as we have a event filter on the whole application we first make sure that the top level widget
3110 // of both this and the watched widget are the same to decide if we should finish the year edition.
3111 QWidget *tlw = window();
3112 QWidget *widget = qobject_cast<QWidget *>(watched);
3113 if (!widget || widget->window() != tlw)
3114 return QWidget::eventFilter(watched, event);
3115
3116 QPoint mousePos = widget->mapTo(tlw, static_cast<QMouseEvent *>(event)->position()).toPoint();
3117 QRect geom = QRect(d->yearEdit->mapTo(tlw, QPoint(0, 0)), d->yearEdit->size());
3118 if (!geom.contains(mousePos)) {
3119 event->accept();
3120 d->_q_yearEditingFinished();
3121 setFocus();
3122 return true;
3123 }
3124 }
3125 return QWidget::eventFilter(watched, event);
3126}
3127
3128/*!
3129 \reimp
3130*/
3131void QCalendarWidget::mousePressEvent(QMouseEvent *event)
3132{
3133 setAttribute(Qt::WA_NoMouseReplay);
3134 QWidget::mousePressEvent(event);
3135 setFocus();
3136}
3137
3138/*!
3139 \reimp
3140*/
3141void QCalendarWidget::resizeEvent(QResizeEvent * event)
3142{
3143 Q_D(QCalendarWidget);
3144
3145 // XXX Should really use a QWidgetStack for yearEdit and yearButton,
3146 // XXX here we hide the year edit when the layout is likely to break
3147 // XXX the manual positioning of the yearEdit over the yearButton.
3148 if (d->yearEdit->isVisible() && event->size().width() != event->oldSize().width())
3149 d->_q_yearEditingFinished();
3150
3151 QWidget::resizeEvent(event);
3152}
3153
3154/*!
3155 \reimp
3156*/
3157void QCalendarWidget::keyPressEvent(QKeyEvent * event)
3158{
3159#if QT_CONFIG(shortcut)
3160 Q_D(QCalendarWidget);
3161 if (d->yearEdit->isVisible()&& event->matches(QKeySequence::Cancel)) {
3162 d->yearEdit->setValue(yearShown());
3163 d->_q_yearEditingFinished();
3164 return;
3165 }
3166#endif
3167 QWidget::keyPressEvent(event);
3168}
3169
3170QT_END_NAMESPACE
3171
3172#include "qcalendarwidget.moc"
3173#include "moc_qcalendarwidget.cpp"
QCalendarTextNavigator * m_navigator
void setNavigatorEnabled(bool enable)
void paintCell(QPainter *painter, const QRect &rect, QDate date) const
QItemSelectionModel * m_selection
QMap< int, QAction * > monthToAction
void showMonth(int year, int month)
void _q_monthChanged(QAction *)
void _q_slotChangeDate(QDate date, bool changeMonth)
void createNavigationBar(QWidget *widget)
void _q_slotShowDate(QDate date)
QCalendarDelegate * m_delegate
void updateCurrentPage(QDate newDate)
void _q_slotChangeDate(QDate date)
The QCalendar class describes calendar systems.
Definition qcalendar.h:54
Definition qmap.h:295
\inmodule QtCore
constexpr QModelIndex() noexcept
Creates a new empty model index.
The QStylePainter class is a convenience class for drawing QStyle elements inside a widget.
void paintEvent(QPaintEvent *e) override
\reimp
virtual Section handleKey(int key)=0
virtual void setDate(QDate date, QCalendar cal=QCalendar())=0
virtual QDate applyToDate(QDate date, QCalendar cal=QCalendar()) const =0
virtual QString text(QDate date, QCalendar cal, int repeat) const =0
static QString highlightString(const QString &str, int pos)
virtual QString text() const =0
void setLocale(const QLocale &locale)
void setInitialDate(QDate date, QCalendar cal)
void handleKeyEvent(QKeyEvent *keyEvent, QCalendar cal)
void setFormat(const QString &format)
QString currentText(QCalendar cal) const
virtual QDate applyToDate(QDate date, QCalendar cal) const override
virtual Section handleKey(int key) override
virtual void setDate(QDate date, QCalendar cal) override
virtual QString text() const override
virtual QString text(QDate date, QCalendar cal, int repeat) const override
void paintCell(QPainter *painter, const QRect &rect, QDate date) const
QString dayName(Qt::DayOfWeek day) const
void showMonth(int year, int month)
QTextCharFormat formatForCell(int row, int col) const
int columnCount(const QModelIndex &parent) const override
Returns the number of columns for the children of the given parent.
QString monthName(const QLocale &locale, int month)
void setFirstColumnDay(Qt::DayOfWeek dayOfWeek)
int columnForDayOfWeek(Qt::DayOfWeek day) const
Qt::ItemFlags flags(const QModelIndex &index) const override
\reimp
StaticDayOfWeekAssociativeArray< QTextCharFormat > m_dayFormats
int columnForFirstOfMonth(QDate date) const
void cellForDate(QDate date, int *row, int *column) const
QVariant data(const QModelIndex &index, int role) const override
Returns the data stored under the given role for the item referred to by the index.
Qt::DayOfWeek firstColumnDay() const
void setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format)
Qt::DayOfWeek dayOfWeekForColumn(int section) const
void setView(QCalendarView *view)
int rowCount(const QModelIndex &parent) const override
Returns the number of rows under the given parent.
void setRange(QDate min, QDate max)
QMap< QDate, QTextCharFormat > m_dateFormats
QDate dateForCell(int row, int column) const
virtual QDate applyToDate(QDate date, QCalendar cal) const override
virtual Section handleKey(int key) override
virtual QString text(QDate date, QCalendar cal, int repeat) const override
virtual void setDate(QDate date, QCalendar cal) override
virtual QString text() const override
void timerEvent(QTimerEvent *e) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
bool eventFilter(QObject *o, QEvent *e) override
Filters events if this object has been installed as an event filter for the watched object.
virtual void keyboardSearch(const QString &) override
Moves to and selects the item best matching the string search.
void mouseReleaseEvent(QMouseEvent *event) override
void mousePressEvent(QMouseEvent *event) override
void dateClicked(QDate date)
bool event(QEvent *event) override
void keyPressEvent(QKeyEvent *event) override
void changeDate(QDate date, bool changeMonth)
void setReadOnly(bool enable)
QDate handleMouseEvent(QMouseEvent *event)
QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override
Returns a QModelIndex object pointing to the next object in the view, based on the given cursorAction...
void mouseDoubleClickEvent(QMouseEvent *event) override
void mouseMoveEvent(QMouseEvent *event) override
virtual QDate applyToDate(QDate date, QCalendar cal) const override
virtual QString text(QDate date, QCalendar cal, int repeat) const override
virtual void setDate(QDate date, QCalendar cal) override
virtual Section handleKey(int key) override
virtual QString text() const override
@ RowCount
@ MinimumDayOffset
@ HeaderRow
@ HeaderColumn
@ ColumnCount
QtPrivate::QPrevNextCalButton QPrevNextCalButton
QtPrivate::QCalendarDateSectionValidator QCalendarDateSectionValidator
QtPrivate::QCalendarModel QCalendarModel
QtPrivate::QCalendarDayValidator QCalendarDayValidator
QtPrivate::QCalendarYearValidator QCalendarYearValidator
QtPrivate::QCalendarDelegate QCalendarDelegate
QtPrivate::QCalendarView QCalendarView
static QString formatNumber(int number, int fieldWidth)
QtPrivate::QCalendarTextNavigator QCalendarTextNavigator
Q_DECLARE_TYPEINFO(QtPrivate::SectionToken, Q_PRIMITIVE_TYPE)
QtPrivate::QCalendarMonthValidator QCalendarMonthValidator
QtPrivate::QCalToolButton QCalToolButton
QtPrivate::QCalendarDateValidator QCalendarDateValidator
#define qApp
constexpr SectionToken(QCalendarDateSectionValidator *v, int rep)
QCalendarDateSectionValidator * validator