source: trunk/src/gui/widgets/qcalendarwidget.cpp@ 1006

Last change on this file since 1006 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 89.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
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
65QT_BEGIN_NAMESPACE
66
67enum {
68 RowCount = 6,
69 ColumnCount = 7,
70 HeaderColumn = 0,
71 HeaderRow = 0,
72 MinimumDayOffset = 1
73};
74
75class QCalendarDateSectionValidator
76{
77public:
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
95protected:
96 QString highlightString(const QString &str, int pos) const;
97private:
98};
99
100QString 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
109class QCalendarDayValidator : public QCalendarDateSectionValidator
110{
111
112public:
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;
119private:
120 int m_pos;
121 int m_day;
122 int m_oldDay;
123};
124
125QCalendarDayValidator::QCalendarDayValidator()
126 : QCalendarDateSectionValidator(), m_pos(0), m_day(1), m_oldDay(1)
127{
128}
129
130QCalendarDateSectionValidator::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
179QDate 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
191void QCalendarDayValidator::setDate(const QDate &date)
192{
193 m_day = m_oldDay = date.day();
194 m_pos = 0;
195}
196
197QString 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
206QString 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
225class QCalendarMonthValidator : public QCalendarDateSectionValidator
226{
227
228public:
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;
235private:
236 int m_pos;
237 int m_month;
238 int m_oldMonth;
239};
240
241QCalendarMonthValidator::QCalendarMonthValidator()
242 : QCalendarDateSectionValidator(), m_pos(0), m_month(1), m_oldMonth(1)
243{
244}
245
246QCalendarDateSectionValidator::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
295QDate 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
309void QCalendarMonthValidator::setDate(const QDate &date)
310{
311 m_month = m_oldMonth = date.month();
312 m_pos = 0;
313}
314
315QString 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
324QString 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
342class QCalendarYearValidator : public QCalendarDateSectionValidator
343{
344
345public:
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;
352private:
353 int pow10(int n);
354 int m_pos;
355 int m_year;
356 int m_oldYear;
357};
358
359QCalendarYearValidator::QCalendarYearValidator()
360 : QCalendarDateSectionValidator(), m_pos(0), m_year(2000), m_oldYear(2000)
361{
362}
363
364int 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
372QCalendarDateSectionValidator::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
410QDate 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
422void QCalendarYearValidator::setDate(const QDate &date)
423{
424 m_year = m_oldYear = date.year();
425 m_pos = 0;
426}
427
428QString 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
441QString 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
455class QCalendarDateValidator
456{
457public:
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
469private:
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
498QCalendarDateValidator::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
507void 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
514QCalendarDateValidator::~QCalendarDateValidator()
515{
516 delete m_yearValidator;
517 delete m_monthValidator;
518 delete m_dayValidator;
519 clear();
520}
521
522// from qdatetime.cpp
523int 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
533void 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
543QString 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
562void 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
574void 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
621void 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
628void 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
639void 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
650void 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
674QWidget *QCalendarTextNavigator::widget() const
675{
676 return m_widget;
677}
678
679void QCalendarTextNavigator::setWidget(QWidget *widget)
680{
681 m_widget = widget;
682}
683
684QDate QCalendarTextNavigator::date() const
685{
686 return m_date;
687}
688
689void QCalendarTextNavigator::setDate(const QDate &date)
690{
691 m_date = date;
692}
693
694void 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
717void 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
727void 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
747void 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
760bool 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
795void QCalendarTextNavigator::timerEvent(QTimerEvent *e)
796{
797 if (e->timerId() == m_acceptTimer.timerId()) {
798 applyDate();
799 removeDateLabel();
800 }
801}
802
803int QCalendarTextNavigator::dateEditAcceptDelay() const
804{
805 return m_editDelay;
806}
807
808void QCalendarTextNavigator::setDateEditAcceptDelay(int delay)
809{
810 m_editDelay = delay;
811}
812
813class QCalendarView;
814
815class QCalendarModel : public QAbstractTableModel
816{
817 Q_OBJECT
818public:
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
899class QCalendarView : public QTableView
900{
901 Q_OBJECT
902public:
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
909signals:
910 void showDate(const QDate &date);
911 void changeDate(const QDate &date, bool changeMonth);
912 void clicked(const QDate &date);
913 void editingFinished();
914protected:
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);
927public:
928 bool readOnly;
929private:
930 bool validDateClicked;
931#ifdef QT_KEYPAD_NAVIGATION
932 QDate origDate;
933#endif
934};
935
936QCalendarModel::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 = Qt::Sunday;
945 m_horizontalHeaderFormat = QCalendarWidget::ShortDayNames;
946 m_weekNumbersShown = true;
947 m_firstColumn = 1;
948 m_firstRow = 1;
949 m_view = 0;
950}
951
952Qt::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
963int 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/*
974This simple algorithm tries to generate a valid date from the month shown.
975Some months don't contain a first day (e.g. Jan of -4713 year,
976so QDate (-4713, 1, 1) would be invalid). In that case we try to generate
977another valid date for that month. Later, returned date's day is the number of cells
978calendar widget will reserve for days before referenceDate. (E.g. if returned date's
979day is 16, that day will be placed in 3rd or 4th row, not in the 1st or 2nd row).
980Depending on referenceData we can change behaviour of Oct 1582. If referenceDate is 1st
981of Oct we render 1 Oct in 1st or 2nd row. If referenceDate is 17 of Oct we show always 16
982dates before 17 of Oct, and since this month contains the hole 5-14 Oct, the first of Oct
983will be rendered in 2nd or 3rd row, showing more dates from previous month.
984*/
985QDate 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
997int QCalendarModel::columnForFirstOfMonth(const QDate &date) const
998{
999 return (columnForDayOfWeek(static_cast<Qt::DayOfWeek>(date.dayOfWeek())) - (date.day() % 7) + 8) % 7;
1000}
1001
1002QDate 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
1019void 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
1055QString 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
1074QTextCharFormat 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
1113QVariant 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
1149Qt::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
1161void 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
1170void 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
1181void 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
1194void 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
1207void 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
1220void 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
1229void 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
1246void QCalendarModel::setFirstColumnDay(Qt::DayOfWeek dayOfWeek)
1247{
1248 if (m_firstDay == dayOfWeek)
1249 return;
1250
1251 m_firstDay = dayOfWeek;
1252 internalUpdate();
1253}
1254
1255Qt::DayOfWeek QCalendarModel::firstColumnDay() const
1256{
1257 return m_firstDay;
1258}
1259
1260bool QCalendarModel::weekNumbersShown() const
1261{
1262 return m_weekNumbersShown;
1263}
1264
1265void 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
1281QCalendarView::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
1294QModelIndex 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
1340void 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
1376void 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
1387bool 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
1400QDate 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
1416void 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
1434void 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
1462void 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
1487void 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
1515class QCalendarDelegate : public QItemDelegate
1516{
1517 Q_OBJECT
1518public:
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
1526private:
1527 QCalendarWidgetPrivate *calendarWidgetPrivate;
1528 mutable QStyleOptionViewItemV4 storedOption;
1529};
1530
1531//Private tool button class
1532class QCalToolButton: public QToolButton
1533{
1534public:
1535 QCalToolButton(QWidget * parent)
1536 : QToolButton(parent)
1537 { }
1538protected:
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
1561class QPrevNextCalButton : public QToolButton
1562{
1563 Q_OBJECT
1564public:
1565 QPrevNextCalButton(QWidget *parent) : QToolButton(parent) {}
1566protected:
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
1576class QCalendarWidgetPrivate : public QWidgetPrivate
1577{
1578 Q_DECLARE_PUBLIC(QCalendarWidget)
1579public:
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
1627void 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
1640void 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
1650QCalendarWidgetPrivate::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
1663void 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
1688void 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
1763void 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
1770void 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
1795void 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
1805void 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
1826void 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
1834QDate QCalendarWidgetPrivate::getCurrentDate()
1835{
1836 QModelIndex index = m_view->currentIndex();
1837 return m_model->dateForCell(index.row(), index.column());
1838}
1839
1840void QCalendarWidgetPrivate::_q_prevMonthClicked()
1841{
1842 QDate currentDate = getCurrentDate().addMonths(-1);
1843 updateCurrentPage(currentDate);
1844}
1845
1846void QCalendarWidgetPrivate::_q_nextMonthClicked()
1847{
1848 QDate currentDate = getCurrentDate().addMonths(1);
1849 updateCurrentPage(currentDate);
1850}
1851
1852void 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
1866void 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
1883void 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
1897void 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
1908void 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
1921void 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
1927void QCalendarWidgetPrivate::_q_slotShowDate(const QDate &date)
1928{
1929 updateCurrentPage(date);
1930}
1931
1932void QCalendarWidgetPrivate::_q_slotChangeDate(const QDate &date)
1933{
1934 _q_slotChangeDate(date, true);
1935}
1936
1937void 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
1952void 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
1966 \image cleanlooks-calendarwidget.png
1967
1968 The widget is initialized with the current month and year, but
1969 QCalendarWidget provides several public slots to change the year
1970 and month that is shown.
1971
1972 By default, today's date is selected, and the user can select a
1973 date using both mouse and keyboard. The currently selected date
1974 can be retrieved using the selectedDate() function. It is
1975 possible to constrain the user selection to a given date range by
1976 setting the minimumDate and maximumDate properties.
1977 Alternatively, both properties can be set in one go using the
1978 setDateRange() convenience slot. Set the \l selectionMode
1979 property to NoSelection to prohibit the user from selecting at
1980 all. Note that a date also can be selected programmatically using
1981 the setSelectedDate() slot.
1982
1983 The currently displayed month and year can be retrieved using the
1984 monthShown() and yearShown() functions, respectively.
1985
1986 A newly created calendar widget uses abbreviated day names, and
1987 both Saturdays and Sundays are marked in red. The calendar grid is
1988 not visible. The week numbers are displayed, and the first column
1989 day is Sunday.
1990
1991 The notation of the days can be altered to a single letter
1992 abbreviations ("M" for "Monday") by setting the
1993 horizontalHeaderFormat property to
1994 QCalendarWidget::SingleLetterDayNames. Setting the same property
1995 to QCalendarWidget::LongDayNames makes the header display the
1996 complete day names. The week numbers can be removed by setting
1997 the verticalHeaderFormat property to
1998 QCalendarWidget::NoVerticalHeader. The calendar grid can be
1999 turned on by setting the gridVisible property to true using the
2000 setGridVisible() function:
2001
2002 \table
2003 \row \o
2004 \image qcalendarwidget-grid.png
2005 \row \o
2006 \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 0
2007 \endtable
2008
2009 Finally, the day in the first column can be altered using the
2010 setFirstDayOfWeek() function.
2011
2012 The QCalendarWidget class also provides three signals,
2013 selectionChanged(), activated() and currentPageChanged() making it
2014 possible to respond to user interaction.
2015
2016 The rendering of the headers, weekdays or single days can be
2017 largely customized by setting QTextCharFormat's for some special
2018 weekday, a special date or for the rendering of the headers.
2019
2020 Only a subset of the properties in QTextCharFormat are used by the
2021 calendar widget. Currently, the foreground, background and font
2022 properties are used to determine the rendering of individual cells
2023 in the widget.
2024
2025 \sa QDate, QDateEdit, QTextCharFormat
2026*/
2027
2028/*!
2029 \enum QCalendarWidget::SelectionMode
2030
2031 This enum describes the types of selection offered to the user for
2032 selecting dates in the calendar.
2033
2034 \value NoSelection Dates cannot be selected.
2035 \value SingleSelection Single dates can be selected.
2036
2037 \sa selectionMode
2038*/
2039
2040/*!
2041 Constructs a calendar widget with the given \a parent.
2042
2043 The widget is initialized with the current month and year, and the
2044 currently selected date is today.
2045
2046 \sa setCurrentPage()
2047*/
2048QCalendarWidget::QCalendarWidget(QWidget *parent)
2049 : QWidget(*new QCalendarWidgetPrivate, parent, 0)
2050{
2051 Q_D(QCalendarWidget);
2052
2053 setAutoFillBackground(true);
2054 setBackgroundRole(QPalette::Window);
2055
2056 QVBoxLayout *layoutV = new QVBoxLayout(this);
2057 layoutV->setMargin(0);
2058 d->m_model = new QCalendarModel(this);
2059 QTextCharFormat fmt;
2060 fmt.setForeground(QBrush(Qt::red));
2061 d->m_model->m_dayFormats.insert(Qt::Saturday, fmt);
2062 d->m_model->m_dayFormats.insert(Qt::Sunday, fmt);
2063 d->m_view = new QCalendarView(this);
2064 d->m_view->setObjectName(QLatin1String("qt_calendar_calendarview"));
2065 d->m_view->setModel(d->m_model);
2066 d->m_model->setView(d->m_view);
2067 d->m_view->setSelectionBehavior(QAbstractItemView::SelectItems);
2068 d->m_view->setSelectionMode(QAbstractItemView::SingleSelection);
2069 d->m_view->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
2070 d->m_view->horizontalHeader()->setClickable(false);
2071 d->m_view->verticalHeader()->setResizeMode(QHeaderView::Stretch);
2072 d->m_view->verticalHeader()->setClickable(false);
2073 d->m_selection = d->m_view->selectionModel();
2074 d->createNavigationBar(this);
2075 d->m_view->setFrameStyle(QFrame::NoFrame);
2076 d->m_delegate = new QCalendarDelegate(d, this);
2077 d->m_view->setItemDelegate(d->m_delegate);
2078 d->update();
2079 d->updateNavigationBar();
2080 setFocusPolicy(Qt::StrongFocus);
2081 setFocusProxy(d->m_view);
2082 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
2083
2084 connect(d->m_view, SIGNAL(showDate(QDate)),
2085 this, SLOT(_q_slotShowDate(QDate)));
2086 connect(d->m_view, SIGNAL(changeDate(QDate,bool)),
2087 this, SLOT(_q_slotChangeDate(QDate,bool)));
2088 connect(d->m_view, SIGNAL(clicked(QDate)),
2089 this, SIGNAL(clicked(QDate)));
2090 connect(d->m_view, SIGNAL(editingFinished()),
2091 this, SLOT(_q_editingFinished()));
2092
2093 connect(d->prevMonth, SIGNAL(clicked(bool)),
2094 this, SLOT(_q_prevMonthClicked()));
2095 connect(d->nextMonth, SIGNAL(clicked(bool)),
2096 this, SLOT(_q_nextMonthClicked()));
2097 connect(d->yearButton, SIGNAL(clicked(bool)),
2098 this, SLOT(_q_yearClicked()));
2099 connect(d->monthMenu, SIGNAL(triggered(QAction*)),
2100 this, SLOT(_q_monthChanged(QAction*)));
2101 connect(d->yearEdit, SIGNAL(editingFinished()),
2102 this, SLOT(_q_yearEditingFinished()));
2103
2104 layoutV->setMargin(0);
2105 layoutV->setSpacing(0);
2106 layoutV->addWidget(d->navBarBackground);
2107 layoutV->addWidget(d->m_view);
2108
2109 d->m_navigator = new QCalendarTextNavigator(this);
2110 setDateEditEnabled(true);
2111}
2112
2113/*!
2114 Destroys the calendar widget.
2115*/
2116QCalendarWidget::~QCalendarWidget()
2117{
2118}
2119
2120/*!
2121 \reimp
2122*/
2123QSize QCalendarWidget::sizeHint() const
2124{
2125 return minimumSizeHint();
2126}
2127
2128/*!
2129 \reimp
2130*/
2131QSize QCalendarWidget::minimumSizeHint() const
2132{
2133 Q_D(const QCalendarWidget);
2134 if (d->cachedSizeHint.isValid())
2135 return d->cachedSizeHint;
2136
2137 ensurePolished();
2138
2139 int w = 0;
2140 int h = 0;
2141
2142 int end = 53;
2143 int rows = 7;
2144 int cols = 8;
2145
2146 const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1) * 2;
2147
2148 if (horizontalHeaderFormat() == QCalendarWidget::NoHorizontalHeader) {
2149 rows = 6;
2150 } else {
2151 for (int i = 1; i <= 7; i++) {
2152 QFontMetrics fm(d->m_model->formatForCell(0, i).font());
2153 w = qMax(w, fm.width(d->m_model->dayName(d->m_model->dayOfWeekForColumn(i))) + marginH);
2154 h = qMax(h, fm.height());
2155 }
2156 }
2157
2158 if (verticalHeaderFormat() == QCalendarWidget::NoVerticalHeader) {
2159 cols = 7;
2160 } else {
2161 for (int i = 1; i <= 6; i++) {
2162 QFontMetrics fm(d->m_model->formatForCell(i, 0).font());
2163 for (int j = 1; j < end; j++)
2164 w = qMax(w, fm.width(QString::number(j)) + marginH);
2165 h = qMax(h, fm.height());
2166 }
2167 }
2168
2169 QFontMetrics fm(d->m_model->formatForCell(1, 1).font());
2170 for (int i = 1; i <= end; i++) {
2171 w = qMax(w, fm.width(QString::number(i)) + marginH);
2172 h = qMax(h, fm.height());
2173 }
2174
2175 if (d->m_view->showGrid()) {
2176 // hardcoded in tableview
2177 w += 1;
2178 h += 1;
2179 }
2180
2181 w += 1; // default column span
2182
2183 h = qMax(h, d->m_view->verticalHeader()->minimumSectionSize());
2184 w = qMax(w, d->m_view->horizontalHeader()->minimumSectionSize());
2185
2186 //add the size of the header.
2187 QSize headerSize(0, 0);
2188 if (d->navBarVisible) {
2189 int headerH = d->navBarBackground->sizeHint().height();
2190 int headerW = 0;
2191
2192 headerW += d->prevMonth->sizeHint().width();
2193 headerW += d->nextMonth->sizeHint().width();
2194
2195 QFontMetrics fm = d->monthButton->fontMetrics();
2196 int monthW = 0;
2197 for (int i = 1; i < 12; i++) {
2198 QString monthName = locale().standaloneMonthName(i, QLocale::LongFormat);
2199 monthW = qMax(monthW, fm.boundingRect(monthName).width());
2200 }
2201 const int buttonDecoMargin = d->monthButton->sizeHint().width() - fm.boundingRect(d->monthButton->text()).width();
2202 headerW += monthW + buttonDecoMargin;
2203
2204 fm = d->yearButton->fontMetrics();
2205 headerW += fm.boundingRect(QLatin1String("5555")).width() + buttonDecoMargin;
2206
2207 headerSize = QSize(headerW, headerH);
2208 }
2209 w *= cols;
2210 w = qMax(headerSize.width(), w);
2211 h = (h * rows) + headerSize.height();
2212 d->cachedSizeHint = QSize(w, h);
2213 return d->cachedSizeHint;
2214}
2215
2216/*!
2217 Paints the cell specified by the given \a date, using the given \a painter and \a rect.
2218*/
2219
2220void QCalendarWidget::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
2221{
2222 Q_D(const QCalendarWidget);
2223 d->m_delegate->paintCell(painter, rect, date);
2224}
2225
2226/*!
2227 \property QCalendarWidget::selectedDate
2228 \brief the currently selected date.
2229
2230 The selected date must be within the date range specified by the
2231 minimumDate and maximumDate properties. By default, the selected
2232 date is the current date.
2233
2234 \sa setDateRange()
2235*/
2236
2237QDate QCalendarWidget::selectedDate() const
2238{
2239 Q_D(const QCalendarWidget);
2240 return d->m_model->m_date;
2241}
2242
2243void QCalendarWidget::setSelectedDate(const QDate &date)
2244{
2245 Q_D(QCalendarWidget);
2246 if (d->m_model->m_date == date && date == d->getCurrentDate())
2247 return;
2248
2249 if (!date.isValid())
2250 return;
2251
2252 d->m_model->setDate(date);
2253 d->update();
2254 QDate newDate = d->m_model->m_date;
2255 d->showMonth(newDate.year(), newDate.month());
2256 emit selectionChanged();
2257}
2258
2259/*!
2260 Returns the year of the currently displayed month. Months are
2261 numbered from 1 to 12.
2262
2263 \sa monthShown(), setCurrentPage()
2264*/
2265
2266int QCalendarWidget::yearShown() const
2267{
2268 Q_D(const QCalendarWidget);
2269 return d->m_model->m_shownYear;
2270}
2271
2272/*!
2273 Returns the currently displayed month. Months are numbered from 1 to
2274 12.
2275
2276 \sa yearShown(), setCurrentPage()
2277*/
2278
2279int QCalendarWidget::monthShown() const
2280{
2281 Q_D(const QCalendarWidget);
2282 return d->m_model->m_shownMonth;
2283}
2284
2285/*!
2286 Displays the given \a month of the given \a year without changing
2287 the selected date. Use the setSelectedDate() function to alter the
2288 selected date.
2289
2290 The currently displayed month and year can be retrieved using the
2291 monthShown() and yearShown() functions respectively.
2292
2293 \sa yearShown(), monthShown(), showPreviousMonth(), showNextMonth(),
2294 showPreviousYear(), showNextYear()
2295*/
2296
2297void QCalendarWidget::setCurrentPage(int year, int month)
2298{
2299 Q_D(QCalendarWidget);
2300 QDate currentDate = d->getCurrentDate();
2301 int day = currentDate.day();
2302 int daysInMonths = QDate(year, month, 1).daysInMonth();
2303 if (day > daysInMonths)
2304 day = daysInMonths;
2305
2306 d->showMonth(year, month);
2307
2308 QDate newDate(year, month, day);
2309 int row = -1, col = -1;
2310 d->m_model->cellForDate(newDate, &row, &col);
2311 if (row != -1 && col != -1) {
2312 d->m_view->selectionModel()->setCurrentIndex(d->m_model->index(row, col),
2313 QItemSelectionModel::NoUpdate);
2314 }
2315}
2316
2317/*!
2318 Shows the next month relative to the currently displayed
2319 month. Note that the selected date is not changed.
2320
2321 \sa showPreviousMonth(), setCurrentPage(), setSelectedDate()
2322*/
2323
2324void QCalendarWidget::showNextMonth()
2325{
2326 int year = yearShown();
2327 int month = monthShown();
2328 if (month == 12) {
2329 ++year;
2330 month = 1;
2331 } else {
2332 ++month;
2333 }
2334 setCurrentPage(year, month);
2335}
2336
2337/*!
2338 Shows the previous month relative to the currently displayed
2339 month. Note that the selected date is not changed.
2340
2341 \sa showNextMonth(), setCurrentPage(), setSelectedDate()
2342*/
2343
2344void QCalendarWidget::showPreviousMonth()
2345{
2346 int year = yearShown();
2347 int month = monthShown();
2348 if (month == 1) {
2349 --year;
2350 month = 12;
2351 } else {
2352 --month;
2353 }
2354 setCurrentPage(year, month);
2355}
2356
2357/*!
2358 Shows the currently displayed month in the \e next year relative
2359 to the currently displayed year. Note that the selected date is
2360 not changed.
2361
2362 \sa showPreviousYear(), setCurrentPage(), setSelectedDate()
2363*/
2364
2365void QCalendarWidget::showNextYear()
2366{
2367 int year = yearShown();
2368 int month = monthShown();
2369 ++year;
2370 setCurrentPage(year, month);
2371}
2372
2373/*!
2374 Shows the currently displayed month in the \e previous year
2375 relative to the currently displayed year. Note that the selected
2376 date is not changed.
2377
2378 \sa showNextYear(), setCurrentPage(), setSelectedDate()
2379*/
2380
2381void QCalendarWidget::showPreviousYear()
2382{
2383 int year = yearShown();
2384 int month = monthShown();
2385 --year;
2386 setCurrentPage(year, month);
2387}
2388
2389/*!
2390 Shows the month of the selected date.
2391
2392 \sa selectedDate(), setCurrentPage()
2393*/
2394void QCalendarWidget::showSelectedDate()
2395{
2396 QDate currentDate = selectedDate();
2397 setCurrentPage(currentDate.year(), currentDate.month());
2398}
2399
2400/*!
2401 Shows the month of the today's date.
2402
2403 \sa selectedDate(), setCurrentPage()
2404*/
2405void QCalendarWidget::showToday()
2406{
2407 QDate currentDate = QDate::currentDate();
2408 setCurrentPage(currentDate.year(), currentDate.month());
2409}
2410
2411/*!
2412 \property QCalendarWidget::minimumDate
2413 \brief the minimum date of the currently specified date range.
2414
2415 The user will not be able to select a date that is before the
2416 currently set minimum date.
2417
2418 \table
2419 \row
2420 \o \image qcalendarwidget-minimum.png
2421 \row
2422 \o
2423 \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 1
2424 \endtable
2425
2426 By default, the minimum date is the earliest date that the QDate
2427 class can handle.
2428
2429 When setting a minimum date, the maximumDate and selectedDate
2430 properties are adjusted if the selection range becomes invalid. If
2431 the provided date is not a valid QDate object, the
2432 setMinimumDate() function does nothing.
2433
2434 \sa setDateRange()
2435*/
2436
2437QDate QCalendarWidget::minimumDate() const
2438{
2439 Q_D(const QCalendarWidget);
2440 return d->m_model->m_minimumDate;
2441}
2442
2443void QCalendarWidget::setMinimumDate(const QDate &date)
2444{
2445 Q_D(QCalendarWidget);
2446 if (!date.isValid() || d->m_model->m_minimumDate == date)
2447 return;
2448
2449 QDate oldDate = d->m_model->m_date;
2450 d->m_model->setMinimumDate(date);
2451 d->yearEdit->setMinimum(d->m_model->m_minimumDate.year());
2452 d->updateMonthMenu();
2453 QDate newDate = d->m_model->m_date;
2454 if (oldDate != newDate) {
2455 d->update();
2456 d->showMonth(newDate.year(), newDate.month());
2457 d->m_navigator->setDate(newDate);
2458 emit selectionChanged();
2459 }
2460}
2461
2462/*!
2463 \property QCalendarWidget::maximumDate
2464 \brief the maximum date of the currently specified date range.
2465
2466 The user will not be able to select a date which is after the
2467 currently set maximum date.
2468
2469 \table
2470 \row
2471 \o \image qcalendarwidget-maximum.png
2472 \row
2473 \o
2474 \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 2
2475 \endtable
2476
2477 By default, the maximum date is the last day the QDate class can
2478 handle.
2479
2480 When setting a maximum date, the minimumDate and selectedDate
2481 properties are adjusted if the selection range becomes invalid. If
2482 the provided date is not a valid QDate object, the
2483 setMaximumDate() function does nothing.
2484
2485 \sa setDateRange()
2486*/
2487
2488QDate QCalendarWidget::maximumDate() const
2489{
2490 Q_D(const QCalendarWidget);
2491 return d->m_model->m_maximumDate;
2492}
2493
2494void QCalendarWidget::setMaximumDate(const QDate &date)
2495{
2496 Q_D(QCalendarWidget);
2497 if (!date.isValid() || d->m_model->m_maximumDate == date)
2498 return;
2499
2500 QDate oldDate = d->m_model->m_date;
2501 d->m_model->setMaximumDate(date);
2502 d->yearEdit->setMaximum(d->m_model->m_maximumDate.year());
2503 d->updateMonthMenu();
2504 QDate newDate = d->m_model->m_date;
2505 if (oldDate != newDate) {
2506 d->update();
2507 d->showMonth(newDate.year(), newDate.month());
2508 d->m_navigator->setDate(newDate);
2509 emit selectionChanged();
2510 }
2511}
2512
2513/*!
2514 Defines a date range by setting the minimumDate and maximumDate
2515 properties.
2516
2517 The date range restricts the user selection, i.e. the user can
2518 only select dates within the specified date range. Note that
2519
2520 \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 3
2521
2522 is analogous to
2523
2524 \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 4
2525
2526 If either the \a min or \a max parameters are not valid QDate
2527 objects, this function does nothing.
2528
2529 \sa setMinimumDate(), setMaximumDate()
2530*/
2531
2532void QCalendarWidget::setDateRange(const QDate &min, const QDate &max)
2533{
2534 Q_D(QCalendarWidget);
2535 if (d->m_model->m_minimumDate == min && d->m_model->m_maximumDate == max)
2536 return;
2537 if (!min.isValid() || !max.isValid())
2538 return;
2539
2540 QDate oldDate = d->m_model->m_date;
2541 d->m_model->setRange(min, max);
2542 d->yearEdit->setMinimum(d->m_model->m_minimumDate.year());
2543 d->yearEdit->setMaximum(d->m_model->m_maximumDate.year());
2544 d->updateMonthMenu();
2545 QDate newDate = d->m_model->m_date;
2546 if (oldDate != newDate) {
2547 d->update();
2548 d->showMonth(newDate.year(), newDate.month());
2549 d->m_navigator->setDate(newDate);
2550 emit selectionChanged();
2551 }
2552}
2553
2554
2555/*! \enum QCalendarWidget::HorizontalHeaderFormat
2556
2557 This enum type defines the various formats the horizontal header can display.
2558
2559 \value SingleLetterDayNames The header displays a single letter abbreviation for day names (e.g. M for Monday).
2560 \value ShortDayNames The header displays a short abbreviation for day names (e.g. Mon for Monday).
2561 \value LongDayNames The header displays complete day names (e.g. Monday).
2562 \value NoHorizontalHeader The header is hidden.
2563
2564 \sa horizontalHeaderFormat(), VerticalHeaderFormat
2565*/
2566
2567/*!
2568 \property QCalendarWidget::horizontalHeaderFormat
2569 \brief the format of the horizontal header.
2570
2571 The default value is QCalendarWidget::ShortDayNames.
2572*/
2573
2574void QCalendarWidget::setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format)
2575{
2576 Q_D(QCalendarWidget);
2577 if (d->m_model->m_horizontalHeaderFormat == format)
2578 return;
2579
2580 d->m_model->setHorizontalHeaderFormat(format);
2581 d->cachedSizeHint = QSize();
2582 d->m_view->viewport()->update();
2583 d->m_view->updateGeometry();
2584}
2585
2586QCalendarWidget::HorizontalHeaderFormat QCalendarWidget::horizontalHeaderFormat() const
2587{
2588 Q_D(const QCalendarWidget);
2589 return d->m_model->m_horizontalHeaderFormat;
2590}
2591
2592
2593/*!
2594 \enum QCalendarWidget::VerticalHeaderFormat
2595
2596 This enum type defines the various formats the vertical header can display.
2597
2598 \value ISOWeekNumbers The header displays ISO week numbers as described by \l QDate::weekNumber().
2599 \value NoVerticalHeader The header is hidden.
2600
2601 \sa verticalHeaderFormat(), HorizontalHeaderFormat
2602*/
2603
2604/*!
2605 \property QCalendarWidget::verticalHeaderFormat
2606 \brief the format of the vertical header.
2607
2608 The default value is QCalendarWidget::ISOWeekNumber.
2609*/
2610
2611QCalendarWidget::VerticalHeaderFormat QCalendarWidget::verticalHeaderFormat() const
2612{
2613 Q_D(const QCalendarWidget);
2614 bool shown = d->m_model->weekNumbersShown();
2615 if (shown)
2616 return QCalendarWidget::ISOWeekNumbers;
2617 return QCalendarWidget::NoVerticalHeader;
2618}
2619
2620void QCalendarWidget::setVerticalHeaderFormat(QCalendarWidget::VerticalHeaderFormat format)
2621{
2622 Q_D(QCalendarWidget);
2623 bool show = false;
2624 if (format == QCalendarWidget::ISOWeekNumbers)
2625 show = true;
2626 if (d->m_model->weekNumbersShown() == show)
2627 return;
2628 d->m_model->setWeekNumbersShown(show);
2629 d->cachedSizeHint = QSize();
2630 d->m_view->viewport()->update();
2631 d->m_view->updateGeometry();
2632}
2633
2634/*!
2635 \property QCalendarWidget::gridVisible
2636 \brief whether the table grid is displayed.
2637
2638 \table
2639 \row
2640 \o \inlineimage qcalendarwidget-grid.png
2641 \row
2642 \o
2643 \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 5
2644 \endtable
2645
2646 The default value is false.
2647*/
2648
2649bool QCalendarWidget::isGridVisible() const
2650{
2651 Q_D(const QCalendarWidget);
2652 return d->m_view->showGrid();
2653}
2654
2655void QCalendarWidget::setGridVisible(bool show)
2656{
2657 Q_D(QCalendarWidget);
2658 d->m_view->setShowGrid(show);
2659 d->cachedSizeHint = QSize();
2660 d->m_view->viewport()->update();
2661 d->m_view->updateGeometry();
2662}
2663
2664/*!
2665 \property QCalendarWidget::selectionMode
2666 \brief the type of selection the user can make in the calendar
2667
2668 When this property is set to SingleSelection, the user can select a date
2669 within the minimum and maximum allowed dates, using either the mouse or
2670 the keyboard.
2671
2672 When the property is set to NoSelection, the user will be unable to select
2673 dates, but they can still be selected programmatically. Note that the date
2674 that is selected when the property is set to NoSelection will still be
2675 the selected date of the calendar.
2676
2677 The default value is SingleSelection.
2678*/
2679
2680QCalendarWidget::SelectionMode QCalendarWidget::selectionMode() const
2681{
2682 Q_D(const QCalendarWidget);
2683 return d->m_view->readOnly ? QCalendarWidget::NoSelection : QCalendarWidget::SingleSelection;
2684}
2685
2686void QCalendarWidget::setSelectionMode(SelectionMode mode)
2687{
2688 Q_D(QCalendarWidget);
2689 d->m_view->readOnly = (mode == QCalendarWidget::NoSelection);
2690 d->setNavigatorEnabled(isDateEditEnabled() && (selectionMode() != QCalendarWidget::NoSelection));
2691 d->update();
2692}
2693
2694/*!
2695 \property QCalendarWidget::firstDayOfWeek
2696 \brief a value identifying the day displayed in the first column.
2697
2698 By default, the day displayed in the first column is Sunday
2699*/
2700
2701void QCalendarWidget::setFirstDayOfWeek(Qt::DayOfWeek dayOfWeek)
2702{
2703 Q_D(QCalendarWidget);
2704 if ((Qt::DayOfWeek)d->m_model->firstColumnDay() == dayOfWeek)
2705 return;
2706
2707 d->m_model->setFirstColumnDay(dayOfWeek);
2708 d->update();
2709}
2710
2711Qt::DayOfWeek QCalendarWidget::firstDayOfWeek() const
2712{
2713 Q_D(const QCalendarWidget);
2714 return (Qt::DayOfWeek)d->m_model->firstColumnDay();
2715}
2716
2717/*!
2718 Returns the text char format for rendering the header.
2719*/
2720QTextCharFormat QCalendarWidget::headerTextFormat() const
2721{
2722 Q_D(const QCalendarWidget);
2723 return d->m_model->m_headerFormat;
2724}
2725
2726/*!
2727 Sets the text char format for rendering the header to \a format.
2728 If you also set a weekday text format, this format's foreground and
2729 background color will take precedence over the header's format.
2730 The other formatting information will still be decided by
2731 the header's format.
2732*/
2733void QCalendarWidget::setHeaderTextFormat(const QTextCharFormat &format)
2734{
2735 Q_D(QCalendarWidget);
2736 d->m_model->m_headerFormat = format;
2737 d->cachedSizeHint = QSize();
2738 d->m_view->viewport()->update();
2739 d->m_view->updateGeometry();
2740}
2741
2742/*!
2743 Returns the text char format for rendering of day in the week \a dayOfWeek.
2744
2745 \sa headerTextFormat()
2746*/
2747QTextCharFormat QCalendarWidget::weekdayTextFormat(Qt::DayOfWeek dayOfWeek) const
2748{
2749 Q_D(const QCalendarWidget);
2750 return d->m_model->m_dayFormats.value(dayOfWeek);
2751}
2752
2753/*!
2754 Sets the text char format for rendering of day in the week \a dayOfWeek to \a format.
2755 The format will take precedence over the header format in case of foreground
2756 and background color. Other text formatting information is taken from the headers format.
2757
2758 \sa setHeaderTextFormat()
2759*/
2760void QCalendarWidget::setWeekdayTextFormat(Qt::DayOfWeek dayOfWeek, const QTextCharFormat &format)
2761{
2762 Q_D(QCalendarWidget);
2763 d->m_model->m_dayFormats[dayOfWeek] = format;
2764 d->cachedSizeHint = QSize();
2765 d->m_view->viewport()->update();
2766 d->m_view->updateGeometry();
2767}
2768
2769/*!
2770 Returns a QMap from QDate to QTextCharFormat showing all dates
2771 that use a special format that alters their rendering.
2772*/
2773QMap<QDate, QTextCharFormat> QCalendarWidget::dateTextFormat() const
2774{
2775 Q_D(const QCalendarWidget);
2776 return d->m_model->m_dateFormats;
2777}
2778
2779/*!
2780 Returns a QTextCharFormat for \a date. The char format can be be
2781 empty if the date is not renderd specially.
2782*/
2783QTextCharFormat QCalendarWidget::dateTextFormat(const QDate &date) const
2784{
2785 Q_D(const QCalendarWidget);
2786 return d->m_model->m_dateFormats.value(date);
2787}
2788
2789/*!
2790 Sets the format used to render the given \a date to that specified by \a format.
2791
2792 If \a date is null, all date formats are cleared.
2793*/
2794void QCalendarWidget::setDateTextFormat(const QDate &date, const QTextCharFormat &format)
2795{
2796 Q_D(QCalendarWidget);
2797 if (date.isNull())
2798 d->m_model->m_dateFormats.clear();
2799 else
2800 d->m_model->m_dateFormats[date] = format;
2801 d->m_view->viewport()->update();
2802 d->m_view->updateGeometry();
2803}
2804
2805/*!
2806 \property QCalendarWidget::dateEditEnabled
2807 \brief whether the date edit popup is enabled
2808 \since 4.3
2809
2810 If this property is enabled, pressing a non-modifier key will cause a
2811 date edit to popup if the calendar widget has focus, allowing the user
2812 to specify a date in the form specified by the current locale.
2813
2814 By default, this property is enabled.
2815
2816 The date edit is simpler in appearance than QDateEdit, but allows the
2817 user to navigate between fields using the left and right cursor keys,
2818 increment and decrement individual fields using the up and down cursor
2819 keys, and enter values directly using the number keys.
2820
2821 \sa QCalendarWidget::dateEditAcceptDelay
2822*/
2823bool QCalendarWidget::isDateEditEnabled() const
2824{
2825 Q_D(const QCalendarWidget);
2826 return d->m_dateEditEnabled;
2827}
2828
2829void QCalendarWidget::setDateEditEnabled(bool enable)
2830{
2831 Q_D(QCalendarWidget);
2832 if (isDateEditEnabled() == enable)
2833 return;
2834
2835 d->m_dateEditEnabled = enable;
2836
2837 d->setNavigatorEnabled(enable && (selectionMode() != QCalendarWidget::NoSelection));
2838}
2839
2840/*!
2841 \property QCalendarWidget::dateEditAcceptDelay
2842 \brief the time an inactive date edit is shown before its contents are accepted
2843 \since 4.3
2844
2845 If the calendar widget's \l{dateEditEnabled}{date edit is enabled}, this
2846 property specifies the amount of time (in millseconds) that the date edit
2847 remains open after the most recent user input. Once this time has elapsed,
2848 the date specified in the date edit is accepted and the popup is closed.
2849
2850 By default, the delay is defined to be 1500 milliseconds (1.5 seconds).
2851*/
2852int QCalendarWidget::dateEditAcceptDelay() const
2853{
2854 Q_D(const QCalendarWidget);
2855 return d->m_navigator->dateEditAcceptDelay();
2856}
2857
2858void QCalendarWidget::setDateEditAcceptDelay(int delay)
2859{
2860 Q_D(QCalendarWidget);
2861 d->m_navigator->setDateEditAcceptDelay(delay);
2862}
2863
2864/*!
2865 \since 4.4
2866
2867 Updates the cell specified by the given \a date unless updates
2868 are disabled or the cell is hidden.
2869
2870 \sa updateCells(), yearShown(), monthShown()
2871*/
2872void QCalendarWidget::updateCell(const QDate &date)
2873{
2874 if (!date.isValid()) {
2875 qWarning("QCalendarWidget::updateCell: Invalid date");
2876 return;
2877 }
2878
2879 if (!isVisible())
2880 return;
2881
2882 Q_D(QCalendarWidget);
2883 int row, column;
2884 d->m_model->cellForDate(date, &row, &column);
2885 if (row == -1 || column == -1)
2886 return;
2887
2888 QModelIndex modelIndex = d->m_model->index(row, column);
2889 if (!modelIndex.isValid())
2890 return;
2891
2892 d->m_view->viewport()->update(d->m_view->visualRect(modelIndex));
2893}
2894
2895/*!
2896 \since 4.4
2897
2898 Updates all visible cells unless updates are disabled.
2899
2900 \sa updateCell()
2901*/
2902void QCalendarWidget::updateCells()
2903{
2904 Q_D(QCalendarWidget);
2905 if (isVisible())
2906 d->m_view->viewport()->update();
2907}
2908
2909/*!
2910 \fn void QCalendarWidget::selectionChanged()
2911
2912 This signal is emitted when the currently selected date is
2913 changed.
2914
2915 The currently selected date can be changed by the user using the
2916 mouse or keyboard, or by the programmer using setSelectedDate().
2917
2918 \sa selectedDate()
2919*/
2920
2921/*!
2922 \fn void QCalendarWidget::currentPageChanged(int year, int month)
2923
2924 This signal is emitted when the currently shown month is changed.
2925 The new \a year and \a month are passed as parameters.
2926
2927 \sa setCurrentPage()
2928*/
2929
2930/*!
2931 \fn void QCalendarWidget::activated(const QDate &date)
2932
2933 This signal is emitted whenever the user presses the Return or
2934 Enter key or double-clicks a \a date in the calendar
2935 widget.
2936*/
2937
2938/*!
2939 \fn void QCalendarWidget::clicked(const QDate &date)
2940
2941 This signal is emitted when a mouse button is clicked. The date
2942 the mouse was clicked on is specified by \a date. The signal is
2943 only emitted when clicked on a valid date, e.g., dates are not
2944 outside the minimumDate() and maximumDate(). If the selection mode
2945 is NoSelection, this signal will not be emitted.
2946
2947*/
2948
2949/*!
2950 \property QCalendarWidget::headerVisible
2951 \brief whether the navigation bar is shown or not
2952
2953 \obsolete
2954
2955 Use navigationBarVisible() instead.
2956
2957 By default, this property is true.
2958*/
2959
2960/*!
2961 \obsolete
2962
2963 Use setNavigationBarVisible() instead.
2964*/
2965bool QCalendarWidget::isHeaderVisible() const
2966{
2967 Q_D(const QCalendarWidget);
2968 return d->navBarVisible;
2969}
2970
2971/*!
2972 \obsolete
2973
2974 Use setNavigationBarVisible() instead.
2975
2976*/
2977void QCalendarWidget::setHeaderVisible(bool visible)
2978{
2979 setNavigationBarVisible(visible);
2980}
2981
2982/*!
2983 \property QCalendarWidget::navigationBarVisible
2984 \brief whether the navigation bar is shown or not
2985
2986 \since 4.3
2987
2988 When this property is true (the default), the next month,
2989 previous month, month selection, year selection controls are
2990 shown on top.
2991
2992 When the property is set to false, these controls are hidden.
2993*/
2994
2995void QCalendarWidget::setNavigationBarVisible(bool visible)
2996{
2997 Q_D(QCalendarWidget);
2998 d->navBarVisible = visible;
2999 d->cachedSizeHint = QSize();
3000 d->navBarBackground->setVisible(visible);
3001 updateGeometry();
3002}
3003
3004/*!
3005 \reimp
3006*/
3007bool QCalendarWidget::event(QEvent *event)
3008{
3009 Q_D(QCalendarWidget);
3010 switch (event->type()) {
3011 case QEvent::LayoutDirectionChange:
3012 d->updateButtonIcons();
3013 case QEvent::LocaleChange:
3014 d->cachedSizeHint = QSize();
3015 d->updateMonthMenuNames();
3016 d->updateNavigationBar();
3017 d->m_view->updateGeometry();
3018 break;
3019 case QEvent::FontChange:
3020 case QEvent::ApplicationFontChange:
3021 d->cachedSizeHint = QSize();
3022 d->m_view->updateGeometry();
3023 break;
3024 case QEvent::StyleChange:
3025 d->cachedSizeHint = QSize();
3026 d->m_view->updateGeometry();
3027 default:
3028 break;
3029 }
3030 return QWidget::event(event);
3031}
3032
3033/*!
3034 \reimp
3035*/
3036bool QCalendarWidget::eventFilter(QObject *watched, QEvent *event)
3037{
3038 Q_D(QCalendarWidget);
3039 if (event->type() == QEvent::MouseButtonPress && d->yearEdit->hasFocus()) {
3040 QWidget *tlw = window();
3041 QWidget *widget = static_cast<QWidget*>(watched);
3042 //as we have a event filter on the whole application we first make sure that the top level widget
3043 //of both this and the watched widget are the same to decide if we should finish the year edition.
3044 if (widget->window() == tlw) {
3045 QPoint mousePos = widget->mapTo(tlw, static_cast<QMouseEvent *>(event)->pos());
3046 QRect geom = QRect(d->yearEdit->mapTo(tlw, QPoint(0, 0)), d->yearEdit->size());
3047 if (!geom.contains(mousePos)) {
3048 event->accept();
3049 d->_q_yearEditingFinished();
3050 setFocus();
3051 return true;
3052 }
3053 }
3054 }
3055 return QWidget::eventFilter(watched, event);
3056}
3057
3058/*!
3059 \reimp
3060*/
3061void QCalendarWidget::mousePressEvent(QMouseEvent *event)
3062{
3063 setAttribute(Qt::WA_NoMouseReplay);
3064 QWidget::mousePressEvent(event);
3065 setFocus();
3066}
3067
3068/*!
3069 \reimp
3070*/
3071void QCalendarWidget::resizeEvent(QResizeEvent * event)
3072{
3073 Q_D(QCalendarWidget);
3074
3075 // XXX Should really use a QWidgetStack for yearEdit and yearButton,
3076 // XXX here we hide the year edit when the layout is likely to break
3077 // XXX the manual positioning of the yearEdit over the yearButton.
3078 if(d->yearEdit->isVisible() && event->size().width() != event->oldSize().width())
3079 d->_q_yearEditingFinished();
3080
3081 QWidget::resizeEvent(event);
3082}
3083
3084/*!
3085 \reimp
3086*/
3087void QCalendarWidget::keyPressEvent(QKeyEvent * event)
3088{
3089 Q_D(QCalendarWidget);
3090 if(d->yearEdit->isVisible()&& event->key() == Qt::Key_Escape)
3091 {
3092 d->yearEdit->setValue(yearShown());
3093 d->_q_yearEditingFinished();
3094 return;
3095 }
3096 QWidget::keyPressEvent(event);
3097}
3098
3099QT_END_NAMESPACE
3100
3101#include "qcalendarwidget.moc"
3102#include "moc_qcalendarwidget.cpp"
3103
3104#endif //QT_NO_CALENDARWIDGET
Note: See TracBrowser for help on using the repository browser.