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

Last change on this file since 324 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 88.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
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 += QLatin1String("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 += QLatin1String("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 += QLatin1String("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 += QLatin1String("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 return QString();
339}
340
341//////////////////////////////////
342
343class QCalendarYearValidator : public QCalendarDateSectionValidator
344{
345
346public:
347 QCalendarYearValidator();
348 virtual Section handleKey(int key);
349 virtual QDate applyToDate(const QDate &date) const;
350 virtual void setDate(const QDate &date);
351 virtual QString text() const;
352 virtual QString text(const QDate &date, int repeat) const;
353private:
354 int pow10(int n);
355 int m_pos;
356 int m_year;
357 int m_oldYear;
358};
359
360QCalendarYearValidator::QCalendarYearValidator()
361 : QCalendarDateSectionValidator(), m_pos(0), m_year(2000), m_oldYear(2000)
362{
363}
364
365int QCalendarYearValidator::pow10(int n)
366{
367 int power = 1;
368 for (int i = 0; i < n; i++)
369 power *= 10;
370 return power;
371}
372
373QCalendarDateSectionValidator::Section QCalendarYearValidator::handleKey(int key)
374{
375 if (key == Qt::Key_Right || key == Qt::Key_Left) {
376 m_pos = 0;
377 return QCalendarDateSectionValidator::ThisSection;
378 } else if (key == Qt::Key_Up) {
379 m_pos = 0;
380 ++m_year;
381 return QCalendarDateSectionValidator::ThisSection;
382 } else if (key == Qt::Key_Down) {
383 m_pos = 0;
384 --m_year;
385 return QCalendarDateSectionValidator::ThisSection;
386 } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
387 --m_pos;
388 if (m_pos < 0)
389 m_pos = 3;
390
391 int pow = pow10(m_pos);
392 m_year = m_oldYear / pow * pow + m_year % (pow * 10) / 10;
393
394 if (m_pos == 0)
395 return QCalendarDateSectionValidator::PrevSection;
396 return QCalendarDateSectionValidator::ThisSection;
397 }
398 if (key < Qt::Key_0 || key > Qt::Key_9)
399 return QCalendarDateSectionValidator::ThisSection;
400 int pressedKey = key - Qt::Key_0;
401 int pow = pow10(m_pos);
402 m_year = m_year / (pow * 10) * (pow * 10) + m_year % pow * 10 + pressedKey;
403 ++m_pos;
404 if (m_pos > 3) {
405 m_pos = 0;
406 return QCalendarDateSectionValidator::NextSection;
407 }
408 return QCalendarDateSectionValidator::ThisSection;
409}
410
411QDate QCalendarYearValidator::applyToDate(const QDate &date) const
412{
413 int year = m_year;
414 if (year < 1)
415 year = 1;
416 QDate newDate(year, date.month(), 1);
417 int day = date.day();
418 if (day > newDate.daysInMonth())
419 day = newDate.daysInMonth();
420 return QDate(year, date.month(), day);
421}
422
423void QCalendarYearValidator::setDate(const QDate &date)
424{
425 m_year = m_oldYear = date.year();
426 m_pos = 0;
427}
428
429QString QCalendarYearValidator::text() const
430{
431 QString str;
432 int pow = 10;
433 for (int i = 0; i < 3; i++) {
434 if (m_year / pow == 0)
435 str += QLatin1String("0");
436 pow *= 10;
437 }
438 str += QString::number(m_year);
439 return highlightString(str, m_pos);
440}
441
442QString QCalendarYearValidator::text(const QDate &date, int repeat) const
443{
444 if (repeat < 4) {
445 QString str;
446 int year = date.year() % 100;
447 if (year / 10 == 0)
448 str = QLatin1String("0");
449 return str + QString::number(year);
450 }
451 return QString::number(date.year());
452}
453
454///////////////////////////////////
455
456class QCalendarDateValidator
457{
458public:
459 QCalendarDateValidator();
460 ~QCalendarDateValidator();
461
462 void handleKeyEvent(QKeyEvent *keyEvent);
463 QString currentText() const;
464 QDate currentDate() const { return m_currentDate; }
465 void setFormat(const QString &format);
466 void setInitialDate(const QDate &date);
467
468 void setLocale(const QLocale &locale);
469
470private:
471
472 struct SectionToken {
473 SectionToken(QCalendarDateSectionValidator *val, int rep) : validator(val), repeat(rep) {}
474 QCalendarDateSectionValidator *validator;
475 int repeat;
476 };
477
478 void toNextToken();
479 void toPreviousToken();
480 void applyToDate();
481
482 int countRepeat(const QString &str, int index) const;
483 void clear();
484
485 QStringList m_separators;
486 QList<SectionToken *> m_tokens;
487 QCalendarDateSectionValidator *m_yearValidator;
488 QCalendarDateSectionValidator *m_monthValidator;
489 QCalendarDateSectionValidator *m_dayValidator;
490
491 SectionToken *m_currentToken;
492
493 QDate m_initialDate;
494 QDate m_currentDate;
495
496 QCalendarDateSectionValidator::Section m_lastSectionMove;
497};
498
499QCalendarDateValidator::QCalendarDateValidator()
500 : m_currentToken(0), m_lastSectionMove(QCalendarDateSectionValidator::ThisSection)
501{
502 m_initialDate = m_currentDate = QDate::currentDate();
503 m_yearValidator = new QCalendarYearValidator();
504 m_monthValidator = new QCalendarMonthValidator();
505 m_dayValidator = new QCalendarDayValidator();
506}
507
508void QCalendarDateValidator::setLocale(const QLocale &locale)
509{
510 m_yearValidator->m_locale = locale;
511 m_monthValidator->m_locale = locale;
512 m_dayValidator->m_locale = locale;
513}
514
515QCalendarDateValidator::~QCalendarDateValidator()
516{
517 delete m_yearValidator;
518 delete m_monthValidator;
519 delete m_dayValidator;
520 clear();
521}
522
523// from qdatetime.cpp
524int QCalendarDateValidator::countRepeat(const QString &str, int index) const
525{
526 Q_ASSERT(index >= 0 && index < str.size());
527 int count = 1;
528 const QChar ch = str.at(index);
529 while (index + count < str.size() && str.at(index + count) == ch)
530 ++count;
531 return count;
532}
533
534void QCalendarDateValidator::setInitialDate(const QDate &date)
535{
536 m_yearValidator->setDate(date);
537 m_monthValidator->setDate(date);
538 m_dayValidator->setDate(date);
539 m_initialDate = date;
540 m_currentDate = date;
541 m_lastSectionMove = QCalendarDateSectionValidator::ThisSection;
542}
543
544QString QCalendarDateValidator::currentText() const
545{
546 QString str;
547 QStringListIterator itSep(m_separators);
548 QListIterator<SectionToken *> itTok(m_tokens);
549 while (itSep.hasNext()) {
550 str += itSep.next();
551 if (itTok.hasNext()) {
552 SectionToken *token = itTok.next();
553 QCalendarDateSectionValidator *validator = token->validator;
554 if (m_currentToken == token)
555 str += validator->text();
556 else
557 str += validator->text(m_currentDate, token->repeat);
558 }
559 }
560 return str;
561}
562
563void QCalendarDateValidator::clear()
564{
565 QListIterator<SectionToken *> it(m_tokens);
566 while (it.hasNext())
567 delete it.next();
568
569 m_tokens.clear();
570 m_separators.clear();
571
572 m_currentToken = 0;
573}
574
575void QCalendarDateValidator::setFormat(const QString &format)
576{
577 clear();
578
579 int pos = 0;
580 const QLatin1String quote("'");
581 bool quoting = false;
582 QString separator;
583 while (pos < format.size()) {
584 QString mid = format.mid(pos);
585 int offset = 1;
586
587 if (mid.startsWith(quote)) {
588 quoting = !quoting;
589 } else {
590 const QChar nextChar = format.at(pos);
591 if (quoting) {
592 separator += nextChar;
593 } else {
594 SectionToken *token = 0;
595 if (nextChar == QLatin1Char('d')) {
596 offset = qMin(4, countRepeat(format, pos));
597 token = new SectionToken(m_dayValidator, offset);
598 } else if (nextChar == QLatin1Char('M')) {
599 offset = qMin(4, countRepeat(format, pos));
600 token = new SectionToken(m_monthValidator, offset);
601 } else if (nextChar == QLatin1Char('y')) {
602 offset = qMin(4, countRepeat(format, pos));
603 token = new SectionToken(m_yearValidator, offset);
604 } else {
605 separator += nextChar;
606 }
607 if (token) {
608 m_tokens.append(token);
609 m_separators.append(separator);
610 separator = QString();
611 if (!m_currentToken)
612 m_currentToken = token;
613
614 }
615 }
616 }
617 pos += offset;
618 }
619 m_separators += separator;
620}
621
622void QCalendarDateValidator::applyToDate()
623{
624 m_currentDate = m_yearValidator->applyToDate(m_currentDate);
625 m_currentDate = m_monthValidator->applyToDate(m_currentDate);
626 m_currentDate = m_dayValidator->applyToDate(m_currentDate);
627}
628
629void QCalendarDateValidator::toNextToken()
630{
631 const int idx = m_tokens.indexOf(m_currentToken);
632 if (idx == -1)
633 return;
634 if (idx + 1 >= m_tokens.count())
635 m_currentToken = m_tokens.first();
636 else
637 m_currentToken = m_tokens.at(idx + 1);
638}
639
640void QCalendarDateValidator::toPreviousToken()
641{
642 const int idx = m_tokens.indexOf(m_currentToken);
643 if (idx == -1)
644 return;
645 if (idx - 1 < 0)
646 m_currentToken = m_tokens.last();
647 else
648 m_currentToken = m_tokens.at(idx - 1);
649}
650
651void QCalendarDateValidator::handleKeyEvent(QKeyEvent *keyEvent)
652{
653 if (!m_currentToken)
654 return;
655
656 int key = keyEvent->key();
657 if (m_lastSectionMove == QCalendarDateSectionValidator::NextSection) {
658 if (key == Qt::Key_Back || key == Qt::Key_Backspace)
659 toPreviousToken();
660 }
661 if (key == Qt::Key_Right)
662 toNextToken();
663 else if (key == Qt::Key_Left)
664 toPreviousToken();
665
666 m_lastSectionMove = m_currentToken->validator->handleKey(key);
667
668 applyToDate();
669 if (m_lastSectionMove == QCalendarDateSectionValidator::NextSection)
670 toNextToken();
671 else if (m_lastSectionMove == QCalendarDateSectionValidator::PrevSection)
672 toPreviousToken();
673}
674
675QWidget *QCalendarTextNavigator::widget() const
676{
677 return m_widget;
678}
679
680void QCalendarTextNavigator::setWidget(QWidget *widget)
681{
682 m_widget = widget;
683}
684
685QDate QCalendarTextNavigator::date() const
686{
687 return m_date;
688}
689
690void QCalendarTextNavigator::setDate(const QDate &date)
691{
692 m_date = date;
693}
694
695void QCalendarTextNavigator::updateDateLabel()
696{
697 if (!m_widget)
698 return;
699
700 m_acceptTimer.start(m_editDelay, this);
701
702 m_dateText->setText(m_dateValidator->currentText());
703
704 QSize s = m_dateFrame->sizeHint();
705 QRect r = m_widget->geometry(); // later, just the table section
706 QRect newRect((r.width() - s.width()) / 2, (r.height() - s.height()) / 2, s.width(), s.height());
707 m_dateFrame->setGeometry(newRect);
708 // need to set palette after geometry update as phonestyle sets transparency
709 // effect in move event.
710 QPalette p = m_dateFrame->palette();
711 p.setBrush(QPalette::Window, m_dateFrame->window()->palette().brush(QPalette::Window));
712 m_dateFrame->setPalette(p);
713
714 m_dateFrame->raise();
715 m_dateFrame->show();
716}
717
718void QCalendarTextNavigator::applyDate()
719{
720 QDate date = m_dateValidator->currentDate();
721 if (m_date == date)
722 return;
723
724 m_date = date;
725 emit dateChanged(date);
726}
727
728void QCalendarTextNavigator::createDateLabel()
729{
730 if (m_dateFrame)
731 return;
732 m_dateFrame = new QFrame(m_widget);
733 QVBoxLayout *vl = new QVBoxLayout;
734 m_dateText = new QLabel;
735 vl->addWidget(m_dateText);
736 m_dateFrame->setLayout(vl);
737 m_dateFrame->setFrameShadow(QFrame::Plain);
738 m_dateFrame->setFrameShape(QFrame::Box);
739 m_dateValidator = new QCalendarDateValidator();
740 m_dateValidator->setLocale(m_widget->locale());
741 m_dateValidator->setFormat(m_widget->locale().dateFormat(QLocale::ShortFormat));
742 m_dateValidator->setInitialDate(m_date);
743
744 m_dateFrame->setAutoFillBackground(true);
745 m_dateFrame->setBackgroundRole(QPalette::Window);
746}
747
748void QCalendarTextNavigator::removeDateLabel()
749{
750 if (!m_dateFrame)
751 return;
752 m_acceptTimer.stop();
753 m_dateFrame->hide();
754 m_dateFrame->deleteLater();
755 delete m_dateValidator;
756 m_dateFrame = 0;
757 m_dateText = 0;
758 m_dateValidator = 0;
759}
760
761bool QCalendarTextNavigator::eventFilter(QObject *o, QEvent *e)
762{
763 if (m_widget) {
764 if (e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease) {
765 QKeyEvent* ke = (QKeyEvent*)e;
766 if ((ke->text().length() > 0 && ke->text()[0].isPrint()) || m_dateFrame) {
767 if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Select) {
768 applyDate();
769 emit editingFinished();
770 removeDateLabel();
771 } else if (ke->key() == Qt::Key_Escape) {
772 removeDateLabel();
773 } else if (e->type() == QEvent::KeyPress) {
774 createDateLabel();
775 m_dateValidator->handleKeyEvent(ke);
776 updateDateLabel();
777 }
778 ke->accept();
779 return true;
780 }
781 // If we are navigating let the user finish his date in old locate.
782 // If we change our mind and want it to update immediately simply uncomment below
783 /*
784 } else if (e->type() == QEvent::LocaleChange) {
785 if (m_dateValidator) {
786 m_dateValidator->setLocale(m_widget->locale());
787 m_dateValidator->setFormat(m_widget->locale().dateFormat(QLocale::ShortFormat));
788 updateDateLabel();
789 }
790 */
791 }
792 }
793 return QObject::eventFilter(o,e);
794}
795
796void QCalendarTextNavigator::timerEvent(QTimerEvent *e)
797{
798 if (e->timerId() == m_acceptTimer.timerId()) {
799 applyDate();
800 removeDateLabel();
801 }
802}
803
804int QCalendarTextNavigator::dateEditAcceptDelay() const
805{
806 return m_editDelay;
807}
808
809void QCalendarTextNavigator::setDateEditAcceptDelay(int delay)
810{
811 m_editDelay = delay;
812}
813
814class QCalendarView;
815
816class QCalendarModel : public QAbstractTableModel
817{
818 Q_OBJECT
819public:
820 QCalendarModel(QObject *parent = 0);
821
822 int rowCount(const QModelIndex &) const
823 { return RowCount + m_firstRow; }
824 int columnCount(const QModelIndex &) const
825 { return ColumnCount + m_firstColumn; }
826 QVariant data(const QModelIndex &index, int role) const;
827 Qt::ItemFlags flags(const QModelIndex &index) const;
828
829 bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())
830 {
831 beginInsertRows(parent, row, row + count - 1);
832 endInsertRows();
833 return true;
834 }
835 bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex())
836 {
837 beginInsertColumns(parent, column, column + count - 1);
838 endInsertColumns();
839 return true;
840 }
841 bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex())
842 {
843 beginRemoveRows(parent, row, row + count - 1);
844 endRemoveRows();
845 return true;
846 }
847 bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex())
848 {
849 beginRemoveColumns(parent, column, column + count - 1);
850 endRemoveColumns();
851 return true;
852 }
853
854 void showMonth(int year, int month);
855 void setDate(const QDate &d);
856
857 void setMinimumDate(const QDate &date);
858 void setMaximumDate(const QDate &date);
859
860 void setRange(const QDate &min, const QDate &max);
861
862 void setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format);
863
864 void setFirstColumnDay(Qt::DayOfWeek dayOfWeek);
865 Qt::DayOfWeek firstColumnDay() const;
866
867 bool weekNumbersShown() const;
868 void setWeekNumbersShown(bool show);
869
870 QTextCharFormat formatForCell(int row, int col) const;
871 Qt::DayOfWeek dayOfWeekForColumn(int section) const;
872 int columnForDayOfWeek(Qt::DayOfWeek day) const;
873 QDate dateForCell(int row, int column) const;
874 void cellForDate(const QDate &date, int *row, int *column) const;
875 QString dayName(Qt::DayOfWeek day) const;
876
877 void setView(QCalendarView *view)
878 { m_view = view; }
879
880 void internalUpdate();
881 QDate referenceDate() const;
882 int columnForFirstOfMonth(const QDate &date) const;
883
884 int m_firstColumn;
885 int m_firstRow;
886 QDate m_date;
887 QDate m_minimumDate;
888 QDate m_maximumDate;
889 int m_shownYear;
890 int m_shownMonth;
891 Qt::DayOfWeek m_firstDay;
892 QCalendarWidget::HorizontalHeaderFormat m_horizontalHeaderFormat;
893 bool m_weekNumbersShown;
894 QMap<Qt::DayOfWeek, QTextCharFormat> m_dayFormats;
895 QMap<QDate, QTextCharFormat> m_dateFormats;
896 QTextCharFormat m_headerFormat;
897 QCalendarView *m_view;
898};
899
900class QCalendarView : public QTableView
901{
902 Q_OBJECT
903public:
904 QCalendarView(QWidget *parent = 0);
905
906 void internalUpdate() { updateGeometries(); }
907 void setReadOnly(bool enable);
908 virtual void keyboardSearch(const QString & search) { Q_UNUSED(search) }
909
910signals:
911 void showDate(const QDate &date);
912 void changeDate(const QDate &date, bool changeMonth);
913 void clicked(const QDate &date);
914 void editingFinished();
915protected:
916 QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers);
917 void mouseDoubleClickEvent(QMouseEvent *event);
918 void mousePressEvent(QMouseEvent *event);
919 void mouseMoveEvent(QMouseEvent *event);
920 void mouseReleaseEvent(QMouseEvent *event);
921#ifndef QT_NO_WHEELEVENT
922 void wheelEvent(QWheelEvent *event);
923#endif
924 void keyPressEvent(QKeyEvent *event);
925 bool event(QEvent *event);
926
927 QDate handleMouseEvent(QMouseEvent *event);
928public:
929 bool readOnly;
930private:
931 bool validDateClicked;
932#ifdef QT_KEYPAD_NAVIGATION
933 QDate origDate;
934#endif
935};
936
937QCalendarModel::QCalendarModel(QObject *parent)
938 : QAbstractTableModel(parent)
939{
940 m_date = QDate::currentDate();
941 m_minimumDate = QDate::fromJulianDay(1);
942 m_maximumDate = QDate(7999, 12, 31);
943 m_shownYear = m_date.year();
944 m_shownMonth = m_date.month();
945 m_firstDay = Qt::Sunday;
946 m_horizontalHeaderFormat = QCalendarWidget::ShortDayNames;
947 m_weekNumbersShown = true;
948 m_firstColumn = 1;
949 m_firstRow = 1;
950 m_view = 0;
951}
952
953Qt::DayOfWeek QCalendarModel::dayOfWeekForColumn(int column) const
954{
955 int col = column - m_firstColumn;
956 if (col < 0 || col > 6)
957 return Qt::Sunday;
958 int day = m_firstDay + col;
959 if (day > 7)
960 day -= 7;
961 return Qt::DayOfWeek(day);
962}
963
964int QCalendarModel::columnForDayOfWeek(Qt::DayOfWeek day) const
965{
966 if (day < 1 || day > 7)
967 return -1;
968 int column = (int)day - (int)m_firstDay;
969 if (column < 0)
970 column += 7;
971 return column + m_firstColumn;
972}
973
974/*
975This simple algorithm tries to generate a valid date from the month shown.
976Some months don't contain a first day (e.g. Jan of -4713 year,
977so QDate (-4713, 1, 1) would be invalid). In that case we try to generate
978another valid date for that month. Later, returned date's day is the number of cells
979calendar widget will reserve for days before referenceDate. (E.g. if returned date's
980day is 16, that day will be placed in 3rd or 4th row, not in the 1st or 2nd row).
981Depending on referenceData we can change behaviour of Oct 1582. If referenceDate is 1st
982of Oct we render 1 Oct in 1st or 2nd row. If referenceDate is 17 of Oct we show always 16
983dates before 17 of Oct, and since this month contains the hole 5-14 Oct, the first of Oct
984will be rendered in 2nd or 3rd row, showing more dates from previous month.
985*/
986QDate QCalendarModel::referenceDate() const
987{
988 int refDay = 1;
989 while (refDay <= 31) {
990 QDate refDate(m_shownYear, m_shownMonth, refDay);
991 if (refDate.isValid())
992 return refDate;
993 refDay += 1;
994 }
995 return QDate();
996}
997
998int QCalendarModel::columnForFirstOfMonth(const QDate &date) const
999{
1000 return (columnForDayOfWeek(static_cast<Qt::DayOfWeek>(date.dayOfWeek())) - (date.day() % 7) + 8) % 7;
1001}
1002
1003QDate QCalendarModel::dateForCell(int row, int column) const
1004{
1005 if (row < m_firstRow || row > m_firstRow + RowCount - 1 ||
1006 column < m_firstColumn || column > m_firstColumn + ColumnCount - 1)
1007 return QDate();
1008 const QDate refDate = referenceDate();
1009 if (!refDate.isValid())
1010 return QDate();
1011
1012 const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
1013 if (columnForFirstOfShownMonth - m_firstColumn < MinimumDayOffset)
1014 row -= 1;
1015
1016 const int requestedDay = 7 * (row - m_firstRow) + column - columnForFirstOfShownMonth - refDate.day() + 1;
1017 return refDate.addDays(requestedDay);
1018}
1019
1020void QCalendarModel::cellForDate(const QDate &date, int *row, int *column) const
1021{
1022 if (!row && !column)
1023 return;
1024
1025 if (row)
1026 *row = -1;
1027 if (column)
1028 *column = -1;
1029
1030 const QDate refDate = referenceDate();
1031 if (!refDate.isValid())
1032 return;
1033
1034 const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
1035 const int requestedPosition = refDate.daysTo(date) - m_firstColumn + columnForFirstOfShownMonth + refDate.day() - 1;
1036
1037 int c = requestedPosition % 7;
1038 int r = requestedPosition / 7;
1039 if (c < 0) {
1040 c += 7;
1041 r -= 1;
1042 }
1043
1044 if (columnForFirstOfShownMonth - m_firstColumn < MinimumDayOffset)
1045 r += 1;
1046
1047 if (r < 0 || r > RowCount - 1 || c < 0 || c > ColumnCount - 1)
1048 return;
1049
1050 if (row)
1051 *row = r + m_firstRow;
1052 if (column)
1053 *column = c + m_firstColumn;
1054}
1055
1056QString QCalendarModel::dayName(Qt::DayOfWeek day) const
1057{
1058 switch (m_horizontalHeaderFormat) {
1059 case QCalendarWidget::SingleLetterDayNames: {
1060 QString standaloneDayName = m_view->locale().standaloneDayName(day, QLocale::NarrowFormat);
1061 if (standaloneDayName == m_view->locale().dayName(day, QLocale::NarrowFormat))
1062 return standaloneDayName.left(1);
1063 return standaloneDayName;
1064 }
1065 case QCalendarWidget::ShortDayNames:
1066 return m_view->locale().dayName(day, QLocale::ShortFormat);
1067 case QCalendarWidget::LongDayNames:
1068 return m_view->locale().dayName(day, QLocale::LongFormat);
1069 default:
1070 break;
1071 }
1072 return QString();
1073}
1074
1075QTextCharFormat QCalendarModel::formatForCell(int row, int col) const
1076{
1077 QPalette pal;
1078 QPalette::ColorGroup cg = QPalette::Active;
1079 if (m_view) {
1080 pal = m_view->palette();
1081 if (!m_view->isEnabled())
1082 cg = QPalette::Disabled;
1083 else if (!m_view->isActiveWindow())
1084 cg = QPalette::Inactive;
1085 }
1086
1087 QTextCharFormat format;
1088 format.setFont(m_view->font());
1089 bool header = (m_weekNumbersShown && col == HeaderColumn)
1090 || (m_horizontalHeaderFormat != QCalendarWidget::NoHorizontalHeader && row == HeaderRow);
1091 format.setBackground(pal.brush(cg, header ? QPalette::AlternateBase : QPalette::Base));
1092 format.setForeground(pal.brush(cg, QPalette::Text));
1093 if (header) {
1094 format.merge(m_headerFormat);
1095 }
1096
1097 if (col >= m_firstColumn && col < m_firstColumn + ColumnCount) {
1098 Qt::DayOfWeek dayOfWeek = dayOfWeekForColumn(col);
1099 if (m_dayFormats.contains(dayOfWeek))
1100 format.merge(m_dayFormats.value(dayOfWeek));
1101 }
1102
1103 if (!header) {
1104 QDate date = dateForCell(row, col);
1105 format.merge(m_dateFormats.value(date));
1106 if(date < m_minimumDate || date > m_maximumDate)
1107 format.setBackground(pal.brush(cg, QPalette::Window));
1108 if (m_shownMonth != date.month())
1109 format.setForeground(pal.brush(QPalette::Disabled, QPalette::Text));
1110 }
1111 return format;
1112}
1113
1114QVariant QCalendarModel::data(const QModelIndex &index, int role) const
1115{
1116 if (role == Qt::TextAlignmentRole)
1117 return (int) Qt::AlignCenter;
1118
1119 int row = index.row();
1120 int column = index.column();
1121
1122 if(role == Qt::DisplayRole) {
1123 if (m_weekNumbersShown && column == HeaderColumn
1124 && row >= m_firstRow && row < m_firstRow + RowCount) {
1125 QDate date = dateForCell(row, columnForDayOfWeek(Qt::Monday));
1126 if (date.isValid())
1127 return date.weekNumber();
1128 }
1129 if (m_horizontalHeaderFormat != QCalendarWidget::NoHorizontalHeader && row == HeaderRow
1130 && column >= m_firstColumn && column < m_firstColumn + ColumnCount)
1131 return dayName(dayOfWeekForColumn(column));
1132 QDate date = dateForCell(row, column);
1133 if (date.isValid())
1134 return date.day();
1135 return QString();
1136 }
1137
1138 QTextCharFormat fmt = formatForCell(row, column);
1139 if (role == Qt::BackgroundColorRole)
1140 return fmt.background().color();
1141 if (role == Qt::TextColorRole)
1142 return fmt.foreground().color();
1143 if (role == Qt::FontRole)
1144 return fmt.font();
1145 if (role == Qt::ToolTipRole)
1146 return fmt.toolTip();
1147 return QVariant();
1148}
1149
1150Qt::ItemFlags QCalendarModel::flags(const QModelIndex &index) const
1151{
1152 QDate date = dateForCell(index.row(), index.column());
1153 if (!date.isValid())
1154 return QAbstractTableModel::flags(index);
1155 if (date < m_minimumDate)
1156 return 0;
1157 if (date > m_maximumDate)
1158 return 0;
1159 return QAbstractTableModel::flags(index);
1160}
1161
1162void QCalendarModel::setDate(const QDate &d)
1163{
1164 m_date = d;
1165 if (m_date < m_minimumDate)
1166 m_date = m_minimumDate;
1167 else if (m_date > m_maximumDate)
1168 m_date = m_maximumDate;
1169}
1170
1171void QCalendarModel::showMonth(int year, int month)
1172{
1173 if (m_shownYear == year && m_shownMonth == month)
1174 return;
1175
1176 m_shownYear = year;
1177 m_shownMonth = month;
1178
1179 internalUpdate();
1180}
1181
1182void QCalendarModel::setMinimumDate(const QDate &d)
1183{
1184 if (!d.isValid() || d == m_minimumDate)
1185 return;
1186
1187 m_minimumDate = d;
1188 if (m_maximumDate < m_minimumDate)
1189 m_maximumDate = m_minimumDate;
1190 if (m_date < m_minimumDate)
1191 m_date = m_minimumDate;
1192 internalUpdate();
1193}
1194
1195void QCalendarModel::setMaximumDate(const QDate &d)
1196{
1197 if (!d.isValid() || d == m_maximumDate)
1198 return;
1199
1200 m_maximumDate = d;
1201 if (m_minimumDate > m_maximumDate)
1202 m_minimumDate = m_maximumDate;
1203 if (m_date > m_maximumDate)
1204 m_date = m_maximumDate;
1205 internalUpdate();
1206}
1207
1208void QCalendarModel::setRange(const QDate &min, const QDate &max)
1209{
1210 m_minimumDate = min;
1211 m_maximumDate = max;
1212 if (m_minimumDate > m_maximumDate)
1213 qSwap(m_minimumDate, m_maximumDate);
1214 if (m_date < m_minimumDate)
1215 m_date = m_minimumDate;
1216 if (m_date > m_maximumDate)
1217 m_date = m_maximumDate;
1218 internalUpdate();
1219}
1220
1221void QCalendarModel::internalUpdate()
1222{
1223 QModelIndex begin = index(0, 0);
1224 QModelIndex end = index(m_firstRow + RowCount - 1, m_firstColumn + ColumnCount - 1);
1225 emit dataChanged(begin, end);
1226 emit headerDataChanged(Qt::Vertical, 0, m_firstRow + RowCount - 1);
1227 emit headerDataChanged(Qt::Horizontal, 0, m_firstColumn + ColumnCount - 1);
1228}
1229
1230void QCalendarModel::setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format)
1231{
1232 if (m_horizontalHeaderFormat == format)
1233 return;
1234
1235 int oldFormat = m_horizontalHeaderFormat;
1236 m_horizontalHeaderFormat = format;
1237 if (oldFormat == QCalendarWidget::NoHorizontalHeader) {
1238 m_firstRow = 1;
1239 insertRow(0);
1240 } else if (m_horizontalHeaderFormat == QCalendarWidget::NoHorizontalHeader) {
1241 m_firstRow = 0;
1242 removeRow(0);
1243 }
1244 internalUpdate();
1245}
1246
1247void QCalendarModel::setFirstColumnDay(Qt::DayOfWeek dayOfWeek)
1248{
1249 if (m_firstDay == dayOfWeek)
1250 return;
1251
1252 m_firstDay = dayOfWeek;
1253 internalUpdate();
1254}
1255
1256Qt::DayOfWeek QCalendarModel::firstColumnDay() const
1257{
1258 return m_firstDay;
1259}
1260
1261bool QCalendarModel::weekNumbersShown() const
1262{
1263 return m_weekNumbersShown;
1264}
1265
1266void QCalendarModel::setWeekNumbersShown(bool show)
1267{
1268 if (m_weekNumbersShown == show)
1269 return;
1270
1271 m_weekNumbersShown = show;
1272 if (show) {
1273 m_firstColumn = 1;
1274 insertColumn(0);
1275 } else {
1276 m_firstColumn = 0;
1277 removeColumn(0);
1278 }
1279 internalUpdate();
1280}
1281
1282QCalendarView::QCalendarView(QWidget *parent)
1283 : QTableView(parent),
1284 readOnly(false),
1285 validDateClicked(false)
1286{
1287 setTabKeyNavigation(false);
1288 setShowGrid(false);
1289 verticalHeader()->setVisible(false);
1290 horizontalHeader()->setVisible(false);
1291 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1292 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1293}
1294
1295QModelIndex QCalendarView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
1296{
1297 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1298 if (!calendarModel)
1299 return QTableView::moveCursor(cursorAction, modifiers);
1300
1301 if (readOnly)
1302 return currentIndex();
1303
1304 QModelIndex index = currentIndex();
1305 QDate currentDate = static_cast<QCalendarModel*>(model())->dateForCell(index.row(), index.column());
1306 switch (cursorAction) {
1307 case QAbstractItemView::MoveUp:
1308 currentDate = currentDate.addDays(-7);
1309 break;
1310 case QAbstractItemView::MoveDown:
1311 currentDate = currentDate.addDays(7);
1312 break;
1313 case QAbstractItemView::MoveLeft:
1314 currentDate = currentDate.addDays(isRightToLeft() ? 1 : -1);
1315 break;
1316 case QAbstractItemView::MoveRight:
1317 currentDate = currentDate.addDays(isRightToLeft() ? -1 : 1);
1318 break;
1319 case QAbstractItemView::MoveHome:
1320 currentDate = QDate(currentDate.year(), currentDate.month(), 1);
1321 break;
1322 case QAbstractItemView::MoveEnd:
1323 currentDate = QDate(currentDate.year(), currentDate.month(), currentDate.daysInMonth());
1324 break;
1325 case QAbstractItemView::MovePageUp:
1326 currentDate = currentDate.addMonths(-1);
1327 break;
1328 case QAbstractItemView::MovePageDown:
1329 currentDate = currentDate.addMonths(1);
1330 break;
1331 case QAbstractItemView::MoveNext:
1332 case QAbstractItemView::MovePrevious:
1333 return currentIndex();
1334 default:
1335 break;
1336 }
1337 emit changeDate(currentDate, true);
1338 return currentIndex();
1339}
1340
1341void QCalendarView::keyPressEvent(QKeyEvent *event)
1342{
1343#ifdef QT_KEYPAD_NAVIGATION
1344 if (event->key() == Qt::Key_Select) {
1345 if (QApplication::keypadNavigationEnabled()) {
1346 if (!hasEditFocus()) {
1347 setEditFocus(true);
1348 return;
1349 }
1350 }
1351 } else if (event->key() == Qt::Key_Back) {
1352 if (QApplication::keypadNavigationEnabled() && hasEditFocus()) {
1353 if (qobject_cast<QCalendarModel *>(model())) {
1354 emit changeDate(origDate, true); //changes selection back to origDate, but doesn't activate
1355 setEditFocus(false);
1356 return;
1357 }
1358 }
1359 }
1360#endif
1361
1362 if (!readOnly) {
1363 switch (event->key()) {
1364 case Qt::Key_Return:
1365 case Qt::Key_Enter:
1366 case Qt::Key_Select:
1367 emit editingFinished();
1368 return;
1369 default:
1370 break;
1371 }
1372 }
1373 QTableView::keyPressEvent(event);
1374}
1375
1376#ifndef QT_NO_WHEELEVENT
1377void QCalendarView::wheelEvent(QWheelEvent *event)
1378{
1379 const int numDegrees = event->delta() / 8;
1380 const int numSteps = numDegrees / 15;
1381 const QModelIndex index = currentIndex();
1382 QDate currentDate = static_cast<QCalendarModel*>(model())->dateForCell(index.row(), index.column());
1383 currentDate = currentDate.addMonths(-numSteps);
1384 emit showDate(currentDate);
1385}
1386#endif
1387
1388bool QCalendarView::event(QEvent *event)
1389{
1390#ifdef QT_KEYPAD_NAVIGATION
1391 if (event->type() == QEvent::FocusIn) {
1392 if (QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model())) {
1393 origDate = calendarModel->m_date;
1394 }
1395 }
1396#endif
1397
1398 return QTableView::event(event);
1399}
1400
1401QDate QCalendarView::handleMouseEvent(QMouseEvent *event)
1402{
1403 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1404 if (!calendarModel)
1405 return QDate();
1406
1407 QPoint pos = event->pos();
1408 QModelIndex index = indexAt(pos);
1409 QDate date = calendarModel->dateForCell(index.row(), index.column());
1410 if (date.isValid() && date >= calendarModel->m_minimumDate
1411 && date <= calendarModel->m_maximumDate) {
1412 return date;
1413 }
1414 return QDate();
1415}
1416
1417void QCalendarView::mouseDoubleClickEvent(QMouseEvent *event)
1418{
1419 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1420 if (!calendarModel) {
1421 QTableView::mouseDoubleClickEvent(event);
1422 return;
1423 }
1424
1425 if (readOnly)
1426 return;
1427
1428 QDate date = handleMouseEvent(event);
1429 validDateClicked = false;
1430 if (date == calendarModel->m_date && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)) {
1431 emit editingFinished();
1432 }
1433}
1434
1435void QCalendarView::mousePressEvent(QMouseEvent *event)
1436{
1437 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1438 if (!calendarModel) {
1439 QTableView::mousePressEvent(event);
1440 return;
1441 }
1442
1443 if (readOnly)
1444 return;
1445
1446 if (event->button() != Qt::LeftButton)
1447 return;
1448
1449 QDate date = handleMouseEvent(event);
1450 if (date.isValid()) {
1451 validDateClicked = true;
1452 int row = -1, col = -1;
1453 static_cast<QCalendarModel *>(model())->cellForDate(date, &row, &col);
1454 if (row != -1 && col != -1) {
1455 selectionModel()->setCurrentIndex(model()->index(row, col), QItemSelectionModel::NoUpdate);
1456 }
1457 } else {
1458 validDateClicked = false;
1459 event->ignore();
1460 }
1461}
1462
1463void QCalendarView::mouseMoveEvent(QMouseEvent *event)
1464{
1465 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1466 if (!calendarModel) {
1467 QTableView::mouseMoveEvent(event);
1468 return;
1469 }
1470
1471 if (readOnly)
1472 return;
1473
1474 if (validDateClicked) {
1475 QDate date = handleMouseEvent(event);
1476 if (date.isValid()) {
1477 int row = -1, col = -1;
1478 static_cast<QCalendarModel *>(model())->cellForDate(date, &row, &col);
1479 if (row != -1 && col != -1) {
1480 selectionModel()->setCurrentIndex(model()->index(row, col), QItemSelectionModel::NoUpdate);
1481 }
1482 }
1483 } else {
1484 event->ignore();
1485 }
1486}
1487
1488void QCalendarView::mouseReleaseEvent(QMouseEvent *event)
1489{
1490 QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
1491 if (!calendarModel) {
1492 QTableView::mouseReleaseEvent(event);
1493 return;
1494 }
1495
1496 if (event->button() != Qt::LeftButton)
1497 return;
1498
1499 if (readOnly)
1500 return;
1501
1502 if (validDateClicked) {
1503 QDate date = handleMouseEvent(event);
1504 if (date.isValid()) {
1505 emit changeDate(date, true);
1506 emit clicked(date);
1507 if (style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick))
1508 emit editingFinished();
1509 }
1510 validDateClicked = false;
1511 } else {
1512 event->ignore();
1513 }
1514}
1515
1516class QCalendarDelegate : public QItemDelegate
1517{
1518 Q_OBJECT
1519public:
1520 QCalendarDelegate(QCalendarWidgetPrivate *w, QObject *parent = 0)
1521 : QItemDelegate(parent), calendarWidgetPrivate(w)
1522 { }
1523 virtual void paint(QPainter *painter, const QStyleOptionViewItem &option,
1524 const QModelIndex &index) const;
1525 void paintCell(QPainter *painter, const QRect &rect, const QDate &date) const;
1526
1527private:
1528 QCalendarWidgetPrivate *calendarWidgetPrivate;
1529 mutable QStyleOptionViewItemV4 storedOption;
1530};
1531
1532//Private tool button class
1533class QCalToolButton: public QToolButton
1534{
1535public:
1536 QCalToolButton(QWidget * parent)
1537 : QToolButton(parent)
1538 { }
1539protected:
1540 void paintEvent(QPaintEvent *e)
1541 {
1542 Q_UNUSED(e)
1543
1544#ifndef Q_WS_MAC
1545 QStyleOptionToolButton opt;
1546 initStyleOption(&opt);
1547
1548 if (opt.state & QStyle::State_MouseOver || isDown()) {
1549 //act as normal button
1550 setPalette(QPalette());
1551 } else {
1552 //set the highlight color for button text
1553 QPalette toolPalette = palette();
1554 toolPalette.setColor(QPalette::ButtonText, toolPalette.color(QPalette::HighlightedText));
1555 setPalette(toolPalette);
1556 }
1557#endif
1558 QToolButton::paintEvent(e);
1559 }
1560};
1561
1562class QPrevNextCalButton : public QToolButton
1563{
1564 Q_OBJECT
1565public:
1566 QPrevNextCalButton(QWidget *parent) : QToolButton(parent) {}
1567protected:
1568 void paintEvent(QPaintEvent *) {
1569 QStylePainter painter(this);
1570 QStyleOptionToolButton opt;
1571 initStyleOption(&opt);
1572 opt.state &= ~QStyle::State_HasFocus;
1573 painter.drawComplexControl(QStyle::CC_ToolButton, opt);
1574 }
1575};
1576
1577class QCalendarWidgetPrivate : public QWidgetPrivate
1578{
1579 Q_DECLARE_PUBLIC(QCalendarWidget)
1580public:
1581 QCalendarWidgetPrivate();
1582
1583 void showMonth(int year, int month);
1584 void update();
1585 void paintCell(QPainter *painter, const QRect &rect, const QDate &date) const;
1586
1587 void _q_slotShowDate(const QDate &date);
1588 void _q_slotChangeDate(const QDate &date);
1589 void _q_slotChangeDate(const QDate &date, bool changeMonth);
1590 void _q_editingFinished();
1591 void _q_monthChanged(QAction*);
1592 void _q_prevMonthClicked();
1593 void _q_nextMonthClicked();
1594 void _q_yearEditingFinished();
1595 void _q_yearClicked();
1596
1597 void createNavigationBar(QWidget *widget);
1598 void updateButtonIcons();
1599 void updateMonthMenu();
1600 void updateMonthMenuNames();
1601 void updateNavigationBar();
1602 void updateCurrentPage(const QDate &newDate);
1603 inline QDate getCurrentDate();
1604 void setNavigatorEnabled(bool enable);
1605
1606 QCalendarModel *m_model;
1607 QCalendarView *m_view;
1608 QCalendarDelegate *m_delegate;
1609 QItemSelectionModel *m_selection;
1610 QCalendarTextNavigator *m_navigator;
1611 bool m_dateEditEnabled;
1612
1613 QToolButton *nextMonth;
1614 QToolButton *prevMonth;
1615 QCalToolButton *monthButton;
1616 QMenu *monthMenu;
1617 QMap<int, QAction *> monthToAction;
1618 QCalToolButton *yearButton;
1619 QSpinBox *yearEdit;
1620 QWidget *navBarBackground;
1621 QSpacerItem *spaceHolder;
1622
1623 bool navBarVisible;
1624 mutable QSize cachedSizeHint;
1625 Qt::FocusPolicy oldFocusPolicy;
1626};
1627
1628void QCalendarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
1629 const QModelIndex &index) const
1630{
1631 QDate date = calendarWidgetPrivate->m_model->dateForCell(index.row(), index.column());
1632 if (date.isValid()) {
1633 storedOption = option;
1634 QRect rect = option.rect;
1635 calendarWidgetPrivate->paintCell(painter, rect, date);
1636 } else {
1637 QItemDelegate::paint(painter, option, index);
1638 }
1639}
1640
1641void QCalendarDelegate::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
1642{
1643 storedOption.rect = rect;
1644 int row = -1;
1645 int col = -1;
1646 calendarWidgetPrivate->m_model->cellForDate(date, &row, &col);
1647 QModelIndex idx = calendarWidgetPrivate->m_model->index(row, col);
1648 QItemDelegate::paint(painter, storedOption, idx);
1649}
1650
1651QCalendarWidgetPrivate::QCalendarWidgetPrivate()
1652 : QWidgetPrivate()
1653{
1654 m_model = 0;
1655 m_view = 0;
1656 m_delegate = 0;
1657 m_selection = 0;
1658 m_navigator = 0;
1659 m_dateEditEnabled = false;
1660 navBarVisible = true;
1661 oldFocusPolicy = Qt::StrongFocus;
1662}
1663
1664void QCalendarWidgetPrivate::setNavigatorEnabled(bool enable)
1665{
1666 Q_Q(QCalendarWidget);
1667
1668 bool navigatorEnabled = (m_navigator->widget() != 0);
1669 if (enable == navigatorEnabled)
1670 return;
1671
1672 if (enable) {
1673 m_navigator->setWidget(q);
1674 q->connect(m_navigator, SIGNAL(dateChanged(QDate)),
1675 q, SLOT(_q_slotChangeDate(QDate)));
1676 q->connect(m_navigator, SIGNAL(editingFinished()),
1677 q, SLOT(_q_editingFinished()));
1678 m_view->installEventFilter(m_navigator);
1679 } else {
1680 m_navigator->setWidget(0);
1681 q->disconnect(m_navigator, SIGNAL(dateChanged(QDate)),
1682 q, SLOT(_q_slotChangeDate(QDate)));
1683 q->disconnect(m_navigator, SIGNAL(editingFinished()),
1684 q, SLOT(_q_editingFinished()));
1685 m_view->removeEventFilter(m_navigator);
1686 }
1687}
1688
1689void QCalendarWidgetPrivate::createNavigationBar(QWidget *widget)
1690{
1691 Q_Q(QCalendarWidget);
1692 navBarBackground = new QWidget(widget);
1693 navBarBackground->setObjectName(QLatin1String("qt_calendar_navigationbar"));
1694 navBarBackground->setAutoFillBackground(true);
1695 navBarBackground->setBackgroundRole(QPalette::Highlight);
1696
1697 prevMonth = new QPrevNextCalButton(navBarBackground);
1698 nextMonth = new QPrevNextCalButton(navBarBackground);
1699 prevMonth->setAutoRaise(true);
1700 nextMonth->setAutoRaise(true);
1701 prevMonth->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1702 nextMonth->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1703 nextMonth->setAutoRaise(true);
1704 updateButtonIcons();
1705 prevMonth->setAutoRepeat(true);
1706 nextMonth->setAutoRepeat(true);
1707
1708 monthButton = new QCalToolButton(navBarBackground);
1709 monthButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1710 monthButton->setAutoRaise(true);
1711 monthButton->setPopupMode(QToolButton::InstantPopup);
1712 monthMenu = new QMenu(monthButton);
1713 for (int i = 1; i <= 12; i++) {
1714 QString monthName(q->locale().standaloneMonthName(i, QLocale::LongFormat));
1715 QAction *act = monthMenu->addAction(monthName);
1716 act->setData(i);
1717 monthToAction[i] = act;
1718 }
1719 monthButton->setMenu(monthMenu);
1720 yearButton = new QCalToolButton(navBarBackground);
1721 yearButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1722 yearButton->setAutoRaise(true);
1723 yearEdit = new QSpinBox(navBarBackground);
1724
1725 QFont font = q->font();
1726 font.setBold(true);
1727 monthButton->setFont(font);
1728 yearButton->setFont(font);
1729 yearEdit->setFrame(false);
1730 yearEdit->setMinimum(m_model->m_minimumDate.year());
1731 yearEdit->setMaximum(m_model->m_maximumDate.year());
1732 yearEdit->hide();
1733 spaceHolder = new QSpacerItem(0,0);
1734
1735 QHBoxLayout *headerLayout = new QHBoxLayout;
1736 headerLayout->setMargin(0);
1737 headerLayout->setSpacing(0);
1738 headerLayout->addWidget(prevMonth);
1739 headerLayout->insertStretch(headerLayout->count());
1740 headerLayout->addWidget(monthButton);
1741 headerLayout->addItem(spaceHolder);
1742 headerLayout->addWidget(yearButton);
1743 headerLayout->insertStretch(headerLayout->count());
1744 headerLayout->addWidget(nextMonth);
1745 navBarBackground->setLayout(headerLayout);
1746
1747 yearEdit->setFocusPolicy(Qt::StrongFocus);
1748 prevMonth->setFocusPolicy(Qt::NoFocus);
1749 nextMonth->setFocusPolicy(Qt::NoFocus);
1750 yearButton->setFocusPolicy(Qt::NoFocus);
1751 monthButton->setFocusPolicy(Qt::NoFocus);
1752
1753 //set names for the header controls.
1754 prevMonth->setObjectName(QLatin1String("qt_calendar_prevmonth"));
1755 nextMonth->setObjectName(QLatin1String("qt_calendar_nextmonth"));
1756 monthButton->setObjectName(QLatin1String("qt_calendar_monthbutton"));
1757 yearButton->setObjectName(QLatin1String("qt_calendar_yearbutton"));
1758 yearEdit->setObjectName(QLatin1String("qt_calendar_yearedit"));
1759
1760 updateMonthMenu();
1761 showMonth(m_model->m_date.year(), m_model->m_date.month());
1762}
1763
1764void QCalendarWidgetPrivate::updateButtonIcons()
1765{
1766 Q_Q(QCalendarWidget);
1767 prevMonth->setIcon(q->style()->standardIcon(q->isRightToLeft() ? QStyle::SP_ArrowRight : QStyle::SP_ArrowLeft, 0, q));
1768 nextMonth->setIcon(q->style()->standardIcon(q->isRightToLeft() ? QStyle::SP_ArrowLeft : QStyle::SP_ArrowRight, 0, q));
1769}
1770
1771void QCalendarWidgetPrivate::updateMonthMenu()
1772{
1773 int beg = 1, end = 12;
1774 bool prevEnabled = true;
1775 bool nextEnabled = true;
1776 if (m_model->m_shownYear == m_model->m_minimumDate.year()) {
1777 beg = m_model->m_minimumDate.month();
1778 if (m_model->m_shownMonth == m_model->m_minimumDate.month())
1779 prevEnabled = false;
1780 }
1781 if (m_model->m_shownYear == m_model->m_maximumDate.year()) {
1782 end = m_model->m_maximumDate.month();
1783 if (m_model->m_shownMonth == m_model->m_maximumDate.month())
1784 nextEnabled = false;
1785 }
1786 prevMonth->setEnabled(prevEnabled);
1787 nextMonth->setEnabled(nextEnabled);
1788 for (int i = 1; i <= 12; i++) {
1789 bool monthEnabled = true;
1790 if (i < beg || i > end)
1791 monthEnabled = false;
1792 monthToAction[i]->setEnabled(monthEnabled);
1793 }
1794}
1795
1796void QCalendarWidgetPrivate::updateMonthMenuNames()
1797{
1798 Q_Q(QCalendarWidget);
1799
1800 for (int i = 1; i <= 12; i++) {
1801 QString monthName(q->locale().standaloneMonthName(i, QLocale::LongFormat));
1802 monthToAction[i]->setText(monthName);
1803 }
1804}
1805
1806void QCalendarWidgetPrivate::updateCurrentPage(const QDate &date)
1807{
1808 Q_Q(QCalendarWidget);
1809
1810 QDate newDate = date;
1811 QDate minDate = q->minimumDate();
1812 QDate maxDate = q->maximumDate();
1813 if (minDate.isValid()&& minDate.daysTo(newDate) < 0)
1814 newDate = minDate;
1815 if (maxDate.isValid()&& maxDate.daysTo(newDate) > 0)
1816 newDate = maxDate;
1817 showMonth(newDate.year(), newDate.month());
1818 int row = -1, col = -1;
1819 m_model->cellForDate(newDate, &row, &col);
1820 if (row != -1 && col != -1)
1821 {
1822 m_view->selectionModel()->setCurrentIndex(m_model->index(row, col),
1823 QItemSelectionModel::NoUpdate);
1824 }
1825}
1826
1827void QCalendarWidgetPrivate::_q_monthChanged(QAction *act)
1828{
1829 monthButton->setText(act->text());
1830 QDate currentDate = getCurrentDate();
1831 QDate newDate = currentDate.addMonths(act->data().toInt()-currentDate.month());
1832 updateCurrentPage(newDate);
1833}
1834
1835QDate QCalendarWidgetPrivate::getCurrentDate()
1836{
1837 QModelIndex index = m_view->currentIndex();
1838 return m_model->dateForCell(index.row(), index.column());
1839}
1840
1841void QCalendarWidgetPrivate::_q_prevMonthClicked()
1842{
1843 QDate currentDate = getCurrentDate().addMonths(-1);
1844 updateCurrentPage(currentDate);
1845}
1846
1847void QCalendarWidgetPrivate::_q_nextMonthClicked()
1848{
1849 QDate currentDate = getCurrentDate().addMonths(1);
1850 updateCurrentPage(currentDate);
1851}
1852
1853void QCalendarWidgetPrivate::_q_yearEditingFinished()
1854{
1855 Q_Q(QCalendarWidget);
1856 yearButton->setText(yearEdit->text());
1857 yearEdit->hide();
1858 q->setFocusPolicy(oldFocusPolicy);
1859 qApp->removeEventFilter(q);
1860 spaceHolder->changeSize(0, 0);
1861 yearButton->show();
1862 QDate currentDate = getCurrentDate();
1863 currentDate = currentDate.addYears(yearEdit->text().toInt() - currentDate.year());
1864 updateCurrentPage(currentDate);
1865}
1866
1867void QCalendarWidgetPrivate::_q_yearClicked()
1868{
1869 Q_Q(QCalendarWidget);
1870 //show the spinbox on top of the button
1871 yearEdit->setGeometry(yearButton->x(), yearButton->y(),
1872 yearEdit->sizeHint().width(), yearButton->height());
1873 spaceHolder->changeSize(yearButton->width(), 0);
1874 yearButton->hide();
1875 oldFocusPolicy = q->focusPolicy();
1876 q->setFocusPolicy(Qt::NoFocus);
1877 yearEdit->show();
1878 qApp->installEventFilter(q);
1879 yearEdit->raise();
1880 yearEdit->selectAll();
1881 yearEdit->setFocus(Qt::MouseFocusReason);
1882}
1883
1884void QCalendarWidgetPrivate::showMonth(int year, int month)
1885{
1886 if (m_model->m_shownYear == year && m_model->m_shownMonth == month)
1887 return;
1888 Q_Q(QCalendarWidget);
1889 m_model->showMonth(year, month);
1890 updateNavigationBar();
1891 emit q->currentPageChanged(year, month);
1892 m_view->internalUpdate();
1893 cachedSizeHint = QSize();
1894 update();
1895 updateMonthMenu();
1896}
1897
1898void QCalendarWidgetPrivate::updateNavigationBar()
1899{
1900 Q_Q(QCalendarWidget);
1901
1902 QString monthName = q->locale().standaloneMonthName(m_model->m_shownMonth, QLocale::LongFormat);
1903
1904 monthButton->setText(monthName);
1905 yearButton->setText(QString::number(m_model->m_shownYear));
1906 yearEdit->setValue(m_model->m_shownYear);
1907}
1908
1909void QCalendarWidgetPrivate::update()
1910{
1911 QDate currentDate = m_model->m_date;
1912 int row, column;
1913 m_model->cellForDate(currentDate, &row, &column);
1914 QModelIndex idx;
1915 m_selection->clear();
1916 if (row != -1 && column != -1) {
1917 idx = m_model->index(row, column);
1918 m_selection->setCurrentIndex(idx, QItemSelectionModel::SelectCurrent);
1919 }
1920}
1921
1922void QCalendarWidgetPrivate::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
1923{
1924 Q_Q(const QCalendarWidget);
1925 q->paintCell(painter, rect, date);
1926}
1927
1928void QCalendarWidgetPrivate::_q_slotShowDate(const QDate &date)
1929{
1930 updateCurrentPage(date);
1931}
1932
1933void QCalendarWidgetPrivate::_q_slotChangeDate(const QDate &date)
1934{
1935 _q_slotChangeDate(date, true);
1936}
1937
1938void QCalendarWidgetPrivate::_q_slotChangeDate(const QDate &date, bool changeMonth)
1939{
1940 QDate oldDate = m_model->m_date;
1941 m_model->setDate(date);
1942 QDate newDate = m_model->m_date;
1943 if (changeMonth)
1944 showMonth(newDate.year(), newDate.month());
1945 if (oldDate != newDate) {
1946 update();
1947 Q_Q(QCalendarWidget);
1948 m_navigator->setDate(newDate);
1949 emit q->selectionChanged();
1950 }
1951}
1952
1953void QCalendarWidgetPrivate::_q_editingFinished()
1954{
1955 Q_Q(QCalendarWidget);
1956 emit q->activated(m_model->m_date);
1957}
1958
1959/*!
1960 \class QCalendarWidget
1961 \brief The QCalendarWidget class provides a monthly based
1962 calendar widget allowing the user to select a date.
1963 \since 4.2
1964 \mainclass
1965 \ingroup advanced
1966
1967 \image cleanlooks-calendarwidget.png
1968
1969 The widget is initialized with the current month and year, but
1970 QCalendarWidget provides several public slots to change the year
1971 and month that is shown. The currently displayed month and year
1972 can be retrieved using the currentPageMonth() and currentPageYear()
1973 functions, respectively.
1974
1975 By default, today's date is selected, and the user can select a
1976 date using both mouse and keyboard. The currently selected date
1977 can be retrieved using the selectedDate() function. It is
1978 possible to constrain the user selection to a given date range by
1979 setting the minimumDate and maximumDate properties.
1980 Alternatively, both properties can be set in one go using the
1981 setDateRange() convenience slot. Set the \l selectionMode
1982 property to NoSelection to prohibit the user from selecting at
1983 all. Note that a date also can be selected programmatically using
1984 the setSelectedDate() slot.
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 int startRow = 0;
2146 int startCol = 0;
2147
2148 const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1) * 2;
2149
2150 if (horizontalHeaderFormat() == QCalendarWidget::NoHorizontalHeader) {
2151 rows = 6;
2152 startRow = 1;
2153 } else {
2154 for (int i = 1; i <= 7; i++) {
2155 QFontMetrics fm(d->m_model->formatForCell(0, i).font());
2156 w = qMax(w, fm.width(d->m_model->dayName(d->m_model->dayOfWeekForColumn(i))) + marginH);
2157 h = qMax(h, fm.height());
2158 }
2159 }
2160
2161 if (verticalHeaderFormat() == QCalendarWidget::NoVerticalHeader) {
2162 cols = 7;
2163 startCol = 1;
2164 } else {
2165 for (int i = 1; i <= 6; i++) {
2166 QFontMetrics fm(d->m_model->formatForCell(i, 0).font());
2167 for (int j = 1; j < end; j++)
2168 w = qMax(w, fm.width(QString::number(j)) + marginH);
2169 h = qMax(h, fm.height());
2170 }
2171 }
2172
2173 QFontMetrics fm(d->m_model->formatForCell(1, 1).font());
2174 for (int i = 1; i <= end; i++) {
2175 w = qMax(w, fm.width(QString::number(i)) + marginH);
2176 h = qMax(h, fm.height());
2177 }
2178
2179 if (d->m_view->showGrid()) {
2180 // hardcoded in tableview
2181 w += 1;
2182 h += 1;
2183 }
2184
2185 w += 1; // default column span
2186
2187 h = qMax(h, d->m_view->verticalHeader()->minimumSectionSize());
2188 w = qMax(w, d->m_view->horizontalHeader()->minimumSectionSize());
2189
2190 //add the size of the header.
2191 QSize headerSize(0, 0);
2192 if (d->navBarVisible) {
2193 int headerH = d->navBarBackground->sizeHint().height();
2194 int headerW = 0;
2195
2196 headerW += d->prevMonth->sizeHint().width();
2197 headerW += d->nextMonth->sizeHint().width();
2198
2199 QFontMetrics fm = d->monthButton->fontMetrics();
2200 int monthW = 0;
2201 for (int i = 1; i < 12; i++) {
2202 QString monthName = locale().standaloneMonthName(i, QLocale::LongFormat);
2203 monthW = qMax(monthW, fm.boundingRect(monthName).width());
2204 }
2205 const int buttonDecoMargin = d->monthButton->sizeHint().width() - fm.boundingRect(d->monthButton->text()).width();
2206 headerW += monthW + buttonDecoMargin;
2207
2208 fm = d->yearButton->fontMetrics();
2209 headerW += fm.boundingRect(QLatin1String("5555")).width() + buttonDecoMargin;
2210
2211 headerSize = QSize(headerW, headerH);
2212 }
2213 w *= cols;
2214 w = qMax(headerSize.width(), w);
2215 h = (h * rows) + headerSize.height();
2216 d->cachedSizeHint = QSize(w, h);
2217 return d->cachedSizeHint;
2218}
2219
2220/*!
2221 Paints the cell specified by the given \a date, using the given \a painter and \a rect.
2222*/
2223
2224void QCalendarWidget::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
2225{
2226 Q_D(const QCalendarWidget);
2227 d->m_delegate->paintCell(painter, rect, date);
2228}
2229
2230/*!
2231 \property QCalendarWidget::selectedDate
2232 \brief the currently selected date.
2233
2234 The selected date must be within the date range specified by the
2235 minimumDate and maximumDate properties. By default, the selected
2236 date is the current date.
2237
2238 \sa setDateRange()
2239*/
2240
2241QDate QCalendarWidget::selectedDate() const
2242{
2243 Q_D(const QCalendarWidget);
2244 return d->m_model->m_date;
2245}
2246
2247void QCalendarWidget::setSelectedDate(const QDate &date)
2248{
2249 Q_D(QCalendarWidget);
2250 if (d->m_model->m_date == date && date == d->getCurrentDate())
2251 return;
2252
2253 if (!date.isValid())
2254 return;
2255
2256 d->m_model->setDate(date);
2257 d->update();
2258 QDate newDate = d->m_model->m_date;
2259 d->showMonth(newDate.year(), newDate.month());
2260 emit selectionChanged();
2261}
2262
2263/*!
2264 Returns the year of the currently displayed month. Months are
2265 numbered from 1 to 12.
2266
2267 \sa monthShown(), setCurrentPage()
2268*/
2269
2270int QCalendarWidget::yearShown() const
2271{
2272 Q_D(const QCalendarWidget);
2273 return d->m_model->m_shownYear;
2274}
2275
2276/*!
2277 Returns the currently displayed month. Months are numbered from 1 to
2278 12.
2279
2280 \sa yearShown(), setCurrentPage()
2281*/
2282
2283int QCalendarWidget::monthShown() const
2284{
2285 Q_D(const QCalendarWidget);
2286 return d->m_model->m_shownMonth;
2287}
2288
2289/*!
2290 Displays the given \a month of the given \a year without changing
2291 the selected date. Use the setSelectedDate() function to alter the
2292 selected date.
2293
2294 The currently displayed month and year can be retrieved using the
2295 currentPageMonth() and currentPageYear() functions respectively.
2296
2297 \sa yearShown(), monthShown(), showPreviousMonth(), showNextMonth(),
2298 showPreviousYear(), showNextYear()
2299*/
2300
2301void QCalendarWidget::setCurrentPage(int year, int month)
2302{
2303 Q_D(QCalendarWidget);
2304 d->showMonth(year, month);
2305}
2306
2307/*!
2308 Shows the next month relative to the currently displayed
2309 month. Note that the selected date is not changed.
2310
2311 \sa showPreviousMonth(), setCurrentPage(), setSelectedDate()
2312*/
2313
2314void QCalendarWidget::showNextMonth()
2315{
2316 int year = yearShown();
2317 int month = monthShown();
2318 if (month == 12) {
2319 ++year;
2320 month = 1;
2321 } else {
2322 ++month;
2323 }
2324 setCurrentPage(year, month);
2325}
2326
2327/*!
2328 Shows the previous month relative to the currently displayed
2329 month. Note that the selected date is not changed.
2330
2331 \sa showNextMonth(), setCurrentPage(), setSelectedDate()
2332*/
2333
2334void QCalendarWidget::showPreviousMonth()
2335{
2336 int year = yearShown();
2337 int month = monthShown();
2338 if (month == 1) {
2339 --year;
2340 month = 12;
2341 } else {
2342 --month;
2343 }
2344 setCurrentPage(year, month);
2345}
2346
2347/*!
2348 Shows the currently displayed month in the \e next year relative
2349 to the currently displayed year. Note that the selected date is
2350 not changed.
2351
2352 \sa showPreviousYear(), setCurrentPage(), setSelectedDate()
2353*/
2354
2355void QCalendarWidget::showNextYear()
2356{
2357 int year = yearShown();
2358 int month = monthShown();
2359 ++year;
2360 setCurrentPage(year, month);
2361}
2362
2363/*!
2364 Shows the currently displayed month in the \e previous year
2365 relative to the currently displayed year. Note that the selected
2366 date is not changed.
2367
2368 \sa showNextYear(), setCurrentPage(), setSelectedDate()
2369*/
2370
2371void QCalendarWidget::showPreviousYear()
2372{
2373 int year = yearShown();
2374 int month = monthShown();
2375 --year;
2376 setCurrentPage(year, month);
2377}
2378
2379/*!
2380 Shows the month of the selected date.
2381
2382 \sa selectedDate(), setCurrentPage()
2383*/
2384void QCalendarWidget::showSelectedDate()
2385{
2386 QDate currentDate = selectedDate();
2387 setCurrentPage(currentDate.year(), currentDate.month());
2388}
2389
2390/*!
2391 Shows the month of the today's date.
2392
2393 \sa selectedDate(), setCurrentPage()
2394*/
2395void QCalendarWidget::showToday()
2396{
2397 QDate currentDate = QDate::currentDate();
2398 setCurrentPage(currentDate.year(), currentDate.month());
2399}
2400
2401/*!
2402 \property QCalendarWidget::minimumDate
2403 \brief the minimum date of the currently specified date range.
2404
2405 The user will not be able to select a date that is before the
2406 currently set minimum date.
2407
2408 \table
2409 \row
2410 \o \image qcalendarwidget-minimum.png
2411 \row
2412 \o
2413 \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 1
2414 \endtable
2415
2416 By default, the minimum date is the earliest date that the QDate
2417 class can handle.
2418
2419 When setting a minimum date, the maximumDate and selectedDate
2420 properties are adjusted if the selection range becomes invalid. If
2421 the provided date is not a valid QDate object, the
2422 setMinimumDate() function does nothing.
2423
2424 \sa setDateRange()
2425*/
2426
2427QDate QCalendarWidget::minimumDate() const
2428{
2429 Q_D(const QCalendarWidget);
2430 return d->m_model->m_minimumDate;
2431}
2432
2433void QCalendarWidget::setMinimumDate(const QDate &date)
2434{
2435 Q_D(QCalendarWidget);
2436 if (!date.isValid() || d->m_model->m_minimumDate == date)
2437 return;
2438
2439 QDate oldDate = d->m_model->m_date;
2440 d->m_model->setMinimumDate(date);
2441 d->yearEdit->setMinimum(d->m_model->m_minimumDate.year());
2442 d->updateMonthMenu();
2443 QDate newDate = d->m_model->m_date;
2444 if (oldDate != newDate) {
2445 d->update();
2446 d->showMonth(newDate.year(), newDate.month());
2447 d->m_navigator->setDate(newDate);
2448 emit selectionChanged();
2449 }
2450}
2451
2452/*!
2453 \property QCalendarWidget::maximumDate
2454 \brief the maximum date of the currently specified date range.
2455
2456 The user will not be able to select a date which is after the
2457 currently set maximum date.
2458
2459 \table
2460 \row
2461 \o \image qcalendarwidget-maximum.png
2462 \row
2463 \o
2464 \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 2
2465 \endtable
2466
2467 By default, the maximum date is the last day the QDate class can
2468 handle.
2469
2470 When setting a maximum date, the minimumDate and selectedDate
2471 properties are adjusted if the selection range becomes invalid. If
2472 the provided date is not a valid QDate object, the
2473 setMaximumDate() function does nothing.
2474
2475 \sa setDateRange()
2476*/
2477
2478QDate QCalendarWidget::maximumDate() const
2479{
2480 Q_D(const QCalendarWidget);
2481 return d->m_model->m_maximumDate;
2482}
2483
2484void QCalendarWidget::setMaximumDate(const QDate &date)
2485{
2486 Q_D(QCalendarWidget);
2487 if (!date.isValid() || d->m_model->m_maximumDate == date)
2488 return;
2489
2490 QDate oldDate = d->m_model->m_date;
2491 d->m_model->setMaximumDate(date);
2492 d->yearEdit->setMaximum(d->m_model->m_maximumDate.year());
2493 d->updateMonthMenu();
2494 QDate newDate = d->m_model->m_date;
2495 if (oldDate != newDate) {
2496 d->update();
2497 d->showMonth(newDate.year(), newDate.month());
2498 d->m_navigator->setDate(newDate);
2499 emit selectionChanged();
2500 }
2501}
2502
2503/*!
2504 Defines a date range by setting the minimumDate and maximumDate
2505 properties.
2506
2507 The date range restricts the user selection, i.e. the user can
2508 only select dates within the specified date range. Note that
2509
2510 \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 3
2511
2512 is analogous to
2513
2514 \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 4
2515
2516 If either the \a min or \a max parameters are not valid QDate
2517 objects, this function does nothing.
2518
2519 \sa setMinimumDate(), setMaximumDate()
2520*/
2521
2522void QCalendarWidget::setDateRange(const QDate &min, const QDate &max)
2523{
2524 Q_D(QCalendarWidget);
2525 if (d->m_model->m_minimumDate == min && d->m_model->m_maximumDate == max)
2526 return;
2527 if (!min.isValid() || !max.isValid())
2528 return;
2529
2530 QDate minimum = min;
2531 QDate maximum = max;
2532 if (min > max) {
2533 minimum = max;
2534 maximum = min;
2535 }
2536
2537 QDate oldDate = d->m_model->m_date;
2538 d->m_model->setRange(min, max);
2539 d->yearEdit->setMinimum(d->m_model->m_minimumDate.year());
2540 d->yearEdit->setMaximum(d->m_model->m_maximumDate.year());
2541 d->updateMonthMenu();
2542 QDate newDate = d->m_model->m_date;
2543 if (oldDate != newDate) {
2544 d->update();
2545 d->showMonth(newDate.year(), newDate.month());
2546 d->m_navigator->setDate(newDate);
2547 emit selectionChanged();
2548 }
2549}
2550
2551
2552/*! \enum QCalendarWidget::HorizontalHeaderFormat
2553
2554 This enum type defines the various formats the horizontal header can display.
2555
2556 \value SingleLetterDayNames The header displays a single letter abbreviation for day names (e.g. M for Monday).
2557 \value ShortDayNames The header displays a short abbreviation for day names (e.g. Mon for Monday).
2558 \value LongDayNames The header displays complete day names (e.g. Monday).
2559 \value NoHorizontalHeader The header is hidden.
2560
2561 \sa horizontalHeaderFormat(), VerticalHeaderFormat
2562*/
2563
2564/*!
2565 \property QCalendarWidget::horizontalHeaderFormat
2566 \brief the format of the horizontal header.
2567
2568 The default value is QCalendarWidget::ShortDayNames.
2569*/
2570
2571void QCalendarWidget::setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format)
2572{
2573 Q_D(QCalendarWidget);
2574 if (d->m_model->m_horizontalHeaderFormat == format)
2575 return;
2576
2577 d->m_model->setHorizontalHeaderFormat(format);
2578 d->cachedSizeHint = QSize();
2579 d->m_view->viewport()->update();
2580 d->m_view->updateGeometry();
2581}
2582
2583QCalendarWidget::HorizontalHeaderFormat QCalendarWidget::horizontalHeaderFormat() const
2584{
2585 Q_D(const QCalendarWidget);
2586 return d->m_model->m_horizontalHeaderFormat;
2587}
2588
2589
2590/*!
2591 \enum QCalendarWidget::VerticalHeaderFormat
2592
2593 This enum type defines the various formats the vertical header can display.
2594
2595 \value ISOWeekNumbers The header displays ISO week numbers as described by \l QDate::weekNumber().
2596 \value NoVerticalHeader The header is hidden.
2597
2598 \sa verticalHeaderFormat(), HorizontalHeaderFormat
2599*/
2600
2601/*!
2602 \property QCalendarWidget::verticalHeaderFormat
2603 \brief the format of the vertical header.
2604
2605 The default value is QCalendarWidget::ISOWeekNumber.
2606*/
2607
2608QCalendarWidget::VerticalHeaderFormat QCalendarWidget::verticalHeaderFormat() const
2609{
2610 Q_D(const QCalendarWidget);
2611 bool shown = d->m_model->weekNumbersShown();
2612 if (shown)
2613 return QCalendarWidget::ISOWeekNumbers;
2614 return QCalendarWidget::NoVerticalHeader;
2615}
2616
2617void QCalendarWidget::setVerticalHeaderFormat(QCalendarWidget::VerticalHeaderFormat format)
2618{
2619 Q_D(QCalendarWidget);
2620 bool show = false;
2621 if (format == QCalendarWidget::ISOWeekNumbers)
2622 show = true;
2623 if (d->m_model->weekNumbersShown() == show)
2624 return;
2625 d->m_model->setWeekNumbersShown(show);
2626 d->cachedSizeHint = QSize();
2627 d->m_view->viewport()->update();
2628 d->m_view->updateGeometry();
2629}
2630
2631/*!
2632 \property QCalendarWidget::gridVisible
2633 \brief whether the table grid is displayed.
2634
2635 \table
2636 \row
2637 \o \inlineimage qcalendarwidget-grid.png
2638 \row
2639 \o
2640 \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 5
2641 \endtable
2642
2643 The default value is false.
2644*/
2645
2646bool QCalendarWidget::isGridVisible() const
2647{
2648 Q_D(const QCalendarWidget);
2649 return d->m_view->showGrid();
2650}
2651
2652void QCalendarWidget::setGridVisible(bool show)
2653{
2654 Q_D(QCalendarWidget);
2655 d->m_view->setShowGrid(show);
2656 d->cachedSizeHint = QSize();
2657 d->m_view->viewport()->update();
2658 d->m_view->updateGeometry();
2659}
2660
2661/*!
2662 \property QCalendarWidget::selectionMode
2663 \brief the type of selection the user can make in the calendar
2664
2665 When this property is set to SingleSelection, the user can select a date
2666 within the minimum and maximum allowed dates, using either the mouse or
2667 the keyboard.
2668
2669 When the property is set to NoSelection, the user will be unable to select
2670 dates, but they can still be selected programmatically. Note that the date
2671 that is selected when the property is set to NoSelection will still be
2672 the selected date of the calendar.
2673
2674 The default value is SingleSelection.
2675*/
2676
2677QCalendarWidget::SelectionMode QCalendarWidget::selectionMode() const
2678{
2679 Q_D(const QCalendarWidget);
2680 return d->m_view->readOnly ? QCalendarWidget::NoSelection : QCalendarWidget::SingleSelection;
2681}
2682
2683void QCalendarWidget::setSelectionMode(SelectionMode mode)
2684{
2685 Q_D(QCalendarWidget);
2686 d->m_view->readOnly = (mode == QCalendarWidget::NoSelection);
2687 d->setNavigatorEnabled(isDateEditEnabled() && (selectionMode() != QCalendarWidget::NoSelection));
2688 d->update();
2689}
2690
2691/*!
2692 \property QCalendarWidget::firstDayOfWeek
2693 \brief a value identifying the day displayed in the first column.
2694
2695 By default, the day displayed in the first column is Sunday
2696*/
2697
2698void QCalendarWidget::setFirstDayOfWeek(Qt::DayOfWeek dayOfWeek)
2699{
2700 Q_D(QCalendarWidget);
2701 if ((Qt::DayOfWeek)d->m_model->firstColumnDay() == dayOfWeek)
2702 return;
2703
2704 d->m_model->setFirstColumnDay(dayOfWeek);
2705 d->update();
2706}
2707
2708Qt::DayOfWeek QCalendarWidget::firstDayOfWeek() const
2709{
2710 Q_D(const QCalendarWidget);
2711 return (Qt::DayOfWeek)d->m_model->firstColumnDay();
2712}
2713
2714/*!
2715 Returns the text char format for rendering the header.
2716*/
2717QTextCharFormat QCalendarWidget::headerTextFormat() const
2718{
2719 Q_D(const QCalendarWidget);
2720 return d->m_model->m_headerFormat;
2721}
2722
2723/*!
2724 Sets the text char format for rendering the header to \a format.
2725 If you also set a weekday text format, this format's foreground and
2726 background color will take precedence over the header's format.
2727 The other formatting information will still be decided by
2728 the header's format.
2729*/
2730void QCalendarWidget::setHeaderTextFormat(const QTextCharFormat &format)
2731{
2732 Q_D(QCalendarWidget);
2733 d->m_model->m_headerFormat = format;
2734 d->cachedSizeHint = QSize();
2735 d->m_view->viewport()->update();
2736 d->m_view->updateGeometry();
2737}
2738
2739/*!
2740 Returns the text char format for rendering of day in the week \a dayOfWeek.
2741
2742 \sa headerTextFormat()
2743*/
2744QTextCharFormat QCalendarWidget::weekdayTextFormat(Qt::DayOfWeek dayOfWeek) const
2745{
2746 Q_D(const QCalendarWidget);
2747 return d->m_model->m_dayFormats.value(dayOfWeek);
2748}
2749
2750/*!
2751 Sets the text char format for rendering of day in the week \a dayOfWeek to \a format.
2752 The format will take precedence over the header format in case of foreground
2753 and background color. Other text formatting information is taken from the headers format.
2754
2755 \sa setHeaderTextFormat()
2756*/
2757void QCalendarWidget::setWeekdayTextFormat(Qt::DayOfWeek dayOfWeek, const QTextCharFormat &format)
2758{
2759 Q_D(QCalendarWidget);
2760 d->m_model->m_dayFormats[dayOfWeek] = format;
2761 d->cachedSizeHint = QSize();
2762 d->m_view->viewport()->update();
2763 d->m_view->updateGeometry();
2764}
2765
2766/*!
2767 Returns a QMap from QDate to QTextCharFormat showing all dates
2768 that use a special format that alters their rendering.
2769*/
2770QMap<QDate, QTextCharFormat> QCalendarWidget::dateTextFormat() const
2771{
2772 Q_D(const QCalendarWidget);
2773 return d->m_model->m_dateFormats;
2774}
2775
2776/*!
2777 Returns a QTextCharFormat for \a date. The char format can be be
2778 empty if the date is not renderd specially.
2779*/
2780QTextCharFormat QCalendarWidget::dateTextFormat(const QDate &date) const
2781{
2782 Q_D(const QCalendarWidget);
2783 return d->m_model->m_dateFormats.value(date);
2784}
2785
2786/*!
2787 Sets the format used to render the given \a date to that specified by \a format.
2788
2789 If \a date is null, all date formats are cleared.
2790*/
2791void QCalendarWidget::setDateTextFormat(const QDate &date, const QTextCharFormat &format)
2792{
2793 Q_D(QCalendarWidget);
2794 if ( date.isNull() && !format.isValid() )
2795 d->m_model->m_dateFormats.clear();
2796 else
2797 d->m_model->m_dateFormats[date] = format;
2798 d->m_view->viewport()->update();
2799 d->m_view->updateGeometry();
2800}
2801
2802/*!
2803 \property QCalendarWidget::dateEditEnabled
2804 \brief whether the date edit popup is enabled
2805 \since 4.3
2806
2807 If this property is enabled, pressing a non-modifier key will cause a
2808 date edit to popup if the calendar widget has focus, allowing the user
2809 to specify a date in the form specified by the current locale.
2810
2811 By default, this property is enabled.
2812
2813 The date edit is simpler in appearance than QDateEdit, but allows the
2814 user to navigate between fields using the left and right cursor keys,
2815 increment and decrement individual fields using the up and down cursor
2816 keys, and enter values directly using the number keys.
2817
2818 \sa QCalendarWidget::dateEditAcceptDelay
2819*/
2820bool QCalendarWidget::isDateEditEnabled() const
2821{
2822 Q_D(const QCalendarWidget);
2823 return d->m_dateEditEnabled;
2824}
2825
2826void QCalendarWidget::setDateEditEnabled(bool enable)
2827{
2828 Q_D(QCalendarWidget);
2829 if (isDateEditEnabled() == enable)
2830 return;
2831
2832 d->m_dateEditEnabled = enable;
2833
2834 d->setNavigatorEnabled(enable && (selectionMode() != QCalendarWidget::NoSelection));
2835}
2836
2837/*!
2838 \property QCalendarWidget::dateEditAcceptDelay
2839 \brief the time an inactive date edit is shown before its contents are accepted
2840 \since 4.3
2841
2842 If the calendar widget's \l{dateEditEnabled}{date edit is enabled}, this
2843 property specifies the amount of time (in millseconds) that the date edit
2844 remains open after the most recent user input. Once this time has elapsed,
2845 the date specified in the date edit is accepted and the popup is closed.
2846
2847 By default, the delay is defined to be 1500 milliseconds (1.5 seconds).
2848*/
2849int QCalendarWidget::dateEditAcceptDelay() const
2850{
2851 Q_D(const QCalendarWidget);
2852 return d->m_navigator->dateEditAcceptDelay();
2853}
2854
2855void QCalendarWidget::setDateEditAcceptDelay(int delay)
2856{
2857 Q_D(QCalendarWidget);
2858 d->m_navigator->setDateEditAcceptDelay(delay);
2859}
2860
2861/*!
2862 \since 4.4
2863
2864 Updates the cell specified by the given \a date unless updates
2865 are disabled or the cell is hidden.
2866
2867 \sa updateCells(), yearShown(), monthShown()
2868*/
2869void QCalendarWidget::updateCell(const QDate &date)
2870{
2871 if (!date.isValid()) {
2872 qWarning("QCalendarWidget::updateCell: Invalid date");
2873 return;
2874 }
2875
2876 if (!isVisible())
2877 return;
2878
2879 Q_D(QCalendarWidget);
2880 int row, column;
2881 d->m_model->cellForDate(date, &row, &column);
2882 if (row == -1 || column == -1)
2883 return;
2884
2885 QModelIndex modelIndex = d->m_model->index(row, column);
2886 if (!modelIndex.isValid())
2887 return;
2888
2889 d->m_view->viewport()->update(d->m_view->visualRect(modelIndex));
2890}
2891
2892/*!
2893 \since 4.4
2894
2895 Updates all visible cells unless updates are disabled.
2896
2897 \sa updateCell()
2898*/
2899void QCalendarWidget::updateCells()
2900{
2901 Q_D(QCalendarWidget);
2902 if (isVisible())
2903 d->m_view->viewport()->update();
2904}
2905
2906/*!
2907 \fn void QCalendarWidget::selectionChanged()
2908
2909 This signal is emitted when the currently selected date is
2910 changed.
2911
2912 The currently selected date can be changed by the user using the
2913 mouse or keyboard, or by the programmer using setSelectedDate().
2914
2915 \sa selectedDate()
2916*/
2917
2918/*!
2919 \fn void QCalendarWidget::currentPageChanged(int year, int month)
2920
2921 This signal is emitted when the currently shown month is changed.
2922 The new \a year and \a month are passed as parameters.
2923
2924 \sa setCurrentPage()
2925*/
2926
2927/*!
2928 \fn void QCalendarWidget::activated(const QDate &date)
2929
2930 This signal is emitted whenever the user presses the Return or
2931 Enter key or double-clicks a \a date in the calendar
2932 widget.
2933*/
2934
2935/*!
2936 \fn void QCalendarWidget::clicked(const QDate &date)
2937
2938 This signal is emitted when a mouse button is clicked. The date
2939 the mouse was clicked on is specified by \a date. The signal is
2940 only emitted when clicked on a valid date, e.g., dates are not
2941 outside the minimumDate() and maximumDate(). If the selection mode
2942 is NoSelection, this signal will not be emitted.
2943
2944*/
2945
2946/*!
2947 \property QCalendarWidget::headerVisible
2948 \brief whether the navigation bar is shown or not
2949
2950 \obsolete
2951
2952 Use navigationBarVisible() instead.
2953
2954 By default, this property is true.
2955*/
2956
2957/*!
2958 \obsolete
2959
2960 Use setNavigationBarVisible() instead.
2961*/
2962bool QCalendarWidget::isHeaderVisible() const
2963{
2964 Q_D(const QCalendarWidget);
2965 return d->navBarVisible;
2966}
2967
2968/*!
2969 \obsolete
2970
2971 Use setNavigationBarVisible() instead.
2972
2973*/
2974void QCalendarWidget::setHeaderVisible(bool visible)
2975{
2976 setNavigationBarVisible(visible);
2977}
2978
2979/*!
2980 \property QCalendarWidget::navigationBarVisible
2981 \brief whether the navigation bar is shown or not
2982
2983 \since 4.3
2984
2985 When this property is true (the default), the next month,
2986 previous month, month selection, year selection controls are
2987 shown on top.
2988
2989 When the property is set to false, these controls are hidden.
2990*/
2991
2992void QCalendarWidget::setNavigationBarVisible(bool visible)
2993{
2994 Q_D(QCalendarWidget);
2995 d->navBarVisible = visible;
2996 d->cachedSizeHint = QSize();
2997 d->navBarBackground->setVisible(visible);
2998 updateGeometry();
2999}
3000
3001/*!
3002 \reimp
3003*/
3004bool QCalendarWidget::event(QEvent *event)
3005{
3006 Q_D(QCalendarWidget);
3007 switch (event->type()) {
3008 case QEvent::LayoutDirectionChange:
3009 d->updateButtonIcons();
3010 case QEvent::LocaleChange:
3011 d->cachedSizeHint = QSize();
3012 d->updateMonthMenuNames();
3013 d->updateNavigationBar();
3014 d->m_view->updateGeometry();
3015 break;
3016 case QEvent::FontChange:
3017 case QEvent::ApplicationFontChange:
3018 d->cachedSizeHint = QSize();
3019 d->m_view->updateGeometry();
3020 break;
3021 case QEvent::StyleChange:
3022 d->cachedSizeHint = QSize();
3023 d->m_view->updateGeometry();
3024 default:
3025 break;
3026 }
3027 return QWidget::event(event);
3028}
3029
3030/*!
3031 \reimp
3032*/
3033bool QCalendarWidget::eventFilter(QObject *watched, QEvent *event)
3034{
3035 Q_D(QCalendarWidget);
3036 if (event->type() == QEvent::MouseButtonPress && d->yearEdit->hasFocus() && !QRect(d->yearEdit->mapToGlobal(QPoint(0, 0)), d->yearEdit->size()).contains(static_cast<QMouseEvent *>(event)->globalPos())) {
3037 event->accept();
3038 d->_q_yearEditingFinished();
3039 setFocus();
3040 return true;
3041 }
3042 return QWidget::eventFilter(watched, event);
3043}
3044
3045/*!
3046 \reimp
3047*/
3048void QCalendarWidget::mousePressEvent(QMouseEvent *event)
3049{
3050 setAttribute(Qt::WA_NoMouseReplay);
3051 QWidget::mousePressEvent(event);
3052 setFocus();
3053}
3054
3055/*!
3056 \reimp
3057*/
3058void QCalendarWidget::resizeEvent(QResizeEvent * event)
3059{
3060 Q_D(QCalendarWidget);
3061
3062 // XXX Should really use a QWidgetStack for yearEdit and yearButton,
3063 // XXX here we hide the year edit when the layout is likely to break
3064 // XXX the manual positioning of the yearEdit over the yearButton.
3065 if(d->yearEdit->isVisible() && event->size().width() != event->oldSize().width())
3066 d->_q_yearEditingFinished();
3067
3068 QWidget::resizeEvent(event);
3069}
3070
3071/*!
3072 \reimp
3073*/
3074void QCalendarWidget::keyPressEvent(QKeyEvent * event)
3075{
3076 Q_D(QCalendarWidget);
3077 if(d->yearEdit->isVisible()&& event->key() == Qt::Key_Escape)
3078 {
3079 d->yearEdit->setValue(yearShown());
3080 d->_q_yearEditingFinished();
3081 return;
3082 }
3083 QWidget::keyPressEvent(event);
3084}
3085
3086QT_END_NAMESPACE
3087
3088#include "qcalendarwidget.moc"
3089#include "moc_qcalendarwidget.cpp"
3090
3091#endif //QT_NO_CALENDARWIDGET
Note: See TracBrowser for help on using the repository browser.