1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qcalendarwidget.h"
44 #ifndef QT_NO_CALENDARWIDGET
46 #include <qabstractitemmodel.h>
47 #include <qitemdelegate.h>
48 #include <qdatetime.h>
49 #include <qtableview.h>
52 #include <qtextformat.h>
53 #include <qheaderview.h>
54 #include <private/qwidget_p.h>
55 #include <qpushbutton.h>
56 #include <qtoolbutton.h>
60 #include <qapplication.h>
61 #include <qbasictimer.h>
62 #include <qstylepainter.h>
63 #include <private/qcalendartextnavigator_p.h>
75 class QCalendarDateSectionValidator
85 QCalendarDateSectionValidator() {}
86 virtual ~QCalendarDateSectionValidator() {}
87 virtual Section handleKey(int key) = 0;
88 virtual QDate applyToDate(const QDate &date) const = 0;
89 virtual void setDate(const QDate &date) = 0;
90 virtual QString text() const = 0;
91 virtual QString text(const QDate &date, int repeat) const = 0;
96 QString highlightString(const QString &str, int pos) const;
100 QString QCalendarDateSectionValidator::highlightString(const QString &str, int pos) const
103 return QLatin1String("<b>") + str + QLatin1String("</b>");
104 int startPos = str.length() - pos;
105 return str.mid(0, startPos) + QLatin1String("<b>") + str.mid(startPos, pos) + QLatin1String("</b>");
109 class QCalendarDayValidator : public QCalendarDateSectionValidator
113 QCalendarDayValidator();
114 virtual Section handleKey(int key);
115 virtual QDate applyToDate(const QDate &date) const;
116 virtual void setDate(const QDate &date);
117 virtual QString text() const;
118 virtual QString text(const QDate &date, int repeat) const;
125 QCalendarDayValidator::QCalendarDayValidator()
126 : QCalendarDateSectionValidator(), m_pos(0), m_day(1), m_oldDay(1)
130 QCalendarDateSectionValidator::Section QCalendarDayValidator::handleKey(int key)
132 if (key == Qt::Key_Right || key == Qt::Key_Left) {
134 return QCalendarDateSectionValidator::ThisSection;
135 } else if (key == Qt::Key_Up) {
140 return QCalendarDateSectionValidator::ThisSection;
141 } else if (key == Qt::Key_Down) {
146 return QCalendarDateSectionValidator::ThisSection;
147 } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
156 //m_day = m_oldDay / 10 * 10 + m_day / 10;
159 return QCalendarDateSectionValidator::PrevSection;
160 return QCalendarDateSectionValidator::ThisSection;
162 if (key < Qt::Key_0 || key > Qt::Key_9)
163 return QCalendarDateSectionValidator::ThisSection;
164 int pressedKey = key - Qt::Key_0;
168 m_day = m_day % 10 * 10 + pressedKey;
174 return QCalendarDateSectionValidator::NextSection;
176 return QCalendarDateSectionValidator::ThisSection;
179 QDate QCalendarDayValidator::applyToDate(const QDate &date) const
186 if (day > date.daysInMonth())
187 day = date.daysInMonth();
188 return QDate(date.year(), date.month(), day);
191 void QCalendarDayValidator::setDate(const QDate &date)
193 m_day = m_oldDay = date.day();
197 QString QCalendarDayValidator::text() const
201 str += QLatin1Char('0');
202 str += QString::number(m_day);
203 return highlightString(str, m_pos);
206 QString QCalendarDayValidator::text(const QDate &date, int repeat) const
209 return QString::number(date.day());
210 } else if (repeat == 2) {
212 if (date.day() / 10 == 0)
213 str += QLatin1Char('0');
214 return str + QString::number(date.day());
215 } else if (repeat == 3) {
216 return m_locale.dayName(date.dayOfWeek(), QLocale::ShortFormat);
217 } else if (repeat >= 4) {
218 return m_locale.dayName(date.dayOfWeek(), QLocale::LongFormat);
223 //////////////////////////////////
225 class QCalendarMonthValidator : public QCalendarDateSectionValidator
229 QCalendarMonthValidator();
230 virtual Section handleKey(int key);
231 virtual QDate applyToDate(const QDate &date) const;
232 virtual void setDate(const QDate &date);
233 virtual QString text() const;
234 virtual QString text(const QDate &date, int repeat) const;
241 QCalendarMonthValidator::QCalendarMonthValidator()
242 : QCalendarDateSectionValidator(), m_pos(0), m_month(1), m_oldMonth(1)
246 QCalendarDateSectionValidator::Section QCalendarMonthValidator::handleKey(int key)
248 if (key == Qt::Key_Right || key == Qt::Key_Left) {
250 return QCalendarDateSectionValidator::ThisSection;
251 } else if (key == Qt::Key_Up) {
256 return QCalendarDateSectionValidator::ThisSection;
257 } else if (key == Qt::Key_Down) {
262 return QCalendarDateSectionValidator::ThisSection;
263 } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
269 m_month = m_oldMonth;
271 m_month = m_month / 10;
272 //m_month = m_oldMonth / 10 * 10 + m_month / 10;
275 return QCalendarDateSectionValidator::PrevSection;
276 return QCalendarDateSectionValidator::ThisSection;
278 if (key < Qt::Key_0 || key > Qt::Key_9)
279 return QCalendarDateSectionValidator::ThisSection;
280 int pressedKey = key - Qt::Key_0;
282 m_month = pressedKey;
284 m_month = m_month % 10 * 10 + pressedKey;
290 return QCalendarDateSectionValidator::NextSection;
292 return QCalendarDateSectionValidator::ThisSection;
295 QDate QCalendarMonthValidator::applyToDate(const QDate &date) const
302 QDate newDate(date.year(), m_month, 1);
303 int day = date.day();
304 if (day > newDate.daysInMonth())
305 day = newDate.daysInMonth();
306 return QDate(date.year(), month, day);
309 void QCalendarMonthValidator::setDate(const QDate &date)
311 m_month = m_oldMonth = date.month();
315 QString QCalendarMonthValidator::text() const
318 if (m_month / 10 == 0)
319 str += QLatin1Char('0');
320 str += QString::number(m_month);
321 return highlightString(str, m_pos);
324 QString QCalendarMonthValidator::text(const QDate &date, int repeat) const
327 return QString::number(date.month());
328 } else if (repeat == 2) {
330 if (date.month() / 10 == 0)
331 str += QLatin1Char('0');
332 return str + QString::number(date.month());
333 } else if (repeat == 3) {
334 return m_locale.standaloneMonthName(date.month(), QLocale::ShortFormat);
335 } else /*if (repeat >= 4)*/ {
336 return m_locale.standaloneMonthName(date.month(), QLocale::LongFormat);
340 //////////////////////////////////
342 class QCalendarYearValidator : public QCalendarDateSectionValidator
346 QCalendarYearValidator();
347 virtual Section handleKey(int key);
348 virtual QDate applyToDate(const QDate &date) const;
349 virtual void setDate(const QDate &date);
350 virtual QString text() const;
351 virtual QString text(const QDate &date, int repeat) const;
359 QCalendarYearValidator::QCalendarYearValidator()
360 : QCalendarDateSectionValidator(), m_pos(0), m_year(2000), m_oldYear(2000)
364 int QCalendarYearValidator::pow10(int n)
367 for (int i = 0; i < n; i++)
372 QCalendarDateSectionValidator::Section QCalendarYearValidator::handleKey(int key)
374 if (key == Qt::Key_Right || key == Qt::Key_Left) {
376 return QCalendarDateSectionValidator::ThisSection;
377 } else if (key == Qt::Key_Up) {
380 return QCalendarDateSectionValidator::ThisSection;
381 } else if (key == Qt::Key_Down) {
384 return QCalendarDateSectionValidator::ThisSection;
385 } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
390 int pow = pow10(m_pos);
391 m_year = m_oldYear / pow * pow + m_year % (pow * 10) / 10;
394 return QCalendarDateSectionValidator::PrevSection;
395 return QCalendarDateSectionValidator::ThisSection;
397 if (key < Qt::Key_0 || key > Qt::Key_9)
398 return QCalendarDateSectionValidator::ThisSection;
399 int pressedKey = key - Qt::Key_0;
400 int pow = pow10(m_pos);
401 m_year = m_year / (pow * 10) * (pow * 10) + m_year % pow * 10 + pressedKey;
405 return QCalendarDateSectionValidator::NextSection;
407 return QCalendarDateSectionValidator::ThisSection;
410 QDate QCalendarYearValidator::applyToDate(const QDate &date) const
415 QDate newDate(year, date.month(), 1);
416 int day = date.day();
417 if (day > newDate.daysInMonth())
418 day = newDate.daysInMonth();
419 return QDate(year, date.month(), day);
422 void QCalendarYearValidator::setDate(const QDate &date)
424 m_year = m_oldYear = date.year();
428 QString QCalendarYearValidator::text() const
432 for (int i = 0; i < 3; i++) {
433 if (m_year / pow == 0)
434 str += QLatin1Char('0');
437 str += QString::number(m_year);
438 return highlightString(str, m_pos);
441 QString QCalendarYearValidator::text(const QDate &date, int repeat) const
445 int year = date.year() % 100;
447 str = QLatin1Char('0');
448 return str + QString::number(year);
450 return QString::number(date.year());
453 ///////////////////////////////////
455 class QCalendarDateValidator
458 QCalendarDateValidator();
459 ~QCalendarDateValidator();
461 void handleKeyEvent(QKeyEvent *keyEvent);
462 QString currentText() const;
463 QDate currentDate() const { return m_currentDate; }
464 void setFormat(const QString &format);
465 void setInitialDate(const QDate &date);
467 void setLocale(const QLocale &locale);
471 struct SectionToken {
472 SectionToken(QCalendarDateSectionValidator *val, int rep) : validator(val), repeat(rep) {}
473 QCalendarDateSectionValidator *validator;
478 void toPreviousToken();
481 int countRepeat(const QString &str, int index) const;
484 QStringList m_separators;
485 QList<SectionToken *> m_tokens;
486 QCalendarDateSectionValidator *m_yearValidator;
487 QCalendarDateSectionValidator *m_monthValidator;
488 QCalendarDateSectionValidator *m_dayValidator;
490 SectionToken *m_currentToken;
495 QCalendarDateSectionValidator::Section m_lastSectionMove;
498 QCalendarDateValidator::QCalendarDateValidator()
499 : m_currentToken(0), m_lastSectionMove(QCalendarDateSectionValidator::ThisSection)
501 m_initialDate = m_currentDate = QDate::currentDate();
502 m_yearValidator = new QCalendarYearValidator();
503 m_monthValidator = new QCalendarMonthValidator();
504 m_dayValidator = new QCalendarDayValidator();
507 void QCalendarDateValidator::setLocale(const QLocale &locale)
509 m_yearValidator->m_locale = locale;
510 m_monthValidator->m_locale = locale;
511 m_dayValidator->m_locale = locale;
514 QCalendarDateValidator::~QCalendarDateValidator()
516 delete m_yearValidator;
517 delete m_monthValidator;
518 delete m_dayValidator;
522 // from qdatetime.cpp
523 int QCalendarDateValidator::countRepeat(const QString &str, int index) const
525 Q_ASSERT(index >= 0 && index < str.size());
527 const QChar ch = str.at(index);
528 while (index + count < str.size() && str.at(index + count) == ch)
533 void QCalendarDateValidator::setInitialDate(const QDate &date)
535 m_yearValidator->setDate(date);
536 m_monthValidator->setDate(date);
537 m_dayValidator->setDate(date);
538 m_initialDate = date;
539 m_currentDate = date;
540 m_lastSectionMove = QCalendarDateSectionValidator::ThisSection;
543 QString QCalendarDateValidator::currentText() const
546 QStringListIterator itSep(m_separators);
547 QListIterator<SectionToken *> itTok(m_tokens);
548 while (itSep.hasNext()) {
550 if (itTok.hasNext()) {
551 SectionToken *token = itTok.next();
552 QCalendarDateSectionValidator *validator = token->validator;
553 if (m_currentToken == token)
554 str += validator->text();
556 str += validator->text(m_currentDate, token->repeat);
562 void QCalendarDateValidator::clear()
564 QListIterator<SectionToken *> it(m_tokens);
569 m_separators.clear();
574 void QCalendarDateValidator::setFormat(const QString &format)
579 const QLatin1Char quote('\'');
580 bool quoting = false;
582 while (pos < format.size()) {
583 QString mid = format.mid(pos);
586 if (mid.startsWith(quote)) {
589 const QChar nextChar = format.at(pos);
591 separator += nextChar;
593 SectionToken *token = 0;
594 if (nextChar == QLatin1Char('d')) {
595 offset = qMin(4, countRepeat(format, pos));
596 token = new SectionToken(m_dayValidator, offset);
597 } else if (nextChar == QLatin1Char('M')) {
598 offset = qMin(4, countRepeat(format, pos));
599 token = new SectionToken(m_monthValidator, offset);
600 } else if (nextChar == QLatin1Char('y')) {
601 offset = qMin(4, countRepeat(format, pos));
602 token = new SectionToken(m_yearValidator, offset);
604 separator += nextChar;
607 m_tokens.append(token);
608 m_separators.append(separator);
609 separator = QString();
611 m_currentToken = token;
618 m_separators += separator;
621 void QCalendarDateValidator::applyToDate()
623 m_currentDate = m_yearValidator->applyToDate(m_currentDate);
624 m_currentDate = m_monthValidator->applyToDate(m_currentDate);
625 m_currentDate = m_dayValidator->applyToDate(m_currentDate);
628 void QCalendarDateValidator::toNextToken()
630 const int idx = m_tokens.indexOf(m_currentToken);
633 if (idx + 1 >= m_tokens.count())
634 m_currentToken = m_tokens.first();
636 m_currentToken = m_tokens.at(idx + 1);
639 void QCalendarDateValidator::toPreviousToken()
641 const int idx = m_tokens.indexOf(m_currentToken);
645 m_currentToken = m_tokens.last();
647 m_currentToken = m_tokens.at(idx - 1);
650 void QCalendarDateValidator::handleKeyEvent(QKeyEvent *keyEvent)
655 int key = keyEvent->key();
656 if (m_lastSectionMove == QCalendarDateSectionValidator::NextSection) {
657 if (key == Qt::Key_Back || key == Qt::Key_Backspace)
660 if (key == Qt::Key_Right)
662 else if (key == Qt::Key_Left)
665 m_lastSectionMove = m_currentToken->validator->handleKey(key);
668 if (m_lastSectionMove == QCalendarDateSectionValidator::NextSection)
670 else if (m_lastSectionMove == QCalendarDateSectionValidator::PrevSection)
674 QWidget *QCalendarTextNavigator::widget() const
679 void QCalendarTextNavigator::setWidget(QWidget *widget)
684 QDate QCalendarTextNavigator::date() const
689 void QCalendarTextNavigator::setDate(const QDate &date)
694 void QCalendarTextNavigator::updateDateLabel()
699 m_acceptTimer.start(m_editDelay, this);
701 m_dateText->setText(m_dateValidator->currentText());
703 QSize s = m_dateFrame->sizeHint();
704 QRect r = m_widget->geometry(); // later, just the table section
705 QRect newRect((r.width() - s.width()) / 2, (r.height() - s.height()) / 2, s.width(), s.height());
706 m_dateFrame->setGeometry(newRect);
707 // need to set palette after geometry update as phonestyle sets transparency
708 // effect in move event.
709 QPalette p = m_dateFrame->palette();
710 p.setBrush(QPalette::Window, m_dateFrame->window()->palette().brush(QPalette::Window));
711 m_dateFrame->setPalette(p);
713 m_dateFrame->raise();
717 void QCalendarTextNavigator::applyDate()
719 QDate date = m_dateValidator->currentDate();
724 emit dateChanged(date);
727 void QCalendarTextNavigator::createDateLabel()
731 m_dateFrame = new QFrame(m_widget);
732 QVBoxLayout *vl = new QVBoxLayout;
733 m_dateText = new QLabel;
734 vl->addWidget(m_dateText);
735 m_dateFrame->setLayout(vl);
736 m_dateFrame->setFrameShadow(QFrame::Plain);
737 m_dateFrame->setFrameShape(QFrame::Box);
738 m_dateValidator = new QCalendarDateValidator();
739 m_dateValidator->setLocale(m_widget->locale());
740 m_dateValidator->setFormat(m_widget->locale().dateFormat(QLocale::ShortFormat));
741 m_dateValidator->setInitialDate(m_date);
743 m_dateFrame->setAutoFillBackground(true);
744 m_dateFrame->setBackgroundRole(QPalette::Window);
747 void QCalendarTextNavigator::removeDateLabel()
751 m_acceptTimer.stop();
753 m_dateFrame->deleteLater();
754 delete m_dateValidator;
760 bool QCalendarTextNavigator::eventFilter(QObject *o, QEvent *e)
763 if (e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease) {
764 QKeyEvent* ke = (QKeyEvent*)e;
765 if ((ke->text().length() > 0 && ke->text()[0].isPrint()) || m_dateFrame) {
766 if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Select) {
768 emit editingFinished();
770 } else if (ke->key() == Qt::Key_Escape) {
772 } else if (e->type() == QEvent::KeyPress) {
774 m_dateValidator->handleKeyEvent(ke);
780 // If we are navigating let the user finish his date in old locate.
781 // If we change our mind and want it to update immediately simply uncomment below
783 } else if (e->type() == QEvent::LocaleChange) {
784 if (m_dateValidator) {
785 m_dateValidator->setLocale(m_widget->locale());
786 m_dateValidator->setFormat(m_widget->locale().dateFormat(QLocale::ShortFormat));
792 return QObject::eventFilter(o,e);
795 void QCalendarTextNavigator::timerEvent(QTimerEvent *e)
797 if (e->timerId() == m_acceptTimer.timerId()) {
803 int QCalendarTextNavigator::dateEditAcceptDelay() const
808 void QCalendarTextNavigator::setDateEditAcceptDelay(int delay)
815 class QCalendarModel : public QAbstractTableModel
819 QCalendarModel(QObject *parent = 0);
821 int rowCount(const QModelIndex &) const
822 { return RowCount + m_firstRow; }
823 int columnCount(const QModelIndex &) const
824 { return ColumnCount + m_firstColumn; }
825 QVariant data(const QModelIndex &index, int role) const;
826 Qt::ItemFlags flags(const QModelIndex &index) const;
828 bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())
830 beginInsertRows(parent, row, row + count - 1);
834 bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex())
836 beginInsertColumns(parent, column, column + count - 1);
840 bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex())
842 beginRemoveRows(parent, row, row + count - 1);
846 bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex())
848 beginRemoveColumns(parent, column, column + count - 1);
853 void showMonth(int year, int month);
854 void setDate(const QDate &d);
856 void setMinimumDate(const QDate &date);
857 void setMaximumDate(const QDate &date);
859 void setRange(const QDate &min, const QDate &max);
861 void setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format);
863 void setFirstColumnDay(Qt::DayOfWeek dayOfWeek);
864 Qt::DayOfWeek firstColumnDay() const;
866 bool weekNumbersShown() const;
867 void setWeekNumbersShown(bool show);
869 QTextCharFormat formatForCell(int row, int col) const;
870 Qt::DayOfWeek dayOfWeekForColumn(int section) const;
871 int columnForDayOfWeek(Qt::DayOfWeek day) const;
872 QDate dateForCell(int row, int column) const;
873 void cellForDate(const QDate &date, int *row, int *column) const;
874 QString dayName(Qt::DayOfWeek day) const;
876 void setView(QCalendarView *view)
879 void internalUpdate();
880 QDate referenceDate() const;
881 int columnForFirstOfMonth(const QDate &date) const;
890 Qt::DayOfWeek m_firstDay;
891 QCalendarWidget::HorizontalHeaderFormat m_horizontalHeaderFormat;
892 bool m_weekNumbersShown;
893 QMap<Qt::DayOfWeek, QTextCharFormat> m_dayFormats;
894 QMap<QDate, QTextCharFormat> m_dateFormats;
895 QTextCharFormat m_headerFormat;
896 QCalendarView *m_view;
899 class QCalendarView : public QTableView
903 QCalendarView(QWidget *parent = 0);
905 void internalUpdate() { updateGeometries(); }
906 void setReadOnly(bool enable);
907 virtual void keyboardSearch(const QString & search) { Q_UNUSED(search) }
910 void showDate(const QDate &date);
911 void changeDate(const QDate &date, bool changeMonth);
912 void clicked(const QDate &date);
913 void editingFinished();
915 QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers);
916 void mouseDoubleClickEvent(QMouseEvent *event);
917 void mousePressEvent(QMouseEvent *event);
918 void mouseMoveEvent(QMouseEvent *event);
919 void mouseReleaseEvent(QMouseEvent *event);
920 #ifndef QT_NO_WHEELEVENT
921 void wheelEvent(QWheelEvent *event);
923 void keyPressEvent(QKeyEvent *event);
924 bool event(QEvent *event);
926 QDate handleMouseEvent(QMouseEvent *event);
930 bool validDateClicked;
931 #ifdef QT_KEYPAD_NAVIGATION
936 QCalendarModel::QCalendarModel(QObject *parent)
937 : QAbstractTableModel(parent)
939 m_date = QDate::currentDate();
940 m_minimumDate = QDate::fromJulianDay(1);
941 m_maximumDate = QDate(7999, 12, 31);
942 m_shownYear = m_date.year();
943 m_shownMonth = m_date.month();
944 m_firstDay = QLocale().firstDayOfWeek();
945 m_horizontalHeaderFormat = QCalendarWidget::ShortDayNames;
946 m_weekNumbersShown = true;
952 Qt::DayOfWeek QCalendarModel::dayOfWeekForColumn(int column) const
954 int col = column - m_firstColumn;
955 if (col < 0 || col > 6)
957 int day = m_firstDay + col;
960 return Qt::DayOfWeek(day);
963 int QCalendarModel::columnForDayOfWeek(Qt::DayOfWeek day) const
965 if (day < 1 || day > 7)
967 int column = (int)day - (int)m_firstDay;
970 return column + m_firstColumn;
974 This simple algorithm tries to generate a valid date from the month shown.
975 Some months don't contain a first day (e.g. Jan of -4713 year,
976 so QDate (-4713, 1, 1) would be invalid). In that case we try to generate
977 another valid date for that month. Later, returned date's day is the number of cells
978 calendar widget will reserve for days before referenceDate. (E.g. if returned date's
979 day is 16, that day will be placed in 3rd or 4th row, not in the 1st or 2nd row).
980 Depending on referenceData we can change behaviour of Oct 1582. If referenceDate is 1st
981 of Oct we render 1 Oct in 1st or 2nd row. If referenceDate is 17 of Oct we show always 16
982 dates before 17 of Oct, and since this month contains the hole 5-14 Oct, the first of Oct
983 will be rendered in 2nd or 3rd row, showing more dates from previous month.
985 QDate QCalendarModel::referenceDate() const
988 while (refDay <= 31) {
989 QDate refDate(m_shownYear, m_shownMonth, refDay);
990 if (refDate.isValid())
997 int QCalendarModel::columnForFirstOfMonth(const QDate &date) const
999 return (columnForDayOfWeek(static_cast<Qt::DayOfWeek>(date.dayOfWeek())) - (date.day() % 7) + 8) % 7;
1002 QDate QCalendarModel::dateForCell(int row, int column) const
1004 if (row < m_firstRow || row > m_firstRow + RowCount - 1 ||
1005 column < m_firstColumn || column > m_firstColumn + ColumnCount - 1)
1007 const QDate refDate = referenceDate();
1008 if (!refDate.isValid())
1011 const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
1012 if (columnForFirstOfShownMonth - m_firstColumn < MinimumDayOffset)
1015 const int requestedDay = 7 * (row - m_firstRow) + column - columnForFirstOfShownMonth - refDate.day() + 1;
1016 return refDate.addDays(requestedDay);
1019 void QCalendarModel::cellForDate(const QDate &date, int *row, int *column) const
1021 if (!row && !column)
1029 const QDate refDate = referenceDate();
1030 if (!refDate.isValid())
1033 const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
1034 const int requestedPosition = refDate.daysTo(date) - m_firstColumn + columnForFirstOfShownMonth + refDate.day() - 1;
1036 int c = requestedPosition % 7;
1037 int r = requestedPosition / 7;
1043 if (columnForFirstOfShownMonth - m_firstColumn < MinimumDayOffset)
1046 if (r < 0 || r > RowCount - 1 || c < 0 || c > ColumnCount - 1)
1050 *row = r + m_firstRow;
1052 *column = c + m_firstColumn;
1055 QString QCalendarModel::dayName(Qt::DayOfWeek day) const
1057 switch (m_horizontalHeaderFormat) {
1058 case QCalendarWidget::SingleLetterDayNames: {
1059 QString standaloneDayName = m_view->locale().standaloneDayName(day, QLocale::NarrowFormat);
1060 if (standaloneDayName == m_view->locale().dayName(day, QLocale::NarrowFormat))
1061 return standaloneDayName.left(1);
1062 return standaloneDayName;
1064 case QCalendarWidget::ShortDayNames:
1065 return m_view->locale().dayName(day, QLocale::ShortFormat);
1066 case QCalendarWidget::LongDayNames:
1067 return m_view->locale().dayName(day, QLocale::LongFormat);
1074 QTextCharFormat QCalendarModel::formatForCell(int row, int col) const
1077 QPalette::ColorGroup cg = QPalette::Active;
1079 pal = m_view->palette();
1080 if (!m_view->isEnabled())
1081 cg = QPalette::Disabled;
1082 else if (!m_view->isActiveWindow())
1083 cg = QPalette::Inactive;
1086 QTextCharFormat format;
1087 format.setFont(m_view->font());
1088 bool header = (m_weekNumbersShown && col == HeaderColumn)
1089 || (m_horizontalHeaderFormat != QCalendarWidget::NoHorizontalHeader && row == HeaderRow);
1090 format.setBackground(pal.brush(cg, header ? QPalette::AlternateBase : QPalette::Base));
1091 format.setForeground(pal.brush(cg, QPalette::Text));
1093 format.merge(m_headerFormat);
1096 if (col >= m_firstColumn && col < m_firstColumn + ColumnCount) {
1097 Qt::DayOfWeek dayOfWeek = dayOfWeekForColumn(col);
1098 if (m_dayFormats.contains(dayOfWeek))
1099 format.merge(m_dayFormats.value(dayOfWeek));
1103 QDate date = dateForCell(row, col);
1104 format.merge(m_dateFormats.value(date));
1105 if(date < m_minimumDate || date > m_maximumDate)
1106 format.setBackground(pal.brush(cg, QPalette::Window));
1107 if (m_shownMonth != date.month())
1108 format.setForeground(pal.brush(QPalette::Disabled, QPalette::Text));
1113 QVariant QCalendarModel::data(const QModelIndex &index, int role) const
1115 if (role == Qt::TextAlignmentRole)
1116 return (int) Qt::AlignCenter;
1118 int row = index.row();
1119 int column = index.column();
1121 if(role == Qt::DisplayRole) {
1122 if (m_weekNumbersShown && column == HeaderColumn
1123 && row >= m_firstRow && row < m_firstRow + RowCount) {
1124 QDate date = dateForCell(row, columnForDayOfWeek(Qt::Monday));
1126 return date.weekNumber();
1128 if (m_horizontalHeaderFormat != QCalendarWidget::NoHorizontalHeader && row == HeaderRow
1129 && column >= m_firstColumn && column < m_firstColumn + ColumnCount)
1130 return dayName(dayOfWeekForColumn(column));
1131 QDate date = dateForCell(row, column);
1137 QTextCharFormat fmt = formatForCell(row, column);
1138 if (role == Qt::BackgroundColorRole)
1139 return fmt.background().color();
1140 if (role == Qt::TextColorRole)
1141 return fmt.foreground().color();
1142 if (role == Qt::FontRole)
1144 if (role == Qt::ToolTipRole)
1145 return fmt.toolTip();
1149 Qt::ItemFlags QCalendarModel::flags(const QModelIndex &index) const
1151 QDate date = dateForCell(index.row(), index.column());
1152 if (!date.isValid())
1153 return QAbstractTableModel::flags(index);
1154 if (date < m_minimumDate)
1156 if (date > m_maximumDate)
1158 return QAbstractTableModel::flags(index);
1161 void QCalendarModel::setDate(const QDate &d)
1164 if (m_date < m_minimumDate)
1165 m_date = m_minimumDate;
1166 else if (m_date > m_maximumDate)
1167 m_date = m_maximumDate;
1170 void QCalendarModel::showMonth(int year, int month)
1172 if (m_shownYear == year && m_shownMonth == month)
1176 m_shownMonth = month;
1181 void QCalendarModel::setMinimumDate(const QDate &d)
1183 if (!d.isValid() || d == m_minimumDate)
1187 if (m_maximumDate < m_minimumDate)
1188 m_maximumDate = m_minimumDate;
1189 if (m_date < m_minimumDate)
1190 m_date = m_minimumDate;
1194 void QCalendarModel::setMaximumDate(const QDate &d)
1196 if (!d.isValid() || d == m_maximumDate)
1200 if (m_minimumDate > m_maximumDate)
1201 m_minimumDate = m_maximumDate;
1202 if (m_date > m_maximumDate)
1203 m_date = m_maximumDate;
1207 void QCalendarModel::setRange(const QDate &min, const QDate &max)
1209 m_minimumDate = min;
1210 m_maximumDate = max;
1211 if (m_minimumDate > m_maximumDate)
1212 qSwap(m_minimumDate, m_maximumDate);
1213 if (m_date < m_minimumDate)
1214 m_date = m_minimumDate;
1215 if (m_date > m_maximumDate)
1216 m_date = m_maximumDate;
1220 void QCalendarModel::internalUpdate()
1222 QModelIndex begin = index(0, 0);
1223 QModelIndex end = index(m_firstRow + RowCount - 1, m_firstColumn + ColumnCount - 1);
1224 emit dataChanged(begin, end);
1225 emit headerDataChanged(Qt::Vertical, 0, m_firstRow + RowCount - 1);
1226 emit headerDataChanged(Qt::Horizontal, 0, m_firstColumn + ColumnCount - 1);
1229 void QCalendarModel::setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format)
1231 if (m_horizontalHeaderFormat == format)
1234 int oldFormat = m_horizontalHeaderFormat;
1235 m_horizontalHeaderFormat = format;
1236 if (oldFormat == QCalendarWidget::NoHorizontalHeader) {
1239 } else if (m_horizontalHeaderFormat == QCalendarWidget::NoHorizontalHeader) {
1246 void QCalendarModel::setFirstColumnDay(Qt::DayOfWeek dayOfWeek)
1248 if (m_firstDay == dayOfWeek)
1251 m_firstDay = dayOfWeek;
1255 Qt::DayOfWeek QCalendarModel::firstColumnDay() const
1260 bool QCalendarModel::weekNumbersShown() const
1262 return m_weekNumbersShown;
1265 void QCalendarModel::setWeekNumbersShown(bool show)
1267 if (m_weekNumbersShown == show)
1270 m_weekNumbersShown = show;
1281 QCalendarView::QCalendarView(QWidget *parent)
1282 : QTableView(parent),
1284 validDateClicked(false)
1286 setTabKeyNavigation(false);
1288 verticalHeader()->setVisible(false);
1289 horizontalHeader()->setVisible(false);
1290 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1291 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1294 QModelIndex QCalendarView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
1296 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1298 return QTableView::moveCursor(cursorAction, modifiers);
1301 return currentIndex();
1303 QModelIndex index = currentIndex();
1304 QDate currentDate = static_cast<QCalendarModel*>(model())->dateForCell(index.row(), index.column());
1305 switch (cursorAction) {
1306 case QAbstractItemView::MoveUp:
1307 currentDate = currentDate.addDays(-7);
1309 case QAbstractItemView::MoveDown:
1310 currentDate = currentDate.addDays(7);
1312 case QAbstractItemView::MoveLeft:
1313 currentDate = currentDate.addDays(isRightToLeft() ? 1 : -1);
1315 case QAbstractItemView::MoveRight:
1316 currentDate = currentDate.addDays(isRightToLeft() ? -1 : 1);
1318 case QAbstractItemView::MoveHome:
1319 currentDate = QDate(currentDate.year(), currentDate.month(), 1);
1321 case QAbstractItemView::MoveEnd:
1322 currentDate = QDate(currentDate.year(), currentDate.month(), currentDate.daysInMonth());
1324 case QAbstractItemView::MovePageUp:
1325 currentDate = currentDate.addMonths(-1);
1327 case QAbstractItemView::MovePageDown:
1328 currentDate = currentDate.addMonths(1);
1330 case QAbstractItemView::MoveNext:
1331 case QAbstractItemView::MovePrevious:
1332 return currentIndex();
1336 emit changeDate(currentDate, true);
1337 return currentIndex();
1340 void QCalendarView::keyPressEvent(QKeyEvent *event)
1342 #ifdef QT_KEYPAD_NAVIGATION
1343 if (event->key() == Qt::Key_Select) {
1344 if (QApplication::keypadNavigationEnabled()) {
1345 if (!hasEditFocus()) {
1350 } else if (event->key() == Qt::Key_Back) {
1351 if (QApplication::keypadNavigationEnabled() && hasEditFocus()) {
1352 if (qobject_cast<QCalendarModel *>(model())) {
1353 emit changeDate(origDate, true); //changes selection back to origDate, but doesn't activate
1354 setEditFocus(false);
1362 switch (event->key()) {
1363 case Qt::Key_Return:
1365 case Qt::Key_Select:
1366 emit editingFinished();
1372 QTableView::keyPressEvent(event);
1375 #ifndef QT_NO_WHEELEVENT
1376 void QCalendarView::wheelEvent(QWheelEvent *event)
1378 const int numDegrees = event->delta() / 8;
1379 const int numSteps = numDegrees / 15;
1380 const QModelIndex index = currentIndex();
1381 QDate currentDate = static_cast<QCalendarModel*>(model())->dateForCell(index.row(), index.column());
1382 currentDate = currentDate.addMonths(-numSteps);
1383 emit showDate(currentDate);
1387 bool QCalendarView::event(QEvent *event)
1389 #ifdef QT_KEYPAD_NAVIGATION
1390 if (event->type() == QEvent::FocusIn) {
1391 if (QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model())) {
1392 origDate = calendarModel->m_date;
1397 return QTableView::event(event);
1400 QDate QCalendarView::handleMouseEvent(QMouseEvent *event)
1402 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1406 QPoint pos = event->pos();
1407 QModelIndex index = indexAt(pos);
1408 QDate date = calendarModel->dateForCell(index.row(), index.column());
1409 if (date.isValid() && date >= calendarModel->m_minimumDate
1410 && date <= calendarModel->m_maximumDate) {
1416 void QCalendarView::mouseDoubleClickEvent(QMouseEvent *event)
1418 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1419 if (!calendarModel) {
1420 QTableView::mouseDoubleClickEvent(event);
1427 QDate date = handleMouseEvent(event);
1428 validDateClicked = false;
1429 if (date == calendarModel->m_date && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)) {
1430 emit editingFinished();
1434 void QCalendarView::mousePressEvent(QMouseEvent *event)
1436 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1437 if (!calendarModel) {
1438 QTableView::mousePressEvent(event);
1445 if (event->button() != Qt::LeftButton)
1448 QDate date = handleMouseEvent(event);
1449 if (date.isValid()) {
1450 validDateClicked = true;
1451 int row = -1, col = -1;
1452 static_cast<QCalendarModel *>(model())->cellForDate(date, &row, &col);
1453 if (row != -1 && col != -1) {
1454 selectionModel()->setCurrentIndex(model()->index(row, col), QItemSelectionModel::NoUpdate);
1457 validDateClicked = false;
1462 void QCalendarView::mouseMoveEvent(QMouseEvent *event)
1464 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1465 if (!calendarModel) {
1466 QTableView::mouseMoveEvent(event);
1473 if (validDateClicked) {
1474 QDate date = handleMouseEvent(event);
1475 if (date.isValid()) {
1476 int row = -1, col = -1;
1477 static_cast<QCalendarModel *>(model())->cellForDate(date, &row, &col);
1478 if (row != -1 && col != -1) {
1479 selectionModel()->setCurrentIndex(model()->index(row, col), QItemSelectionModel::NoUpdate);
1487 void QCalendarView::mouseReleaseEvent(QMouseEvent *event)
1489 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1490 if (!calendarModel) {
1491 QTableView::mouseReleaseEvent(event);
1495 if (event->button() != Qt::LeftButton)
1501 if (validDateClicked) {
1502 QDate date = handleMouseEvent(event);
1503 if (date.isValid()) {
1504 emit changeDate(date, true);
1506 if (style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick))
1507 emit editingFinished();
1509 validDateClicked = false;
1515 class QCalendarDelegate : public QItemDelegate
1519 QCalendarDelegate(QCalendarWidgetPrivate *w, QObject *parent = 0)
1520 : QItemDelegate(parent), calendarWidgetPrivate(w)
1522 virtual void paint(QPainter *painter, const QStyleOptionViewItem &option,
1523 const QModelIndex &index) const;
1524 void paintCell(QPainter *painter, const QRect &rect, const QDate &date) const;
1527 QCalendarWidgetPrivate *calendarWidgetPrivate;
1528 mutable QStyleOptionViewItemV4 storedOption;
1531 //Private tool button class
1532 class QCalToolButton: public QToolButton
1535 QCalToolButton(QWidget * parent)
1536 : QToolButton(parent)
1539 void paintEvent(QPaintEvent *e)
1544 QStyleOptionToolButton opt;
1545 initStyleOption(&opt);
1547 if (opt.state & QStyle::State_MouseOver || isDown()) {
1548 //act as normal button
1549 setPalette(QPalette());
1551 //set the highlight color for button text
1552 QPalette toolPalette = palette();
1553 toolPalette.setColor(QPalette::ButtonText, toolPalette.color(QPalette::HighlightedText));
1554 setPalette(toolPalette);
1557 QToolButton::paintEvent(e);
1561 class QPrevNextCalButton : public QToolButton
1565 QPrevNextCalButton(QWidget *parent) : QToolButton(parent) {}
1567 void paintEvent(QPaintEvent *) {
1568 QStylePainter painter(this);
1569 QStyleOptionToolButton opt;
1570 initStyleOption(&opt);
1571 opt.state &= ~QStyle::State_HasFocus;
1572 painter.drawComplexControl(QStyle::CC_ToolButton, opt);
1576 class QCalendarWidgetPrivate : public QWidgetPrivate
1578 Q_DECLARE_PUBLIC(QCalendarWidget)
1580 QCalendarWidgetPrivate();
1582 void showMonth(int year, int month);
1584 void paintCell(QPainter *painter, const QRect &rect, const QDate &date) const;
1586 void _q_slotShowDate(const QDate &date);
1587 void _q_slotChangeDate(const QDate &date);
1588 void _q_slotChangeDate(const QDate &date, bool changeMonth);
1589 void _q_editingFinished();
1590 void _q_monthChanged(QAction*);
1591 void _q_prevMonthClicked();
1592 void _q_nextMonthClicked();
1593 void _q_yearEditingFinished();
1594 void _q_yearClicked();
1596 void createNavigationBar(QWidget *widget);
1597 void updateButtonIcons();
1598 void updateMonthMenu();
1599 void updateMonthMenuNames();
1600 void updateNavigationBar();
1601 void updateCurrentPage(const QDate &newDate);
1602 inline QDate getCurrentDate();
1603 void setNavigatorEnabled(bool enable);
1605 QCalendarModel *m_model;
1606 QCalendarView *m_view;
1607 QCalendarDelegate *m_delegate;
1608 QItemSelectionModel *m_selection;
1609 QCalendarTextNavigator *m_navigator;
1610 bool m_dateEditEnabled;
1612 QToolButton *nextMonth;
1613 QToolButton *prevMonth;
1614 QCalToolButton *monthButton;
1616 QMap<int, QAction *> monthToAction;
1617 QCalToolButton *yearButton;
1619 QWidget *navBarBackground;
1620 QSpacerItem *spaceHolder;
1623 mutable QSize cachedSizeHint;
1624 Qt::FocusPolicy oldFocusPolicy;
1627 void QCalendarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
1628 const QModelIndex &index) const
1630 QDate date = calendarWidgetPrivate->m_model->dateForCell(index.row(), index.column());
1631 if (date.isValid()) {
1632 storedOption = option;
1633 QRect rect = option.rect;
1634 calendarWidgetPrivate->paintCell(painter, rect, date);
1636 QItemDelegate::paint(painter, option, index);
1640 void QCalendarDelegate::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
1642 storedOption.rect = rect;
1645 calendarWidgetPrivate->m_model->cellForDate(date, &row, &col);
1646 QModelIndex idx = calendarWidgetPrivate->m_model->index(row, col);
1647 QItemDelegate::paint(painter, storedOption, idx);
1650 QCalendarWidgetPrivate::QCalendarWidgetPrivate()
1658 m_dateEditEnabled = false;
1659 navBarVisible = true;
1660 oldFocusPolicy = Qt::StrongFocus;
1663 void QCalendarWidgetPrivate::setNavigatorEnabled(bool enable)
1665 Q_Q(QCalendarWidget);
1667 bool navigatorEnabled = (m_navigator->widget() != 0);
1668 if (enable == navigatorEnabled)
1672 m_navigator->setWidget(q);
1673 q->connect(m_navigator, SIGNAL(dateChanged(QDate)),
1674 q, SLOT(_q_slotChangeDate(QDate)));
1675 q->connect(m_navigator, SIGNAL(editingFinished()),
1676 q, SLOT(_q_editingFinished()));
1677 m_view->installEventFilter(m_navigator);
1679 m_navigator->setWidget(0);
1680 q->disconnect(m_navigator, SIGNAL(dateChanged(QDate)),
1681 q, SLOT(_q_slotChangeDate(QDate)));
1682 q->disconnect(m_navigator, SIGNAL(editingFinished()),
1683 q, SLOT(_q_editingFinished()));
1684 m_view->removeEventFilter(m_navigator);
1688 void QCalendarWidgetPrivate::createNavigationBar(QWidget *widget)
1690 Q_Q(QCalendarWidget);
1691 navBarBackground = new QWidget(widget);
1692 navBarBackground->setObjectName(QLatin1String("qt_calendar_navigationbar"));
1693 navBarBackground->setAutoFillBackground(true);
1694 navBarBackground->setBackgroundRole(QPalette::Highlight);
1696 prevMonth = new QPrevNextCalButton(navBarBackground);
1697 nextMonth = new QPrevNextCalButton(navBarBackground);
1698 prevMonth->setAutoRaise(true);
1699 nextMonth->setAutoRaise(true);
1700 prevMonth->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1701 nextMonth->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1702 nextMonth->setAutoRaise(true);
1703 updateButtonIcons();
1704 prevMonth->setAutoRepeat(true);
1705 nextMonth->setAutoRepeat(true);
1707 monthButton = new QCalToolButton(navBarBackground);
1708 monthButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1709 monthButton->setAutoRaise(true);
1710 monthButton->setPopupMode(QToolButton::InstantPopup);
1711 monthMenu = new QMenu(monthButton);
1712 for (int i = 1; i <= 12; i++) {
1713 QString monthName(q->locale().standaloneMonthName(i, QLocale::LongFormat));
1714 QAction *act = monthMenu->addAction(monthName);
1716 monthToAction[i] = act;
1718 monthButton->setMenu(monthMenu);
1719 yearButton = new QCalToolButton(navBarBackground);
1720 yearButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1721 yearButton->setAutoRaise(true);
1722 yearEdit = new QSpinBox(navBarBackground);
1724 QFont font = q->font();
1726 monthButton->setFont(font);
1727 yearButton->setFont(font);
1728 yearEdit->setFrame(false);
1729 yearEdit->setMinimum(m_model->m_minimumDate.year());
1730 yearEdit->setMaximum(m_model->m_maximumDate.year());
1732 spaceHolder = new QSpacerItem(0,0);
1734 QHBoxLayout *headerLayout = new QHBoxLayout;
1735 headerLayout->setMargin(0);
1736 headerLayout->setSpacing(0);
1737 headerLayout->addWidget(prevMonth);
1738 headerLayout->insertStretch(headerLayout->count());
1739 headerLayout->addWidget(monthButton);
1740 headerLayout->addItem(spaceHolder);
1741 headerLayout->addWidget(yearButton);
1742 headerLayout->insertStretch(headerLayout->count());
1743 headerLayout->addWidget(nextMonth);
1744 navBarBackground->setLayout(headerLayout);
1746 yearEdit->setFocusPolicy(Qt::StrongFocus);
1747 prevMonth->setFocusPolicy(Qt::NoFocus);
1748 nextMonth->setFocusPolicy(Qt::NoFocus);
1749 yearButton->setFocusPolicy(Qt::NoFocus);
1750 monthButton->setFocusPolicy(Qt::NoFocus);
1752 //set names for the header controls.
1753 prevMonth->setObjectName(QLatin1String("qt_calendar_prevmonth"));
1754 nextMonth->setObjectName(QLatin1String("qt_calendar_nextmonth"));
1755 monthButton->setObjectName(QLatin1String("qt_calendar_monthbutton"));
1756 yearButton->setObjectName(QLatin1String("qt_calendar_yearbutton"));
1757 yearEdit->setObjectName(QLatin1String("qt_calendar_yearedit"));
1760 showMonth(m_model->m_date.year(), m_model->m_date.month());
1763 void QCalendarWidgetPrivate::updateButtonIcons()
1765 Q_Q(QCalendarWidget);
1766 prevMonth->setIcon(q->style()->standardIcon(q->isRightToLeft() ? QStyle::SP_ArrowRight : QStyle::SP_ArrowLeft, 0, q));
1767 nextMonth->setIcon(q->style()->standardIcon(q->isRightToLeft() ? QStyle::SP_ArrowLeft : QStyle::SP_ArrowRight, 0, q));
1770 void QCalendarWidgetPrivate::updateMonthMenu()
1772 int beg = 1, end = 12;
1773 bool prevEnabled = true;
1774 bool nextEnabled = true;
1775 if (m_model->m_shownYear == m_model->m_minimumDate.year()) {
1776 beg = m_model->m_minimumDate.month();
1777 if (m_model->m_shownMonth == m_model->m_minimumDate.month())
1778 prevEnabled = false;
1780 if (m_model->m_shownYear == m_model->m_maximumDate.year()) {
1781 end = m_model->m_maximumDate.month();
1782 if (m_model->m_shownMonth == m_model->m_maximumDate.month())
1783 nextEnabled = false;
1785 prevMonth->setEnabled(prevEnabled);
1786 nextMonth->setEnabled(nextEnabled);
1787 for (int i = 1; i <= 12; i++) {
1788 bool monthEnabled = true;
1789 if (i < beg || i > end)
1790 monthEnabled = false;
1791 monthToAction[i]->setEnabled(monthEnabled);
1795 void QCalendarWidgetPrivate::updateMonthMenuNames()
1797 Q_Q(QCalendarWidget);
1799 for (int i = 1; i <= 12; i++) {
1800 QString monthName(q->locale().standaloneMonthName(i, QLocale::LongFormat));
1801 monthToAction[i]->setText(monthName);
1805 void QCalendarWidgetPrivate::updateCurrentPage(const QDate &date)
1807 Q_Q(QCalendarWidget);
1809 QDate newDate = date;
1810 QDate minDate = q->minimumDate();
1811 QDate maxDate = q->maximumDate();
1812 if (minDate.isValid()&& minDate.daysTo(newDate) < 0)
1814 if (maxDate.isValid()&& maxDate.daysTo(newDate) > 0)
1816 showMonth(newDate.year(), newDate.month());
1817 int row = -1, col = -1;
1818 m_model->cellForDate(newDate, &row, &col);
1819 if (row != -1 && col != -1)
1821 m_view->selectionModel()->setCurrentIndex(m_model->index(row, col),
1822 QItemSelectionModel::NoUpdate);
1826 void QCalendarWidgetPrivate::_q_monthChanged(QAction *act)
1828 monthButton->setText(act->text());
1829 QDate currentDate = getCurrentDate();
1830 QDate newDate = currentDate.addMonths(act->data().toInt()-currentDate.month());
1831 updateCurrentPage(newDate);
1834 QDate QCalendarWidgetPrivate::getCurrentDate()
1836 QModelIndex index = m_view->currentIndex();
1837 return m_model->dateForCell(index.row(), index.column());
1840 void QCalendarWidgetPrivate::_q_prevMonthClicked()
1842 QDate currentDate = getCurrentDate().addMonths(-1);
1843 updateCurrentPage(currentDate);
1846 void QCalendarWidgetPrivate::_q_nextMonthClicked()
1848 QDate currentDate = getCurrentDate().addMonths(1);
1849 updateCurrentPage(currentDate);
1852 void QCalendarWidgetPrivate::_q_yearEditingFinished()
1854 Q_Q(QCalendarWidget);
1855 yearButton->setText(yearEdit->text());
1857 q->setFocusPolicy(oldFocusPolicy);
1858 qApp->removeEventFilter(q);
1859 spaceHolder->changeSize(0, 0);
1861 QDate currentDate = getCurrentDate();
1862 currentDate = currentDate.addYears(yearEdit->text().toInt() - currentDate.year());
1863 updateCurrentPage(currentDate);
1866 void QCalendarWidgetPrivate::_q_yearClicked()
1868 Q_Q(QCalendarWidget);
1869 //show the spinbox on top of the button
1870 yearEdit->setGeometry(yearButton->x(), yearButton->y(),
1871 yearEdit->sizeHint().width(), yearButton->height());
1872 spaceHolder->changeSize(yearButton->width(), 0);
1874 oldFocusPolicy = q->focusPolicy();
1875 q->setFocusPolicy(Qt::NoFocus);
1877 qApp->installEventFilter(q);
1879 yearEdit->selectAll();
1880 yearEdit->setFocus(Qt::MouseFocusReason);
1883 void QCalendarWidgetPrivate::showMonth(int year, int month)
1885 if (m_model->m_shownYear == year && m_model->m_shownMonth == month)
1887 Q_Q(QCalendarWidget);
1888 m_model->showMonth(year, month);
1889 updateNavigationBar();
1890 emit q->currentPageChanged(year, month);
1891 m_view->internalUpdate();
1892 cachedSizeHint = QSize();
1897 void QCalendarWidgetPrivate::updateNavigationBar()
1899 Q_Q(QCalendarWidget);
1901 QString monthName = q->locale().standaloneMonthName(m_model->m_shownMonth, QLocale::LongFormat);
1903 monthButton->setText(monthName);
1904 yearButton->setText(QString::number(m_model->m_shownYear));
1905 yearEdit->setValue(m_model->m_shownYear);
1908 void QCalendarWidgetPrivate::update()
1910 QDate currentDate = m_model->m_date;
1912 m_model->cellForDate(currentDate, &row, &column);
1914 m_selection->clear();
1915 if (row != -1 && column != -1) {
1916 idx = m_model->index(row, column);
1917 m_selection->setCurrentIndex(idx, QItemSelectionModel::SelectCurrent);
1921 void QCalendarWidgetPrivate::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
1923 Q_Q(const QCalendarWidget);
1924 q->paintCell(painter, rect, date);
1927 void QCalendarWidgetPrivate::_q_slotShowDate(const QDate &date)
1929 updateCurrentPage(date);
1932 void QCalendarWidgetPrivate::_q_slotChangeDate(const QDate &date)
1934 _q_slotChangeDate(date, true);
1937 void QCalendarWidgetPrivate::_q_slotChangeDate(const QDate &date, bool changeMonth)
1939 QDate oldDate = m_model->m_date;
1940 m_model->setDate(date);
1941 QDate newDate = m_model->m_date;
1943 showMonth(newDate.year(), newDate.month());
1944 if (oldDate != newDate) {
1946 Q_Q(QCalendarWidget);
1947 m_navigator->setDate(newDate);
1948 emit q->selectionChanged();
1952 void QCalendarWidgetPrivate::_q_editingFinished()
1954 Q_Q(QCalendarWidget);
1955 emit q->activated(m_model->m_date);
1959 \class QCalendarWidget
1960 \brief The QCalendarWidget class provides a monthly based
1961 calendar widget allowing the user to select a date.
1967 \image cleanlooks-calendarwidget.png
1969 The widget is initialized with the current month and year, but
1970 QCalendarWidget provides several public slots to change the year
1971 and month that is shown.
1973 By default, today's date is selected, and the user can select a
1974 date using both mouse and keyboard. The currently selected date
1975 can be retrieved using the selectedDate() function. It is
1976 possible to constrain the user selection to a given date range by
1977 setting the minimumDate and maximumDate properties.
1978 Alternatively, both properties can be set in one go using the
1979 setDateRange() convenience slot. Set the \l selectionMode
1980 property to NoSelection to prohibit the user from selecting at
1981 all. Note that a date also can be selected programmatically using
1982 the setSelectedDate() slot.
1984 The currently displayed month and year can be retrieved using the
1985 monthShown() and yearShown() functions, respectively.
1987 A newly created calendar widget uses abbreviated day names, and
1988 both Saturdays and Sundays are marked in red. The calendar grid is
1989 not visible. The week numbers are displayed, and the first column
1990 day is the first day of the week for the calendar's locale.
1992 The notation of the days can be altered to a single letter
1993 abbreviations ("M" for "Monday") by setting the
1994 horizontalHeaderFormat property to
1995 QCalendarWidget::SingleLetterDayNames. Setting the same property
1996 to QCalendarWidget::LongDayNames makes the header display the
1997 complete day names. The week numbers can be removed by setting
1998 the verticalHeaderFormat property to
1999 QCalendarWidget::NoVerticalHeader. The calendar grid can be
2000 turned on by setting the gridVisible property to true using the
2001 setGridVisible() function:
2005 \image qcalendarwidget-grid.png
2007 \snippet code/src_gui_widgets_qcalendarwidget.cpp 0
2010 Finally, the day in the first column can be altered using the
2011 setFirstDayOfWeek() function.
2013 The QCalendarWidget class also provides three signals,
2014 selectionChanged(), activated() and currentPageChanged() making it
2015 possible to respond to user interaction.
2017 The rendering of the headers, weekdays or single days can be
2018 largely customized by setting QTextCharFormat's for some special
2019 weekday, a special date or for the rendering of the headers.
2021 Only a subset of the properties in QTextCharFormat are used by the
2022 calendar widget. Currently, the foreground, background and font
2023 properties are used to determine the rendering of individual cells
2026 \sa QDate, QDateEdit, QTextCharFormat
2030 \enum QCalendarWidget::SelectionMode
2032 This enum describes the types of selection offered to the user for
2033 selecting dates in the calendar.
2035 \value NoSelection Dates cannot be selected.
2036 \value SingleSelection Single dates can be selected.
2042 Constructs a calendar widget with the given \a parent.
2044 The widget is initialized with the current month and year, and the
2045 currently selected date is today.
2047 \sa setCurrentPage()
2049 QCalendarWidget::QCalendarWidget(QWidget *parent)
2050 : QWidget(*new QCalendarWidgetPrivate, parent, 0)
2052 Q_D(QCalendarWidget);
2054 setAutoFillBackground(true);
2055 setBackgroundRole(QPalette::Window);
2057 QVBoxLayout *layoutV = new QVBoxLayout(this);
2058 layoutV->setMargin(0);
2059 d->m_model = new QCalendarModel(this);
2060 QTextCharFormat fmt;
2061 fmt.setForeground(QBrush(Qt::red));
2062 d->m_model->m_dayFormats.insert(Qt::Saturday, fmt);
2063 d->m_model->m_dayFormats.insert(Qt::Sunday, fmt);
2064 d->m_view = new QCalendarView(this);
2065 d->m_view->setObjectName(QLatin1String("qt_calendar_calendarview"));
2066 d->m_view->setModel(d->m_model);
2067 d->m_model->setView(d->m_view);
2068 d->m_view->setSelectionBehavior(QAbstractItemView::SelectItems);
2069 d->m_view->setSelectionMode(QAbstractItemView::SingleSelection);
2070 d->m_view->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
2071 d->m_view->horizontalHeader()->setSectionsClickable(false);
2072 d->m_view->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
2073 d->m_view->verticalHeader()->setSectionsClickable(false);
2074 d->m_selection = d->m_view->selectionModel();
2075 d->createNavigationBar(this);
2076 d->m_view->setFrameStyle(QFrame::NoFrame);
2077 d->m_delegate = new QCalendarDelegate(d, this);
2078 d->m_view->setItemDelegate(d->m_delegate);
2080 d->updateNavigationBar();
2081 setFocusPolicy(Qt::StrongFocus);
2082 setFocusProxy(d->m_view);
2083 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
2085 connect(d->m_view, SIGNAL(showDate(QDate)),
2086 this, SLOT(_q_slotShowDate(QDate)));
2087 connect(d->m_view, SIGNAL(changeDate(QDate,bool)),
2088 this, SLOT(_q_slotChangeDate(QDate,bool)));
2089 connect(d->m_view, SIGNAL(clicked(QDate)),
2090 this, SIGNAL(clicked(QDate)));
2091 connect(d->m_view, SIGNAL(editingFinished()),
2092 this, SLOT(_q_editingFinished()));
2094 connect(d->prevMonth, SIGNAL(clicked(bool)),
2095 this, SLOT(_q_prevMonthClicked()));
2096 connect(d->nextMonth, SIGNAL(clicked(bool)),
2097 this, SLOT(_q_nextMonthClicked()));
2098 connect(d->yearButton, SIGNAL(clicked(bool)),
2099 this, SLOT(_q_yearClicked()));
2100 connect(d->monthMenu, SIGNAL(triggered(QAction*)),
2101 this, SLOT(_q_monthChanged(QAction*)));
2102 connect(d->yearEdit, SIGNAL(editingFinished()),
2103 this, SLOT(_q_yearEditingFinished()));
2105 layoutV->setMargin(0);
2106 layoutV->setSpacing(0);
2107 layoutV->addWidget(d->navBarBackground);
2108 layoutV->addWidget(d->m_view);
2110 d->m_navigator = new QCalendarTextNavigator(this);
2111 setDateEditEnabled(true);
2115 Destroys the calendar widget.
2117 QCalendarWidget::~QCalendarWidget()
2124 QSize QCalendarWidget::sizeHint() const
2126 return minimumSizeHint();
2132 QSize QCalendarWidget::minimumSizeHint() const
2134 Q_D(const QCalendarWidget);
2135 if (d->cachedSizeHint.isValid())
2136 return d->cachedSizeHint;
2147 const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1) * 2;
2149 if (horizontalHeaderFormat() == QCalendarWidget::NoHorizontalHeader) {
2152 for (int i = 1; i <= 7; i++) {
2153 QFontMetrics fm(d->m_model->formatForCell(0, i).font());
2154 w = qMax(w, fm.width(d->m_model->dayName(d->m_model->dayOfWeekForColumn(i))) + marginH);
2155 h = qMax(h, fm.height());
2159 if (verticalHeaderFormat() == QCalendarWidget::NoVerticalHeader) {
2162 for (int i = 1; i <= 6; i++) {
2163 QFontMetrics fm(d->m_model->formatForCell(i, 0).font());
2164 for (int j = 1; j < end; j++)
2165 w = qMax(w, fm.width(QString::number(j)) + marginH);
2166 h = qMax(h, fm.height());
2170 QFontMetrics fm(d->m_model->formatForCell(1, 1).font());
2171 for (int i = 1; i <= end; i++) {
2172 w = qMax(w, fm.width(QString::number(i)) + marginH);
2173 h = qMax(h, fm.height());
2176 if (d->m_view->showGrid()) {
2177 // hardcoded in tableview
2182 w += 1; // default column span
2184 h = qMax(h, d->m_view->verticalHeader()->minimumSectionSize());
2185 w = qMax(w, d->m_view->horizontalHeader()->minimumSectionSize());
2187 //add the size of the header.
2188 QSize headerSize(0, 0);
2189 if (d->navBarVisible) {
2190 int headerH = d->navBarBackground->sizeHint().height();
2193 headerW += d->prevMonth->sizeHint().width();
2194 headerW += d->nextMonth->sizeHint().width();
2196 QFontMetrics fm = d->monthButton->fontMetrics();
2198 for (int i = 1; i < 12; i++) {
2199 QString monthName = locale().standaloneMonthName(i, QLocale::LongFormat);
2200 monthW = qMax(monthW, fm.boundingRect(monthName).width());
2202 const int buttonDecoMargin = d->monthButton->sizeHint().width() - fm.boundingRect(d->monthButton->text()).width();
2203 headerW += monthW + buttonDecoMargin;
2205 fm = d->yearButton->fontMetrics();
2206 headerW += fm.boundingRect(QLatin1String("5555")).width() + buttonDecoMargin;
2208 headerSize = QSize(headerW, headerH);
2211 w = qMax(headerSize.width(), w);
2212 h = (h * rows) + headerSize.height();
2213 d->cachedSizeHint = QSize(w, h);
2214 return d->cachedSizeHint;
2218 Paints the cell specified by the given \a date, using the given \a painter and \a rect.
2221 void QCalendarWidget::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
2223 Q_D(const QCalendarWidget);
2224 d->m_delegate->paintCell(painter, rect, date);
2228 \property QCalendarWidget::selectedDate
2229 \brief the currently selected date.
2231 The selected date must be within the date range specified by the
2232 minimumDate and maximumDate properties. By default, the selected
2233 date is the current date.
2238 QDate QCalendarWidget::selectedDate() const
2240 Q_D(const QCalendarWidget);
2241 return d->m_model->m_date;
2244 void QCalendarWidget::setSelectedDate(const QDate &date)
2246 Q_D(QCalendarWidget);
2247 if (d->m_model->m_date == date && date == d->getCurrentDate())
2250 if (!date.isValid())
2253 d->m_model->setDate(date);
2255 QDate newDate = d->m_model->m_date;
2256 d->showMonth(newDate.year(), newDate.month());
2257 emit selectionChanged();
2261 Returns the year of the currently displayed month. Months are
2262 numbered from 1 to 12.
2264 \sa monthShown(), setCurrentPage()
2267 int QCalendarWidget::yearShown() const
2269 Q_D(const QCalendarWidget);
2270 return d->m_model->m_shownYear;
2274 Returns the currently displayed month. Months are numbered from 1 to
2277 \sa yearShown(), setCurrentPage()
2280 int QCalendarWidget::monthShown() const
2282 Q_D(const QCalendarWidget);
2283 return d->m_model->m_shownMonth;
2287 Displays the given \a month of the given \a year without changing
2288 the selected date. Use the setSelectedDate() function to alter the
2291 The currently displayed month and year can be retrieved using the
2292 monthShown() and yearShown() functions respectively.
2294 \sa yearShown(), monthShown(), showPreviousMonth(), showNextMonth(),
2295 showPreviousYear(), showNextYear()
2298 void QCalendarWidget::setCurrentPage(int year, int month)
2300 Q_D(QCalendarWidget);
2301 QDate currentDate = d->getCurrentDate();
2302 int day = currentDate.day();
2303 int daysInMonths = QDate(year, month, 1).daysInMonth();
2304 if (day > daysInMonths)
2307 d->showMonth(year, month);
2309 QDate newDate(year, month, day);
2310 int row = -1, col = -1;
2311 d->m_model->cellForDate(newDate, &row, &col);
2312 if (row != -1 && col != -1) {
2313 d->m_view->selectionModel()->setCurrentIndex(d->m_model->index(row, col),
2314 QItemSelectionModel::NoUpdate);
2319 Shows the next month relative to the currently displayed
2320 month. Note that the selected date is not changed.
2322 \sa showPreviousMonth(), setCurrentPage(), setSelectedDate()
2325 void QCalendarWidget::showNextMonth()
2327 int year = yearShown();
2328 int month = monthShown();
2335 setCurrentPage(year, month);
2339 Shows the previous month relative to the currently displayed
2340 month. Note that the selected date is not changed.
2342 \sa showNextMonth(), setCurrentPage(), setSelectedDate()
2345 void QCalendarWidget::showPreviousMonth()
2347 int year = yearShown();
2348 int month = monthShown();
2355 setCurrentPage(year, month);
2359 Shows the currently displayed month in the \e next year relative
2360 to the currently displayed year. Note that the selected date is
2363 \sa showPreviousYear(), setCurrentPage(), setSelectedDate()
2366 void QCalendarWidget::showNextYear()
2368 int year = yearShown();
2369 int month = monthShown();
2371 setCurrentPage(year, month);
2375 Shows the currently displayed month in the \e previous year
2376 relative to the currently displayed year. Note that the selected
2377 date is not changed.
2379 \sa showNextYear(), setCurrentPage(), setSelectedDate()
2382 void QCalendarWidget::showPreviousYear()
2384 int year = yearShown();
2385 int month = monthShown();
2387 setCurrentPage(year, month);
2391 Shows the month of the selected date.
2393 \sa selectedDate(), setCurrentPage()
2395 void QCalendarWidget::showSelectedDate()
2397 QDate currentDate = selectedDate();
2398 setCurrentPage(currentDate.year(), currentDate.month());
2402 Shows the month of the today's date.
2404 \sa selectedDate(), setCurrentPage()
2406 void QCalendarWidget::showToday()
2408 QDate currentDate = QDate::currentDate();
2409 setCurrentPage(currentDate.year(), currentDate.month());
2413 \property QCalendarWidget::minimumDate
2414 \brief the minimum date of the currently specified date range.
2416 The user will not be able to select a date that is before the
2417 currently set minimum date.
2421 \li \image qcalendarwidget-minimum.png
2424 \snippet code/src_gui_widgets_qcalendarwidget.cpp 1
2427 By default, the minimum date is the earliest date that the QDate
2430 When setting a minimum date, the maximumDate and selectedDate
2431 properties are adjusted if the selection range becomes invalid. If
2432 the provided date is not a valid QDate object, the
2433 setMinimumDate() function does nothing.
2438 QDate QCalendarWidget::minimumDate() const
2440 Q_D(const QCalendarWidget);
2441 return d->m_model->m_minimumDate;
2444 void QCalendarWidget::setMinimumDate(const QDate &date)
2446 Q_D(QCalendarWidget);
2447 if (!date.isValid() || d->m_model->m_minimumDate == date)
2450 QDate oldDate = d->m_model->m_date;
2451 d->m_model->setMinimumDate(date);
2452 d->yearEdit->setMinimum(d->m_model->m_minimumDate.year());
2453 d->updateMonthMenu();
2454 QDate newDate = d->m_model->m_date;
2455 if (oldDate != newDate) {
2457 d->showMonth(newDate.year(), newDate.month());
2458 d->m_navigator->setDate(newDate);
2459 emit selectionChanged();
2464 \property QCalendarWidget::maximumDate
2465 \brief the maximum date of the currently specified date range.
2467 The user will not be able to select a date which is after the
2468 currently set maximum date.
2472 \li \image qcalendarwidget-maximum.png
2475 \snippet code/src_gui_widgets_qcalendarwidget.cpp 2
2478 By default, the maximum date is the last day the QDate class can
2481 When setting a maximum date, the minimumDate and selectedDate
2482 properties are adjusted if the selection range becomes invalid. If
2483 the provided date is not a valid QDate object, the
2484 setMaximumDate() function does nothing.
2489 QDate QCalendarWidget::maximumDate() const
2491 Q_D(const QCalendarWidget);
2492 return d->m_model->m_maximumDate;
2495 void QCalendarWidget::setMaximumDate(const QDate &date)
2497 Q_D(QCalendarWidget);
2498 if (!date.isValid() || d->m_model->m_maximumDate == date)
2501 QDate oldDate = d->m_model->m_date;
2502 d->m_model->setMaximumDate(date);
2503 d->yearEdit->setMaximum(d->m_model->m_maximumDate.year());
2504 d->updateMonthMenu();
2505 QDate newDate = d->m_model->m_date;
2506 if (oldDate != newDate) {
2508 d->showMonth(newDate.year(), newDate.month());
2509 d->m_navigator->setDate(newDate);
2510 emit selectionChanged();
2515 Defines a date range by setting the minimumDate and maximumDate
2518 The date range restricts the user selection, i.e. the user can
2519 only select dates within the specified date range. Note that
2521 \snippet code/src_gui_widgets_qcalendarwidget.cpp 3
2525 \snippet code/src_gui_widgets_qcalendarwidget.cpp 4
2527 If either the \a min or \a max parameters are not valid QDate
2528 objects, this function does nothing.
2530 \sa setMinimumDate(), setMaximumDate()
2533 void QCalendarWidget::setDateRange(const QDate &min, const QDate &max)
2535 Q_D(QCalendarWidget);
2536 if (d->m_model->m_minimumDate == min && d->m_model->m_maximumDate == max)
2538 if (!min.isValid() || !max.isValid())
2541 QDate oldDate = d->m_model->m_date;
2542 d->m_model->setRange(min, max);
2543 d->yearEdit->setMinimum(d->m_model->m_minimumDate.year());
2544 d->yearEdit->setMaximum(d->m_model->m_maximumDate.year());
2545 d->updateMonthMenu();
2546 QDate newDate = d->m_model->m_date;
2547 if (oldDate != newDate) {
2549 d->showMonth(newDate.year(), newDate.month());
2550 d->m_navigator->setDate(newDate);
2551 emit selectionChanged();
2556 /*! \enum QCalendarWidget::HorizontalHeaderFormat
2558 This enum type defines the various formats the horizontal header can display.
2560 \value SingleLetterDayNames The header displays a single letter abbreviation for day names (e.g. M for Monday).
2561 \value ShortDayNames The header displays a short abbreviation for day names (e.g. Mon for Monday).
2562 \value LongDayNames The header displays complete day names (e.g. Monday).
2563 \value NoHorizontalHeader The header is hidden.
2565 \sa horizontalHeaderFormat(), VerticalHeaderFormat
2569 \property QCalendarWidget::horizontalHeaderFormat
2570 \brief the format of the horizontal header.
2572 The default value is QCalendarWidget::ShortDayNames.
2575 void QCalendarWidget::setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format)
2577 Q_D(QCalendarWidget);
2578 if (d->m_model->m_horizontalHeaderFormat == format)
2581 d->m_model->setHorizontalHeaderFormat(format);
2582 d->cachedSizeHint = QSize();
2583 d->m_view->viewport()->update();
2584 d->m_view->updateGeometry();
2587 QCalendarWidget::HorizontalHeaderFormat QCalendarWidget::horizontalHeaderFormat() const
2589 Q_D(const QCalendarWidget);
2590 return d->m_model->m_horizontalHeaderFormat;
2595 \enum QCalendarWidget::VerticalHeaderFormat
2597 This enum type defines the various formats the vertical header can display.
2599 \value ISOWeekNumbers The header displays ISO week numbers as described by \l QDate::weekNumber().
2600 \value NoVerticalHeader The header is hidden.
2602 \sa verticalHeaderFormat(), HorizontalHeaderFormat
2606 \property QCalendarWidget::verticalHeaderFormat
2607 \brief the format of the vertical header.
2609 The default value is QCalendarWidget::ISOWeekNumber.
2612 QCalendarWidget::VerticalHeaderFormat QCalendarWidget::verticalHeaderFormat() const
2614 Q_D(const QCalendarWidget);
2615 bool shown = d->m_model->weekNumbersShown();
2617 return QCalendarWidget::ISOWeekNumbers;
2618 return QCalendarWidget::NoVerticalHeader;
2621 void QCalendarWidget::setVerticalHeaderFormat(QCalendarWidget::VerticalHeaderFormat format)
2623 Q_D(QCalendarWidget);
2625 if (format == QCalendarWidget::ISOWeekNumbers)
2627 if (d->m_model->weekNumbersShown() == show)
2629 d->m_model->setWeekNumbersShown(show);
2630 d->cachedSizeHint = QSize();
2631 d->m_view->viewport()->update();
2632 d->m_view->updateGeometry();
2636 \property QCalendarWidget::gridVisible
2637 \brief whether the table grid is displayed.
2641 \li \inlineimage qcalendarwidget-grid.png
2644 \snippet code/src_gui_widgets_qcalendarwidget.cpp 5
2647 The default value is false.
2650 bool QCalendarWidget::isGridVisible() const
2652 Q_D(const QCalendarWidget);
2653 return d->m_view->showGrid();
2656 void QCalendarWidget::setGridVisible(bool show)
2658 Q_D(QCalendarWidget);
2659 d->m_view->setShowGrid(show);
2660 d->cachedSizeHint = QSize();
2661 d->m_view->viewport()->update();
2662 d->m_view->updateGeometry();
2666 \property QCalendarWidget::selectionMode
2667 \brief the type of selection the user can make in the calendar
2669 When this property is set to SingleSelection, the user can select a date
2670 within the minimum and maximum allowed dates, using either the mouse or
2673 When the property is set to NoSelection, the user will be unable to select
2674 dates, but they can still be selected programmatically. Note that the date
2675 that is selected when the property is set to NoSelection will still be
2676 the selected date of the calendar.
2678 The default value is SingleSelection.
2681 QCalendarWidget::SelectionMode QCalendarWidget::selectionMode() const
2683 Q_D(const QCalendarWidget);
2684 return d->m_view->readOnly ? QCalendarWidget::NoSelection : QCalendarWidget::SingleSelection;
2687 void QCalendarWidget::setSelectionMode(SelectionMode mode)
2689 Q_D(QCalendarWidget);
2690 d->m_view->readOnly = (mode == QCalendarWidget::NoSelection);
2691 d->setNavigatorEnabled(isDateEditEnabled() && (selectionMode() != QCalendarWidget::NoSelection));
2696 \property QCalendarWidget::firstDayOfWeek
2697 \brief a value identifying the day displayed in the first column.
2699 By default, the day displayed in the first column
2700 is the first day of the week for the calendar's locale.
2703 void QCalendarWidget::setFirstDayOfWeek(Qt::DayOfWeek dayOfWeek)
2705 Q_D(QCalendarWidget);
2706 if ((Qt::DayOfWeek)d->m_model->firstColumnDay() == dayOfWeek)
2709 d->m_model->setFirstColumnDay(dayOfWeek);
2713 Qt::DayOfWeek QCalendarWidget::firstDayOfWeek() const
2715 Q_D(const QCalendarWidget);
2716 return (Qt::DayOfWeek)d->m_model->firstColumnDay();
2720 Returns the text char format for rendering the header.
2722 QTextCharFormat QCalendarWidget::headerTextFormat() const
2724 Q_D(const QCalendarWidget);
2725 return d->m_model->m_headerFormat;
2729 Sets the text char format for rendering the header to \a format.
2730 If you also set a weekday text format, this format's foreground and
2731 background color will take precedence over the header's format.
2732 The other formatting information will still be decided by
2733 the header's format.
2735 void QCalendarWidget::setHeaderTextFormat(const QTextCharFormat &format)
2737 Q_D(QCalendarWidget);
2738 d->m_model->m_headerFormat = format;
2739 d->cachedSizeHint = QSize();
2740 d->m_view->viewport()->update();
2741 d->m_view->updateGeometry();
2745 Returns the text char format for rendering of day in the week \a dayOfWeek.
2747 \sa headerTextFormat()
2749 QTextCharFormat QCalendarWidget::weekdayTextFormat(Qt::DayOfWeek dayOfWeek) const
2751 Q_D(const QCalendarWidget);
2752 return d->m_model->m_dayFormats.value(dayOfWeek);
2756 Sets the text char format for rendering of day in the week \a dayOfWeek to \a format.
2757 The format will take precedence over the header format in case of foreground
2758 and background color. Other text formatting information is taken from the headers format.
2760 \sa setHeaderTextFormat()
2762 void QCalendarWidget::setWeekdayTextFormat(Qt::DayOfWeek dayOfWeek, const QTextCharFormat &format)
2764 Q_D(QCalendarWidget);
2765 d->m_model->m_dayFormats[dayOfWeek] = format;
2766 d->cachedSizeHint = QSize();
2767 d->m_view->viewport()->update();
2768 d->m_view->updateGeometry();
2772 Returns a QMap from QDate to QTextCharFormat showing all dates
2773 that use a special format that alters their rendering.
2775 QMap<QDate, QTextCharFormat> QCalendarWidget::dateTextFormat() const
2777 Q_D(const QCalendarWidget);
2778 return d->m_model->m_dateFormats;
2782 Returns a QTextCharFormat for \a date. The char format can be be
2783 empty if the date is not renderd specially.
2785 QTextCharFormat QCalendarWidget::dateTextFormat(const QDate &date) const
2787 Q_D(const QCalendarWidget);
2788 return d->m_model->m_dateFormats.value(date);
2792 Sets the format used to render the given \a date to that specified by \a format.
2794 If \a date is null, all date formats are cleared.
2796 void QCalendarWidget::setDateTextFormat(const QDate &date, const QTextCharFormat &format)
2798 Q_D(QCalendarWidget);
2800 d->m_model->m_dateFormats.clear();
2802 d->m_model->m_dateFormats[date] = format;
2803 d->m_view->viewport()->update();
2804 d->m_view->updateGeometry();
2808 \property QCalendarWidget::dateEditEnabled
2809 \brief whether the date edit popup is enabled
2812 If this property is enabled, pressing a non-modifier key will cause a
2813 date edit to popup if the calendar widget has focus, allowing the user
2814 to specify a date in the form specified by the current locale.
2816 By default, this property is enabled.
2818 The date edit is simpler in appearance than QDateEdit, but allows the
2819 user to navigate between fields using the left and right cursor keys,
2820 increment and decrement individual fields using the up and down cursor
2821 keys, and enter values directly using the number keys.
2823 \sa QCalendarWidget::dateEditAcceptDelay
2825 bool QCalendarWidget::isDateEditEnabled() const
2827 Q_D(const QCalendarWidget);
2828 return d->m_dateEditEnabled;
2831 void QCalendarWidget::setDateEditEnabled(bool enable)
2833 Q_D(QCalendarWidget);
2834 if (isDateEditEnabled() == enable)
2837 d->m_dateEditEnabled = enable;
2839 d->setNavigatorEnabled(enable && (selectionMode() != QCalendarWidget::NoSelection));
2843 \property QCalendarWidget::dateEditAcceptDelay
2844 \brief the time an inactive date edit is shown before its contents are accepted
2847 If the calendar widget's \l{dateEditEnabled}{date edit is enabled}, this
2848 property specifies the amount of time (in millseconds) that the date edit
2849 remains open after the most recent user input. Once this time has elapsed,
2850 the date specified in the date edit is accepted and the popup is closed.
2852 By default, the delay is defined to be 1500 milliseconds (1.5 seconds).
2854 int QCalendarWidget::dateEditAcceptDelay() const
2856 Q_D(const QCalendarWidget);
2857 return d->m_navigator->dateEditAcceptDelay();
2860 void QCalendarWidget::setDateEditAcceptDelay(int delay)
2862 Q_D(QCalendarWidget);
2863 d->m_navigator->setDateEditAcceptDelay(delay);
2869 Updates the cell specified by the given \a date unless updates
2870 are disabled or the cell is hidden.
2872 \sa updateCells(), yearShown(), monthShown()
2874 void QCalendarWidget::updateCell(const QDate &date)
2876 if (!date.isValid()) {
2877 qWarning("QCalendarWidget::updateCell: Invalid date");
2884 Q_D(QCalendarWidget);
2886 d->m_model->cellForDate(date, &row, &column);
2887 if (row == -1 || column == -1)
2890 QModelIndex modelIndex = d->m_model->index(row, column);
2891 if (!modelIndex.isValid())
2894 d->m_view->viewport()->update(d->m_view->visualRect(modelIndex));
2900 Updates all visible cells unless updates are disabled.
2904 void QCalendarWidget::updateCells()
2906 Q_D(QCalendarWidget);
2908 d->m_view->viewport()->update();
2912 \fn void QCalendarWidget::selectionChanged()
2914 This signal is emitted when the currently selected date is
2917 The currently selected date can be changed by the user using the
2918 mouse or keyboard, or by the programmer using setSelectedDate().
2924 \fn void QCalendarWidget::currentPageChanged(int year, int month)
2926 This signal is emitted when the currently shown month is changed.
2927 The new \a year and \a month are passed as parameters.
2929 \sa setCurrentPage()
2933 \fn void QCalendarWidget::activated(const QDate &date)
2935 This signal is emitted whenever the user presses the Return or
2936 Enter key or double-clicks a \a date in the calendar
2941 \fn void QCalendarWidget::clicked(const QDate &date)
2943 This signal is emitted when a mouse button is clicked. The date
2944 the mouse was clicked on is specified by \a date. The signal is
2945 only emitted when clicked on a valid date, e.g., dates are not
2946 outside the minimumDate() and maximumDate(). If the selection mode
2947 is NoSelection, this signal will not be emitted.
2952 \property QCalendarWidget::headerVisible
2953 \brief whether the navigation bar is shown or not
2957 Use navigationBarVisible() instead.
2959 By default, this property is true.
2963 \property QCalendarWidget::navigationBarVisible
2964 \brief whether the navigation bar is shown or not
2968 When this property is true (the default), the next month,
2969 previous month, month selection, year selection controls are
2972 When the property is set to false, these controls are hidden.
2975 bool QCalendarWidget::isNavigationBarVisible() const
2977 Q_D(const QCalendarWidget);
2978 return d->navBarVisible;
2982 void QCalendarWidget::setNavigationBarVisible(bool visible)
2984 Q_D(QCalendarWidget);
2985 d->navBarVisible = visible;
2986 d->cachedSizeHint = QSize();
2987 d->navBarBackground->setVisible(visible);
2994 bool QCalendarWidget::event(QEvent *event)
2996 Q_D(QCalendarWidget);
2997 switch (event->type()) {
2998 case QEvent::LayoutDirectionChange:
2999 d->updateButtonIcons();
3000 case QEvent::LocaleChange:
3001 d->m_model->setFirstColumnDay(locale().firstDayOfWeek());
3002 d->cachedSizeHint = QSize();
3003 d->updateMonthMenuNames();
3004 d->updateNavigationBar();
3005 d->m_view->updateGeometry();
3007 case QEvent::FontChange:
3008 case QEvent::ApplicationFontChange:
3009 d->cachedSizeHint = QSize();
3010 d->m_view->updateGeometry();
3012 case QEvent::StyleChange:
3013 d->cachedSizeHint = QSize();
3014 d->m_view->updateGeometry();
3018 return QWidget::event(event);
3024 bool QCalendarWidget::eventFilter(QObject *watched, QEvent *event)
3026 Q_D(QCalendarWidget);
3027 if (event->type() == QEvent::MouseButtonPress && d->yearEdit->hasFocus()) {
3028 QWidget *tlw = window();
3029 QWidget *widget = static_cast<QWidget*>(watched);
3030 //as we have a event filter on the whole application we first make sure that the top level widget
3031 //of both this and the watched widget are the same to decide if we should finish the year edition.
3032 if (widget->window() == tlw) {
3033 QPoint mousePos = widget->mapTo(tlw, static_cast<QMouseEvent *>(event)->pos());
3034 QRect geom = QRect(d->yearEdit->mapTo(tlw, QPoint(0, 0)), d->yearEdit->size());
3035 if (!geom.contains(mousePos)) {
3037 d->_q_yearEditingFinished();
3043 return QWidget::eventFilter(watched, event);
3049 void QCalendarWidget::mousePressEvent(QMouseEvent *event)
3051 setAttribute(Qt::WA_NoMouseReplay);
3052 QWidget::mousePressEvent(event);
3059 void QCalendarWidget::resizeEvent(QResizeEvent * event)
3061 Q_D(QCalendarWidget);
3063 // XXX Should really use a QWidgetStack for yearEdit and yearButton,
3064 // XXX here we hide the year edit when the layout is likely to break
3065 // XXX the manual positioning of the yearEdit over the yearButton.
3066 if(d->yearEdit->isVisible() && event->size().width() != event->oldSize().width())
3067 d->_q_yearEditingFinished();
3069 QWidget::resizeEvent(event);
3075 void QCalendarWidget::keyPressEvent(QKeyEvent * event)
3077 Q_D(QCalendarWidget);
3078 if(d->yearEdit->isVisible()&& event->key() == Qt::Key_Escape)
3080 d->yearEdit->setValue(yearShown());
3081 d->_q_yearEditingFinished();
3084 QWidget::keyPressEvent(event);
3089 #include "qcalendarwidget.moc"
3090 #include "moc_qcalendarwidget.cpp"
3092 #endif //QT_NO_CALENDARWIDGET