Fix QDateEdit displaying day as a number for short and long day formats
[profile/ivi/qtbase.git] / src / widgets / widgets / qdatetimeedit.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <math.h>
43 #include <private/qdatetimeedit_p.h>
44 #include <qabstractspinbox.h>
45 #include <qapplication.h>
46 #include <qdatetimeedit.h>
47 #include <qdesktopwidget.h>
48 #include <qdebug.h>
49 #include <qevent.h>
50 #include <qlineedit.h>
51 #include <private/qlineedit_p.h>
52 #include <qlocale.h>
53 #include <qpainter.h>
54 #include <qlayout.h>
55 #include <qset.h>
56 #include <qstyle.h>
57
58 #ifndef QT_NO_DATETIMEEDIT
59
60 //#define QDATETIMEEDIT_QDTEDEBUG
61 #ifdef QDATETIMEEDIT_QDTEDEBUG
62 #  define QDTEDEBUG qDebug() << QString::fromLatin1("%1:%2").arg(__FILE__).arg(__LINE__)
63 #  define QDTEDEBUGN qDebug
64 #else
65 #  define QDTEDEBUG if (false) qDebug()
66 #  define QDTEDEBUGN if (false) qDebug
67 #endif
68
69 QT_BEGIN_NAMESPACE
70
71 // --- QDateTimeEdit ---
72
73 /*!
74   \class QDateTimeEdit
75   \brief The QDateTimeEdit class provides a widget for editing dates and times.
76
77   \ingroup basicwidgets
78   \inmodule QtWidgets
79
80   QDateTimeEdit allows the user to edit dates by using the keyboard or
81   the arrow keys to increase and decrease date and time values. The
82   arrow keys can be used to move from section to section within the
83   QDateTimeEdit box. Dates and times appear in accordance with the
84   format set; see setDisplayFormat().
85
86   \snippet code/src_gui_widgets_qdatetimeedit.cpp 0
87
88   Here we've created a new QDateTimeEdit object initialized with
89   today's date, and restricted the valid date range to today plus or
90   minus 365 days. We've set the order to month, day, year.
91
92   The minimum value for QDateTimeEdit is 14 September 1752,
93   and 2 January 4713BC for QDate. You can change this by calling
94   setMinimumDate(), setMaximumDate(),  setMinimumTime(),
95   and setMaximumTime().
96
97   \section1 Using a Pop-up Calendar Widget
98
99   QDateTimeEdit can be configured to allow a QCalendarWidget to be used
100   to select dates. This is enabled by setting the calendarPopup property.
101   Additionally, you can supply a custom calendar widget for use as the
102   calendar pop-up by calling the setCalendarWidget() function. The existing
103   calendar widget can be retrieved with calendarWidget().
104
105   \table 100%
106   \row \li \inlineimage windowsxp-datetimeedit.png Screenshot of a Windows XP style date time editing widget
107        \li A date time editing widget shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
108   \row \li \inlineimage macintosh-datetimeedit.png Screenshot of a Macintosh style date time editing widget
109        \li A date time editing widget shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
110   \row \li \inlineimage plastique-datetimeedit.png Screenshot of a Plastique style date time editing widget
111        \li A date time editing widget shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
112   \endtable
113
114   \sa QDateEdit, QTimeEdit, QDate, QTime
115 */
116
117 /*!
118   \enum QDateTimeEdit::Section
119
120   \value NoSection
121   \value AmPmSection
122   \value MSecSection
123   \value SecondSection
124   \value MinuteSection
125   \value HourSection
126   \value DaySection
127   \value MonthSection
128   \value YearSection
129   \omitvalue DateSections_Mask
130   \omitvalue TimeSections_Mask
131 */
132
133 /*!
134   \fn void QDateTimeEdit::dateTimeChanged(const QDateTime &datetime)
135
136   This signal is emitted whenever the date or time is changed. The
137   new date and time is passed in \a datetime.
138 */
139
140 /*!
141   \fn void QDateTimeEdit::timeChanged(const QTime &time)
142
143   This signal is emitted whenever the time is changed. The new time
144   is passed in \a time.
145 */
146
147 /*!
148   \fn void QDateTimeEdit::dateChanged(const QDate &date)
149
150   This signal is emitted whenever the date is changed. The new date
151   is passed in \a date.
152 */
153
154
155 /*!
156   Constructs an empty date time editor with a \a parent.
157 */
158
159 QDateTimeEdit::QDateTimeEdit(QWidget *parent)
160     : QAbstractSpinBox(*new QDateTimeEditPrivate, parent)
161 {
162     Q_D(QDateTimeEdit);
163     d->init(QDateTime(QDATETIMEEDIT_DATE_INITIAL, QDATETIMEEDIT_TIME_MIN));
164 }
165
166 /*!
167   Constructs an empty date time editor with a \a parent. The value
168   is set to \a datetime.
169 */
170
171 QDateTimeEdit::QDateTimeEdit(const QDateTime &datetime, QWidget *parent)
172     : QAbstractSpinBox(*new QDateTimeEditPrivate, parent)
173 {
174     Q_D(QDateTimeEdit);
175     d->init(datetime.isValid() ? datetime : QDateTime(QDATETIMEEDIT_DATE_INITIAL,
176                                                       QDATETIMEEDIT_TIME_MIN));
177 }
178
179 /*!
180   \fn QDateTimeEdit::QDateTimeEdit(const QDate &date, QWidget *parent)
181
182   Constructs an empty date time editor with a \a parent.
183   The value is set to \a date.
184 */
185
186 QDateTimeEdit::QDateTimeEdit(const QDate &date, QWidget *parent)
187     : QAbstractSpinBox(*new QDateTimeEditPrivate, parent)
188 {
189     Q_D(QDateTimeEdit);
190     d->init(date.isValid() ? date : QDATETIMEEDIT_DATE_INITIAL);
191 }
192
193 /*!
194   \fn QDateTimeEdit::QDateTimeEdit(const QTime &time, QWidget *parent)
195
196   Constructs an empty date time editor with a \a parent.
197   The value is set to \a time.
198 */
199
200 QDateTimeEdit::QDateTimeEdit(const QTime &time, QWidget *parent)
201     : QAbstractSpinBox(*new QDateTimeEditPrivate, parent)
202 {
203     Q_D(QDateTimeEdit);
204     d->init(time.isValid() ? time : QDATETIMEEDIT_TIME_MIN);
205 }
206
207 /*!
208   \internal
209 */
210
211 QDateTimeEdit::QDateTimeEdit(const QVariant &var, QVariant::Type parserType, QWidget *parent)
212     : QAbstractSpinBox(*new QDateTimeEditPrivate, parent)
213 {
214     Q_D(QDateTimeEdit);
215     d->parserType = parserType;
216     d->init(var);
217 }
218
219 /*!
220   \property QDateTimeEdit::dateTime
221   \brief the QDateTime that is set in the QDateTimeEdit
222
223   When setting this property the timespec of the QDateTimeEdit remains the same
224   and the timespec of the new QDateTime is ignored.
225
226   By default, this property contains a date that refers to January 1,
227   2000 and a time of 00:00:00 and 0 milliseconds.
228
229   \sa date, time
230 */
231
232 QDateTime QDateTimeEdit::dateTime() const
233 {
234     Q_D(const QDateTimeEdit);
235     return d->value.toDateTime();
236 }
237
238 void QDateTimeEdit::setDateTime(const QDateTime &datetime)
239 {
240     Q_D(QDateTimeEdit);
241     if (datetime.isValid()) {
242         d->clearCache();
243         if (!(d->sections & DateSections_Mask))
244             setDateRange(datetime.date(), datetime.date());
245         d->setValue(QDateTime(datetime.date(), datetime.time(), d->spec), EmitIfChanged);
246     }
247 }
248
249 /*!
250   \property QDateTimeEdit::date
251   \brief the QDate that is set in the widget
252
253   By default, this property contains a date that refers to January 1, 2000.
254
255   \sa time, dateTime
256 */
257
258 /*!
259     Returns the date of the date time edit.
260 */
261 QDate QDateTimeEdit::date() const
262 {
263     Q_D(const QDateTimeEdit);
264     return d->value.toDate();
265 }
266
267 void QDateTimeEdit::setDate(const QDate &date)
268 {
269     Q_D(QDateTimeEdit);
270     if (date.isValid()) {
271         if (!(d->sections & DateSections_Mask))
272             setDateRange(date, date);
273
274         d->clearCache();
275         d->setValue(QDateTime(date, d->value.toTime(), d->spec), EmitIfChanged);
276         d->updateTimeSpec();
277     }
278 }
279
280 /*!
281   \property QDateTimeEdit::time
282   \brief the QTime that is set in the widget
283
284   By default, this property contains a time of 00:00:00 and 0 milliseconds.
285
286   \sa date, dateTime
287 */
288
289 /*!
290     Returns the time of the date time edit.
291 */
292 QTime QDateTimeEdit::time() const
293 {
294     Q_D(const QDateTimeEdit);
295     return d->value.toTime();
296 }
297
298 void QDateTimeEdit::setTime(const QTime &time)
299 {
300     Q_D(QDateTimeEdit);
301     if (time.isValid()) {
302         d->clearCache();
303         d->setValue(QDateTime(d->value.toDate(), time, d->spec), EmitIfChanged);
304     }
305 }
306
307
308 /*!
309   \property QDateTimeEdit::minimumDateTime
310   \since 4.4
311
312   \brief the minimum datetime of the date time edit
313
314   When setting this property the \l maximumDateTime() is adjusted if
315   necessary to ensure that the range remains valid. If the datetime is
316   not a valid QDateTime object, this function does nothing.
317
318   The default minimumDateTime can be restored with
319   clearMinimumDateTime()
320
321   By default, this property contains a date that refers to September 14,
322   1752 and a time of 00:00:00 and 0 milliseconds.
323
324   \sa maximumDateTime(), minimumTime(), maximumTime(), minimumDate(),
325   maximumDate(), setDateTimeRange(), setDateRange(), setTimeRange(),
326   clearMaximumDateTime(), clearMinimumDate(),
327   clearMaximumDate(), clearMinimumTime(), clearMaximumTime()
328 */
329
330 QDateTime QDateTimeEdit::minimumDateTime() const
331 {
332     Q_D(const QDateTimeEdit);
333     return d->minimum.toDateTime();
334 }
335
336 void QDateTimeEdit::clearMinimumDateTime()
337 {
338     setMinimumDateTime(QDateTime(QDATETIMEEDIT_COMPAT_DATE_MIN, QDATETIMEEDIT_TIME_MIN));
339 }
340
341 void QDateTimeEdit::setMinimumDateTime(const QDateTime &dt)
342 {
343     Q_D(QDateTimeEdit);
344     if (dt.isValid() && dt.date() >= QDATETIMEEDIT_DATE_MIN) {
345         const QDateTime m = dt.toTimeSpec(d->spec);
346         const QDateTime max = d->maximum.toDateTime();
347         d->setRange(m, (max > m ? max : m));
348     }
349 }
350
351 /*!
352   \property QDateTimeEdit::maximumDateTime
353   \since 4.4
354
355   \brief the maximum datetime of the date time edit
356
357   When setting this property the \l minimumDateTime() is adjusted if
358   necessary to ensure that the range remains valid. If the datetime is
359   not a valid QDateTime object, this function does nothing.
360
361   The default maximumDateTime can be restored with
362   clearMaximumDateTime().
363
364   By default, this property contains a date that refers to 31 December,
365   7999 and a time of 23:59:59 and 999 milliseconds.
366
367   \sa minimumDateTime(), minimumTime(), maximumTime(), minimumDate(),
368   maximumDate(), setDateTimeRange(), setDateRange(), setTimeRange(),
369   clearMinimumDateTime(), clearMinimumDate(),
370   clearMaximumDate(), clearMinimumTime(), clearMaximumTime()
371 */
372
373 QDateTime QDateTimeEdit::maximumDateTime() const
374 {
375     Q_D(const QDateTimeEdit);
376     return d->maximum.toDateTime();
377 }
378
379 void QDateTimeEdit::clearMaximumDateTime()
380 {
381     setMaximumDateTime(QDATETIMEEDIT_DATETIME_MAX);
382 }
383
384 void QDateTimeEdit::setMaximumDateTime(const QDateTime &dt)
385 {
386     Q_D(QDateTimeEdit);
387     if (dt.isValid() && dt.date() <= QDATETIMEEDIT_DATE_MAX) {
388         const QDateTime m = dt.toTimeSpec(d->spec);
389         const QDateTime min = d->minimum.toDateTime();
390         d->setRange((min < m ? min : m), m);
391     }
392 }
393
394
395 /*!
396   Convenience function to set minimum and maximum date time with one
397   function call.
398   \since 4.4
399
400   \snippet code/src_gui_widgets_qdatetimeedit.cpp 1
401
402   is analogous to:
403
404   \snippet code/src_gui_widgets_qdatetimeedit.cpp 2
405
406   If either \a min or \a max are not valid, this function does
407   nothing.
408
409   \sa setMinimumDate(), maximumDate(), setMaximumDate(),
410   clearMinimumDate(), setMinimumTime(), maximumTime(),
411   setMaximumTime(), clearMinimumTime(), QDateTime::isValid()
412 */
413
414 void QDateTimeEdit::setDateTimeRange(const QDateTime &min, const QDateTime &max)
415 {
416     Q_D(QDateTimeEdit);
417     const QDateTime minimum = min.toTimeSpec(d->spec);
418     QDateTime maximum = max.toTimeSpec(d->spec);
419     if (min > max)
420         maximum = minimum;
421     d->setRange(minimum, maximum);
422 }
423
424 /*!
425   \property QDateTimeEdit::minimumDate
426
427   \brief the minimum date of the date time edit
428
429   When setting this property the \l maximumDate is adjusted if
430   necessary, to ensure that the range remains valid. If the date is
431   not a valid QDate object, this function does nothing.
432
433   By default, this property contains a date that refers to September 14, 1752.
434   The minimum date must be at least the first day in year 100, otherwise
435   setMinimumDate() has no effect.
436
437   \sa minimumTime(), maximumTime(), setDateRange()
438 */
439
440 QDate QDateTimeEdit::minimumDate() const
441 {
442     Q_D(const QDateTimeEdit);
443     return d->minimum.toDate();
444 }
445
446 void QDateTimeEdit::setMinimumDate(const QDate &min)
447 {
448     Q_D(QDateTimeEdit);
449     if (min.isValid() && min >= QDATETIMEEDIT_DATE_MIN) {
450         setMinimumDateTime(QDateTime(min, d->minimum.toTime(), d->spec));
451     }
452 }
453
454 void QDateTimeEdit::clearMinimumDate()
455 {
456     setMinimumDate(QDATETIMEEDIT_COMPAT_DATE_MIN);
457 }
458
459 /*!
460   \property QDateTimeEdit::maximumDate
461
462   \brief the maximum date of the date time edit
463
464   When setting this property the \l minimumDate is adjusted if
465   necessary to ensure that the range remains valid. If the date is
466   not a valid QDate object, this function does nothing.
467
468   By default, this property contains a date that refers to December 31, 7999.
469
470   \sa minimumDate, minimumTime, maximumTime, setDateRange()
471 */
472
473 QDate QDateTimeEdit::maximumDate() const
474 {
475     Q_D(const QDateTimeEdit);
476     return d->maximum.toDate();
477 }
478
479 void QDateTimeEdit::setMaximumDate(const QDate &max)
480 {
481     Q_D(QDateTimeEdit);
482     if (max.isValid()) {
483         setMaximumDateTime(QDateTime(max, d->maximum.toTime(), d->spec));
484     }
485 }
486
487 void QDateTimeEdit::clearMaximumDate()
488 {
489     setMaximumDate(QDATETIMEEDIT_DATE_MAX);
490 }
491
492 /*!
493   \property QDateTimeEdit::minimumTime
494
495   \brief the minimum time of the date time edit
496
497   When setting this property the \l maximumTime is adjusted if
498   necessary, to ensure that the range remains valid. If the time is
499   not a valid QTime object, this function does nothing.
500
501   By default, this property contains a time of 00:00:00 and 0 milliseconds.
502
503   \sa maximumTime, minimumDate, maximumDate, setTimeRange()
504 */
505
506 QTime QDateTimeEdit::minimumTime() const
507 {
508     Q_D(const QDateTimeEdit);
509     return d->minimum.toTime();
510 }
511
512 void QDateTimeEdit::setMinimumTime(const QTime &min)
513 {
514     Q_D(QDateTimeEdit);
515     if (min.isValid()) {
516         const QDateTime m(d->minimum.toDate(), min, d->spec);
517         setMinimumDateTime(m);
518     }
519 }
520
521 void QDateTimeEdit::clearMinimumTime()
522 {
523     setMinimumTime(QDATETIMEEDIT_TIME_MIN);
524 }
525
526 /*!
527   \property QDateTimeEdit::maximumTime
528
529   \brief the maximum time of the date time edit
530
531   When setting this property, the \l minimumTime is adjusted if
532   necessary to ensure that the range remains valid. If the time is
533   not a valid QTime object, this function does nothing.
534
535   By default, this property contains a time of 23:59:59 and 999 milliseconds.
536
537   \sa minimumTime, minimumDate, maximumDate, setTimeRange()
538 */
539 QTime QDateTimeEdit::maximumTime() const
540 {
541     Q_D(const QDateTimeEdit);
542     return d->maximum.toTime();
543 }
544
545 void QDateTimeEdit::setMaximumTime(const QTime &max)
546 {
547     Q_D(QDateTimeEdit);
548     if (max.isValid()) {
549         const QDateTime m(d->maximum.toDate(), max);
550         setMaximumDateTime(m);
551     }
552 }
553
554 void QDateTimeEdit::clearMaximumTime()
555 {
556     setMaximumTime(QDATETIMEEDIT_TIME_MAX);
557 }
558
559 /*!
560   Convenience function to set minimum and maximum date with one
561   function call.
562
563   \snippet code/src_gui_widgets_qdatetimeedit.cpp 3
564
565   is analogous to:
566
567   \snippet code/src_gui_widgets_qdatetimeedit.cpp 4
568
569   If either \a min or \a max are not valid, this function does
570   nothing.
571
572   \sa setMinimumDate(), maximumDate(), setMaximumDate(),
573   clearMinimumDate(), setMinimumTime(), maximumTime(),
574   setMaximumTime(), clearMinimumTime(), QDate::isValid()
575 */
576
577 void QDateTimeEdit::setDateRange(const QDate &min, const QDate &max)
578 {
579     Q_D(QDateTimeEdit);
580     if (min.isValid() && max.isValid()) {
581         setDateTimeRange(QDateTime(min, d->minimum.toTime(), d->spec),
582                          QDateTime(max, d->maximum.toTime(), d->spec));
583     }
584 }
585
586 /*!
587   Convenience function to set minimum and maximum time with one
588   function call.
589
590   \snippet code/src_gui_widgets_qdatetimeedit.cpp 5
591
592   is analogous to:
593
594   \snippet code/src_gui_widgets_qdatetimeedit.cpp 6
595
596   If either \a min or \a max are not valid, this function does
597   nothing.
598
599   \sa setMinimumDate(), maximumDate(), setMaximumDate(),
600   clearMinimumDate(), setMinimumTime(), maximumTime(),
601   setMaximumTime(), clearMinimumTime(), QTime::isValid()
602 */
603
604 void QDateTimeEdit::setTimeRange(const QTime &min, const QTime &max)
605 {
606     Q_D(QDateTimeEdit);
607     if (min.isValid() && max.isValid()) {
608         setDateTimeRange(QDateTime(d->minimum.toDate(), min, d->spec),
609                          QDateTime(d->maximum.toDate(), max, d->spec));
610     }
611 }
612
613 /*!
614   \property QDateTimeEdit::displayedSections
615
616   \brief the currently displayed fields of the date time edit
617
618   Returns a bit set of the displayed sections for this format.
619   \a setDisplayFormat(), displayFormat()
620 */
621
622 QDateTimeEdit::Sections QDateTimeEdit::displayedSections() const
623 {
624     Q_D(const QDateTimeEdit);
625     return d->sections;
626 }
627
628 /*!
629   \property QDateTimeEdit::currentSection
630
631   \brief the current section of the spinbox
632   \a setCurrentSection()
633 */
634
635 QDateTimeEdit::Section QDateTimeEdit::currentSection() const
636 {
637     Q_D(const QDateTimeEdit);
638 #ifdef QT_KEYPAD_NAVIGATION
639     if (QApplication::keypadNavigationEnabled() && d->focusOnButton)
640         return NoSection;
641 #endif
642     return d->convertToPublic(d->sectionType(d->currentSectionIndex));
643 }
644
645 void QDateTimeEdit::setCurrentSection(Section section)
646 {
647     Q_D(QDateTimeEdit);
648     if (section == NoSection || !(section & d->sections))
649         return;
650
651     d->updateCache(d->value, d->displayText());
652     const int size = d->sectionNodes.size();
653     int index = d->currentSectionIndex + 1;
654     for (int i=0; i<2; ++i) {
655         while (index < size) {
656             if (d->convertToPublic(d->sectionType(index)) == section) {
657                 d->edit->setCursorPosition(d->sectionPos(index));
658                 QDTEDEBUG << d->sectionPos(index);
659                 return;
660             }
661             ++index;
662         }
663         index = 0;
664     }
665 }
666
667 /*!
668   \since 4.3
669
670   Returns the Section at \a index.
671
672   If the format is 'yyyy/MM/dd', sectionAt(0) returns YearSection,
673   sectionAt(1) returns MonthSection, and sectionAt(2) returns
674   YearSection,
675 */
676
677 QDateTimeEdit::Section QDateTimeEdit::sectionAt(int index) const
678 {
679     Q_D(const QDateTimeEdit);
680     if (index < 0 || index >= d->sectionNodes.size())
681         return NoSection;
682     return d->convertToPublic(d->sectionType(index));
683 }
684
685 /*!
686   \since 4.3
687
688   \property QDateTimeEdit::sectionCount
689
690   \brief the number of sections displayed.
691   If the format is 'yyyy/yy/yyyy', sectionCount returns 3
692 */
693
694 int QDateTimeEdit::sectionCount() const
695 {
696     Q_D(const QDateTimeEdit);
697     return d->sectionNodes.size();
698 }
699
700
701 /*!
702   \since 4.3
703
704   \property QDateTimeEdit::currentSectionIndex
705
706   \brief the current section index of the spinbox
707
708   If the format is 'yyyy/MM/dd', the displayText is '2001/05/21' and
709   the cursorPosition is 5 currentSectionIndex returns 1. If the
710   cursorPosition is 3 currentSectionIndex is 0 etc.
711
712   \a setCurrentSection()
713   \sa currentSection()
714 */
715
716 int QDateTimeEdit::currentSectionIndex() const
717 {
718     Q_D(const QDateTimeEdit);
719     return d->currentSectionIndex;
720 }
721
722 void QDateTimeEdit::setCurrentSectionIndex(int index)
723 {
724     Q_D(QDateTimeEdit);
725     if (index < 0 || index >= d->sectionNodes.size())
726         return;
727     d->edit->setCursorPosition(d->sectionPos(index));
728 }
729
730 /*!
731   \since 4.4
732
733   \brief Returns the calendar widget for the editor if calendarPopup is
734   set to true and (sections() & DateSections_Mask) != 0.
735
736   This function creates and returns a calendar widget if none has been set.
737 */
738
739
740 QCalendarWidget *QDateTimeEdit::calendarWidget() const
741 {
742     Q_D(const QDateTimeEdit);
743     if (!d->calendarPopup || !(d->sections & QDateTimeParser::DateSectionMask))
744         return 0;
745     if (!d->monthCalendar) {
746         const_cast<QDateTimeEditPrivate*>(d)->initCalendarPopup();
747     }
748     return d->monthCalendar->calendarWidget();
749 }
750
751 /*!
752   \since 4.4
753
754   Sets the given \a calendarWidget as the widget to be used for the calendar
755   pop-up. The editor does not automatically take ownership of the calendar widget.
756
757   \note calendarPopup must be set to true before setting the calendar widget.
758   \sa calendarPopup
759 */
760 void QDateTimeEdit::setCalendarWidget(QCalendarWidget *calendarWidget)
761 {
762     Q_D(QDateTimeEdit);
763     if (!calendarWidget) {
764         qWarning("QDateTimeEdit::setCalendarWidget: Cannot set a null calendar widget");
765         return;
766     }
767
768     if (!d->calendarPopup) {
769         qWarning("QDateTimeEdit::setCalendarWidget: calendarPopup is set to false");
770         return;
771     }
772
773     if (!(d->display & QDateTimeParser::DateSectionMask)) {
774         qWarning("QDateTimeEdit::setCalendarWidget: no date sections specified");
775         return;
776     }
777     d->initCalendarPopup(calendarWidget);
778 }
779
780
781 /*!
782   \since 4.2
783
784   Selects \a section. If \a section doesn't exist in the currently
785   displayed sections this function does nothing. If \a section is
786   NoSection this function will unselect all text in the editor.
787   Otherwise this function will move the cursor and the current section
788   to the selected section.
789
790   \sa currentSection()
791 */
792
793 void QDateTimeEdit::setSelectedSection(Section section)
794 {
795     Q_D(QDateTimeEdit);
796     if (section == NoSection) {
797         d->edit->setSelection(d->edit->cursorPosition(), 0);
798     } else if (section & d->sections) {
799         if (currentSection() != section)
800             setCurrentSection(section);
801         d->setSelected(d->currentSectionIndex);
802     }
803 }
804
805
806
807 /*!
808   \fn QString QDateTimeEdit::sectionText(Section section) const
809
810   Returns the text from the given \a section.
811
812   \sa currentSection()
813 */
814
815 QString QDateTimeEdit::sectionText(Section section) const
816 {
817     Q_D(const QDateTimeEdit);
818     if (section == QDateTimeEdit::NoSection || !(section & d->sections)) {
819         return QString();
820     }
821
822     d->updateCache(d->value, d->displayText());
823     const int sectionIndex = d->absoluteIndex(section, 0);
824     return d->sectionText(sectionIndex);
825 }
826
827 /*!
828   \property QDateTimeEdit::displayFormat
829
830   \brief the format used to display the time/date of the date time edit
831
832   This format is the same as the one used described in QDateTime::toString()
833   and QDateTime::fromString()
834
835   Example format strings (assuming that the date is 2nd of July 1969):
836
837   \table
838   \header \li Format \li Result
839   \row \li dd.MM.yyyy \li 02.07.1969
840   \row \li MMM d yy \li Jul 2 69
841   \row \li MMMM d yy \li July 2 69
842   \endtable
843
844   Note that if you specify a two digit year, it will be interpreted
845   to be in the century in which the date time edit was initialized.
846   The default century is the 21 (2000-2099).
847
848   If you specify an invalid format the format will not be set.
849
850   \sa QDateTime::toString(), displayedSections()
851 */
852
853 QString QDateTimeEdit::displayFormat() const
854 {
855     Q_D(const QDateTimeEdit);
856     return isRightToLeft() ? d->unreversedFormat : d->displayFormat;
857 }
858
859 template<typename C> static inline C reverse(const C &l)
860 {
861     C ret;
862     for (int i=l.size() - 1; i>=0; --i)
863         ret.append(l.at(i));
864     return ret;
865 }
866
867 void QDateTimeEdit::setDisplayFormat(const QString &format)
868 {
869     Q_D(QDateTimeEdit);
870     if (d->parseFormat(format)) {
871         d->unreversedFormat.clear();
872         if (isRightToLeft()) {
873             d->unreversedFormat = format;
874             d->displayFormat.clear();
875             for (int i=d->sectionNodes.size() - 1; i>=0; --i) {
876                 d->displayFormat += d->separators.at(i + 1);
877                 d->displayFormat += d->sectionFormat(i);
878             }
879             d->displayFormat += d->separators.at(0);
880             d->separators = reverse(d->separators);
881             d->sectionNodes = reverse(d->sectionNodes);
882         }
883
884         d->formatExplicitlySet = true;
885         d->sections = d->convertSections(d->display);
886         d->clearCache();
887
888         d->currentSectionIndex = qMin(d->currentSectionIndex, d->sectionNodes.size() - 1);
889         const bool timeShown = (d->sections & TimeSections_Mask);
890         const bool dateShown = (d->sections & DateSections_Mask);
891         Q_ASSERT(dateShown || timeShown);
892         if (timeShown && !dateShown) {
893             QTime time = d->value.toTime();
894             setDateRange(d->value.toDate(), d->value.toDate());
895             if (d->minimum.toTime() >= d->maximum.toTime()) {
896                 setTimeRange(QDATETIMEEDIT_TIME_MIN, QDATETIMEEDIT_TIME_MAX);
897                 // if the time range became invalid during the adjustment, the time would have been reset
898                 setTime(time);
899             }
900         } else if (dateShown && !timeShown) {
901             setTimeRange(QDATETIMEEDIT_TIME_MIN, QDATETIMEEDIT_TIME_MAX);
902             d->value = QDateTime(d->value.toDate(), QTime(), d->spec);
903         }
904         d->updateEdit();
905         d->_q_editorCursorPositionChanged(-1, 0);
906     }
907 }
908
909 /*!
910     \property QDateTimeEdit::calendarPopup
911     \brief the current calendar pop-up showing mode.
912     \since 4.2
913
914     The calendar pop-up will be shown upon clicking the arrow button.
915     This property is valid only if there is a valid date display format.
916
917     \sa setDisplayFormat()
918 */
919
920 bool QDateTimeEdit::calendarPopup() const
921 {
922     Q_D(const QDateTimeEdit);
923     return d->calendarPopup;
924 }
925
926 void QDateTimeEdit::setCalendarPopup(bool enable)
927 {
928     Q_D(QDateTimeEdit);
929     if (enable == d->calendarPopup)
930         return;
931     setAttribute(Qt::WA_MacShowFocusRect, !enable);
932     d->calendarPopup = enable;
933 #ifdef QT_KEYPAD_NAVIGATION
934     if (!enable)
935         d->focusOnButton = false;
936 #endif
937     d->updateEditFieldGeometry();
938     update();
939 }
940
941 /*!
942     \property QDateTimeEdit::timeSpec
943     \brief the current timespec used by the date time edit.
944     \since 4.4
945 */
946
947 Qt::TimeSpec QDateTimeEdit::timeSpec() const
948 {
949     Q_D(const QDateTimeEdit);
950     return d->spec;
951 }
952
953 void QDateTimeEdit::setTimeSpec(Qt::TimeSpec spec)
954 {
955     Q_D(QDateTimeEdit);
956     if (spec != d->spec) {
957         d->spec = spec;
958         d->updateTimeSpec();
959     }
960 }
961
962 /*!
963   \reimp
964 */
965
966 QSize QDateTimeEdit::sizeHint() const
967 {
968     Q_D(const QDateTimeEdit);
969     if (d->cachedSizeHint.isEmpty()) {
970         ensurePolished();
971
972         const QFontMetrics fm(fontMetrics());
973         int h = d->edit->sizeHint().height();
974         int w = 0;
975         QString s;
976         s = d->textFromValue(d->minimum) + QLatin1String("   ");
977         w = qMax<int>(w, fm.width(s));
978         s = d->textFromValue(d->maximum) + QLatin1String("   ");
979         w = qMax<int>(w, fm.width(s));
980         if (d->specialValueText.size()) {
981             s = d->specialValueText;
982             w = qMax<int>(w, fm.width(s));
983         }
984         w += 2; // cursor blinking space
985
986         QSize hint(w, h);
987
988 #ifdef Q_WS_MAC
989         if (d->calendarPopupEnabled()) {
990             QStyleOptionComboBox opt;
991             d->cachedSizeHint = style()->sizeFromContents(QStyle::CT_ComboBox, &opt, hint, this);
992         } else {
993 #else
994         {
995 #endif
996             QSize extra(35, 6);
997             QStyleOptionSpinBox opt;
998             initStyleOption(&opt);
999             opt.rect.setSize(hint + extra);
1000             extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
1001                                                 QStyle::SC_SpinBoxEditField, this).size();
1002             // get closer to final result by repeating the calculation
1003             opt.rect.setSize(hint + extra);
1004             extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
1005                                                 QStyle::SC_SpinBoxEditField, this).size();
1006             hint += extra;
1007
1008             opt.rect = rect();
1009             d->cachedSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this)
1010                                 .expandedTo(QApplication::globalStrut());
1011         }
1012
1013         d->cachedMinimumSizeHint = d->cachedSizeHint;
1014         // essentially make minimumSizeHint return the same as sizeHint for datetimeedits
1015     }
1016     return d->cachedSizeHint;
1017 }
1018
1019 /*!
1020   \reimp
1021 */
1022
1023 bool QDateTimeEdit::event(QEvent *event)
1024 {
1025     Q_D(QDateTimeEdit);
1026     switch (event->type()) {
1027     case QEvent::ApplicationLayoutDirectionChange: {
1028         const bool was = d->formatExplicitlySet;
1029         const QString oldFormat = d->displayFormat;
1030         d->displayFormat.clear();
1031         setDisplayFormat(oldFormat);
1032         d->formatExplicitlySet = was;
1033         break; }
1034     case QEvent::LocaleChange:
1035         d->updateEdit();
1036         break;
1037     case QEvent::StyleChange:
1038 #ifdef Q_WS_MAC
1039     case QEvent::MacSizeChange:
1040 #endif
1041         d->setLayoutItemMargins(QStyle::SE_DateTimeEditLayoutItem);
1042         break;
1043     default:
1044         break;
1045     }
1046     return QAbstractSpinBox::event(event);
1047 }
1048
1049 /*!
1050   \reimp
1051 */
1052
1053 void QDateTimeEdit::clear()
1054 {
1055     Q_D(QDateTimeEdit);
1056     d->clearSection(d->currentSectionIndex);
1057 }
1058 /*!
1059   \reimp
1060 */
1061
1062 void QDateTimeEdit::keyPressEvent(QKeyEvent *event)
1063 {
1064     Q_D(QDateTimeEdit);
1065     int oldCurrent = d->currentSectionIndex;
1066     bool select = true;
1067     bool inserted = false;
1068
1069     switch (event->key()) {
1070 #ifdef QT_KEYPAD_NAVIGATION
1071     case Qt::Key_NumberSign:    //shortcut to popup calendar
1072         if (QApplication::keypadNavigationEnabled() && d->calendarPopupEnabled()) {
1073             d->initCalendarPopup();
1074             d->positionCalendarPopup();
1075             d->monthCalendar->show();
1076             return;
1077         }
1078         break;
1079     case Qt::Key_Select:
1080         if (QApplication::keypadNavigationEnabled()) {
1081             if (hasEditFocus()) {
1082                 if (d->focusOnButton) {
1083                     d->initCalendarPopup();
1084                     d->positionCalendarPopup();
1085                     d->monthCalendar->show();
1086                     d->focusOnButton = false;
1087                     return;
1088                 }
1089                 setEditFocus(false);
1090                 selectAll();
1091             } else {
1092                 setEditFocus(true);
1093
1094                 //hide cursor
1095                 d->edit->d_func()->setCursorVisible(false);
1096                 d->edit->d_func()->control->setCursorBlinkPeriod(0);
1097                 d->setSelected(0);
1098             }
1099         }
1100         return;
1101 #endif
1102     case Qt::Key_Enter:
1103     case Qt::Key_Return:
1104         d->interpret(AlwaysEmit);
1105         d->setSelected(d->currentSectionIndex, true);
1106         event->ignore();
1107         emit editingFinished();
1108         return;
1109     default:
1110 #ifdef QT_KEYPAD_NAVIGATION
1111         if (QApplication::keypadNavigationEnabled() && !hasEditFocus()
1112             && !event->text().isEmpty() && event->text().at(0).isLetterOrNumber()) {
1113             setEditFocus(true);
1114
1115             //hide cursor
1116             d->edit->d_func()->setCursorVisible(false);
1117             d->edit->d_func()->control->setCursorBlinkPeriod(0);
1118             d->setSelected(0);
1119             oldCurrent = 0;
1120         }
1121 #endif
1122         if (!d->isSeparatorKey(event)) {
1123             inserted = select = !event->text().isEmpty() && event->text().at(0).isPrint()
1124                        && !(event->modifiers() & ~(Qt::ShiftModifier|Qt::KeypadModifier));
1125             break;
1126         }
1127     case Qt::Key_Left:
1128     case Qt::Key_Right:
1129         if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) {
1130             if (
1131 #ifdef QT_KEYPAD_NAVIGATION
1132                 QApplication::keypadNavigationEnabled() && !hasEditFocus()
1133                 || !QApplication::keypadNavigationEnabled() &&
1134 #endif
1135                 !(event->modifiers() & Qt::ControlModifier)) {
1136                 select = false;
1137                 break;
1138             }
1139 #ifdef Q_WS_MAC
1140             else
1141 #ifdef QT_KEYPAD_NAVIGATION
1142                 if (!QApplication::keypadNavigationEnabled())
1143 #endif
1144             {
1145                 select = (event->modifiers() & Qt::ShiftModifier);
1146                 break;
1147             }
1148 #endif
1149         }
1150         // else fall through
1151     case Qt::Key_Backtab:
1152     case Qt::Key_Tab: {
1153         event->accept();
1154         if (d->specialValue()) {
1155             d->edit->setSelection(d->edit->cursorPosition(), 0);
1156             return;
1157         }
1158         const bool forward = event->key() != Qt::Key_Left && event->key() != Qt::Key_Backtab
1159                              && (event->key() != Qt::Key_Tab || !(event->modifiers() & Qt::ShiftModifier));
1160 #ifdef QT_KEYPAD_NAVIGATION
1161         int newSection = d->nextPrevSection(d->currentSectionIndex, forward);
1162         if (QApplication::keypadNavigationEnabled()) {
1163             if (d->focusOnButton) {
1164                 newSection = forward ? 0 : d->sectionNodes.size() - 1;
1165                 d->focusOnButton = false;
1166                 update();
1167             } else if (newSection < 0 && select && d->calendarPopupEnabled()) {
1168                 setSelectedSection(NoSection);
1169                 d->focusOnButton = true;
1170                 update();
1171                 return;
1172             }
1173         }
1174         // only allow date/time sections to be selected.
1175         if (newSection & ~(QDateTimeParser::TimeSectionMask | QDateTimeParser::DateSectionMask))
1176             return;
1177 #endif
1178         //key tab and backtab will be managed thrgout QWidget::event
1179         if (event->key() != Qt::Key_Backtab && event->key() != Qt::Key_Tab)
1180             focusNextPrevChild(forward);
1181
1182         return; }
1183     }
1184     QAbstractSpinBox::keyPressEvent(event);
1185     if (select && !d->edit->hasSelectedText()) {
1186         if (inserted && d->sectionAt(d->edit->cursorPosition()) == QDateTimeParser::NoSectionIndex) {
1187             QString str = d->displayText();
1188             int pos = d->edit->cursorPosition();
1189             if (validate(str, pos) == QValidator::Acceptable
1190                 && (d->sectionNodes.at(oldCurrent).count != 1
1191                     || d->sectionMaxSize(oldCurrent) == d->sectionSize(oldCurrent)
1192                     || d->skipToNextSection(oldCurrent, d->value.toDateTime(), d->sectionText(oldCurrent)))) {
1193                 QDTEDEBUG << "Setting currentsection to"
1194                           << d->closestSection(d->edit->cursorPosition(), true) << event->key()
1195                           << oldCurrent << str;
1196                 const int tmp = d->closestSection(d->edit->cursorPosition(), true);
1197                 if (tmp >= 0)
1198                     d->currentSectionIndex = tmp;
1199             }
1200         }
1201         if (d->currentSectionIndex != oldCurrent) {
1202             d->setSelected(d->currentSectionIndex);
1203         }
1204     }
1205     if (d->specialValue()) {
1206         d->edit->setSelection(d->edit->cursorPosition(), 0);
1207     }
1208 }
1209
1210 /*!
1211   \reimp
1212 */
1213
1214 #ifndef QT_NO_WHEELEVENT
1215 void QDateTimeEdit::wheelEvent(QWheelEvent *event)
1216 {
1217     QAbstractSpinBox::wheelEvent(event);
1218 }
1219 #endif
1220
1221 /*!
1222   \reimp
1223 */
1224
1225 void QDateTimeEdit::focusInEvent(QFocusEvent *event)
1226 {
1227     Q_D(QDateTimeEdit);
1228     QAbstractSpinBox::focusInEvent(event);
1229     QString *frm = 0;
1230     const int oldPos = d->edit->cursorPosition();
1231     if (!d->formatExplicitlySet) {
1232         if (d->displayFormat == d->defaultTimeFormat) {
1233             frm = &d->defaultTimeFormat;
1234         } else if (d->displayFormat == d->defaultDateFormat) {
1235             frm = &d->defaultDateFormat;
1236         } else if (d->displayFormat == d->defaultDateTimeFormat) {
1237             frm = &d->defaultDateTimeFormat;
1238         }
1239
1240         if (frm) {
1241             d->readLocaleSettings();
1242             if (d->displayFormat != *frm) {
1243                 setDisplayFormat(*frm);
1244                 d->formatExplicitlySet = false;
1245                 d->edit->setCursorPosition(oldPos);
1246             }
1247         }
1248     }
1249     const bool oldHasHadFocus = d->hasHadFocus;
1250     d->hasHadFocus = true;
1251     bool first = true;
1252     switch (event->reason()) {
1253     case Qt::BacktabFocusReason:
1254         first = false;
1255         break;
1256     case Qt::MouseFocusReason:
1257     case Qt::PopupFocusReason:
1258         return;
1259     case Qt::ActiveWindowFocusReason:
1260         if (oldHasHadFocus)
1261             return;
1262     case Qt::ShortcutFocusReason:
1263     case Qt::TabFocusReason:
1264     default:
1265         break;
1266     }
1267     if (isRightToLeft())
1268         first = !first;
1269     d->updateEdit(); // needed to make it update specialValueText
1270
1271     d->setSelected(first ? 0 : d->sectionNodes.size() - 1);
1272 }
1273
1274 /*!
1275   \reimp
1276 */
1277
1278 bool QDateTimeEdit::focusNextPrevChild(bool next)
1279 {
1280     Q_D(QDateTimeEdit);
1281     const int newSection = d->nextPrevSection(d->currentSectionIndex, next);
1282     switch (d->sectionType(newSection)) {
1283     case QDateTimeParser::NoSection:
1284     case QDateTimeParser::FirstSection:
1285     case QDateTimeParser::LastSection:
1286         return QAbstractSpinBox::focusNextPrevChild(next);
1287     default:
1288         d->edit->deselect();
1289         d->edit->setCursorPosition(d->sectionPos(newSection));
1290         QDTEDEBUG << d->sectionPos(newSection);
1291         d->setSelected(newSection, true);
1292         return false;
1293     }
1294 }
1295
1296 /*!
1297   \reimp
1298 */
1299
1300 void QDateTimeEdit::stepBy(int steps)
1301 {
1302     Q_D(QDateTimeEdit);
1303 #ifdef QT_KEYPAD_NAVIGATION
1304     // with keypad navigation and not editFocus, left right change the date/time by a fixed amount.
1305     if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
1306         // if date based, shift by day.  else shift by 15min
1307         if (d->sections & DateSections_Mask) {
1308             setDateTime(dateTime().addDays(steps));
1309         } else {
1310             int minutes = time().hour()*60 + time().minute();
1311             int blocks = minutes/15;
1312             blocks += steps;
1313             /* rounding involved */
1314             if (minutes % 15) {
1315                 if (steps < 0) {
1316                     blocks += 1; // do one less step;
1317                 }
1318             }
1319
1320             minutes = blocks * 15;
1321
1322             /* need to take wrapping into account */
1323             if (!d->wrapping) {
1324                 int max_minutes = d->maximum.toTime().hour()*60 + d->maximum.toTime().minute();
1325                 int min_minutes = d->minimum.toTime().hour()*60 + d->minimum.toTime().minute();
1326
1327                 if (minutes >= max_minutes) {
1328                     setTime(maximumTime());
1329                     return;
1330                 } else if (minutes <= min_minutes) {
1331                     setTime(minimumTime());
1332                     return;
1333                 }
1334             }
1335             setTime(QTime(minutes/60, minutes%60));
1336         }
1337         return;
1338     }
1339 #endif
1340     // don't optimize away steps == 0. This is the only way to select
1341     // the currentSection in Qt 4.1.x
1342     if (d->specialValue() && displayedSections() != AmPmSection) {
1343         for (int i=0; i<d->sectionNodes.size(); ++i) {
1344             if (d->sectionType(i) != QDateTimeParser::AmPmSection) {
1345                 d->currentSectionIndex = i;
1346                 break;
1347             }
1348         }
1349     }
1350     d->setValue(d->stepBy(d->currentSectionIndex, steps, false), EmitIfChanged);
1351     d->updateCache(d->value, d->displayText());
1352
1353     d->setSelected(d->currentSectionIndex);
1354     d->updateTimeSpec();
1355 }
1356
1357 /*!
1358   This virtual function is used by the date time edit whenever it
1359   needs to display \a dateTime.
1360
1361   If you reimplement this, you may also need to reimplement validate().
1362
1363   \sa dateTimeFromText(), validate()
1364 */
1365 QString QDateTimeEdit::textFromDateTime(const QDateTime &dateTime) const
1366 {
1367     Q_D(const QDateTimeEdit);
1368     return locale().toString(dateTime, d->displayFormat);
1369 }
1370
1371
1372 /*!
1373   Returns an appropriate datetime for the given \a text.
1374
1375   This virtual function is used by the datetime edit whenever it
1376   needs to interpret text entered by the user as a value.
1377
1378   \sa textFromDateTime(), validate()
1379 */
1380 QDateTime QDateTimeEdit::dateTimeFromText(const QString &text) const
1381 {
1382     Q_D(const QDateTimeEdit);
1383     QString copy = text;
1384     int pos = d->edit->cursorPosition();
1385     QValidator::State state = QValidator::Acceptable;
1386     return d->validateAndInterpret(copy, pos, state);
1387 }
1388
1389 /*!
1390   \reimp
1391 */
1392
1393 QValidator::State QDateTimeEdit::validate(QString &text, int &pos) const
1394 {
1395     Q_D(const QDateTimeEdit);
1396     QValidator::State state;
1397     d->validateAndInterpret(text, pos, state);
1398     return state;
1399 }
1400
1401 /*!
1402   \reimp
1403 */
1404
1405
1406 void QDateTimeEdit::fixup(QString &input) const
1407 {
1408     Q_D(const QDateTimeEdit);
1409     QValidator::State state;
1410     int copy = d->edit->cursorPosition();
1411
1412     d->validateAndInterpret(input, copy, state, true);
1413 }
1414
1415
1416 /*!
1417   \reimp
1418 */
1419
1420 QDateTimeEdit::StepEnabled QDateTimeEdit::stepEnabled() const
1421 {
1422     Q_D(const QDateTimeEdit);
1423     if (d->readOnly)
1424         return StepEnabled(0);
1425     if (d->specialValue()) {
1426         return (d->minimum == d->maximum ? StepEnabled(0) : StepEnabled(StepUpEnabled));
1427     }
1428
1429     QAbstractSpinBox::StepEnabled ret = 0;
1430
1431 #ifdef QT_KEYPAD_NAVIGATION
1432     if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
1433         if (d->wrapping)
1434             return StepEnabled(StepUpEnabled | StepDownEnabled);
1435         // 3 cases.  date, time, datetime.  each case look
1436         // at just the relavant component.
1437         QVariant max, min, val;
1438         if (!(d->sections & DateSections_Mask)) {
1439             // time only, no date
1440             max = d->maximum.toTime();
1441             min = d->minimum.toTime();
1442             val = d->value.toTime();
1443         } else if (!(d->sections & TimeSections_Mask)) {
1444             // date only, no time
1445             max = d->maximum.toDate();
1446             min = d->minimum.toDate();
1447             val = d->value.toDate();
1448         } else {
1449             // both
1450             max = d->maximum;
1451             min = d->minimum;
1452             val = d->value;
1453         }
1454         if (val != min)
1455             ret |= QAbstractSpinBox::StepDownEnabled;
1456         if (val != max)
1457             ret |= QAbstractSpinBox::StepUpEnabled;
1458         return ret;
1459     }
1460 #endif
1461     switch (d->sectionType(d->currentSectionIndex)) {
1462     case QDateTimeParser::NoSection:
1463     case QDateTimeParser::FirstSection:
1464     case QDateTimeParser::LastSection: return 0;
1465     default: break;
1466     }
1467     if (d->wrapping)
1468         return StepEnabled(StepDownEnabled|StepUpEnabled);
1469
1470     QVariant v = d->stepBy(d->currentSectionIndex, 1, true);
1471     if (v != d->value) {
1472         ret |= QAbstractSpinBox::StepUpEnabled;
1473     }
1474     v = d->stepBy(d->currentSectionIndex, -1, true);
1475     if (v != d->value) {
1476         ret |= QAbstractSpinBox::StepDownEnabled;
1477     }
1478
1479     return ret;
1480 }
1481
1482
1483 /*!
1484   \reimp
1485 */
1486
1487 void QDateTimeEdit::mousePressEvent(QMouseEvent *event)
1488 {
1489     Q_D(QDateTimeEdit);
1490     if (!d->calendarPopupEnabled()) {
1491         QAbstractSpinBox::mousePressEvent(event);
1492         return;
1493     }
1494     d->updateHoverControl(event->pos());
1495     if (d->hoverControl == QStyle::SC_ComboBoxArrow) {
1496         event->accept();
1497         if (d->readOnly) {
1498             return;
1499         }
1500         d->updateArrow(QStyle::State_Sunken);
1501         d->initCalendarPopup();
1502         d->positionCalendarPopup();
1503         //Show the calendar
1504         d->monthCalendar->show();
1505     } else {
1506         QAbstractSpinBox::mousePressEvent(event);
1507     }
1508 }
1509
1510 /*!
1511   \class QTimeEdit
1512   \brief The QTimeEdit class provides a widget for editing times based on
1513   the QDateTimeEdit widget.
1514
1515   \ingroup basicwidgets
1516   \inmodule QtWidgets
1517
1518   Many of the properties and functions provided by QTimeEdit are implemented in
1519   QDateTimeEdit. The following properties are most relevant to users of this
1520   class:
1521
1522   \list
1523   \li \l{QDateTimeEdit::time}{time} holds the date displayed by the widget.
1524   \li \l{QDateTimeEdit::minimumTime}{minimumTime} defines the minimum (earliest) time
1525      that can be set by the user.
1526   \li \l{QDateTimeEdit::maximumTime}{maximumTime} defines the maximum (latest) time
1527      that can be set by the user.
1528   \li \l{QDateTimeEdit::displayFormat}{displayFormat} contains a string that is used
1529      to format the time displayed in the widget.
1530   \endlist
1531
1532   \table 100%
1533   \row \li \inlineimage windowsxp-timeedit.png Screenshot of a Windows XP style time editing widget
1534        \li A time editing widget shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
1535   \row \li \inlineimage macintosh-timeedit.png Screenshot of a Macintosh style time editing widget
1536        \li A time editing widget shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
1537   \row \li \inlineimage plastique-timeedit.png Screenshot of a Plastique style time editing widget
1538        \li A time editing widget shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
1539   \endtable
1540
1541   \sa QDateEdit, QDateTimeEdit
1542 */
1543
1544 /*!
1545   Constructs an empty time editor with a \a parent.
1546 */
1547
1548
1549 QTimeEdit::QTimeEdit(QWidget *parent)
1550     : QDateTimeEdit(QDATETIMEEDIT_TIME_MIN, QVariant::Time, parent)
1551 {
1552     connect(this, SIGNAL(timeChanged(QTime)), SIGNAL(userTimeChanged(QTime)));
1553 }
1554
1555 /*!
1556   Constructs an empty time editor with a \a parent. The time is set
1557   to \a time.
1558 */
1559
1560 QTimeEdit::QTimeEdit(const QTime &time, QWidget *parent)
1561     : QDateTimeEdit(time, QVariant::Time, parent)
1562 {
1563 }
1564
1565 /*!
1566   \property QTimeEdit::time
1567   \internal
1568   \sa QDateTimeEdit::time
1569 */
1570
1571 /*!
1572   \fn void QTimeEdit::userTimeChanged(const QTime &time)
1573
1574   This signal only exists to fully implement the time Q_PROPERTY on the class.
1575   Normally timeChanged should be used instead.
1576
1577   \internal
1578 */
1579
1580
1581 /*!
1582   \class QDateEdit
1583   \brief The QDateEdit class provides a widget for editing dates based on
1584   the QDateTimeEdit widget.
1585
1586   \ingroup basicwidgets
1587   \inmodule QtWidgets
1588
1589   Many of the properties and functions provided by QDateEdit are implemented in
1590   QDateTimeEdit. The following properties are most relevant to users of this
1591   class:
1592
1593   \list
1594   \li \l{QDateTimeEdit::date}{date} holds the date displayed by the widget.
1595   \li \l{QDateTimeEdit::minimumDate}{minimumDate} defines the minimum (earliest)
1596      date that can be set by the user.
1597   \li \l{QDateTimeEdit::maximumDate}{maximumDate} defines the maximum (latest) date
1598      that can be set by the user.
1599   \li \l{QDateTimeEdit::displayFormat}{displayFormat} contains a string that is used
1600      to format the date displayed in the widget.
1601   \endlist
1602
1603   \table 100%
1604   \row \li \inlineimage windowsxp-dateedit.png Screenshot of a Windows XP style date editing widget
1605        \li A date editing widget shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
1606   \row \li \inlineimage macintosh-dateedit.png Screenshot of a Macintosh style date editing widget
1607        \li A date editing widget shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
1608   \row \li \inlineimage plastique-dateedit.png Screenshot of a Plastique style date editing widget
1609        \li A date editing widget shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
1610   \endtable
1611
1612   \sa QTimeEdit, QDateTimeEdit
1613 */
1614
1615 /*!
1616   Constructs an empty date editor with a \a parent.
1617 */
1618
1619 QDateEdit::QDateEdit(QWidget *parent)
1620     : QDateTimeEdit(QDATETIMEEDIT_DATE_INITIAL, QVariant::Date, parent)
1621 {
1622     connect(this, SIGNAL(dateChanged(QDate)), SIGNAL(userDateChanged(QDate)));
1623 }
1624
1625 /*!
1626   Constructs an empty date editor with a \a parent. The date is set
1627   to \a date.
1628 */
1629
1630 QDateEdit::QDateEdit(const QDate &date, QWidget *parent)
1631     : QDateTimeEdit(date, QVariant::Date, parent)
1632 {
1633 }
1634
1635 /*!
1636   \property QDateEdit::date
1637   \internal
1638   \sa QDateTimeEdit::date
1639 */
1640
1641 /*!
1642   \fn void QDateEdit::userDateChanged(const QDate &date)
1643
1644   This signal only exists to fully implement the date Q_PROPERTY on the class.
1645   Normally dateChanged should be used instead.
1646
1647   \internal
1648 */
1649
1650
1651 // --- QDateTimeEditPrivate ---
1652
1653 /*!
1654   \internal
1655   Constructs a QDateTimeEditPrivate object
1656 */
1657
1658
1659 QDateTimeEditPrivate::QDateTimeEditPrivate()
1660     : QDateTimeParser(QVariant::DateTime, QDateTimeParser::DateTimeEdit)
1661 {
1662     hasHadFocus = false;
1663     formatExplicitlySet = false;
1664     cacheGuard = false;
1665     fixday = true;
1666     type = QVariant::DateTime;
1667     sections = 0;
1668     cachedDay = -1;
1669     currentSectionIndex = FirstSectionIndex;
1670
1671     first.type = FirstSection;
1672     last.type = LastSection;
1673     none.type = NoSection;
1674     first.pos = 0;
1675     last.pos = -1;
1676     none.pos = -1;
1677     sections = 0;
1678     calendarPopup = false;
1679     minimum = QDATETIMEEDIT_COMPAT_DATETIME_MIN;
1680     maximum = QDATETIMEEDIT_DATETIME_MAX;
1681     arrowState = QStyle::State_None;
1682     monthCalendar = 0;
1683     readLocaleSettings();
1684
1685 #ifdef QT_KEYPAD_NAVIGATION
1686     focusOnButton = false;
1687 #endif
1688 }
1689
1690 void QDateTimeEditPrivate::updateTimeSpec()
1691 {
1692     minimum = minimum.toDateTime().toTimeSpec(spec);
1693     maximum = maximum.toDateTime().toTimeSpec(spec);
1694     value = value.toDateTime().toTimeSpec(spec);
1695
1696     // time zone changes can lead to 00:00:00 becomes 01:00:00 and 23:59:59 becomes 00:59:59 (invalid range)
1697     const bool dateShown = (sections & QDateTimeEdit::DateSections_Mask);
1698     if (!dateShown) {
1699         if (minimum.toTime() >= maximum.toTime()){
1700             minimum = QDateTime(value.toDate(), QDATETIMEEDIT_TIME_MIN, spec);
1701             maximum = QDateTime(value.toDate(), QDATETIMEEDIT_TIME_MAX, spec);
1702         }
1703     }
1704 }
1705
1706 void QDateTimeEditPrivate::updateEdit()
1707 {
1708     const QString newText = (specialValue() ? specialValueText : textFromValue(value));
1709     if (newText == displayText())
1710         return;
1711     int selsize = edit->selectedText().size();
1712     const bool sb = edit->blockSignals(true);
1713
1714     edit->setText(newText);
1715
1716     if (!specialValue()
1717 #ifdef QT_KEYPAD_NAVIGATION
1718         && !(QApplication::keypadNavigationEnabled() && !edit->hasEditFocus())
1719 #endif
1720             ) {
1721         int cursor = sectionPos(currentSectionIndex);
1722         QDTEDEBUG << "cursor is " << cursor << currentSectionIndex;
1723         cursor = qBound(0, cursor, displayText().size());
1724         QDTEDEBUG << cursor;
1725         if (selsize > 0) {
1726             edit->setSelection(cursor, selsize);
1727             QDTEDEBUG << cursor << selsize;
1728         } else {
1729             edit->setCursorPosition(cursor);
1730             QDTEDEBUG << cursor;
1731
1732         }
1733     }
1734     edit->blockSignals(sb);
1735 }
1736
1737
1738 /*!
1739   \internal
1740
1741   Selects the section \a s. If \a forward is false selects backwards.
1742 */
1743
1744 void QDateTimeEditPrivate::setSelected(int sectionIndex, bool forward)
1745 {
1746     if (specialValue()
1747 #ifdef QT_KEYPAD_NAVIGATION
1748         || (QApplication::keypadNavigationEnabled() && !edit->hasEditFocus())
1749 #endif
1750         ) {
1751         edit->selectAll();
1752     } else {
1753         const SectionNode &node = sectionNode(sectionIndex);
1754         if (node.type == NoSection || node.type == LastSection || node.type == FirstSection)
1755             return;
1756
1757         updateCache(value, displayText());
1758         const int size = sectionSize(sectionIndex);
1759         if (forward) {
1760             edit->setSelection(sectionPos(node), size);
1761         } else {
1762             edit->setSelection(sectionPos(node) + size, -size);
1763         }
1764     }
1765 }
1766
1767 /*!
1768   \internal
1769
1770   Returns the section at index \a index or NoSection if there are no sections there.
1771 */
1772
1773 int QDateTimeEditPrivate::sectionAt(int pos) const
1774 {
1775     if (pos < separators.first().size()) {
1776         return (pos == 0 ? FirstSectionIndex : NoSectionIndex);
1777     } else if (displayText().size() - pos < separators.last().size() + 1) {
1778         if (separators.last().size() == 0) {
1779             return sectionNodes.count() - 1;
1780         }
1781         return (pos == displayText().size() ? LastSectionIndex : NoSectionIndex);
1782     }
1783     updateCache(value, displayText());
1784
1785     for (int i=0; i<sectionNodes.size(); ++i) {
1786         const int tmp = sectionPos(i);
1787         if (pos < tmp + sectionSize(i)) {
1788             return (pos < tmp ? -1 : i);
1789         }
1790     }
1791     return -1;
1792 }
1793
1794 /*!
1795   \internal
1796
1797   Returns the closest section of index \a index. Searches forward
1798   for a section if \a forward is true. Otherwise searches backwards.
1799 */
1800
1801 int QDateTimeEditPrivate::closestSection(int pos, bool forward) const
1802 {
1803     Q_ASSERT(pos >= 0);
1804     if (pos < separators.first().size()) {
1805         return forward ? 0 : FirstSectionIndex;
1806     } else if (displayText().size() - pos < separators.last().size() + 1) {
1807         return forward ? LastSectionIndex : sectionNodes.size() - 1;
1808     }
1809     updateCache(value, displayText());
1810     for (int i=0; i<sectionNodes.size(); ++i) {
1811         const int tmp = sectionPos(sectionNodes.at(i));
1812         if (pos < tmp + sectionSize(i)) {
1813             if (pos < tmp && !forward) {
1814                 return i-1;
1815             }
1816             return i;
1817         } else if (i == sectionNodes.size() - 1 && pos > tmp) {
1818             return i;
1819         }
1820     }
1821     qWarning("QDateTimeEdit: Internal Error: closestSection returned NoSection");
1822     return NoSectionIndex;
1823 }
1824
1825 /*!
1826   \internal
1827
1828   Returns a copy of the section that is before or after \a current, depending on \a forward.
1829 */
1830
1831 int QDateTimeEditPrivate::nextPrevSection(int current, bool forward) const
1832 {
1833     Q_Q(const QDateTimeEdit);
1834     if (q->isRightToLeft())
1835         forward = !forward;
1836
1837     switch (current) {
1838     case FirstSectionIndex: return forward ? 0 : FirstSectionIndex;
1839     case LastSectionIndex: return (forward ? LastSectionIndex : sectionNodes.size() - 1);
1840     case NoSectionIndex: return FirstSectionIndex;
1841     default: break;
1842     }
1843     Q_ASSERT(current >= 0 && current < sectionNodes.size());
1844
1845     current += (forward ? 1 : -1);
1846     if (current >= sectionNodes.size()) {
1847         return LastSectionIndex;
1848     } else if (current < 0) {
1849         return FirstSectionIndex;
1850     }
1851
1852     return current;
1853 }
1854
1855 /*!
1856   \internal
1857
1858   Clears the text of section \a s.
1859 */
1860
1861 void QDateTimeEditPrivate::clearSection(int index)
1862 {
1863     const QLatin1Char space(' ');
1864     int cursorPos = edit->cursorPosition();
1865     bool blocked = edit->blockSignals(true);
1866     QString t = edit->text();
1867     const int pos = sectionPos(index);
1868     if (pos == -1) {
1869         qWarning("QDateTimeEdit: Internal error (%s:%d)", __FILE__, __LINE__);
1870         return;
1871     }
1872     const int size = sectionSize(index);
1873     t.replace(pos, size, QString().fill(space, size));
1874     edit->setText(t);
1875     edit->setCursorPosition(cursorPos);
1876     QDTEDEBUG << cursorPos;
1877
1878     edit->blockSignals(blocked);
1879 }
1880
1881
1882 /*!
1883   \internal
1884
1885   updates the cached values
1886 */
1887
1888 void QDateTimeEditPrivate::updateCache(const QVariant &val, const QString &str) const
1889 {
1890     if (val != cachedValue || str != cachedText || cacheGuard) {
1891         cacheGuard = true;
1892         QString copy = str;
1893         int unused = edit->cursorPosition();
1894         QValidator::State unusedState;
1895         validateAndInterpret(copy, unused, unusedState);
1896         cacheGuard = false;
1897     }
1898 }
1899
1900 /*!
1901   \internal
1902
1903   parses and validates \a input
1904 */
1905
1906 QDateTime QDateTimeEditPrivate::validateAndInterpret(QString &input, int &position,
1907                                                      QValidator::State &state, bool fixup) const
1908 {
1909     if (input.isEmpty()) {
1910         if (sectionNodes.size() == 1 || !specialValueText.isEmpty()) {
1911             state = QValidator::Intermediate;
1912         } else {
1913             state = QValidator::Invalid;
1914         }
1915         return getZeroVariant().toDateTime();
1916     } else if (cachedText == input && !fixup) {
1917         state = cachedState;
1918         return cachedValue.toDateTime();
1919     } else if (!specialValueText.isEmpty()) {
1920         bool changeCase = false;
1921         const int max = qMin(specialValueText.size(), input.size());
1922         int i;
1923         for (i=0; i<max; ++i) {
1924             const QChar ic = input.at(i);
1925             const QChar sc = specialValueText.at(i);
1926             if (ic != sc) {
1927                 if (sc.toLower() == ic.toLower()) {
1928                     changeCase = true;
1929                 } else {
1930                     break;
1931                 }
1932             }
1933         }
1934         if (i == max) {
1935             state = specialValueText.size() == input.size() ? QValidator::Acceptable : QValidator::Intermediate;
1936             if (changeCase) {
1937                 input = specialValueText.left(max);
1938             }
1939             return minimum.toDateTime();
1940         }
1941     }
1942     StateNode tmp = parse(input, position, value.toDateTime(), fixup);
1943     input = tmp.input;
1944     state = QValidator::State(int(tmp.state));
1945     if (state == QValidator::Acceptable) {
1946         if (tmp.conflicts && conflictGuard != tmp.value) {
1947             conflictGuard = tmp.value;
1948             clearCache();
1949             input = textFromValue(tmp.value);
1950             updateCache(tmp.value, input);
1951             conflictGuard.clear();
1952         } else {
1953             cachedText = input;
1954             cachedState = state;
1955             cachedValue = tmp.value;
1956         }
1957     } else {
1958         clearCache();
1959     }
1960     return (tmp.value.isNull() ? getZeroVariant().toDateTime() : tmp.value);
1961 }
1962
1963
1964 /*!
1965   \internal
1966 */
1967
1968 QString QDateTimeEditPrivate::textFromValue(const QVariant &f) const
1969 {
1970     Q_Q(const QDateTimeEdit);
1971     return q->textFromDateTime(f.toDateTime());
1972 }
1973
1974 /*!
1975   \internal
1976
1977   This function's name is slightly confusing; it is not to be confused
1978   with QAbstractSpinBox::valueFromText().
1979 */
1980
1981 QVariant QDateTimeEditPrivate::valueFromText(const QString &f) const
1982 {
1983     Q_Q(const QDateTimeEdit);
1984     return q->dateTimeFromText(f).toTimeSpec(spec);
1985 }
1986
1987
1988 /*!
1989   \internal
1990
1991   Internal function called by QDateTimeEdit::stepBy(). Also takes a
1992   Section for which section to step on and a bool \a test for
1993   whether or not to modify the internal cachedDay variable. This is
1994   necessary because the function is called from the const function
1995   QDateTimeEdit::stepEnabled() as well as QDateTimeEdit::stepBy().
1996 */
1997
1998 QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) const
1999 {
2000     Q_Q(const QDateTimeEdit);
2001     QDateTime v = value.toDateTime();
2002     QString str = displayText();
2003     int pos = edit->cursorPosition();
2004     const SectionNode sn = sectionNode(sectionIndex);
2005
2006     int val;
2007     // to make sure it behaves reasonably when typing something and then stepping in non-tracking mode
2008     if (!test && pendingEmit) {
2009         if (q->validate(str, pos) != QValidator::Acceptable) {
2010             v = value.toDateTime();
2011         } else {
2012             v = q->dateTimeFromText(str);
2013         }
2014         val = getDigit(v, sectionIndex);
2015     } else {
2016         val = getDigit(v, sectionIndex);
2017     }
2018
2019     val += steps;
2020
2021     const int min = absoluteMin(sectionIndex);
2022     const int max = absoluteMax(sectionIndex, value.toDateTime());
2023
2024     if (val < min) {
2025         val = (wrapping ? max - (min - val) + 1 : min);
2026     } else if (val > max) {
2027         val = (wrapping ? min + val - max - 1 : max);
2028     }
2029
2030
2031     const int oldDay = v.date().day();
2032
2033     setDigit(v, sectionIndex, val);
2034     // if this sets year or month it will make
2035     // sure that days are lowered if needed.
2036
2037     const QDateTime minimumDateTime = minimum.toDateTime();
2038     const QDateTime maximumDateTime = maximum.toDateTime();
2039     // changing one section should only modify that section, if possible
2040     if (sn.type != AmPmSection && (v < minimumDateTime || v > maximumDateTime)) {
2041         const int localmin = getDigit(minimumDateTime, sectionIndex);
2042         const int localmax = getDigit(maximumDateTime, sectionIndex);
2043
2044         if (wrapping) {
2045             // just because we hit the roof in one direction, it
2046             // doesn't mean that we hit the floor in the other
2047             if (steps > 0) {
2048                 setDigit(v, sectionIndex, min);
2049                 if (!(sn.type & (DaySection|DayOfWeekSectionShort|DayOfWeekSectionLong)) && sections & DateSectionMask) {
2050                     const int daysInMonth = v.date().daysInMonth();
2051                     if (v.date().day() < oldDay && v.date().day() < daysInMonth) {
2052                         const int adds = qMin(oldDay, daysInMonth);
2053                         v = v.addDays(adds - v.date().day());
2054                     }
2055                 }
2056
2057                 if (v < minimumDateTime) {
2058                     setDigit(v, sectionIndex, localmin);
2059                     if (v < minimumDateTime)
2060                         setDigit(v, sectionIndex, localmin + 1);
2061                 }
2062             } else {
2063                 setDigit(v, sectionIndex, max);
2064                 if (!(sn.type & (DaySection|DayOfWeekSectionShort|DayOfWeekSectionLong)) && sections & DateSectionMask) {
2065                     const int daysInMonth = v.date().daysInMonth();
2066                     if (v.date().day() < oldDay && v.date().day() < daysInMonth) {
2067                         const int adds = qMin(oldDay, daysInMonth);
2068                         v = v.addDays(adds - v.date().day());
2069                     }
2070                 }
2071
2072                 if (v > maximumDateTime) {
2073                     setDigit(v, sectionIndex, localmax);
2074                     if (v > maximumDateTime)
2075                         setDigit(v, sectionIndex, localmax - 1);
2076                 }
2077             }
2078         } else {
2079             setDigit(v, sectionIndex, (steps > 0 ? localmax : localmin));
2080         }
2081     }
2082     if (!test && oldDay != v.date().day() && !(sn.type & (DaySection|DayOfWeekSectionShort|DayOfWeekSectionLong))) {
2083         // this should not happen when called from stepEnabled
2084         cachedDay = qMax<int>(oldDay, cachedDay);
2085     }
2086
2087     if (v < minimumDateTime) {
2088         if (wrapping) {
2089             QDateTime t = v;
2090             setDigit(t, sectionIndex, steps < 0 ? max : min);
2091             bool mincmp = (t >= minimumDateTime);
2092             bool maxcmp = (t <= maximumDateTime);
2093             if (!mincmp || !maxcmp) {
2094                 setDigit(t, sectionIndex, getDigit(steps < 0
2095                                                    ? maximumDateTime
2096                                                    : minimumDateTime, sectionIndex));
2097                 mincmp = (t >= minimumDateTime);
2098                 maxcmp = (t <= maximumDateTime);
2099             }
2100             if (mincmp && maxcmp) {
2101                 v = t;
2102             }
2103         } else {
2104             v = value.toDateTime();
2105         }
2106     } else if (v > maximumDateTime) {
2107         if (wrapping) {
2108             QDateTime t = v;
2109             setDigit(t, sectionIndex, steps > 0 ? min : max);
2110             bool mincmp = (t >= minimumDateTime);
2111             bool maxcmp = (t <= maximumDateTime);
2112             if (!mincmp || !maxcmp) {
2113                 setDigit(t, sectionIndex, getDigit(steps > 0 ?
2114                                                    minimumDateTime :
2115                                                    maximumDateTime, sectionIndex));
2116                 mincmp = (t >= minimumDateTime);
2117                 maxcmp = (t <= maximumDateTime);
2118             }
2119             if (mincmp && maxcmp) {
2120                 v = t;
2121             }
2122         } else {
2123             v = value.toDateTime();
2124         }
2125     }
2126
2127     const QDateTime ret = bound(v, value, steps).toDateTime().toTimeSpec(spec);
2128     return ret;
2129 }
2130
2131 /*!
2132   \internal
2133 */
2134
2135 void QDateTimeEditPrivate::emitSignals(EmitPolicy ep, const QVariant &old)
2136 {
2137     Q_Q(QDateTimeEdit);
2138     if (ep == NeverEmit) {
2139         return;
2140     }
2141     pendingEmit = false;
2142
2143     const bool dodate = value.toDate().isValid() && (sections & DateSectionMask);
2144     const bool datechanged = (ep == AlwaysEmit || old.toDate() != value.toDate());
2145     const bool dotime = value.toTime().isValid() && (sections & TimeSectionMask);
2146     const bool timechanged = (ep == AlwaysEmit || old.toTime() != value.toTime());
2147
2148     updateCache(value, displayText());
2149
2150     syncCalendarWidget();
2151     if (datechanged || timechanged)
2152         emit q->dateTimeChanged(value.toDateTime());
2153     if (dodate && datechanged)
2154         emit q->dateChanged(value.toDate());
2155     if (dotime && timechanged)
2156         emit q->timeChanged(value.toTime());
2157
2158 }
2159
2160 /*!
2161   \internal
2162 */
2163
2164 void QDateTimeEditPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos)
2165 {
2166     if (ignoreCursorPositionChanged || specialValue())
2167         return;
2168     const QString oldText = displayText();
2169     updateCache(value, oldText);
2170
2171     const bool allowChange = !edit->hasSelectedText();
2172     const bool forward = oldpos <= newpos;
2173     ignoreCursorPositionChanged = true;
2174     int s = sectionAt(newpos);
2175     if (s == NoSectionIndex && forward && newpos > 0) {
2176         s = sectionAt(newpos - 1);
2177     }
2178
2179     int c = newpos;
2180
2181     const int selstart = edit->selectionStart();
2182     const int selSection = sectionAt(selstart);
2183     const int l = selSection != -1 ? sectionSize(selSection) : 0;
2184
2185     if (s == NoSectionIndex) {
2186         if (l > 0 && selstart == sectionPos(selSection) && edit->selectedText().size() == l) {
2187             s = selSection;
2188             if (allowChange)
2189                 setSelected(selSection, true);
2190             c = -1;
2191         } else {
2192             int closest = closestSection(newpos, forward);
2193             c = sectionPos(closest) + (forward ? 0 : qMax<int>(0, sectionSize(closest)));
2194
2195             if (allowChange) {
2196                 edit->setCursorPosition(c);
2197                 QDTEDEBUG << c;
2198             }
2199             s = closest;
2200         }
2201     }
2202
2203     if (allowChange && currentSectionIndex != s) {
2204         interpret(EmitIfChanged);
2205     }
2206     if (c == -1) {
2207         setSelected(s, true);
2208     } else if (!edit->hasSelectedText()) {
2209         if (oldpos < newpos) {
2210             edit->setCursorPosition(displayText().size() - (oldText.size() - c));
2211         } else {
2212             edit->setCursorPosition(c);
2213         }
2214     }
2215
2216     QDTEDEBUG << "currentSectionIndex is set to" << sectionName(sectionType(s))
2217               << oldpos << newpos
2218               << "was" << sectionName(sectionType(currentSectionIndex));
2219
2220     currentSectionIndex = s;
2221     Q_ASSERT_X(currentSectionIndex < sectionNodes.size(),
2222                "QDateTimeEditPrivate::_q_editorCursorPositionChanged()",
2223                qPrintable(QString::fromLatin1("Internal error (%1 %2)").
2224                           arg(currentSectionIndex).
2225                           arg(sectionNodes.size())));
2226
2227     ignoreCursorPositionChanged = false;
2228 }
2229
2230 /*!
2231   \internal
2232
2233   Try to get the format from the local settings
2234 */
2235 void QDateTimeEditPrivate::readLocaleSettings()
2236 {
2237     const QLocale loc;
2238     defaultTimeFormat = loc.timeFormat(QLocale::ShortFormat);
2239     defaultDateFormat = loc.dateFormat(QLocale::ShortFormat);
2240     defaultDateTimeFormat = loc.dateTimeFormat(QLocale::ShortFormat);
2241 }
2242
2243 QDateTimeEdit::Section QDateTimeEditPrivate::convertToPublic(QDateTimeParser::Section s)
2244 {
2245     switch (s & ~Internal) {
2246     case AmPmSection: return QDateTimeEdit::AmPmSection;
2247     case MSecSection: return QDateTimeEdit::MSecSection;
2248     case SecondSection: return QDateTimeEdit::SecondSection;
2249     case MinuteSection: return QDateTimeEdit::MinuteSection;
2250     case DayOfWeekSectionShort:
2251     case DayOfWeekSectionLong:
2252     case DaySection: return QDateTimeEdit::DaySection;
2253     case MonthSection: return QDateTimeEdit::MonthSection;
2254     case YearSection2Digits:
2255     case YearSection: return QDateTimeEdit::YearSection;
2256     case Hour12Section:
2257     case Hour24Section: return QDateTimeEdit::HourSection;
2258     case FirstSection:
2259     case NoSection:
2260     case LastSection: break;
2261     }
2262     return QDateTimeEdit::NoSection;
2263 }
2264
2265 QDateTimeEdit::Sections QDateTimeEditPrivate::convertSections(QDateTimeParser::Sections s)
2266 {
2267     QDateTimeEdit::Sections ret = 0;
2268     if (s & QDateTimeParser::MSecSection)
2269         ret |= QDateTimeEdit::MSecSection;
2270     if (s & QDateTimeParser::SecondSection)
2271         ret |= QDateTimeEdit::SecondSection;
2272     if (s & QDateTimeParser::MinuteSection)
2273         ret |= QDateTimeEdit::MinuteSection;
2274     if (s & (QDateTimeParser::Hour24Section|QDateTimeParser::Hour12Section))
2275         ret |= QDateTimeEdit::HourSection;
2276     if (s & QDateTimeParser::AmPmSection)
2277         ret |= QDateTimeEdit::AmPmSection;
2278     if (s & (QDateTimeParser::DaySection|QDateTimeParser::DayOfWeekSectionShort|QDateTimeParser::DayOfWeekSectionLong))
2279         ret |= QDateTimeEdit::DaySection;
2280     if (s & QDateTimeParser::MonthSection)
2281         ret |= QDateTimeEdit::MonthSection;
2282     if (s & (QDateTimeParser::YearSection|QDateTimeParser::YearSection2Digits))
2283         ret |= QDateTimeEdit::YearSection;
2284
2285     return ret;
2286 }
2287
2288 /*!
2289     \reimp
2290 */
2291
2292 void QDateTimeEdit::paintEvent(QPaintEvent *event)
2293 {
2294     Q_D(QDateTimeEdit);
2295     if (!d->calendarPopupEnabled()) {
2296         QAbstractSpinBox::paintEvent(event);
2297         return;
2298     }
2299
2300     QStyleOptionSpinBox opt;
2301     initStyleOption(&opt);
2302
2303     QStyleOptionComboBox optCombo;
2304
2305     optCombo.init(this);
2306     optCombo.editable = true;
2307         optCombo.frame = opt.frame;
2308     optCombo.subControls = opt.subControls;
2309     optCombo.activeSubControls = opt.activeSubControls;
2310     optCombo.state = opt.state;
2311     if (d->readOnly) {
2312         optCombo.state &= ~QStyle::State_Enabled;
2313     }
2314
2315     QPainter p(this);
2316     style()->drawComplexControl(QStyle::CC_ComboBox, &optCombo, &p, this);
2317 }
2318
2319 QString QDateTimeEditPrivate::getAmPmText(AmPm ap, Case cs) const
2320 {
2321     if (ap == AmText) {
2322         return (cs == UpperCase ? QDateTimeEdit::tr("AM") : QDateTimeEdit::tr("am"));
2323     } else {
2324         return (cs == UpperCase ? QDateTimeEdit::tr("PM") : QDateTimeEdit::tr("pm"));
2325     }
2326 }
2327
2328 int QDateTimeEditPrivate::absoluteIndex(QDateTimeEdit::Section s, int index) const
2329 {
2330     for (int i=0; i<sectionNodes.size(); ++i) {
2331         if (convertToPublic(sectionNodes.at(i).type) == s && index-- == 0) {
2332             return i;
2333         }
2334     }
2335     return NoSectionIndex;
2336 }
2337
2338 int QDateTimeEditPrivate::absoluteIndex(const SectionNode &s) const
2339 {
2340     return sectionNodes.indexOf(s);
2341 }
2342
2343 void QDateTimeEditPrivate::interpret(EmitPolicy ep)
2344 {
2345     Q_Q(QDateTimeEdit);
2346     QString tmp = displayText();
2347     int pos = edit->cursorPosition();
2348     const QValidator::State state = q->validate(tmp, pos);
2349     if (state != QValidator::Acceptable
2350         && correctionMode == QAbstractSpinBox::CorrectToPreviousValue
2351         && (state == QValidator::Invalid || !(fieldInfo(currentSectionIndex) & AllowPartial))) {
2352         setValue(value, ep);
2353         updateTimeSpec();
2354     } else {
2355         QAbstractSpinBoxPrivate::interpret(ep);
2356     }
2357 }
2358
2359 void QDateTimeEditPrivate::clearCache() const
2360 {
2361     QAbstractSpinBoxPrivate::clearCache();
2362     cachedDay = -1;
2363 }
2364
2365 /*!
2366     Initialize \a option with the values from this QDataTimeEdit. This method
2367     is useful for subclasses when they need a QStyleOptionSpinBox, but don't want
2368     to fill in all the information themselves.
2369
2370     \sa QStyleOption::initFrom()
2371 */
2372 void QDateTimeEdit::initStyleOption(QStyleOptionSpinBox *option) const
2373 {
2374     if (!option)
2375         return;
2376
2377     Q_D(const QDateTimeEdit);
2378     QAbstractSpinBox::initStyleOption(option);
2379     if (d->calendarPopupEnabled()) {
2380         option->subControls = QStyle::SC_ComboBoxFrame | QStyle::SC_ComboBoxEditField
2381                               | QStyle::SC_ComboBoxArrow;
2382         if (d->arrowState == QStyle::State_Sunken)
2383             option->state |= QStyle::State_Sunken;
2384         else
2385             option->state &= ~QStyle::State_Sunken;
2386     }
2387 }
2388
2389 void QDateTimeEditPrivate::init(const QVariant &var)
2390 {
2391     Q_Q(QDateTimeEdit);
2392     switch (var.type()) {
2393     case QVariant::Date:
2394         value = QDateTime(var.toDate(), QDATETIMEEDIT_TIME_MIN);
2395         q->setDisplayFormat(defaultDateFormat);
2396         if (sectionNodes.isEmpty()) // ### safeguard for broken locale
2397             q->setDisplayFormat(QLatin1String("dd/MM/yyyy"));
2398         break;
2399     case QVariant::DateTime:
2400         value = var;
2401         q->setDisplayFormat(defaultDateTimeFormat);
2402         if (sectionNodes.isEmpty()) // ### safeguard for broken locale
2403             q->setDisplayFormat(QLatin1String("dd/MM/yyyy hh:mm:ss"));
2404         break;
2405     case QVariant::Time:
2406         value = QDateTime(QDATETIMEEDIT_DATE_INITIAL, var.toTime());
2407         q->setDisplayFormat(defaultTimeFormat);
2408         if (sectionNodes.isEmpty()) // ### safeguard for broken locale
2409             q->setDisplayFormat(QLatin1String("hh:mm:ss"));
2410         break;
2411     default:
2412         Q_ASSERT_X(0, "QDateTimeEditPrivate::init", "Internal error");
2413         break;
2414     }
2415 #ifdef QT_KEYPAD_NAVIGATION
2416     if (QApplication::keypadNavigationEnabled())
2417         q->setCalendarPopup(true);
2418 #endif
2419     updateTimeSpec();
2420     q->setInputMethodHints(Qt::ImhPreferNumbers);
2421     setLayoutItemMargins(QStyle::SE_DateTimeEditLayoutItem);
2422 }
2423
2424 void QDateTimeEditPrivate::_q_resetButton()
2425 {
2426     updateArrow(QStyle::State_None);
2427 }
2428
2429 void QDateTimeEditPrivate::updateArrow(QStyle::StateFlag state)
2430 {
2431     Q_Q(QDateTimeEdit);
2432
2433     if (arrowState == state)
2434         return;
2435     arrowState = state;
2436     if (arrowState != QStyle::State_None)
2437         buttonState |= Mouse;
2438     else {
2439         buttonState = 0;
2440         hoverControl = QStyle::SC_ComboBoxFrame;
2441     }
2442     q->update();
2443 }
2444
2445 /*!
2446     \internal
2447     Returns the hover control at \a pos.
2448     This will update the hoverRect and hoverControl.
2449 */
2450 QStyle::SubControl QDateTimeEditPrivate::newHoverControl(const QPoint &pos)
2451 {
2452     if (!calendarPopupEnabled())
2453         return QAbstractSpinBoxPrivate::newHoverControl(pos);
2454
2455     Q_Q(QDateTimeEdit);
2456
2457     QStyleOptionComboBox optCombo;
2458     optCombo.init(q);
2459     optCombo.editable = true;
2460     optCombo.subControls = QStyle::SC_All;
2461     hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &optCombo, pos, q);
2462     return hoverControl;
2463 }
2464
2465 void QDateTimeEditPrivate::updateEditFieldGeometry()
2466 {
2467     if (!calendarPopupEnabled()) {
2468         QAbstractSpinBoxPrivate::updateEditFieldGeometry();
2469         return;
2470     }
2471
2472     Q_Q(QDateTimeEdit);
2473
2474     QStyleOptionComboBox optCombo;
2475     optCombo.init(q);
2476     optCombo.editable = true;
2477     optCombo.subControls = QStyle::SC_ComboBoxEditField;
2478     edit->setGeometry(q->style()->subControlRect(QStyle::CC_ComboBox, &optCombo,
2479                                                  QStyle::SC_ComboBoxEditField, q));
2480 }
2481
2482 QVariant QDateTimeEditPrivate::getZeroVariant() const
2483 {
2484     Q_ASSERT(type == QVariant::DateTime);
2485     return QDateTime(QDATETIMEEDIT_DATE_INITIAL, QTime(), spec);
2486 }
2487
2488 void QDateTimeEditPrivate::setRange(const QVariant &min, const QVariant &max)
2489 {
2490     QAbstractSpinBoxPrivate::setRange(min, max);
2491     syncCalendarWidget();
2492 }
2493
2494
2495 bool QDateTimeEditPrivate::isSeparatorKey(const QKeyEvent *ke) const
2496 {
2497     if (!ke->text().isEmpty() && currentSectionIndex + 1 < sectionNodes.size() && currentSectionIndex >= 0) {
2498         if (fieldInfo(currentSectionIndex) & Numeric) {
2499             if (ke->text().at(0).isNumber())
2500                 return false;
2501         } else if (ke->text().at(0).isLetterOrNumber()) {
2502             return false;
2503         }
2504         return separators.at(currentSectionIndex + 1).contains(ke->text());
2505     }
2506     return false;
2507 }
2508
2509 void QDateTimeEditPrivate::initCalendarPopup(QCalendarWidget *cw)
2510 {
2511     Q_Q(QDateTimeEdit);
2512     if (!monthCalendar) {
2513         monthCalendar = new QCalendarPopup(q, cw);
2514         monthCalendar->setObjectName(QLatin1String("qt_datetimedit_calendar"));
2515         QObject::connect(monthCalendar, SIGNAL(newDateSelected(QDate)), q, SLOT(setDate(QDate)));
2516         QObject::connect(monthCalendar, SIGNAL(hidingCalendar(QDate)), q, SLOT(setDate(QDate)));
2517         QObject::connect(monthCalendar, SIGNAL(activated(QDate)), q, SLOT(setDate(QDate)));
2518         QObject::connect(monthCalendar, SIGNAL(activated(QDate)), monthCalendar, SLOT(close()));
2519         QObject::connect(monthCalendar, SIGNAL(resetButton()), q, SLOT(_q_resetButton()));
2520     } else if (cw) {
2521         monthCalendar->setCalendarWidget(cw);
2522     }
2523     syncCalendarWidget();
2524 }
2525
2526 void QDateTimeEditPrivate::positionCalendarPopup()
2527 {
2528     Q_Q(QDateTimeEdit);
2529     QPoint pos = (q->layoutDirection() == Qt::RightToLeft) ? q->rect().bottomRight() : q->rect().bottomLeft();
2530     QPoint pos2 = (q->layoutDirection() == Qt::RightToLeft) ? q->rect().topRight() : q->rect().topLeft();
2531     pos = q->mapToGlobal(pos);
2532     pos2 = q->mapToGlobal(pos2);
2533     QSize size = monthCalendar->sizeHint();
2534     QRect screen = QApplication::desktop()->availableGeometry(pos);
2535     //handle popup falling "off screen"
2536     if (q->layoutDirection() == Qt::RightToLeft) {
2537         pos.setX(pos.x()-size.width());
2538         pos2.setX(pos2.x()-size.width());
2539         if (pos.x() < screen.left())
2540             pos.setX(qMax(pos.x(), screen.left()));
2541         else if (pos.x()+size.width() > screen.right())
2542             pos.setX(qMax(pos.x()-size.width(), screen.right()-size.width()));
2543     } else {
2544         if (pos.x()+size.width() > screen.right())
2545             pos.setX(screen.right()-size.width());
2546         pos.setX(qMax(pos.x(), screen.left()));
2547     }
2548     if (pos.y() + size.height() > screen.bottom())
2549         pos.setY(pos2.y() - size.height());
2550     else if (pos.y() < screen.top())
2551         pos.setY(screen.top());
2552     if (pos.y() < screen.top())
2553         pos.setY(screen.top());
2554     if (pos.y()+size.height() > screen.bottom())
2555         pos.setY(screen.bottom()-size.height());
2556     monthCalendar->move(pos);
2557 }
2558
2559 bool QDateTimeEditPrivate::calendarPopupEnabled() const
2560 {
2561     return (calendarPopup && (sections & (DateSectionMask)));
2562 }
2563
2564 void QDateTimeEditPrivate::syncCalendarWidget()
2565 {
2566     Q_Q(QDateTimeEdit);
2567     if (monthCalendar) {
2568         const bool sb = monthCalendar->blockSignals(true);
2569         monthCalendar->setDateRange(q->minimumDate(), q->maximumDate());
2570         monthCalendar->setDate(q->date());
2571         monthCalendar->blockSignals(sb);
2572     }
2573 }
2574
2575 QCalendarPopup::QCalendarPopup(QWidget * parent, QCalendarWidget *cw)
2576     : QWidget(parent, Qt::Popup)
2577 {
2578     setAttribute(Qt::WA_WindowPropagation);
2579
2580     dateChanged = false;
2581     if (!cw) {
2582         verifyCalendarInstance();
2583     } else {
2584         setCalendarWidget(cw);
2585     }
2586 }
2587
2588 QCalendarWidget *QCalendarPopup::verifyCalendarInstance()
2589 {
2590     if (calendar.isNull()) {
2591         QCalendarWidget *cw = new QCalendarWidget(this);
2592         cw->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
2593 #ifdef QT_KEYPAD_NAVIGATION
2594         if (QApplication::keypadNavigationEnabled())
2595             cw->setHorizontalHeaderFormat(QCalendarWidget::SingleLetterDayNames);
2596 #endif
2597         setCalendarWidget(cw);
2598         return cw;
2599     } else {
2600         return calendar.data();
2601     }
2602 }
2603
2604 void QCalendarPopup::setCalendarWidget(QCalendarWidget *cw)
2605 {
2606     Q_ASSERT(cw);
2607     QVBoxLayout *widgetLayout = qobject_cast<QVBoxLayout*>(layout());
2608     if (!widgetLayout) {
2609         widgetLayout = new QVBoxLayout(this);
2610         widgetLayout->setMargin(0);
2611         widgetLayout->setSpacing(0);
2612     }
2613     delete calendar.data();
2614     calendar = QPointer<QCalendarWidget>(cw);
2615     widgetLayout->addWidget(cw);
2616
2617     connect(cw, SIGNAL(activated(QDate)), this, SLOT(dateSelected(QDate)));
2618     connect(cw, SIGNAL(clicked(QDate)), this, SLOT(dateSelected(QDate)));
2619     connect(cw, SIGNAL(selectionChanged()), this, SLOT(dateSelectionChanged()));
2620
2621     cw->setFocus();
2622 }
2623
2624
2625 void QCalendarPopup::setDate(const QDate &date)
2626 {
2627     oldDate = date;
2628     verifyCalendarInstance()->setSelectedDate(date);
2629 }
2630
2631 void QCalendarPopup::setDateRange(const QDate &min, const QDate &max)
2632 {
2633     QCalendarWidget *cw = verifyCalendarInstance();
2634     cw->setMinimumDate(min);
2635     cw->setMaximumDate(max);
2636 }
2637
2638 void QCalendarPopup::mousePressEvent(QMouseEvent *event)
2639 {
2640     QDateTimeEdit *dateTime = qobject_cast<QDateTimeEdit *>(parentWidget());
2641     if (dateTime) {
2642         QStyleOptionComboBox opt;
2643         opt.init(dateTime);
2644         QRect arrowRect = dateTime->style()->subControlRect(QStyle::CC_ComboBox, &opt,
2645                                                             QStyle::SC_ComboBoxArrow, dateTime);
2646         arrowRect.moveTo(dateTime->mapToGlobal(arrowRect .topLeft()));
2647         if (arrowRect.contains(event->globalPos()) || rect().contains(event->pos()))
2648             setAttribute(Qt::WA_NoMouseReplay);
2649     }
2650     QWidget::mousePressEvent(event);
2651 }
2652
2653 void QCalendarPopup::mouseReleaseEvent(QMouseEvent*)
2654 {
2655     emit resetButton();
2656 }
2657
2658 bool QCalendarPopup::event(QEvent *event)
2659 {
2660     if (event->type() == QEvent::KeyPress) {
2661         QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
2662         if (keyEvent->key()== Qt::Key_Escape)
2663             dateChanged = false;
2664     }
2665     return QWidget::event(event);
2666 }
2667
2668 void QCalendarPopup::dateSelectionChanged()
2669 {
2670     dateChanged = true;
2671     emit newDateSelected(verifyCalendarInstance()->selectedDate());
2672 }
2673 void QCalendarPopup::dateSelected(const QDate &date)
2674 {
2675     dateChanged = true;
2676     emit activated(date);
2677     close();
2678 }
2679
2680 void QCalendarPopup::hideEvent(QHideEvent *)
2681 {
2682     emit resetButton();
2683     if (!dateChanged)
2684         emit hidingCalendar(oldDate);
2685 }
2686
2687 QT_END_NAMESPACE
2688 #include "moc_qdatetimeedit.cpp"
2689
2690 #endif // QT_NO_DATETIMEEDIT