Make QCalendarWidget use its locale's firstDayOfWeek.
[profile/ivi/qtbase.git] / src / widgets / widgets / qcalendarwidget.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qcalendarwidget.h"
43
44 #ifndef QT_NO_CALENDARWIDGET
45
46 #include <qabstractitemmodel.h>
47 #include <qitemdelegate.h>
48 #include <qdatetime.h>
49 #include <qtableview.h>
50 #include <qlayout.h>
51 #include <qevent.h>
52 #include <qtextformat.h>
53 #include <qheaderview.h>
54 #include <private/qwidget_p.h>
55 #include <qpushbutton.h>
56 #include <qtoolbutton.h>
57 #include <qlabel.h>
58 #include <qspinbox.h>
59 #include <qmenu.h>
60 #include <qapplication.h>
61 #include <qbasictimer.h>
62 #include <qstylepainter.h>
63 #include <private/qcalendartextnavigator_p.h>
64
65 QT_BEGIN_NAMESPACE
66
67 enum {
68     RowCount = 6,
69     ColumnCount = 7,
70     HeaderColumn = 0,
71     HeaderRow = 0,
72     MinimumDayOffset = 1
73 };
74
75 class QCalendarDateSectionValidator
76 {
77 public:
78
79     enum Section {
80         NextSection,
81         ThisSection,
82         PrevSection
83     };
84
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;
92
93     QLocale m_locale;
94
95 protected:
96     QString highlightString(const QString &str, int pos) const;
97 private:
98 };
99
100 QString QCalendarDateSectionValidator::highlightString(const QString &str, int pos) const
101 {
102     if (pos == 0)
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>");
106
107 }
108
109 class QCalendarDayValidator : public QCalendarDateSectionValidator
110 {
111
112 public:
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;
119 private:
120     int m_pos;
121     int m_day;
122     int m_oldDay;
123 };
124
125 QCalendarDayValidator::QCalendarDayValidator()
126     : QCalendarDateSectionValidator(), m_pos(0), m_day(1), m_oldDay(1)
127 {
128 }
129
130 QCalendarDateSectionValidator::Section QCalendarDayValidator::handleKey(int key)
131 {
132     if (key == Qt::Key_Right || key == Qt::Key_Left) {
133         m_pos = 0;
134         return QCalendarDateSectionValidator::ThisSection;
135     } else if (key == Qt::Key_Up) {
136         m_pos = 0;
137         ++m_day;
138         if (m_day > 31)
139             m_day = 1;
140         return QCalendarDateSectionValidator::ThisSection;
141     } else if (key == Qt::Key_Down) {
142         m_pos = 0;
143         --m_day;
144         if (m_day < 1)
145             m_day = 31;
146         return QCalendarDateSectionValidator::ThisSection;
147     } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
148         --m_pos;
149         if (m_pos < 0)
150             m_pos = 1;
151
152         if (m_pos == 0)
153             m_day = m_oldDay;
154         else
155             m_day = m_day / 10;
156             //m_day = m_oldDay / 10 * 10 + m_day / 10;
157
158         if (m_pos == 0)
159             return QCalendarDateSectionValidator::PrevSection;
160         return QCalendarDateSectionValidator::ThisSection;
161     }
162     if (key < Qt::Key_0 || key > Qt::Key_9)
163         return QCalendarDateSectionValidator::ThisSection;
164     int pressedKey = key - Qt::Key_0;
165     if (m_pos == 0)
166         m_day = pressedKey;
167     else
168         m_day = m_day % 10 * 10 + pressedKey;
169     if (m_day > 31)
170         m_day = 31;
171     ++m_pos;
172     if (m_pos > 1) {
173         m_pos = 0;
174         return QCalendarDateSectionValidator::NextSection;
175     }
176     return QCalendarDateSectionValidator::ThisSection;
177 }
178
179 QDate QCalendarDayValidator::applyToDate(const QDate &date) const
180 {
181     int day = m_day;
182     if (day < 1)
183         day = 1;
184     else if (day > 31)
185         day = 31;
186     if (day > date.daysInMonth())
187         day = date.daysInMonth();
188     return QDate(date.year(), date.month(), day);
189 }
190
191 void QCalendarDayValidator::setDate(const QDate &date)
192 {
193     m_day = m_oldDay = date.day();
194     m_pos = 0;
195 }
196
197 QString QCalendarDayValidator::text() const
198 {
199     QString str;
200     if (m_day / 10 == 0)
201         str += QLatin1Char('0');
202     str += QString::number(m_day);
203     return highlightString(str, m_pos);
204 }
205
206 QString QCalendarDayValidator::text(const QDate &date, int repeat) const
207 {
208     if (repeat <= 1) {
209         return QString::number(date.day());
210     } else if (repeat == 2) {
211         QString str;
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);
219     }
220     return QString();
221 }
222
223 //////////////////////////////////
224
225 class QCalendarMonthValidator : public QCalendarDateSectionValidator
226 {
227
228 public:
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;
235 private:
236     int m_pos;
237     int m_month;
238     int m_oldMonth;
239 };
240
241 QCalendarMonthValidator::QCalendarMonthValidator()
242     : QCalendarDateSectionValidator(), m_pos(0), m_month(1), m_oldMonth(1)
243 {
244 }
245
246 QCalendarDateSectionValidator::Section QCalendarMonthValidator::handleKey(int key)
247 {
248     if (key == Qt::Key_Right || key == Qt::Key_Left) {
249         m_pos = 0;
250         return QCalendarDateSectionValidator::ThisSection;
251     } else if (key == Qt::Key_Up) {
252         m_pos = 0;
253         ++m_month;
254         if (m_month > 12)
255             m_month = 1;
256         return QCalendarDateSectionValidator::ThisSection;
257     } else if (key == Qt::Key_Down) {
258         m_pos = 0;
259         --m_month;
260         if (m_month < 1)
261             m_month = 12;
262         return QCalendarDateSectionValidator::ThisSection;
263     } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
264         --m_pos;
265         if (m_pos < 0)
266             m_pos = 1;
267
268         if (m_pos == 0)
269             m_month = m_oldMonth;
270         else
271             m_month = m_month / 10;
272             //m_month = m_oldMonth / 10 * 10 + m_month / 10;
273
274         if (m_pos == 0)
275             return QCalendarDateSectionValidator::PrevSection;
276         return QCalendarDateSectionValidator::ThisSection;
277     }
278     if (key < Qt::Key_0 || key > Qt::Key_9)
279         return QCalendarDateSectionValidator::ThisSection;
280     int pressedKey = key - Qt::Key_0;
281     if (m_pos == 0)
282         m_month = pressedKey;
283     else
284         m_month = m_month % 10 * 10 + pressedKey;
285     if (m_month > 12)
286         m_month = 12;
287     ++m_pos;
288     if (m_pos > 1) {
289         m_pos = 0;
290         return QCalendarDateSectionValidator::NextSection;
291     }
292     return QCalendarDateSectionValidator::ThisSection;
293 }
294
295 QDate QCalendarMonthValidator::applyToDate(const QDate &date) const
296 {
297     int month = m_month;
298     if (month < 1)
299         month = 1;
300     else if (month > 12)
301         month = 12;
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);
307 }
308
309 void QCalendarMonthValidator::setDate(const QDate &date)
310 {
311     m_month = m_oldMonth = date.month();
312     m_pos = 0;
313 }
314
315 QString QCalendarMonthValidator::text() const
316 {
317     QString str;
318     if (m_month / 10 == 0)
319         str += QLatin1Char('0');
320     str += QString::number(m_month);
321     return highlightString(str, m_pos);
322 }
323
324 QString QCalendarMonthValidator::text(const QDate &date, int repeat) const
325 {
326     if (repeat <= 1) {
327         return QString::number(date.month());
328     } else if (repeat == 2) {
329         QString str;
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);
337     }
338 }
339
340 //////////////////////////////////
341
342 class QCalendarYearValidator : public QCalendarDateSectionValidator
343 {
344
345 public:
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;
352 private:
353     int pow10(int n);
354     int m_pos;
355     int m_year;
356     int m_oldYear;
357 };
358
359 QCalendarYearValidator::QCalendarYearValidator()
360     : QCalendarDateSectionValidator(), m_pos(0), m_year(2000), m_oldYear(2000)
361 {
362 }
363
364 int QCalendarYearValidator::pow10(int n)
365 {
366     int power = 1;
367     for (int i = 0; i < n; i++)
368         power *= 10;
369     return power;
370 }
371
372 QCalendarDateSectionValidator::Section QCalendarYearValidator::handleKey(int key)
373 {
374     if (key == Qt::Key_Right || key == Qt::Key_Left) {
375         m_pos = 0;
376         return QCalendarDateSectionValidator::ThisSection;
377     } else if (key == Qt::Key_Up) {
378         m_pos = 0;
379         ++m_year;
380         return QCalendarDateSectionValidator::ThisSection;
381     } else if (key == Qt::Key_Down) {
382         m_pos = 0;
383         --m_year;
384         return QCalendarDateSectionValidator::ThisSection;
385     } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
386         --m_pos;
387         if (m_pos < 0)
388             m_pos = 3;
389
390         int pow = pow10(m_pos);
391         m_year = m_oldYear / pow * pow + m_year % (pow * 10) / 10;
392
393         if (m_pos == 0)
394             return QCalendarDateSectionValidator::PrevSection;
395         return QCalendarDateSectionValidator::ThisSection;
396     }
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;
402     ++m_pos;
403     if (m_pos > 3) {
404         m_pos = 0;
405         return QCalendarDateSectionValidator::NextSection;
406     }
407     return QCalendarDateSectionValidator::ThisSection;
408 }
409
410 QDate QCalendarYearValidator::applyToDate(const QDate &date) const
411 {
412     int year = m_year;
413     if (year < 1)
414         year = 1;
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);
420 }
421
422 void QCalendarYearValidator::setDate(const QDate &date)
423 {
424     m_year = m_oldYear = date.year();
425     m_pos = 0;
426 }
427
428 QString QCalendarYearValidator::text() const
429 {
430     QString str;
431     int pow = 10;
432     for (int i = 0; i < 3; i++) {
433         if (m_year / pow == 0)
434             str += QLatin1Char('0');
435         pow *= 10;
436     }
437     str += QString::number(m_year);
438     return highlightString(str, m_pos);
439 }
440
441 QString QCalendarYearValidator::text(const QDate &date, int repeat) const
442 {
443     if (repeat < 4) {
444         QString str;
445         int year = date.year() % 100;
446         if (year / 10 == 0)
447             str = QLatin1Char('0');
448         return str + QString::number(year);
449     }
450     return QString::number(date.year());
451 }
452
453 ///////////////////////////////////
454
455 class QCalendarDateValidator
456 {
457 public:
458     QCalendarDateValidator();
459     ~QCalendarDateValidator();
460
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);
466
467     void setLocale(const QLocale &locale);
468
469 private:
470
471     struct SectionToken {
472         SectionToken(QCalendarDateSectionValidator *val, int rep) : validator(val), repeat(rep) {}
473         QCalendarDateSectionValidator *validator;
474         int repeat;
475     };
476
477     void toNextToken();
478     void toPreviousToken();
479     void applyToDate();
480
481     int countRepeat(const QString &str, int index) const;
482     void clear();
483
484     QStringList m_separators;
485     QList<SectionToken *> m_tokens;
486     QCalendarDateSectionValidator *m_yearValidator;
487     QCalendarDateSectionValidator *m_monthValidator;
488     QCalendarDateSectionValidator *m_dayValidator;
489
490     SectionToken *m_currentToken;
491
492     QDate m_initialDate;
493     QDate m_currentDate;
494
495     QCalendarDateSectionValidator::Section m_lastSectionMove;
496 };
497
498 QCalendarDateValidator::QCalendarDateValidator()
499     : m_currentToken(0), m_lastSectionMove(QCalendarDateSectionValidator::ThisSection)
500 {
501     m_initialDate = m_currentDate = QDate::currentDate();
502     m_yearValidator = new QCalendarYearValidator();
503     m_monthValidator = new QCalendarMonthValidator();
504     m_dayValidator = new QCalendarDayValidator();
505 }
506
507 void QCalendarDateValidator::setLocale(const QLocale &locale)
508 {
509     m_yearValidator->m_locale = locale;
510     m_monthValidator->m_locale = locale;
511     m_dayValidator->m_locale = locale;
512 }
513
514 QCalendarDateValidator::~QCalendarDateValidator()
515 {
516     delete m_yearValidator;
517     delete m_monthValidator;
518     delete m_dayValidator;
519     clear();
520 }
521
522 // from qdatetime.cpp
523 int QCalendarDateValidator::countRepeat(const QString &str, int index) const
524 {
525     Q_ASSERT(index >= 0 && index < str.size());
526     int count = 1;
527     const QChar ch = str.at(index);
528     while (index + count < str.size() && str.at(index + count) == ch)
529         ++count;
530     return count;
531 }
532
533 void QCalendarDateValidator::setInitialDate(const QDate &date)
534 {
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;
541 }
542
543 QString QCalendarDateValidator::currentText() const
544 {
545     QString str;
546     QStringListIterator itSep(m_separators);
547     QListIterator<SectionToken *> itTok(m_tokens);
548     while (itSep.hasNext()) {
549         str += itSep.next();
550         if (itTok.hasNext()) {
551             SectionToken *token = itTok.next();
552             QCalendarDateSectionValidator *validator = token->validator;
553             if (m_currentToken == token)
554                 str += validator->text();
555             else
556                 str += validator->text(m_currentDate, token->repeat);
557         }
558     }
559     return str;
560 }
561
562 void QCalendarDateValidator::clear()
563 {
564     QListIterator<SectionToken *> it(m_tokens);
565     while (it.hasNext())
566         delete it.next();
567
568     m_tokens.clear();
569     m_separators.clear();
570
571     m_currentToken = 0;
572 }
573
574 void QCalendarDateValidator::setFormat(const QString &format)
575 {
576     clear();
577
578     int pos = 0;
579     const QLatin1Char quote('\'');
580     bool quoting = false;
581     QString separator;
582     while (pos < format.size()) {
583         QString mid = format.mid(pos);
584         int offset = 1;
585
586         if (mid.startsWith(quote)) {
587             quoting = !quoting;
588         } else {
589             const QChar nextChar = format.at(pos);
590             if (quoting) {
591                 separator += nextChar;
592             } else {
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);
603                 } else {
604                     separator += nextChar;
605                 }
606                 if (token) {
607                     m_tokens.append(token);
608                     m_separators.append(separator);
609                     separator = QString();
610                     if (!m_currentToken)
611                         m_currentToken = token;
612
613                 }
614             }
615         }
616         pos += offset;
617     }
618     m_separators += separator;
619 }
620
621 void QCalendarDateValidator::applyToDate()
622 {
623     m_currentDate = m_yearValidator->applyToDate(m_currentDate);
624     m_currentDate = m_monthValidator->applyToDate(m_currentDate);
625     m_currentDate = m_dayValidator->applyToDate(m_currentDate);
626 }
627
628 void QCalendarDateValidator::toNextToken()
629 {
630     const int idx = m_tokens.indexOf(m_currentToken);
631     if (idx == -1)
632         return;
633     if (idx + 1 >= m_tokens.count())
634         m_currentToken = m_tokens.first();
635     else
636         m_currentToken = m_tokens.at(idx + 1);
637 }
638
639 void QCalendarDateValidator::toPreviousToken()
640 {
641     const int idx = m_tokens.indexOf(m_currentToken);
642     if (idx == -1)
643         return;
644     if (idx - 1 < 0)
645         m_currentToken = m_tokens.last();
646     else
647         m_currentToken = m_tokens.at(idx - 1);
648 }
649
650 void QCalendarDateValidator::handleKeyEvent(QKeyEvent *keyEvent)
651 {
652     if (!m_currentToken)
653         return;
654
655     int key = keyEvent->key();
656     if (m_lastSectionMove == QCalendarDateSectionValidator::NextSection) {
657         if (key == Qt::Key_Back || key == Qt::Key_Backspace)
658             toPreviousToken();
659     }
660     if (key == Qt::Key_Right)
661         toNextToken();
662     else if (key == Qt::Key_Left)
663         toPreviousToken();
664
665     m_lastSectionMove = m_currentToken->validator->handleKey(key);
666
667     applyToDate();
668     if (m_lastSectionMove == QCalendarDateSectionValidator::NextSection)
669         toNextToken();
670     else if (m_lastSectionMove == QCalendarDateSectionValidator::PrevSection)
671         toPreviousToken();
672 }
673
674 QWidget *QCalendarTextNavigator::widget() const
675 {
676     return m_widget;
677 }
678
679 void QCalendarTextNavigator::setWidget(QWidget *widget)
680 {
681     m_widget = widget;
682 }
683
684 QDate QCalendarTextNavigator::date() const
685 {
686     return m_date;
687 }
688
689 void QCalendarTextNavigator::setDate(const QDate &date)
690 {
691     m_date = date;
692 }
693
694 void QCalendarTextNavigator::updateDateLabel()
695 {
696     if (!m_widget)
697         return;
698
699     m_acceptTimer.start(m_editDelay, this);
700
701     m_dateText->setText(m_dateValidator->currentText());
702
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);
712
713     m_dateFrame->raise();
714     m_dateFrame->show();
715 }
716
717 void QCalendarTextNavigator::applyDate()
718 {
719     QDate date = m_dateValidator->currentDate();
720     if (m_date == date)
721         return;
722
723     m_date = date;
724     emit dateChanged(date);
725 }
726
727 void QCalendarTextNavigator::createDateLabel()
728 {
729     if (m_dateFrame)
730         return;
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);
742
743     m_dateFrame->setAutoFillBackground(true);
744     m_dateFrame->setBackgroundRole(QPalette::Window);
745 }
746
747 void QCalendarTextNavigator::removeDateLabel()
748 {
749     if (!m_dateFrame)
750         return;
751     m_acceptTimer.stop();
752     m_dateFrame->hide();
753     m_dateFrame->deleteLater();
754     delete m_dateValidator;
755     m_dateFrame = 0;
756     m_dateText = 0;
757     m_dateValidator = 0;
758 }
759
760 bool QCalendarTextNavigator::eventFilter(QObject *o, QEvent *e)
761 {
762     if (m_widget) {
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) {
767                     applyDate();
768                     emit editingFinished();
769                     removeDateLabel();
770                 } else if (ke->key() == Qt::Key_Escape) {
771                     removeDateLabel();
772                 } else if (e->type() == QEvent::KeyPress) {
773                     createDateLabel();
774                     m_dateValidator->handleKeyEvent(ke);
775                     updateDateLabel();
776                 }
777                 ke->accept();
778                 return true;
779             }
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
782             /*
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));
787                 updateDateLabel();
788             }
789             */
790         }
791     }
792     return QObject::eventFilter(o,e);
793 }
794
795 void QCalendarTextNavigator::timerEvent(QTimerEvent *e)
796 {
797     if (e->timerId() == m_acceptTimer.timerId()) {
798         applyDate();
799         removeDateLabel();
800     }
801 }
802
803 int QCalendarTextNavigator::dateEditAcceptDelay() const
804 {
805     return m_editDelay;
806 }
807
808 void QCalendarTextNavigator::setDateEditAcceptDelay(int delay)
809 {
810     m_editDelay = delay;
811 }
812
813 class QCalendarView;
814
815 class QCalendarModel : public QAbstractTableModel
816 {
817     Q_OBJECT
818 public:
819     QCalendarModel(QObject *parent = 0);
820
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;
827
828     bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())
829     {
830         beginInsertRows(parent, row, row + count - 1);
831         endInsertRows();
832         return true;
833     }
834     bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex())
835     {
836         beginInsertColumns(parent, column, column + count - 1);
837         endInsertColumns();
838         return true;
839     }
840     bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex())
841     {
842         beginRemoveRows(parent, row, row + count - 1);
843         endRemoveRows();
844         return true;
845     }
846     bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex())
847     {
848         beginRemoveColumns(parent, column, column + count - 1);
849         endRemoveColumns();
850         return true;
851     }
852
853     void showMonth(int year, int month);
854     void setDate(const QDate &d);
855
856     void setMinimumDate(const QDate &date);
857     void setMaximumDate(const QDate &date);
858
859     void setRange(const QDate &min, const QDate &max);
860
861     void setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format);
862
863     void setFirstColumnDay(Qt::DayOfWeek dayOfWeek);
864     Qt::DayOfWeek firstColumnDay() const;
865
866     bool weekNumbersShown() const;
867     void setWeekNumbersShown(bool show);
868
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;
875
876     void setView(QCalendarView *view)
877         { m_view = view; }
878
879     void internalUpdate();
880     QDate referenceDate() const;
881     int columnForFirstOfMonth(const QDate &date) const;
882
883     int m_firstColumn;
884     int m_firstRow;
885     QDate m_date;
886     QDate m_minimumDate;
887     QDate m_maximumDate;
888     int m_shownYear;
889     int m_shownMonth;
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;
897 };
898
899 class QCalendarView : public QTableView
900 {
901     Q_OBJECT
902 public:
903     QCalendarView(QWidget *parent = 0);
904
905     void internalUpdate() { updateGeometries(); }
906     void setReadOnly(bool enable);
907     virtual void keyboardSearch(const QString & search) { Q_UNUSED(search) }
908
909 signals:
910     void showDate(const QDate &date);
911     void changeDate(const QDate &date, bool changeMonth);
912     void clicked(const QDate &date);
913     void editingFinished();
914 protected:
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);
922 #endif
923     void keyPressEvent(QKeyEvent *event);
924     bool event(QEvent *event);
925
926     QDate handleMouseEvent(QMouseEvent *event);
927 public:
928     bool readOnly;
929 private:
930     bool validDateClicked;
931 #ifdef QT_KEYPAD_NAVIGATION
932     QDate origDate;
933 #endif
934 };
935
936 QCalendarModel::QCalendarModel(QObject *parent)
937     : QAbstractTableModel(parent)
938 {
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;
947     m_firstColumn = 1;
948     m_firstRow = 1;
949     m_view = 0;
950 }
951
952 Qt::DayOfWeek QCalendarModel::dayOfWeekForColumn(int column) const
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
963 int QCalendarModel::columnForDayOfWeek(Qt::DayOfWeek day) const
964 {
965     if (day < 1 || day > 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 /*
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.
984 */
985 QDate QCalendarModel::referenceDate() const
986 {
987     int refDay = 1;
988     while (refDay <= 31) {
989         QDate refDate(m_shownYear, m_shownMonth, refDay);
990         if (refDate.isValid())
991             return refDate;
992         refDay += 1;
993     }
994     return QDate();
995 }
996
997 int QCalendarModel::columnForFirstOfMonth(const QDate &date) const
998 {
999     return (columnForDayOfWeek(static_cast<Qt::DayOfWeek>(date.dayOfWeek())) - (date.day() % 7) + 8) % 7;
1000 }
1001
1002 QDate QCalendarModel::dateForCell(int row, int column) const
1003 {
1004     if (row < m_firstRow || row > m_firstRow + RowCount - 1 ||
1005                 column < m_firstColumn || column > m_firstColumn + ColumnCount - 1)
1006         return QDate();
1007     const QDate refDate = referenceDate();
1008     if (!refDate.isValid())
1009         return QDate();
1010
1011     const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
1012     if (columnForFirstOfShownMonth - m_firstColumn < MinimumDayOffset)
1013         row -= 1;
1014
1015     const int requestedDay = 7 * (row - m_firstRow) + column - columnForFirstOfShownMonth - refDate.day() + 1;
1016     return refDate.addDays(requestedDay);
1017 }
1018
1019 void QCalendarModel::cellForDate(const QDate &date, int *row, int *column) const
1020 {
1021     if (!row && !column)
1022         return;
1023
1024     if (row)
1025         *row = -1;
1026     if (column)
1027         *column = -1;
1028
1029     const QDate refDate = referenceDate();
1030     if (!refDate.isValid())
1031         return;
1032
1033     const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
1034     const int requestedPosition = refDate.daysTo(date) - m_firstColumn + columnForFirstOfShownMonth + refDate.day() - 1;
1035
1036     int c = requestedPosition % 7;
1037     int r = requestedPosition / 7;
1038     if (c < 0) {
1039         c += 7;
1040         r -= 1;
1041     }
1042
1043     if (columnForFirstOfShownMonth - m_firstColumn < MinimumDayOffset)
1044         r += 1;
1045
1046     if (r < 0 || r > RowCount - 1 || c < 0 || c > ColumnCount - 1)
1047         return;
1048
1049     if (row)
1050         *row = r + m_firstRow;
1051     if (column)
1052         *column = c + m_firstColumn;
1053 }
1054
1055 QString QCalendarModel::dayName(Qt::DayOfWeek day) const
1056 {
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;
1063         }
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);
1068         default:
1069             break;
1070     }
1071     return QString();
1072 }
1073
1074 QTextCharFormat QCalendarModel::formatForCell(int row, int col) const
1075 {
1076     QPalette pal;
1077     QPalette::ColorGroup cg = QPalette::Active;
1078     if (m_view) {
1079         pal = m_view->palette();
1080         if (!m_view->isEnabled())
1081             cg = QPalette::Disabled;
1082         else if (!m_view->isActiveWindow())
1083             cg = QPalette::Inactive;
1084     }
1085
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));
1092     if (header) {
1093         format.merge(m_headerFormat);
1094     }
1095
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));
1100     }
1101
1102     if (!header) {
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));
1109     }
1110     return format;
1111 }
1112
1113 QVariant QCalendarModel::data(const QModelIndex &index, int role) const
1114 {
1115     if (role == Qt::TextAlignmentRole)
1116         return (int) Qt::AlignCenter;
1117
1118     int row = index.row();
1119     int column = index.column();
1120
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));
1125             if (date.isValid())
1126                 return date.weekNumber();
1127         }
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);
1132         if (date.isValid())
1133             return date.day();
1134         return QString();
1135     }
1136
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)
1143         return fmt.font();
1144     if (role == Qt::ToolTipRole)
1145         return fmt.toolTip();
1146     return QVariant();
1147 }
1148
1149 Qt::ItemFlags QCalendarModel::flags(const QModelIndex &index) const
1150 {
1151     QDate date = dateForCell(index.row(), index.column());
1152     if (!date.isValid())
1153         return QAbstractTableModel::flags(index);
1154     if (date < m_minimumDate)
1155         return 0;
1156     if (date > m_maximumDate)
1157         return 0;
1158     return QAbstractTableModel::flags(index);
1159 }
1160
1161 void QCalendarModel::setDate(const QDate &d)
1162 {
1163     m_date = d;
1164     if (m_date < m_minimumDate)
1165         m_date = m_minimumDate;
1166     else if (m_date > m_maximumDate)
1167         m_date = m_maximumDate;
1168 }
1169
1170 void QCalendarModel::showMonth(int year, int month)
1171 {
1172     if (m_shownYear == year && m_shownMonth == month)
1173         return;
1174
1175     m_shownYear = year;
1176     m_shownMonth = month;
1177
1178     internalUpdate();
1179 }
1180
1181 void QCalendarModel::setMinimumDate(const QDate &d)
1182 {
1183     if (!d.isValid() || d == m_minimumDate)
1184         return;
1185
1186     m_minimumDate = d;
1187     if (m_maximumDate < m_minimumDate)
1188         m_maximumDate = m_minimumDate;
1189     if (m_date < m_minimumDate)
1190         m_date = m_minimumDate;
1191     internalUpdate();
1192 }
1193
1194 void QCalendarModel::setMaximumDate(const QDate &d)
1195 {
1196     if (!d.isValid() || d == m_maximumDate)
1197         return;
1198
1199     m_maximumDate = d;
1200     if (m_minimumDate > m_maximumDate)
1201         m_minimumDate = m_maximumDate;
1202     if (m_date > m_maximumDate)
1203         m_date = m_maximumDate;
1204     internalUpdate();
1205 }
1206
1207 void QCalendarModel::setRange(const QDate &min, const QDate &max)
1208 {
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;
1217     internalUpdate();
1218 }
1219
1220 void QCalendarModel::internalUpdate()
1221 {
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);
1227 }
1228
1229 void QCalendarModel::setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format)
1230 {
1231     if (m_horizontalHeaderFormat == format)
1232         return;
1233
1234     int oldFormat = m_horizontalHeaderFormat;
1235     m_horizontalHeaderFormat = format;
1236     if (oldFormat == QCalendarWidget::NoHorizontalHeader) {
1237         m_firstRow = 1;
1238         insertRow(0);
1239     } else if (m_horizontalHeaderFormat == QCalendarWidget::NoHorizontalHeader) {
1240         m_firstRow = 0;
1241         removeRow(0);
1242     }
1243     internalUpdate();
1244 }
1245
1246 void QCalendarModel::setFirstColumnDay(Qt::DayOfWeek dayOfWeek)
1247 {
1248     if (m_firstDay == dayOfWeek)
1249         return;
1250
1251     m_firstDay = dayOfWeek;
1252     internalUpdate();
1253 }
1254
1255 Qt::DayOfWeek QCalendarModel::firstColumnDay() const
1256 {
1257     return m_firstDay;
1258 }
1259
1260 bool QCalendarModel::weekNumbersShown() const
1261 {
1262     return m_weekNumbersShown;
1263 }
1264
1265 void QCalendarModel::setWeekNumbersShown(bool show)
1266 {
1267     if (m_weekNumbersShown == show)
1268         return;
1269
1270     m_weekNumbersShown = show;
1271     if (show) {
1272         m_firstColumn = 1;
1273         insertColumn(0);
1274     } else {
1275         m_firstColumn = 0;
1276         removeColumn(0);
1277     }
1278     internalUpdate();
1279 }
1280
1281 QCalendarView::QCalendarView(QWidget *parent)
1282     : QTableView(parent),
1283     readOnly(false),
1284     validDateClicked(false)
1285 {
1286     setTabKeyNavigation(false);
1287     setShowGrid(false);
1288     verticalHeader()->setVisible(false);
1289     horizontalHeader()->setVisible(false);
1290     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1291     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1292 }
1293
1294 QModelIndex QCalendarView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
1295 {
1296     QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1297     if (!calendarModel)
1298         return QTableView::moveCursor(cursorAction, modifiers);
1299
1300     if (readOnly)
1301         return currentIndex();
1302
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);
1308             break;
1309         case QAbstractItemView::MoveDown:
1310             currentDate = currentDate.addDays(7);
1311             break;
1312         case QAbstractItemView::MoveLeft:
1313             currentDate = currentDate.addDays(isRightToLeft() ? 1 : -1);
1314             break;
1315         case QAbstractItemView::MoveRight:
1316             currentDate = currentDate.addDays(isRightToLeft() ? -1 : 1);
1317             break;
1318         case QAbstractItemView::MoveHome:
1319             currentDate = QDate(currentDate.year(), currentDate.month(), 1);
1320             break;
1321         case QAbstractItemView::MoveEnd:
1322             currentDate = QDate(currentDate.year(), currentDate.month(), currentDate.daysInMonth());
1323             break;
1324         case QAbstractItemView::MovePageUp:
1325             currentDate = currentDate.addMonths(-1);
1326             break;
1327         case QAbstractItemView::MovePageDown:
1328             currentDate = currentDate.addMonths(1);
1329             break;
1330         case QAbstractItemView::MoveNext:
1331         case QAbstractItemView::MovePrevious:
1332             return currentIndex();
1333         default:
1334             break;
1335     }
1336     emit changeDate(currentDate, true);
1337     return currentIndex();
1338 }
1339
1340 void QCalendarView::keyPressEvent(QKeyEvent *event)
1341 {
1342 #ifdef QT_KEYPAD_NAVIGATION
1343     if (event->key() == Qt::Key_Select) {
1344         if (QApplication::keypadNavigationEnabled()) {
1345             if (!hasEditFocus()) {
1346                 setEditFocus(true);
1347                 return;
1348             }
1349         }
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);
1355                 return;
1356             }
1357         }
1358     }
1359 #endif
1360
1361     if (!readOnly) {
1362         switch (event->key()) {
1363             case Qt::Key_Return:
1364             case Qt::Key_Enter:
1365             case Qt::Key_Select:
1366                 emit editingFinished();
1367                 return;
1368             default:
1369                 break;
1370         }
1371     }
1372     QTableView::keyPressEvent(event);
1373 }
1374
1375 #ifndef QT_NO_WHEELEVENT
1376 void QCalendarView::wheelEvent(QWheelEvent *event)
1377 {
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);
1384 }
1385 #endif
1386
1387 bool QCalendarView::event(QEvent *event)
1388 {
1389 #ifdef QT_KEYPAD_NAVIGATION
1390     if (event->type() == QEvent::FocusIn) {
1391         if (QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model())) {
1392             origDate = calendarModel->m_date;
1393         }
1394     }
1395 #endif
1396
1397     return QTableView::event(event);
1398 }
1399
1400 QDate QCalendarView::handleMouseEvent(QMouseEvent *event)
1401 {
1402     QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1403     if (!calendarModel)
1404         return QDate();
1405
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) {
1411         return date;
1412     }
1413     return QDate();
1414 }
1415
1416 void QCalendarView::mouseDoubleClickEvent(QMouseEvent *event)
1417 {
1418     QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1419     if (!calendarModel) {
1420         QTableView::mouseDoubleClickEvent(event);
1421         return;
1422     }
1423
1424     if (readOnly)
1425         return;
1426
1427     QDate date = handleMouseEvent(event);
1428     validDateClicked = false;
1429     if (date == calendarModel->m_date && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)) {
1430         emit editingFinished();
1431     }
1432 }
1433
1434 void QCalendarView::mousePressEvent(QMouseEvent *event)
1435 {
1436     QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1437     if (!calendarModel) {
1438         QTableView::mousePressEvent(event);
1439         return;
1440     }
1441
1442     if (readOnly)
1443         return;
1444
1445     if (event->button() != Qt::LeftButton)
1446         return;
1447
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);
1455         }
1456     } else {
1457         validDateClicked = false;
1458         event->ignore();
1459     }
1460 }
1461
1462 void QCalendarView::mouseMoveEvent(QMouseEvent *event)
1463 {
1464     QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1465     if (!calendarModel) {
1466         QTableView::mouseMoveEvent(event);
1467         return;
1468     }
1469
1470     if (readOnly)
1471         return;
1472
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);
1480             }
1481         }
1482     } else {
1483         event->ignore();
1484     }
1485 }
1486
1487 void QCalendarView::mouseReleaseEvent(QMouseEvent *event)
1488 {
1489     QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1490     if (!calendarModel) {
1491         QTableView::mouseReleaseEvent(event);
1492         return;
1493     }
1494
1495     if (event->button() != Qt::LeftButton)
1496         return;
1497
1498     if (readOnly)
1499         return;
1500
1501     if (validDateClicked) {
1502         QDate date = handleMouseEvent(event);
1503         if (date.isValid()) {
1504             emit changeDate(date, true);
1505             emit clicked(date);
1506             if (style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick))
1507                 emit editingFinished();
1508         }
1509         validDateClicked = false;
1510     } else {
1511         event->ignore();
1512     }
1513 }
1514
1515 class QCalendarDelegate : public QItemDelegate
1516 {
1517     Q_OBJECT
1518 public:
1519     QCalendarDelegate(QCalendarWidgetPrivate *w, QObject *parent = 0)
1520         : QItemDelegate(parent), calendarWidgetPrivate(w)
1521             { }
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;
1525
1526 private:
1527     QCalendarWidgetPrivate *calendarWidgetPrivate;
1528     mutable QStyleOptionViewItemV4 storedOption;
1529 };
1530
1531 //Private tool button class
1532 class QCalToolButton: public QToolButton
1533 {
1534 public:
1535     QCalToolButton(QWidget * parent)
1536         : QToolButton(parent)
1537           {  }
1538 protected:
1539     void paintEvent(QPaintEvent *e)
1540     {
1541         Q_UNUSED(e)
1542
1543 #ifndef Q_WS_MAC
1544         QStyleOptionToolButton opt;
1545         initStyleOption(&opt);
1546
1547         if (opt.state & QStyle::State_MouseOver || isDown()) {
1548             //act as normal button
1549             setPalette(QPalette());
1550         } else {
1551             //set the highlight color for button text
1552             QPalette toolPalette = palette();
1553             toolPalette.setColor(QPalette::ButtonText, toolPalette.color(QPalette::HighlightedText));
1554             setPalette(toolPalette);
1555         }
1556 #endif
1557         QToolButton::paintEvent(e);
1558     }
1559 };
1560
1561 class QPrevNextCalButton : public QToolButton
1562 {
1563     Q_OBJECT
1564 public:
1565     QPrevNextCalButton(QWidget *parent) : QToolButton(parent) {}
1566 protected:
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);
1573     }
1574 };
1575
1576 class QCalendarWidgetPrivate : public QWidgetPrivate
1577 {
1578     Q_DECLARE_PUBLIC(QCalendarWidget)
1579 public:
1580     QCalendarWidgetPrivate();
1581
1582     void showMonth(int year, int month);
1583     void update();
1584     void paintCell(QPainter *painter, const QRect &rect, const QDate &date) const;
1585
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();
1595
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);
1604
1605     QCalendarModel *m_model;
1606     QCalendarView *m_view;
1607     QCalendarDelegate *m_delegate;
1608     QItemSelectionModel *m_selection;
1609     QCalendarTextNavigator *m_navigator;
1610     bool m_dateEditEnabled;
1611
1612     QToolButton *nextMonth;
1613     QToolButton *prevMonth;
1614     QCalToolButton *monthButton;
1615     QMenu *monthMenu;
1616     QMap<int, QAction *> monthToAction;
1617     QCalToolButton *yearButton;
1618     QSpinBox *yearEdit;
1619     QWidget *navBarBackground;
1620     QSpacerItem *spaceHolder;
1621
1622     bool navBarVisible;
1623     mutable QSize cachedSizeHint;
1624     Qt::FocusPolicy oldFocusPolicy;
1625 };
1626
1627 void QCalendarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
1628             const QModelIndex &index) const
1629 {
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);
1635     } else {
1636         QItemDelegate::paint(painter, option, index);
1637     }
1638 }
1639
1640 void QCalendarDelegate::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
1641 {
1642     storedOption.rect = rect;
1643     int row = -1;
1644     int col = -1;
1645     calendarWidgetPrivate->m_model->cellForDate(date, &row, &col);
1646     QModelIndex idx = calendarWidgetPrivate->m_model->index(row, col);
1647     QItemDelegate::paint(painter, storedOption, idx);
1648 }
1649
1650 QCalendarWidgetPrivate::QCalendarWidgetPrivate()
1651     : QWidgetPrivate()
1652 {
1653     m_model = 0;
1654     m_view = 0;
1655     m_delegate = 0;
1656     m_selection = 0;
1657     m_navigator = 0;
1658     m_dateEditEnabled = false;
1659     navBarVisible = true;
1660     oldFocusPolicy = Qt::StrongFocus;
1661 }
1662
1663 void QCalendarWidgetPrivate::setNavigatorEnabled(bool enable)
1664 {
1665     Q_Q(QCalendarWidget);
1666
1667     bool navigatorEnabled = (m_navigator->widget() != 0);
1668     if (enable == navigatorEnabled)
1669         return;
1670
1671     if (enable) {
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);
1678     } else {
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);
1685     }
1686 }
1687
1688 void QCalendarWidgetPrivate::createNavigationBar(QWidget *widget)
1689 {
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);
1695
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);
1706
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);
1715         act->setData(i);
1716         monthToAction[i] = act;
1717     }
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);
1723
1724     QFont font = q->font();
1725     font.setBold(true);
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());
1731     yearEdit->hide();
1732     spaceHolder = new QSpacerItem(0,0);
1733
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);
1745
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);
1751
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"));
1758
1759     updateMonthMenu();
1760     showMonth(m_model->m_date.year(), m_model->m_date.month());
1761 }
1762
1763 void QCalendarWidgetPrivate::updateButtonIcons()
1764 {
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));
1768 }
1769
1770 void QCalendarWidgetPrivate::updateMonthMenu()
1771 {
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;
1779     }
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;
1784     }
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);
1792     }
1793 }
1794
1795 void QCalendarWidgetPrivate::updateMonthMenuNames()
1796 {
1797     Q_Q(QCalendarWidget);
1798
1799     for (int i = 1; i <= 12; i++) {
1800         QString monthName(q->locale().standaloneMonthName(i, QLocale::LongFormat));
1801         monthToAction[i]->setText(monthName);
1802     }
1803 }
1804
1805 void QCalendarWidgetPrivate::updateCurrentPage(const QDate &date)
1806 {
1807     Q_Q(QCalendarWidget);
1808
1809     QDate newDate = date;
1810     QDate minDate = q->minimumDate();
1811     QDate maxDate = q->maximumDate();
1812     if (minDate.isValid()&& minDate.daysTo(newDate) < 0)
1813         newDate = minDate;
1814     if (maxDate.isValid()&& maxDate.daysTo(newDate) > 0)
1815         newDate = maxDate;
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)
1820     {
1821         m_view->selectionModel()->setCurrentIndex(m_model->index(row, col),
1822                                                   QItemSelectionModel::NoUpdate);
1823     }
1824 }
1825
1826 void QCalendarWidgetPrivate::_q_monthChanged(QAction *act)
1827 {
1828     monthButton->setText(act->text());
1829     QDate currentDate = getCurrentDate();
1830     QDate newDate = currentDate.addMonths(act->data().toInt()-currentDate.month());
1831     updateCurrentPage(newDate);
1832 }
1833
1834 QDate QCalendarWidgetPrivate::getCurrentDate()
1835 {
1836     QModelIndex index = m_view->currentIndex();
1837     return m_model->dateForCell(index.row(), index.column());
1838 }
1839
1840 void QCalendarWidgetPrivate::_q_prevMonthClicked()
1841 {
1842     QDate currentDate = getCurrentDate().addMonths(-1);
1843     updateCurrentPage(currentDate);
1844 }
1845
1846 void QCalendarWidgetPrivate::_q_nextMonthClicked()
1847 {
1848     QDate currentDate = getCurrentDate().addMonths(1);
1849     updateCurrentPage(currentDate);
1850 }
1851
1852 void QCalendarWidgetPrivate::_q_yearEditingFinished()
1853 {
1854     Q_Q(QCalendarWidget);
1855     yearButton->setText(yearEdit->text());
1856     yearEdit->hide();
1857     q->setFocusPolicy(oldFocusPolicy);
1858     qApp->removeEventFilter(q);
1859     spaceHolder->changeSize(0, 0);
1860     yearButton->show();
1861     QDate currentDate = getCurrentDate();
1862     currentDate = currentDate.addYears(yearEdit->text().toInt() - currentDate.year());
1863     updateCurrentPage(currentDate);
1864 }
1865
1866 void QCalendarWidgetPrivate::_q_yearClicked()
1867 {
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);
1873     yearButton->hide();
1874     oldFocusPolicy = q->focusPolicy();
1875     q->setFocusPolicy(Qt::NoFocus);
1876     yearEdit->show();
1877     qApp->installEventFilter(q);
1878     yearEdit->raise();
1879     yearEdit->selectAll();
1880     yearEdit->setFocus(Qt::MouseFocusReason);
1881 }
1882
1883 void QCalendarWidgetPrivate::showMonth(int year, int month)
1884 {
1885     if (m_model->m_shownYear == year && m_model->m_shownMonth == month)
1886         return;
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();
1893     update();
1894     updateMonthMenu();
1895 }
1896
1897 void QCalendarWidgetPrivate::updateNavigationBar()
1898 {
1899     Q_Q(QCalendarWidget);
1900
1901     QString monthName = q->locale().standaloneMonthName(m_model->m_shownMonth, QLocale::LongFormat);
1902
1903     monthButton->setText(monthName);
1904     yearButton->setText(QString::number(m_model->m_shownYear));
1905     yearEdit->setValue(m_model->m_shownYear);
1906 }
1907
1908 void QCalendarWidgetPrivate::update()
1909 {
1910     QDate currentDate = m_model->m_date;
1911     int row, column;
1912     m_model->cellForDate(currentDate, &row, &column);
1913     QModelIndex idx;
1914     m_selection->clear();
1915     if (row != -1 && column != -1) {
1916         idx = m_model->index(row, column);
1917         m_selection->setCurrentIndex(idx, QItemSelectionModel::SelectCurrent);
1918     }
1919 }
1920
1921 void QCalendarWidgetPrivate::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
1922 {
1923     Q_Q(const QCalendarWidget);
1924     q->paintCell(painter, rect, date);
1925 }
1926
1927 void QCalendarWidgetPrivate::_q_slotShowDate(const QDate &date)
1928 {
1929     updateCurrentPage(date);
1930 }
1931
1932 void QCalendarWidgetPrivate::_q_slotChangeDate(const QDate &date)
1933 {
1934     _q_slotChangeDate(date, true);
1935 }
1936
1937 void QCalendarWidgetPrivate::_q_slotChangeDate(const QDate &date, bool changeMonth)
1938 {
1939     QDate oldDate = m_model->m_date;
1940     m_model->setDate(date);
1941     QDate newDate = m_model->m_date;
1942     if (changeMonth)
1943         showMonth(newDate.year(), newDate.month());
1944     if (oldDate != newDate) {
1945         update();
1946         Q_Q(QCalendarWidget);
1947         m_navigator->setDate(newDate);
1948         emit q->selectionChanged();
1949     }
1950 }
1951
1952 void QCalendarWidgetPrivate::_q_editingFinished()
1953 {
1954     Q_Q(QCalendarWidget);
1955     emit q->activated(m_model->m_date);
1956 }
1957
1958 /*!
1959     \class QCalendarWidget
1960     \brief The QCalendarWidget class provides a monthly based
1961     calendar widget allowing the user to select a date.
1962     \since 4.2
1963
1964     \ingroup advanced
1965     \inmodule QtWidgets
1966
1967     \image cleanlooks-calendarwidget.png
1968
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.
1972
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.
1983
1984     The currently displayed month and year can be retrieved using the
1985     monthShown() and yearShown() functions, respectively.
1986
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.
1991
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:
2002
2003     \table
2004     \row \li
2005         \image qcalendarwidget-grid.png
2006     \row \li
2007         \snippet code/src_gui_widgets_qcalendarwidget.cpp 0
2008     \endtable
2009
2010     Finally, the day in the first column can be altered using the
2011     setFirstDayOfWeek() function.
2012
2013     The QCalendarWidget class also provides three signals,
2014     selectionChanged(), activated() and currentPageChanged() making it
2015     possible to respond to user interaction.
2016
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.
2020
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
2024     in the widget.
2025
2026     \sa QDate, QDateEdit, QTextCharFormat
2027 */
2028
2029 /*!
2030     \enum QCalendarWidget::SelectionMode
2031
2032     This enum describes the types of selection offered to the user for
2033     selecting dates in the calendar.
2034
2035     \value NoSelection      Dates cannot be selected.
2036     \value SingleSelection  Single dates can be selected.
2037
2038     \sa selectionMode
2039 */
2040
2041 /*!
2042     Constructs a calendar widget with the given \a parent.
2043
2044     The widget is initialized with the current month and year, and the
2045     currently selected date is today.
2046
2047     \sa setCurrentPage()
2048 */
2049 QCalendarWidget::QCalendarWidget(QWidget *parent)
2050     : QWidget(*new QCalendarWidgetPrivate, parent, 0)
2051 {
2052     Q_D(QCalendarWidget);
2053
2054     setAutoFillBackground(true);
2055     setBackgroundRole(QPalette::Window);
2056
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);
2079     d->update();
2080     d->updateNavigationBar();
2081     setFocusPolicy(Qt::StrongFocus);
2082     setFocusProxy(d->m_view);
2083     setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
2084
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()));
2093
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()));
2104
2105     layoutV->setMargin(0);
2106     layoutV->setSpacing(0);
2107     layoutV->addWidget(d->navBarBackground);
2108     layoutV->addWidget(d->m_view);
2109
2110     d->m_navigator = new QCalendarTextNavigator(this);
2111     setDateEditEnabled(true);
2112 }
2113
2114 /*!
2115    Destroys the calendar widget.
2116 */
2117 QCalendarWidget::~QCalendarWidget()
2118 {
2119 }
2120
2121 /*!
2122    \reimp
2123 */
2124 QSize QCalendarWidget::sizeHint() const
2125 {
2126     return minimumSizeHint();
2127 }
2128
2129 /*!
2130    \reimp
2131 */
2132 QSize QCalendarWidget::minimumSizeHint() const
2133 {
2134     Q_D(const QCalendarWidget);
2135     if (d->cachedSizeHint.isValid())
2136         return d->cachedSizeHint;
2137
2138     ensurePolished();
2139
2140     int w = 0;
2141     int h = 0;
2142
2143     int end = 53;
2144     int rows = 7;
2145     int cols = 8;
2146
2147     const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1) * 2;
2148
2149     if (horizontalHeaderFormat() == QCalendarWidget::NoHorizontalHeader) {
2150         rows = 6;
2151     } else {
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());
2156         }
2157     }
2158
2159     if (verticalHeaderFormat() == QCalendarWidget::NoVerticalHeader) {
2160         cols = 7;
2161     } else {
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());
2167         }
2168     }
2169
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());
2174     }
2175
2176     if (d->m_view->showGrid()) {
2177         // hardcoded in tableview
2178         w += 1;
2179         h += 1;
2180     }
2181
2182     w += 1; // default column span
2183
2184     h = qMax(h, d->m_view->verticalHeader()->minimumSectionSize());
2185     w = qMax(w, d->m_view->horizontalHeader()->minimumSectionSize());
2186
2187     //add the size of the header.
2188     QSize headerSize(0, 0);
2189     if (d->navBarVisible) {
2190         int headerH = d->navBarBackground->sizeHint().height();
2191         int headerW = 0;
2192
2193         headerW += d->prevMonth->sizeHint().width();
2194         headerW += d->nextMonth->sizeHint().width();
2195
2196         QFontMetrics fm = d->monthButton->fontMetrics();
2197         int monthW = 0;
2198         for (int i = 1; i < 12; i++) {
2199             QString monthName = locale().standaloneMonthName(i, QLocale::LongFormat);
2200             monthW = qMax(monthW, fm.boundingRect(monthName).width());
2201         }
2202         const int buttonDecoMargin = d->monthButton->sizeHint().width() - fm.boundingRect(d->monthButton->text()).width();
2203         headerW += monthW + buttonDecoMargin;
2204
2205         fm = d->yearButton->fontMetrics();
2206         headerW += fm.boundingRect(QLatin1String("5555")).width() + buttonDecoMargin;
2207
2208         headerSize = QSize(headerW, headerH);
2209     }
2210     w *= cols;
2211     w = qMax(headerSize.width(), w);
2212     h = (h * rows) + headerSize.height();
2213     d->cachedSizeHint = QSize(w, h);
2214     return d->cachedSizeHint;
2215 }
2216
2217 /*!
2218     Paints the cell specified by the given \a date, using the given \a painter and \a rect.
2219 */
2220
2221 void QCalendarWidget::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
2222 {
2223     Q_D(const QCalendarWidget);
2224     d->m_delegate->paintCell(painter, rect, date);
2225 }
2226
2227 /*!
2228     \property QCalendarWidget::selectedDate
2229     \brief the currently selected date.
2230
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.
2234
2235     \sa setDateRange()
2236 */
2237
2238 QDate QCalendarWidget::selectedDate() const
2239 {
2240     Q_D(const QCalendarWidget);
2241     return d->m_model->m_date;
2242 }
2243
2244 void QCalendarWidget::setSelectedDate(const QDate &date)
2245 {
2246     Q_D(QCalendarWidget);
2247     if (d->m_model->m_date == date && date == d->getCurrentDate())
2248         return;
2249
2250     if (!date.isValid())
2251         return;
2252
2253     d->m_model->setDate(date);
2254     d->update();
2255     QDate newDate = d->m_model->m_date;
2256     d->showMonth(newDate.year(), newDate.month());
2257     emit selectionChanged();
2258 }
2259
2260 /*!
2261     Returns the year of the currently displayed month. Months are
2262     numbered from 1 to 12.
2263
2264     \sa monthShown(), setCurrentPage()
2265 */
2266
2267 int QCalendarWidget::yearShown() const
2268 {
2269     Q_D(const QCalendarWidget);
2270     return d->m_model->m_shownYear;
2271 }
2272
2273 /*!
2274     Returns the currently displayed month. Months are numbered from 1 to
2275     12.
2276
2277     \sa yearShown(), setCurrentPage()
2278 */
2279
2280 int QCalendarWidget::monthShown() const
2281 {
2282     Q_D(const QCalendarWidget);
2283     return d->m_model->m_shownMonth;
2284 }
2285
2286 /*!
2287     Displays the given \a month of the given \a year without changing
2288     the selected date. Use the setSelectedDate() function to alter the
2289     selected date.
2290
2291     The currently displayed month and year can be retrieved using the
2292     monthShown() and yearShown() functions respectively.
2293
2294     \sa yearShown(), monthShown(), showPreviousMonth(), showNextMonth(),
2295     showPreviousYear(), showNextYear()
2296 */
2297
2298 void QCalendarWidget::setCurrentPage(int year, int month)
2299 {
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)
2305         day = daysInMonths;
2306
2307     d->showMonth(year, month);
2308
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);
2315     }
2316 }
2317
2318 /*!
2319     Shows the next month relative to the currently displayed
2320     month. Note that the selected date is not changed.
2321
2322     \sa showPreviousMonth(), setCurrentPage(), setSelectedDate()
2323 */
2324
2325 void QCalendarWidget::showNextMonth()
2326 {
2327     int year = yearShown();
2328     int month = monthShown();
2329     if (month == 12) {
2330         ++year;
2331         month = 1;
2332     } else {
2333         ++month;
2334     }
2335     setCurrentPage(year, month);
2336 }
2337
2338 /*!
2339     Shows the previous month relative to the currently displayed
2340     month. Note that the selected date is not changed.
2341
2342     \sa showNextMonth(), setCurrentPage(), setSelectedDate()
2343 */
2344
2345 void QCalendarWidget::showPreviousMonth()
2346 {
2347     int year = yearShown();
2348     int month = monthShown();
2349     if (month == 1) {
2350         --year;
2351         month = 12;
2352     } else {
2353         --month;
2354     }
2355     setCurrentPage(year, month);
2356 }
2357
2358 /*!
2359     Shows the currently displayed month in the \e next year relative
2360     to the currently displayed year. Note that the selected date is
2361     not changed.
2362
2363     \sa showPreviousYear(), setCurrentPage(), setSelectedDate()
2364 */
2365
2366 void QCalendarWidget::showNextYear()
2367 {
2368     int year = yearShown();
2369     int month = monthShown();
2370     ++year;
2371     setCurrentPage(year, month);
2372 }
2373
2374 /*!
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.
2378
2379     \sa showNextYear(), setCurrentPage(), setSelectedDate()
2380 */
2381
2382 void QCalendarWidget::showPreviousYear()
2383 {
2384     int year = yearShown();
2385     int month = monthShown();
2386     --year;
2387     setCurrentPage(year, month);
2388 }
2389
2390 /*!
2391     Shows the month of the selected date.
2392
2393     \sa selectedDate(), setCurrentPage()
2394 */
2395 void QCalendarWidget::showSelectedDate()
2396 {
2397     QDate currentDate = selectedDate();
2398     setCurrentPage(currentDate.year(), currentDate.month());
2399 }
2400
2401 /*!
2402     Shows the month of the today's date.
2403
2404     \sa selectedDate(), setCurrentPage()
2405 */
2406 void QCalendarWidget::showToday()
2407 {
2408     QDate currentDate = QDate::currentDate();
2409     setCurrentPage(currentDate.year(), currentDate.month());
2410 }
2411
2412 /*!
2413     \property QCalendarWidget::minimumDate
2414     \brief the minimum date of the currently specified date range.
2415
2416     The user will not be able to select a date that is before the
2417     currently set minimum date.
2418
2419     \table
2420     \row
2421     \li \image qcalendarwidget-minimum.png
2422     \row
2423     \li
2424     \snippet code/src_gui_widgets_qcalendarwidget.cpp 1
2425     \endtable
2426
2427     By default, the minimum date is the earliest date that the QDate
2428     class can handle.
2429
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.
2434
2435     \sa setDateRange()
2436 */
2437
2438 QDate QCalendarWidget::minimumDate() const
2439 {
2440     Q_D(const QCalendarWidget);
2441     return d->m_model->m_minimumDate;
2442 }
2443
2444 void QCalendarWidget::setMinimumDate(const QDate &date)
2445 {
2446     Q_D(QCalendarWidget);
2447     if (!date.isValid() || d->m_model->m_minimumDate == date)
2448         return;
2449
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) {
2456         d->update();
2457         d->showMonth(newDate.year(), newDate.month());
2458         d->m_navigator->setDate(newDate);
2459         emit selectionChanged();
2460     }
2461 }
2462
2463 /*!
2464     \property QCalendarWidget::maximumDate
2465     \brief the maximum date of the currently specified date range.
2466
2467     The user will not be able to select a date which is after the
2468     currently set maximum date.
2469
2470     \table
2471     \row
2472     \li \image qcalendarwidget-maximum.png
2473     \row
2474     \li
2475     \snippet code/src_gui_widgets_qcalendarwidget.cpp 2
2476     \endtable
2477
2478     By default, the maximum date is the last day the QDate class can
2479     handle.
2480
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.
2485
2486     \sa setDateRange()
2487 */
2488
2489 QDate QCalendarWidget::maximumDate() const
2490 {
2491     Q_D(const QCalendarWidget);
2492     return d->m_model->m_maximumDate;
2493 }
2494
2495 void QCalendarWidget::setMaximumDate(const QDate &date)
2496 {
2497     Q_D(QCalendarWidget);
2498     if (!date.isValid() || d->m_model->m_maximumDate == date)
2499         return;
2500
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) {
2507         d->update();
2508         d->showMonth(newDate.year(), newDate.month());
2509         d->m_navigator->setDate(newDate);
2510         emit selectionChanged();
2511     }
2512 }
2513
2514 /*!
2515     Defines a date range by setting the minimumDate and maximumDate
2516     properties.
2517
2518     The date range restricts the user selection, i.e. the user can
2519     only select dates within the specified date range. Note that
2520
2521     \snippet code/src_gui_widgets_qcalendarwidget.cpp 3
2522
2523     is analogous to
2524
2525     \snippet code/src_gui_widgets_qcalendarwidget.cpp 4
2526
2527     If either the \a min or \a max parameters are not valid QDate
2528     objects, this function does nothing.
2529
2530     \sa setMinimumDate(), setMaximumDate()
2531 */
2532
2533 void QCalendarWidget::setDateRange(const QDate &min, const QDate &max)
2534 {
2535     Q_D(QCalendarWidget);
2536     if (d->m_model->m_minimumDate == min && d->m_model->m_maximumDate == max)
2537         return;
2538     if (!min.isValid() || !max.isValid())
2539         return;
2540
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) {
2548         d->update();
2549         d->showMonth(newDate.year(), newDate.month());
2550         d->m_navigator->setDate(newDate);
2551         emit selectionChanged();
2552     }
2553 }
2554
2555
2556 /*! \enum QCalendarWidget::HorizontalHeaderFormat
2557
2558     This enum type defines the various formats the horizontal header can display.
2559
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.
2564
2565     \sa horizontalHeaderFormat(), VerticalHeaderFormat
2566 */
2567
2568 /*!
2569     \property QCalendarWidget::horizontalHeaderFormat
2570     \brief the format of the horizontal header.
2571
2572     The default value is QCalendarWidget::ShortDayNames.
2573 */
2574
2575 void QCalendarWidget::setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format)
2576 {
2577     Q_D(QCalendarWidget);
2578     if (d->m_model->m_horizontalHeaderFormat == format)
2579         return;
2580
2581     d->m_model->setHorizontalHeaderFormat(format);
2582     d->cachedSizeHint = QSize();
2583     d->m_view->viewport()->update();
2584     d->m_view->updateGeometry();
2585 }
2586
2587 QCalendarWidget::HorizontalHeaderFormat QCalendarWidget::horizontalHeaderFormat() const
2588 {
2589     Q_D(const QCalendarWidget);
2590     return d->m_model->m_horizontalHeaderFormat;
2591 }
2592
2593
2594 /*! 
2595     \enum QCalendarWidget::VerticalHeaderFormat
2596
2597     This enum type defines the various formats the vertical header can display.
2598
2599     \value ISOWeekNumbers The header displays ISO week numbers as described by \l QDate::weekNumber().
2600     \value NoVerticalHeader The header is hidden.
2601
2602     \sa verticalHeaderFormat(), HorizontalHeaderFormat
2603 */
2604
2605 /*!
2606     \property QCalendarWidget::verticalHeaderFormat
2607     \brief the format of the vertical header.
2608
2609     The default value is QCalendarWidget::ISOWeekNumber.
2610 */
2611
2612 QCalendarWidget::VerticalHeaderFormat QCalendarWidget::verticalHeaderFormat() const
2613 {
2614     Q_D(const QCalendarWidget);
2615     bool shown = d->m_model->weekNumbersShown();
2616     if (shown)
2617         return QCalendarWidget::ISOWeekNumbers;
2618     return QCalendarWidget::NoVerticalHeader;
2619 }
2620
2621 void QCalendarWidget::setVerticalHeaderFormat(QCalendarWidget::VerticalHeaderFormat format)
2622 {
2623     Q_D(QCalendarWidget);
2624     bool show = false;
2625     if (format == QCalendarWidget::ISOWeekNumbers)
2626         show = true;
2627     if (d->m_model->weekNumbersShown() == show)
2628         return;
2629     d->m_model->setWeekNumbersShown(show);
2630     d->cachedSizeHint = QSize();
2631     d->m_view->viewport()->update();
2632     d->m_view->updateGeometry();
2633 }
2634
2635 /*!
2636     \property QCalendarWidget::gridVisible
2637     \brief whether the table grid is displayed.
2638
2639     \table
2640     \row
2641         \li \inlineimage qcalendarwidget-grid.png
2642     \row
2643         \li
2644         \snippet code/src_gui_widgets_qcalendarwidget.cpp 5
2645     \endtable
2646
2647     The default value is false.
2648 */
2649
2650 bool QCalendarWidget::isGridVisible() const
2651 {
2652     Q_D(const QCalendarWidget);
2653     return d->m_view->showGrid();
2654 }
2655
2656 void QCalendarWidget::setGridVisible(bool show)
2657 {
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();
2663 }
2664
2665 /*!
2666     \property QCalendarWidget::selectionMode
2667     \brief the type of selection the user can make in the calendar
2668
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
2671     the keyboard.
2672
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.
2677
2678     The default value is SingleSelection.
2679 */
2680
2681 QCalendarWidget::SelectionMode QCalendarWidget::selectionMode() const
2682 {
2683     Q_D(const QCalendarWidget);
2684     return d->m_view->readOnly ? QCalendarWidget::NoSelection : QCalendarWidget::SingleSelection;
2685 }
2686
2687 void QCalendarWidget::setSelectionMode(SelectionMode mode)
2688 {
2689     Q_D(QCalendarWidget);
2690     d->m_view->readOnly = (mode == QCalendarWidget::NoSelection);
2691     d->setNavigatorEnabled(isDateEditEnabled() && (selectionMode() != QCalendarWidget::NoSelection));
2692     d->update();
2693 }
2694
2695 /*!
2696     \property QCalendarWidget::firstDayOfWeek
2697     \brief a value identifying the day displayed in the first column.
2698
2699     By default, the day displayed in the first column
2700     is the first day of the week for the calendar's locale.
2701 */
2702
2703 void QCalendarWidget::setFirstDayOfWeek(Qt::DayOfWeek dayOfWeek)
2704 {
2705     Q_D(QCalendarWidget);
2706     if ((Qt::DayOfWeek)d->m_model->firstColumnDay() == dayOfWeek)
2707         return;
2708
2709     d->m_model->setFirstColumnDay(dayOfWeek);
2710     d->update();
2711 }
2712
2713 Qt::DayOfWeek QCalendarWidget::firstDayOfWeek() const
2714 {
2715     Q_D(const QCalendarWidget);
2716     return (Qt::DayOfWeek)d->m_model->firstColumnDay();
2717 }
2718
2719 /*!
2720     Returns the text char format for rendering the header.
2721 */
2722 QTextCharFormat QCalendarWidget::headerTextFormat() const
2723 {
2724     Q_D(const QCalendarWidget);
2725     return d->m_model->m_headerFormat;
2726 }
2727
2728 /*!
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.
2734 */
2735 void QCalendarWidget::setHeaderTextFormat(const QTextCharFormat &format)
2736 {
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();
2742 }
2743
2744 /*!
2745     Returns the text char format for rendering of day in the week \a dayOfWeek.
2746
2747     \sa headerTextFormat()
2748 */
2749 QTextCharFormat QCalendarWidget::weekdayTextFormat(Qt::DayOfWeek dayOfWeek) const
2750 {
2751     Q_D(const QCalendarWidget);
2752     return d->m_model->m_dayFormats.value(dayOfWeek);
2753 }
2754
2755 /*!
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.
2759
2760     \sa setHeaderTextFormat()
2761 */
2762 void QCalendarWidget::setWeekdayTextFormat(Qt::DayOfWeek dayOfWeek, const QTextCharFormat &format)
2763 {
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();
2769 }
2770
2771 /*!
2772     Returns a QMap from QDate to QTextCharFormat showing all dates
2773     that use a special format that alters their rendering.
2774 */
2775 QMap<QDate, QTextCharFormat> QCalendarWidget::dateTextFormat() const
2776 {
2777     Q_D(const QCalendarWidget);
2778     return d->m_model->m_dateFormats;
2779 }
2780
2781 /*!
2782     Returns a QTextCharFormat for \a date. The char format can be be
2783     empty if the date is not renderd specially.
2784 */
2785 QTextCharFormat QCalendarWidget::dateTextFormat(const QDate &date) const
2786 {
2787     Q_D(const QCalendarWidget);
2788     return d->m_model->m_dateFormats.value(date);
2789 }
2790
2791 /*!
2792     Sets the format used to render the given \a date to that specified by \a format.
2793
2794     If \a date is null, all date formats are cleared.
2795 */
2796 void QCalendarWidget::setDateTextFormat(const QDate &date, const QTextCharFormat &format)
2797 {
2798     Q_D(QCalendarWidget);
2799     if (date.isNull())
2800         d->m_model->m_dateFormats.clear();
2801     else
2802         d->m_model->m_dateFormats[date] = format;
2803     d->m_view->viewport()->update();
2804     d->m_view->updateGeometry();
2805 }
2806
2807 /*!
2808     \property QCalendarWidget::dateEditEnabled
2809     \brief whether the date edit popup is enabled
2810     \since 4.3
2811
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.
2815
2816     By default, this property is enabled.
2817
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.
2822
2823     \sa QCalendarWidget::dateEditAcceptDelay
2824 */
2825 bool QCalendarWidget::isDateEditEnabled() const
2826 {
2827     Q_D(const QCalendarWidget);
2828     return d->m_dateEditEnabled;
2829 }
2830
2831 void QCalendarWidget::setDateEditEnabled(bool enable)
2832 {
2833     Q_D(QCalendarWidget);
2834     if (isDateEditEnabled() == enable)
2835         return;
2836
2837     d->m_dateEditEnabled = enable;
2838
2839     d->setNavigatorEnabled(enable && (selectionMode() != QCalendarWidget::NoSelection));
2840 }
2841
2842 /*!
2843     \property QCalendarWidget::dateEditAcceptDelay
2844     \brief the time an inactive date edit is shown before its contents are accepted
2845     \since 4.3
2846
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.
2851
2852     By default, the delay is defined to be 1500 milliseconds (1.5 seconds).
2853 */
2854 int QCalendarWidget::dateEditAcceptDelay() const
2855 {
2856     Q_D(const QCalendarWidget);
2857     return d->m_navigator->dateEditAcceptDelay();
2858 }
2859
2860 void QCalendarWidget::setDateEditAcceptDelay(int delay)
2861 {
2862     Q_D(QCalendarWidget);
2863     d->m_navigator->setDateEditAcceptDelay(delay);
2864 }
2865
2866 /*!
2867     \since 4.4
2868
2869     Updates the cell specified by the given \a date unless updates
2870     are disabled or the cell is hidden.
2871
2872     \sa updateCells(), yearShown(), monthShown()
2873 */
2874 void QCalendarWidget::updateCell(const QDate &date)
2875 {
2876     if (!date.isValid()) {
2877         qWarning("QCalendarWidget::updateCell: Invalid date");
2878         return;
2879     }
2880
2881     if (!isVisible())
2882         return;
2883
2884     Q_D(QCalendarWidget);
2885     int row, column;
2886     d->m_model->cellForDate(date, &row, &column);
2887     if (row == -1 || column == -1)
2888         return;
2889
2890     QModelIndex modelIndex = d->m_model->index(row, column);
2891     if (!modelIndex.isValid())
2892         return;
2893
2894     d->m_view->viewport()->update(d->m_view->visualRect(modelIndex));
2895 }
2896
2897 /*!
2898     \since 4.4
2899
2900     Updates all visible cells unless updates are disabled.
2901
2902     \sa updateCell()
2903 */
2904 void QCalendarWidget::updateCells()
2905 {
2906     Q_D(QCalendarWidget);
2907     if (isVisible())
2908         d->m_view->viewport()->update();
2909 }
2910
2911 /*!
2912     \fn void QCalendarWidget::selectionChanged()
2913
2914     This signal is emitted when the currently selected date is
2915     changed.
2916
2917     The currently selected date can be changed by the user using the
2918     mouse or keyboard, or by the programmer using setSelectedDate().
2919
2920     \sa selectedDate()
2921 */
2922
2923 /*!
2924     \fn void QCalendarWidget::currentPageChanged(int year, int month)
2925
2926     This signal is emitted when the currently shown month is changed.
2927     The new \a year and \a month are passed as parameters.
2928
2929     \sa setCurrentPage()
2930 */
2931
2932 /*!
2933     \fn void QCalendarWidget::activated(const QDate &date)
2934
2935     This signal is emitted whenever the user presses the Return or
2936     Enter key or double-clicks a \a date in the calendar
2937     widget.
2938 */
2939
2940 /*!
2941     \fn void QCalendarWidget::clicked(const QDate &date)
2942
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.
2948
2949 */
2950
2951 /*!
2952     \property QCalendarWidget::headerVisible
2953     \brief whether the navigation bar is shown or not
2954
2955     \obsolete
2956
2957     Use navigationBarVisible() instead.
2958
2959     By default, this property is true.
2960 */
2961
2962 /*!
2963     \property QCalendarWidget::navigationBarVisible
2964     \brief whether the navigation bar is shown or not
2965
2966     \since 4.3
2967
2968     When this property is true (the default), the next month,
2969     previous month, month selection, year selection controls are
2970     shown on top.
2971
2972     When the property is set to false, these controls are hidden.
2973 */
2974
2975 bool QCalendarWidget::isNavigationBarVisible() const
2976 {
2977     Q_D(const QCalendarWidget);
2978     return d->navBarVisible;
2979 }
2980
2981
2982 void QCalendarWidget::setNavigationBarVisible(bool visible)
2983 {
2984     Q_D(QCalendarWidget);
2985     d->navBarVisible = visible;
2986     d->cachedSizeHint = QSize();
2987     d->navBarBackground->setVisible(visible);
2988     updateGeometry();
2989 }
2990
2991 /*!
2992   \reimp
2993 */
2994 bool QCalendarWidget::event(QEvent *event)
2995 {
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();
3006             break;
3007         case QEvent::FontChange:
3008         case QEvent::ApplicationFontChange:
3009             d->cachedSizeHint = QSize();
3010             d->m_view->updateGeometry();
3011             break;
3012         case QEvent::StyleChange:
3013             d->cachedSizeHint = QSize();
3014             d->m_view->updateGeometry();
3015         default:
3016             break;
3017     }
3018     return QWidget::event(event);
3019 }
3020
3021 /*!
3022   \reimp
3023 */
3024 bool QCalendarWidget::eventFilter(QObject *watched, QEvent *event)
3025 {
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)) {
3036                 event->accept();
3037                 d->_q_yearEditingFinished();
3038                 setFocus();
3039                 return true;
3040             }
3041         }
3042     }
3043     return QWidget::eventFilter(watched, event);
3044 }
3045
3046 /*!
3047   \reimp
3048 */
3049 void QCalendarWidget::mousePressEvent(QMouseEvent *event)
3050 {
3051     setAttribute(Qt::WA_NoMouseReplay);
3052     QWidget::mousePressEvent(event);
3053     setFocus();
3054 }
3055
3056 /*!
3057   \reimp
3058 */
3059 void QCalendarWidget::resizeEvent(QResizeEvent * event)
3060 {
3061     Q_D(QCalendarWidget);
3062
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();
3068
3069     QWidget::resizeEvent(event);
3070 }
3071
3072 /*!
3073   \reimp
3074 */
3075 void QCalendarWidget::keyPressEvent(QKeyEvent * event)
3076 {
3077     Q_D(QCalendarWidget);
3078     if(d->yearEdit->isVisible()&& event->key() == Qt::Key_Escape)
3079     {
3080         d->yearEdit->setValue(yearShown());
3081         d->_q_yearEditingFinished();
3082         return;
3083     }
3084     QWidget::keyPressEvent(event);
3085 }
3086
3087 QT_END_NAMESPACE
3088
3089 #include "qcalendarwidget.moc"
3090 #include "moc_qcalendarwidget.cpp"
3091
3092 #endif //QT_NO_CALENDARWIDGET