4c418bde9e923db0c08534e33e3da7a6de21c3d4
[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   \fn void QTimeEdit::userTimeChanged(const QTime &time)
1567
1568   This signal only exists to fully implement the time Q_PROPERTY on the class.
1569   Normally timeChanged should be used instead.
1570
1571   \internal
1572 */
1573
1574
1575 /*!
1576   \class QDateEdit
1577   \brief The QDateEdit class provides a widget for editing dates based on
1578   the QDateTimeEdit widget.
1579
1580   \ingroup basicwidgets
1581   \inmodule QtWidgets
1582
1583   Many of the properties and functions provided by QDateEdit are implemented in
1584   QDateTimeEdit. The following properties are most relevant to users of this
1585   class:
1586
1587   \list
1588   \li \l{QDateTimeEdit::date}{date} holds the date displayed by the widget.
1589   \li \l{QDateTimeEdit::minimumDate}{minimumDate} defines the minimum (earliest)
1590      date that can be set by the user.
1591   \li \l{QDateTimeEdit::maximumDate}{maximumDate} defines the maximum (latest) date
1592      that can be set by the user.
1593   \li \l{QDateTimeEdit::displayFormat}{displayFormat} contains a string that is used
1594      to format the date displayed in the widget.
1595   \endlist
1596
1597   \table 100%
1598   \row \li \inlineimage windowsxp-dateedit.png Screenshot of a Windows XP style date editing widget
1599        \li A date editing widget shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
1600   \row \li \inlineimage macintosh-dateedit.png Screenshot of a Macintosh style date editing widget
1601        \li A date editing widget shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
1602   \row \li \inlineimage plastique-dateedit.png Screenshot of a Plastique style date editing widget
1603        \li A date editing widget shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
1604   \endtable
1605
1606   \sa QTimeEdit, QDateTimeEdit
1607 */
1608
1609 /*!
1610   Constructs an empty date editor with a \a parent.
1611 */
1612
1613 QDateEdit::QDateEdit(QWidget *parent)
1614     : QDateTimeEdit(QDATETIMEEDIT_DATE_INITIAL, QVariant::Date, parent)
1615 {
1616     connect(this, SIGNAL(dateChanged(QDate)), SIGNAL(userDateChanged(QDate)));
1617 }
1618
1619 /*!
1620   Constructs an empty date editor with a \a parent. The date is set
1621   to \a date.
1622 */
1623
1624 QDateEdit::QDateEdit(const QDate &date, QWidget *parent)
1625     : QDateTimeEdit(date, QVariant::Date, parent)
1626 {
1627 }
1628
1629 /*!
1630   \fn void QDateEdit::userDateChanged(const QDate &date)
1631
1632   This signal only exists to fully implement the date Q_PROPERTY on the class.
1633   Normally dateChanged should be used instead.
1634
1635   \internal
1636 */
1637
1638
1639 // --- QDateTimeEditPrivate ---
1640
1641 /*!
1642   \internal
1643   Constructs a QDateTimeEditPrivate object
1644 */
1645
1646
1647 QDateTimeEditPrivate::QDateTimeEditPrivate()
1648     : QDateTimeParser(QVariant::DateTime, QDateTimeParser::DateTimeEdit)
1649 {
1650     hasHadFocus = false;
1651     formatExplicitlySet = false;
1652     cacheGuard = false;
1653     fixday = true;
1654     type = QVariant::DateTime;
1655     sections = 0;
1656     cachedDay = -1;
1657     currentSectionIndex = FirstSectionIndex;
1658
1659     first.type = FirstSection;
1660     last.type = LastSection;
1661     none.type = NoSection;
1662     first.pos = 0;
1663     last.pos = -1;
1664     none.pos = -1;
1665     sections = 0;
1666     calendarPopup = false;
1667     minimum = QDATETIMEEDIT_COMPAT_DATETIME_MIN;
1668     maximum = QDATETIMEEDIT_DATETIME_MAX;
1669     arrowState = QStyle::State_None;
1670     monthCalendar = 0;
1671     readLocaleSettings();
1672
1673 #ifdef QT_KEYPAD_NAVIGATION
1674     focusOnButton = false;
1675 #endif
1676 }
1677
1678 void QDateTimeEditPrivate::updateTimeSpec()
1679 {
1680     minimum = minimum.toDateTime().toTimeSpec(spec);
1681     maximum = maximum.toDateTime().toTimeSpec(spec);
1682     value = value.toDateTime().toTimeSpec(spec);
1683
1684     // time zone changes can lead to 00:00:00 becomes 01:00:00 and 23:59:59 becomes 00:59:59 (invalid range)
1685     const bool dateShown = (sections & QDateTimeEdit::DateSections_Mask);
1686     if (!dateShown) {
1687         if (minimum.toTime() >= maximum.toTime()){
1688             minimum = QDateTime(value.toDate(), QDATETIMEEDIT_TIME_MIN, spec);
1689             maximum = QDateTime(value.toDate(), QDATETIMEEDIT_TIME_MAX, spec);
1690         }
1691     }
1692 }
1693
1694 void QDateTimeEditPrivate::updateEdit()
1695 {
1696     const QString newText = (specialValue() ? specialValueText : textFromValue(value));
1697     if (newText == displayText())
1698         return;
1699     int selsize = edit->selectedText().size();
1700     const bool sb = edit->blockSignals(true);
1701
1702     edit->setText(newText);
1703
1704     if (!specialValue()
1705 #ifdef QT_KEYPAD_NAVIGATION
1706         && !(QApplication::keypadNavigationEnabled() && !edit->hasEditFocus())
1707 #endif
1708             ) {
1709         int cursor = sectionPos(currentSectionIndex);
1710         QDTEDEBUG << "cursor is " << cursor << currentSectionIndex;
1711         cursor = qBound(0, cursor, displayText().size());
1712         QDTEDEBUG << cursor;
1713         if (selsize > 0) {
1714             edit->setSelection(cursor, selsize);
1715             QDTEDEBUG << cursor << selsize;
1716         } else {
1717             edit->setCursorPosition(cursor);
1718             QDTEDEBUG << cursor;
1719
1720         }
1721     }
1722     edit->blockSignals(sb);
1723 }
1724
1725
1726 /*!
1727   \internal
1728
1729   Selects the section \a s. If \a forward is false selects backwards.
1730 */
1731
1732 void QDateTimeEditPrivate::setSelected(int sectionIndex, bool forward)
1733 {
1734     if (specialValue()
1735 #ifdef QT_KEYPAD_NAVIGATION
1736         || (QApplication::keypadNavigationEnabled() && !edit->hasEditFocus())
1737 #endif
1738         ) {
1739         edit->selectAll();
1740     } else {
1741         const SectionNode &node = sectionNode(sectionIndex);
1742         if (node.type == NoSection || node.type == LastSection || node.type == FirstSection)
1743             return;
1744
1745         updateCache(value, displayText());
1746         const int size = sectionSize(sectionIndex);
1747         if (forward) {
1748             edit->setSelection(sectionPos(node), size);
1749         } else {
1750             edit->setSelection(sectionPos(node) + size, -size);
1751         }
1752     }
1753 }
1754
1755 /*!
1756   \internal
1757
1758   Returns the section at index \a index or NoSection if there are no sections there.
1759 */
1760
1761 int QDateTimeEditPrivate::sectionAt(int pos) const
1762 {
1763     if (pos < separators.first().size()) {
1764         return (pos == 0 ? FirstSectionIndex : NoSectionIndex);
1765     } else if (displayText().size() - pos < separators.last().size() + 1) {
1766         if (separators.last().size() == 0) {
1767             return sectionNodes.count() - 1;
1768         }
1769         return (pos == displayText().size() ? LastSectionIndex : NoSectionIndex);
1770     }
1771     updateCache(value, displayText());
1772
1773     for (int i=0; i<sectionNodes.size(); ++i) {
1774         const int tmp = sectionPos(i);
1775         if (pos < tmp + sectionSize(i)) {
1776             return (pos < tmp ? -1 : i);
1777         }
1778     }
1779     return -1;
1780 }
1781
1782 /*!
1783   \internal
1784
1785   Returns the closest section of index \a index. Searches forward
1786   for a section if \a forward is true. Otherwise searches backwards.
1787 */
1788
1789 int QDateTimeEditPrivate::closestSection(int pos, bool forward) const
1790 {
1791     Q_ASSERT(pos >= 0);
1792     if (pos < separators.first().size()) {
1793         return forward ? 0 : FirstSectionIndex;
1794     } else if (displayText().size() - pos < separators.last().size() + 1) {
1795         return forward ? LastSectionIndex : sectionNodes.size() - 1;
1796     }
1797     updateCache(value, displayText());
1798     for (int i=0; i<sectionNodes.size(); ++i) {
1799         const int tmp = sectionPos(sectionNodes.at(i));
1800         if (pos < tmp + sectionSize(i)) {
1801             if (pos < tmp && !forward) {
1802                 return i-1;
1803             }
1804             return i;
1805         } else if (i == sectionNodes.size() - 1 && pos > tmp) {
1806             return i;
1807         }
1808     }
1809     qWarning("QDateTimeEdit: Internal Error: closestSection returned NoSection");
1810     return NoSectionIndex;
1811 }
1812
1813 /*!
1814   \internal
1815
1816   Returns a copy of the section that is before or after \a current, depending on \a forward.
1817 */
1818
1819 int QDateTimeEditPrivate::nextPrevSection(int current, bool forward) const
1820 {
1821     Q_Q(const QDateTimeEdit);
1822     if (q->isRightToLeft())
1823         forward = !forward;
1824
1825     switch (current) {
1826     case FirstSectionIndex: return forward ? 0 : FirstSectionIndex;
1827     case LastSectionIndex: return (forward ? LastSectionIndex : sectionNodes.size() - 1);
1828     case NoSectionIndex: return FirstSectionIndex;
1829     default: break;
1830     }
1831     Q_ASSERT(current >= 0 && current < sectionNodes.size());
1832
1833     current += (forward ? 1 : -1);
1834     if (current >= sectionNodes.size()) {
1835         return LastSectionIndex;
1836     } else if (current < 0) {
1837         return FirstSectionIndex;
1838     }
1839
1840     return current;
1841 }
1842
1843 /*!
1844   \internal
1845
1846   Clears the text of section \a s.
1847 */
1848
1849 void QDateTimeEditPrivate::clearSection(int index)
1850 {
1851     const QLatin1Char space(' ');
1852     int cursorPos = edit->cursorPosition();
1853     bool blocked = edit->blockSignals(true);
1854     QString t = edit->text();
1855     const int pos = sectionPos(index);
1856     if (pos == -1) {
1857         qWarning("QDateTimeEdit: Internal error (%s:%d)", __FILE__, __LINE__);
1858         return;
1859     }
1860     const int size = sectionSize(index);
1861     t.replace(pos, size, QString().fill(space, size));
1862     edit->setText(t);
1863     edit->setCursorPosition(cursorPos);
1864     QDTEDEBUG << cursorPos;
1865
1866     edit->blockSignals(blocked);
1867 }
1868
1869
1870 /*!
1871   \internal
1872
1873   updates the cached values
1874 */
1875
1876 void QDateTimeEditPrivate::updateCache(const QVariant &val, const QString &str) const
1877 {
1878     if (val != cachedValue || str != cachedText || cacheGuard) {
1879         cacheGuard = true;
1880         QString copy = str;
1881         int unused = edit->cursorPosition();
1882         QValidator::State unusedState;
1883         validateAndInterpret(copy, unused, unusedState);
1884         cacheGuard = false;
1885     }
1886 }
1887
1888 /*!
1889   \internal
1890
1891   parses and validates \a input
1892 */
1893
1894 QDateTime QDateTimeEditPrivate::validateAndInterpret(QString &input, int &position,
1895                                                      QValidator::State &state, bool fixup) const
1896 {
1897     if (input.isEmpty()) {
1898         if (sectionNodes.size() == 1 || !specialValueText.isEmpty()) {
1899             state = QValidator::Intermediate;
1900         } else {
1901             state = QValidator::Invalid;
1902         }
1903         return getZeroVariant().toDateTime();
1904     } else if (cachedText == input && !fixup) {
1905         state = cachedState;
1906         return cachedValue.toDateTime();
1907     } else if (!specialValueText.isEmpty()) {
1908         bool changeCase = false;
1909         const int max = qMin(specialValueText.size(), input.size());
1910         int i;
1911         for (i=0; i<max; ++i) {
1912             const QChar ic = input.at(i);
1913             const QChar sc = specialValueText.at(i);
1914             if (ic != sc) {
1915                 if (sc.toLower() == ic.toLower()) {
1916                     changeCase = true;
1917                 } else {
1918                     break;
1919                 }
1920             }
1921         }
1922         if (i == max) {
1923             state = specialValueText.size() == input.size() ? QValidator::Acceptable : QValidator::Intermediate;
1924             if (changeCase) {
1925                 input = specialValueText.left(max);
1926             }
1927             return minimum.toDateTime();
1928         }
1929     }
1930     StateNode tmp = parse(input, position, value.toDateTime(), fixup);
1931     input = tmp.input;
1932     state = QValidator::State(int(tmp.state));
1933     if (state == QValidator::Acceptable) {
1934         if (tmp.conflicts && conflictGuard != tmp.value) {
1935             conflictGuard = tmp.value;
1936             clearCache();
1937             input = textFromValue(tmp.value);
1938             updateCache(tmp.value, input);
1939             conflictGuard.clear();
1940         } else {
1941             cachedText = input;
1942             cachedState = state;
1943             cachedValue = tmp.value;
1944         }
1945     } else {
1946         clearCache();
1947     }
1948     return (tmp.value.isNull() ? getZeroVariant().toDateTime() : tmp.value);
1949 }
1950
1951
1952 /*!
1953   \internal
1954 */
1955
1956 QString QDateTimeEditPrivate::textFromValue(const QVariant &f) const
1957 {
1958     Q_Q(const QDateTimeEdit);
1959     return q->textFromDateTime(f.toDateTime());
1960 }
1961
1962 /*!
1963   \internal
1964
1965   This function's name is slightly confusing; it is not to be confused
1966   with QAbstractSpinBox::valueFromText().
1967 */
1968
1969 QVariant QDateTimeEditPrivate::valueFromText(const QString &f) const
1970 {
1971     Q_Q(const QDateTimeEdit);
1972     return q->dateTimeFromText(f).toTimeSpec(spec);
1973 }
1974
1975
1976 /*!
1977   \internal
1978
1979   Internal function called by QDateTimeEdit::stepBy(). Also takes a
1980   Section for which section to step on and a bool \a test for
1981   whether or not to modify the internal cachedDay variable. This is
1982   necessary because the function is called from the const function
1983   QDateTimeEdit::stepEnabled() as well as QDateTimeEdit::stepBy().
1984 */
1985
1986 QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) const
1987 {
1988     Q_Q(const QDateTimeEdit);
1989     QDateTime v = value.toDateTime();
1990     QString str = displayText();
1991     int pos = edit->cursorPosition();
1992     const SectionNode sn = sectionNode(sectionIndex);
1993
1994     int val;
1995     // to make sure it behaves reasonably when typing something and then stepping in non-tracking mode
1996     if (!test && pendingEmit) {
1997         if (q->validate(str, pos) != QValidator::Acceptable) {
1998             v = value.toDateTime();
1999         } else {
2000             v = q->dateTimeFromText(str);
2001         }
2002         val = getDigit(v, sectionIndex);
2003     } else {
2004         val = getDigit(v, sectionIndex);
2005     }
2006
2007     val += steps;
2008
2009     const int min = absoluteMin(sectionIndex);
2010     const int max = absoluteMax(sectionIndex, value.toDateTime());
2011
2012     if (val < min) {
2013         val = (wrapping ? max - (min - val) + 1 : min);
2014     } else if (val > max) {
2015         val = (wrapping ? min + val - max - 1 : max);
2016     }
2017
2018
2019     const int oldDay = v.date().day();
2020
2021     setDigit(v, sectionIndex, val);
2022     // if this sets year or month it will make
2023     // sure that days are lowered if needed.
2024
2025     const QDateTime minimumDateTime = minimum.toDateTime();
2026     const QDateTime maximumDateTime = maximum.toDateTime();
2027     // changing one section should only modify that section, if possible
2028     if (sn.type != AmPmSection && (v < minimumDateTime || v > maximumDateTime)) {
2029         const int localmin = getDigit(minimumDateTime, sectionIndex);
2030         const int localmax = getDigit(maximumDateTime, sectionIndex);
2031
2032         if (wrapping) {
2033             // just because we hit the roof in one direction, it
2034             // doesn't mean that we hit the floor in the other
2035             if (steps > 0) {
2036                 setDigit(v, sectionIndex, min);
2037                 if (!(sn.type & (DaySection|DayOfWeekSection)) && sections & DateSectionMask) {
2038                     const int daysInMonth = v.date().daysInMonth();
2039                     if (v.date().day() < oldDay && v.date().day() < daysInMonth) {
2040                         const int adds = qMin(oldDay, daysInMonth);
2041                         v = v.addDays(adds - v.date().day());
2042                     }
2043                 }
2044
2045                 if (v < minimumDateTime) {
2046                     setDigit(v, sectionIndex, localmin);
2047                     if (v < minimumDateTime)
2048                         setDigit(v, sectionIndex, localmin + 1);
2049                 }
2050             } else {
2051                 setDigit(v, sectionIndex, max);
2052                 if (!(sn.type & (DaySection|DayOfWeekSection)) && sections & DateSectionMask) {
2053                     const int daysInMonth = v.date().daysInMonth();
2054                     if (v.date().day() < oldDay && v.date().day() < daysInMonth) {
2055                         const int adds = qMin(oldDay, daysInMonth);
2056                         v = v.addDays(adds - v.date().day());
2057                     }
2058                 }
2059
2060                 if (v > maximumDateTime) {
2061                     setDigit(v, sectionIndex, localmax);
2062                     if (v > maximumDateTime)
2063                         setDigit(v, sectionIndex, localmax - 1);
2064                 }
2065             }
2066         } else {
2067             setDigit(v, sectionIndex, (steps > 0 ? localmax : localmin));
2068         }
2069     }
2070     if (!test && oldDay != v.date().day() && !(sn.type & (DaySection|DayOfWeekSection))) {
2071         // this should not happen when called from stepEnabled
2072         cachedDay = qMax<int>(oldDay, cachedDay);
2073     }
2074
2075     if (v < minimumDateTime) {
2076         if (wrapping) {
2077             QDateTime t = v;
2078             setDigit(t, sectionIndex, steps < 0 ? max : min);
2079             bool mincmp = (t >= minimumDateTime);
2080             bool maxcmp = (t <= maximumDateTime);
2081             if (!mincmp || !maxcmp) {
2082                 setDigit(t, sectionIndex, getDigit(steps < 0
2083                                                    ? maximumDateTime
2084                                                    : minimumDateTime, sectionIndex));
2085                 mincmp = (t >= minimumDateTime);
2086                 maxcmp = (t <= maximumDateTime);
2087             }
2088             if (mincmp && maxcmp) {
2089                 v = t;
2090             }
2091         } else {
2092             v = value.toDateTime();
2093         }
2094     } else if (v > maximumDateTime) {
2095         if (wrapping) {
2096             QDateTime t = v;
2097             setDigit(t, sectionIndex, steps > 0 ? min : max);
2098             bool mincmp = (t >= minimumDateTime);
2099             bool maxcmp = (t <= maximumDateTime);
2100             if (!mincmp || !maxcmp) {
2101                 setDigit(t, sectionIndex, getDigit(steps > 0 ?
2102                                                    minimumDateTime :
2103                                                    maximumDateTime, sectionIndex));
2104                 mincmp = (t >= minimumDateTime);
2105                 maxcmp = (t <= maximumDateTime);
2106             }
2107             if (mincmp && maxcmp) {
2108                 v = t;
2109             }
2110         } else {
2111             v = value.toDateTime();
2112         }
2113     }
2114
2115     const QDateTime ret = bound(v, value, steps).toDateTime().toTimeSpec(spec);
2116     return ret;
2117 }
2118
2119 /*!
2120   \internal
2121 */
2122
2123 void QDateTimeEditPrivate::emitSignals(EmitPolicy ep, const QVariant &old)
2124 {
2125     Q_Q(QDateTimeEdit);
2126     if (ep == NeverEmit) {
2127         return;
2128     }
2129     pendingEmit = false;
2130
2131     const bool dodate = value.toDate().isValid() && (sections & DateSectionMask);
2132     const bool datechanged = (ep == AlwaysEmit || old.toDate() != value.toDate());
2133     const bool dotime = value.toTime().isValid() && (sections & TimeSectionMask);
2134     const bool timechanged = (ep == AlwaysEmit || old.toTime() != value.toTime());
2135
2136     updateCache(value, displayText());
2137
2138     syncCalendarWidget();
2139     if (datechanged || timechanged)
2140         emit q->dateTimeChanged(value.toDateTime());
2141     if (dodate && datechanged)
2142         emit q->dateChanged(value.toDate());
2143     if (dotime && timechanged)
2144         emit q->timeChanged(value.toTime());
2145
2146 }
2147
2148 /*!
2149   \internal
2150 */
2151
2152 void QDateTimeEditPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos)
2153 {
2154     if (ignoreCursorPositionChanged || specialValue())
2155         return;
2156     const QString oldText = displayText();
2157     updateCache(value, oldText);
2158
2159     const bool allowChange = !edit->hasSelectedText();
2160     const bool forward = oldpos <= newpos;
2161     ignoreCursorPositionChanged = true;
2162     int s = sectionAt(newpos);
2163     if (s == NoSectionIndex && forward && newpos > 0) {
2164         s = sectionAt(newpos - 1);
2165     }
2166
2167     int c = newpos;
2168
2169     const int selstart = edit->selectionStart();
2170     const int selSection = sectionAt(selstart);
2171     const int l = selSection != -1 ? sectionSize(selSection) : 0;
2172
2173     if (s == NoSectionIndex) {
2174         if (l > 0 && selstart == sectionPos(selSection) && edit->selectedText().size() == l) {
2175             s = selSection;
2176             if (allowChange)
2177                 setSelected(selSection, true);
2178             c = -1;
2179         } else {
2180             int closest = closestSection(newpos, forward);
2181             c = sectionPos(closest) + (forward ? 0 : qMax<int>(0, sectionSize(closest)));
2182
2183             if (allowChange) {
2184                 edit->setCursorPosition(c);
2185                 QDTEDEBUG << c;
2186             }
2187             s = closest;
2188         }
2189     }
2190
2191     if (allowChange && currentSectionIndex != s) {
2192         interpret(EmitIfChanged);
2193     }
2194     if (c == -1) {
2195         setSelected(s, true);
2196     } else if (!edit->hasSelectedText()) {
2197         if (oldpos < newpos) {
2198             edit->setCursorPosition(displayText().size() - (oldText.size() - c));
2199         } else {
2200             edit->setCursorPosition(c);
2201         }
2202     }
2203
2204     QDTEDEBUG << "currentSectionIndex is set to" << sectionName(sectionType(s))
2205               << oldpos << newpos
2206               << "was" << sectionName(sectionType(currentSectionIndex));
2207
2208     currentSectionIndex = s;
2209     Q_ASSERT_X(currentSectionIndex < sectionNodes.size(),
2210                "QDateTimeEditPrivate::_q_editorCursorPositionChanged()",
2211                qPrintable(QString::fromLatin1("Internal error (%1 %2)").
2212                           arg(currentSectionIndex).
2213                           arg(sectionNodes.size())));
2214
2215     ignoreCursorPositionChanged = false;
2216 }
2217
2218 /*!
2219   \internal
2220
2221   Try to get the format from the local settings
2222 */
2223 void QDateTimeEditPrivate::readLocaleSettings()
2224 {
2225     const QLocale loc;
2226     defaultTimeFormat = loc.timeFormat(QLocale::ShortFormat);
2227     defaultDateFormat = loc.dateFormat(QLocale::ShortFormat);
2228     defaultDateTimeFormat = loc.dateTimeFormat(QLocale::ShortFormat);
2229 }
2230
2231 QDateTimeEdit::Section QDateTimeEditPrivate::convertToPublic(QDateTimeParser::Section s)
2232 {
2233     switch (s & ~Internal) {
2234     case AmPmSection: return QDateTimeEdit::AmPmSection;
2235     case MSecSection: return QDateTimeEdit::MSecSection;
2236     case SecondSection: return QDateTimeEdit::SecondSection;
2237     case MinuteSection: return QDateTimeEdit::MinuteSection;
2238     case DayOfWeekSection:
2239     case DaySection: return QDateTimeEdit::DaySection;
2240     case MonthSection: return QDateTimeEdit::MonthSection;
2241     case YearSection2Digits:
2242     case YearSection: return QDateTimeEdit::YearSection;
2243     case Hour12Section:
2244     case Hour24Section: return QDateTimeEdit::HourSection;
2245     case FirstSection:
2246     case NoSection:
2247     case LastSection: break;
2248     }
2249     return QDateTimeEdit::NoSection;
2250 }
2251
2252 QDateTimeEdit::Sections QDateTimeEditPrivate::convertSections(QDateTimeParser::Sections s)
2253 {
2254     QDateTimeEdit::Sections ret = 0;
2255     if (s & QDateTimeParser::MSecSection)
2256         ret |= QDateTimeEdit::MSecSection;
2257     if (s & QDateTimeParser::SecondSection)
2258         ret |= QDateTimeEdit::SecondSection;
2259     if (s & QDateTimeParser::MinuteSection)
2260         ret |= QDateTimeEdit::MinuteSection;
2261     if (s & (QDateTimeParser::Hour24Section|QDateTimeParser::Hour12Section))
2262         ret |= QDateTimeEdit::HourSection;
2263     if (s & QDateTimeParser::AmPmSection)
2264         ret |= QDateTimeEdit::AmPmSection;
2265     if (s & (QDateTimeParser::DaySection|QDateTimeParser::DayOfWeekSection))
2266         ret |= QDateTimeEdit::DaySection;
2267     if (s & QDateTimeParser::MonthSection)
2268         ret |= QDateTimeEdit::MonthSection;
2269     if (s & (QDateTimeParser::YearSection|QDateTimeParser::YearSection2Digits))
2270         ret |= QDateTimeEdit::YearSection;
2271
2272     return ret;
2273 }
2274
2275 /*!
2276     \reimp
2277 */
2278
2279 void QDateTimeEdit::paintEvent(QPaintEvent *event)
2280 {
2281     Q_D(QDateTimeEdit);
2282     if (!d->calendarPopupEnabled()) {
2283         QAbstractSpinBox::paintEvent(event);
2284         return;
2285     }
2286
2287     QStyleOptionSpinBox opt;
2288     initStyleOption(&opt);
2289
2290     QStyleOptionComboBox optCombo;
2291
2292     optCombo.init(this);
2293     optCombo.editable = true;
2294         optCombo.frame = opt.frame;
2295     optCombo.subControls = opt.subControls;
2296     optCombo.activeSubControls = opt.activeSubControls;
2297     optCombo.state = opt.state;
2298     if (d->readOnly) {
2299         optCombo.state &= ~QStyle::State_Enabled;
2300     }
2301
2302     QPainter p(this);
2303     style()->drawComplexControl(QStyle::CC_ComboBox, &optCombo, &p, this);
2304 }
2305
2306 QString QDateTimeEditPrivate::getAmPmText(AmPm ap, Case cs) const
2307 {
2308     if (ap == AmText) {
2309         return (cs == UpperCase ? QDateTimeEdit::tr("AM") : QDateTimeEdit::tr("am"));
2310     } else {
2311         return (cs == UpperCase ? QDateTimeEdit::tr("PM") : QDateTimeEdit::tr("pm"));
2312     }
2313 }
2314
2315 int QDateTimeEditPrivate::absoluteIndex(QDateTimeEdit::Section s, int index) const
2316 {
2317     for (int i=0; i<sectionNodes.size(); ++i) {
2318         if (convertToPublic(sectionNodes.at(i).type) == s && index-- == 0) {
2319             return i;
2320         }
2321     }
2322     return NoSectionIndex;
2323 }
2324
2325 int QDateTimeEditPrivate::absoluteIndex(const SectionNode &s) const
2326 {
2327     return sectionNodes.indexOf(s);
2328 }
2329
2330 void QDateTimeEditPrivate::interpret(EmitPolicy ep)
2331 {
2332     Q_Q(QDateTimeEdit);
2333     QString tmp = displayText();
2334     int pos = edit->cursorPosition();
2335     const QValidator::State state = q->validate(tmp, pos);
2336     if (state != QValidator::Acceptable
2337         && correctionMode == QAbstractSpinBox::CorrectToPreviousValue
2338         && (state == QValidator::Invalid || !(fieldInfo(currentSectionIndex) & AllowPartial))) {
2339         setValue(value, ep);
2340         updateTimeSpec();
2341     } else {
2342         QAbstractSpinBoxPrivate::interpret(ep);
2343     }
2344 }
2345
2346 void QDateTimeEditPrivate::clearCache() const
2347 {
2348     QAbstractSpinBoxPrivate::clearCache();
2349     cachedDay = -1;
2350 }
2351
2352 /*!
2353     Initialize \a option with the values from this QDataTimeEdit. This method
2354     is useful for subclasses when they need a QStyleOptionSpinBox, but don't want
2355     to fill in all the information themselves.
2356
2357     \sa QStyleOption::initFrom()
2358 */
2359 void QDateTimeEdit::initStyleOption(QStyleOptionSpinBox *option) const
2360 {
2361     if (!option)
2362         return;
2363
2364     Q_D(const QDateTimeEdit);
2365     QAbstractSpinBox::initStyleOption(option);
2366     if (d->calendarPopupEnabled()) {
2367         option->subControls = QStyle::SC_ComboBoxFrame | QStyle::SC_ComboBoxEditField
2368                               | QStyle::SC_ComboBoxArrow;
2369         if (d->arrowState == QStyle::State_Sunken)
2370             option->state |= QStyle::State_Sunken;
2371         else
2372             option->state &= ~QStyle::State_Sunken;
2373     }
2374 }
2375
2376 void QDateTimeEditPrivate::init(const QVariant &var)
2377 {
2378     Q_Q(QDateTimeEdit);
2379     switch (var.type()) {
2380     case QVariant::Date:
2381         value = QDateTime(var.toDate(), QDATETIMEEDIT_TIME_MIN);
2382         q->setDisplayFormat(defaultDateFormat);
2383         if (sectionNodes.isEmpty()) // ### safeguard for broken locale
2384             q->setDisplayFormat(QLatin1String("dd/MM/yyyy"));
2385         break;
2386     case QVariant::DateTime:
2387         value = var;
2388         q->setDisplayFormat(defaultDateTimeFormat);
2389         if (sectionNodes.isEmpty()) // ### safeguard for broken locale
2390             q->setDisplayFormat(QLatin1String("dd/MM/yyyy hh:mm:ss"));
2391         break;
2392     case QVariant::Time:
2393         value = QDateTime(QDATETIMEEDIT_DATE_INITIAL, var.toTime());
2394         q->setDisplayFormat(defaultTimeFormat);
2395         if (sectionNodes.isEmpty()) // ### safeguard for broken locale
2396             q->setDisplayFormat(QLatin1String("hh:mm:ss"));
2397         break;
2398     default:
2399         Q_ASSERT_X(0, "QDateTimeEditPrivate::init", "Internal error");
2400         break;
2401     }
2402 #ifdef QT_KEYPAD_NAVIGATION
2403     if (QApplication::keypadNavigationEnabled())
2404         q->setCalendarPopup(true);
2405 #endif
2406     updateTimeSpec();
2407     q->setInputMethodHints(Qt::ImhPreferNumbers);
2408     setLayoutItemMargins(QStyle::SE_DateTimeEditLayoutItem);
2409 }
2410
2411 void QDateTimeEditPrivate::_q_resetButton()
2412 {
2413     updateArrow(QStyle::State_None);
2414 }
2415
2416 void QDateTimeEditPrivate::updateArrow(QStyle::StateFlag state)
2417 {
2418     Q_Q(QDateTimeEdit);
2419
2420     if (arrowState == state)
2421         return;
2422     arrowState = state;
2423     if (arrowState != QStyle::State_None)
2424         buttonState |= Mouse;
2425     else {
2426         buttonState = 0;
2427         hoverControl = QStyle::SC_ComboBoxFrame;
2428     }
2429     q->update();
2430 }
2431
2432 /*!
2433     \internal
2434     Returns the hover control at \a pos.
2435     This will update the hoverRect and hoverControl.
2436 */
2437 QStyle::SubControl QDateTimeEditPrivate::newHoverControl(const QPoint &pos)
2438 {
2439     if (!calendarPopupEnabled())
2440         return QAbstractSpinBoxPrivate::newHoverControl(pos);
2441
2442     Q_Q(QDateTimeEdit);
2443
2444     QStyleOptionComboBox optCombo;
2445     optCombo.init(q);
2446     optCombo.editable = true;
2447     optCombo.subControls = QStyle::SC_All;
2448     hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &optCombo, pos, q);
2449     return hoverControl;
2450 }
2451
2452 void QDateTimeEditPrivate::updateEditFieldGeometry()
2453 {
2454     if (!calendarPopupEnabled()) {
2455         QAbstractSpinBoxPrivate::updateEditFieldGeometry();
2456         return;
2457     }
2458
2459     Q_Q(QDateTimeEdit);
2460
2461     QStyleOptionComboBox optCombo;
2462     optCombo.init(q);
2463     optCombo.editable = true;
2464     optCombo.subControls = QStyle::SC_ComboBoxEditField;
2465     edit->setGeometry(q->style()->subControlRect(QStyle::CC_ComboBox, &optCombo,
2466                                                  QStyle::SC_ComboBoxEditField, q));
2467 }
2468
2469 QVariant QDateTimeEditPrivate::getZeroVariant() const
2470 {
2471     Q_ASSERT(type == QVariant::DateTime);
2472     return QDateTime(QDATETIMEEDIT_DATE_INITIAL, QTime(), spec);
2473 }
2474
2475 void QDateTimeEditPrivate::setRange(const QVariant &min, const QVariant &max)
2476 {
2477     QAbstractSpinBoxPrivate::setRange(min, max);
2478     syncCalendarWidget();
2479 }
2480
2481
2482 bool QDateTimeEditPrivate::isSeparatorKey(const QKeyEvent *ke) const
2483 {
2484     if (!ke->text().isEmpty() && currentSectionIndex + 1 < sectionNodes.size() && currentSectionIndex >= 0) {
2485         if (fieldInfo(currentSectionIndex) & Numeric) {
2486             if (ke->text().at(0).isNumber())
2487                 return false;
2488         } else if (ke->text().at(0).isLetterOrNumber()) {
2489             return false;
2490         }
2491         return separators.at(currentSectionIndex + 1).contains(ke->text());
2492     }
2493     return false;
2494 }
2495
2496 void QDateTimeEditPrivate::initCalendarPopup(QCalendarWidget *cw)
2497 {
2498     Q_Q(QDateTimeEdit);
2499     if (!monthCalendar) {
2500         monthCalendar = new QCalendarPopup(q, cw);
2501         monthCalendar->setObjectName(QLatin1String("qt_datetimedit_calendar"));
2502         QObject::connect(monthCalendar, SIGNAL(newDateSelected(QDate)), q, SLOT(setDate(QDate)));
2503         QObject::connect(monthCalendar, SIGNAL(hidingCalendar(QDate)), q, SLOT(setDate(QDate)));
2504         QObject::connect(monthCalendar, SIGNAL(activated(QDate)), q, SLOT(setDate(QDate)));
2505         QObject::connect(monthCalendar, SIGNAL(activated(QDate)), monthCalendar, SLOT(close()));
2506         QObject::connect(monthCalendar, SIGNAL(resetButton()), q, SLOT(_q_resetButton()));
2507     } else if (cw) {
2508         monthCalendar->setCalendarWidget(cw);
2509     }
2510     syncCalendarWidget();
2511 }
2512
2513 void QDateTimeEditPrivate::positionCalendarPopup()
2514 {
2515     Q_Q(QDateTimeEdit);
2516     QPoint pos = (q->layoutDirection() == Qt::RightToLeft) ? q->rect().bottomRight() : q->rect().bottomLeft();
2517     QPoint pos2 = (q->layoutDirection() == Qt::RightToLeft) ? q->rect().topRight() : q->rect().topLeft();
2518     pos = q->mapToGlobal(pos);
2519     pos2 = q->mapToGlobal(pos2);
2520     QSize size = monthCalendar->sizeHint();
2521     QRect screen = QApplication::desktop()->availableGeometry(pos);
2522     //handle popup falling "off screen"
2523     if (q->layoutDirection() == Qt::RightToLeft) {
2524         pos.setX(pos.x()-size.width());
2525         pos2.setX(pos2.x()-size.width());
2526         if (pos.x() < screen.left())
2527             pos.setX(qMax(pos.x(), screen.left()));
2528         else if (pos.x()+size.width() > screen.right())
2529             pos.setX(qMax(pos.x()-size.width(), screen.right()-size.width()));
2530     } else {
2531         if (pos.x()+size.width() > screen.right())
2532             pos.setX(screen.right()-size.width());
2533         pos.setX(qMax(pos.x(), screen.left()));
2534     }
2535     if (pos.y() + size.height() > screen.bottom())
2536         pos.setY(pos2.y() - size.height());
2537     else if (pos.y() < screen.top())
2538         pos.setY(screen.top());
2539     if (pos.y() < screen.top())
2540         pos.setY(screen.top());
2541     if (pos.y()+size.height() > screen.bottom())
2542         pos.setY(screen.bottom()-size.height());
2543     monthCalendar->move(pos);
2544 }
2545
2546 bool QDateTimeEditPrivate::calendarPopupEnabled() const
2547 {
2548     return (calendarPopup && (sections & (DateSectionMask)));
2549 }
2550
2551 void QDateTimeEditPrivate::syncCalendarWidget()
2552 {
2553     Q_Q(QDateTimeEdit);
2554     if (monthCalendar) {
2555         const bool sb = monthCalendar->blockSignals(true);
2556         monthCalendar->setDateRange(q->minimumDate(), q->maximumDate());
2557         monthCalendar->setDate(q->date());
2558         monthCalendar->blockSignals(sb);
2559     }
2560 }
2561
2562 QCalendarPopup::QCalendarPopup(QWidget * parent, QCalendarWidget *cw)
2563     : QWidget(parent, Qt::Popup)
2564 {
2565     setAttribute(Qt::WA_WindowPropagation);
2566
2567     dateChanged = false;
2568     if (!cw) {
2569         verifyCalendarInstance();
2570     } else {
2571         setCalendarWidget(cw);
2572     }
2573 }
2574
2575 QCalendarWidget *QCalendarPopup::verifyCalendarInstance()
2576 {
2577     if (calendar.isNull()) {
2578         QCalendarWidget *cw = new QCalendarWidget(this);
2579         cw->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
2580 #ifdef QT_KEYPAD_NAVIGATION
2581         if (QApplication::keypadNavigationEnabled())
2582             cw->setHorizontalHeaderFormat(QCalendarWidget::SingleLetterDayNames);
2583 #endif
2584         setCalendarWidget(cw);
2585         return cw;
2586     } else {
2587         return calendar.data();
2588     }
2589 }
2590
2591 void QCalendarPopup::setCalendarWidget(QCalendarWidget *cw)
2592 {
2593     Q_ASSERT(cw);
2594     QVBoxLayout *widgetLayout = qobject_cast<QVBoxLayout*>(layout());
2595     if (!widgetLayout) {
2596         widgetLayout = new QVBoxLayout(this);
2597         widgetLayout->setMargin(0);
2598         widgetLayout->setSpacing(0);
2599     }
2600     delete calendar.data();
2601     calendar = QWeakPointer<QCalendarWidget>(cw);
2602     widgetLayout->addWidget(cw);
2603
2604     connect(cw, SIGNAL(activated(QDate)), this, SLOT(dateSelected(QDate)));
2605     connect(cw, SIGNAL(clicked(QDate)), this, SLOT(dateSelected(QDate)));
2606     connect(cw, SIGNAL(selectionChanged()), this, SLOT(dateSelectionChanged()));
2607
2608     cw->setFocus();
2609 }
2610
2611
2612 void QCalendarPopup::setDate(const QDate &date)
2613 {
2614     oldDate = date;
2615     verifyCalendarInstance()->setSelectedDate(date);
2616 }
2617
2618 void QCalendarPopup::setDateRange(const QDate &min, const QDate &max)
2619 {
2620     QCalendarWidget *cw = verifyCalendarInstance();
2621     cw->setMinimumDate(min);
2622     cw->setMaximumDate(max);
2623 }
2624
2625 void QCalendarPopup::mousePressEvent(QMouseEvent *event)
2626 {
2627     QDateTimeEdit *dateTime = qobject_cast<QDateTimeEdit *>(parentWidget());
2628     if (dateTime) {
2629         QStyleOptionComboBox opt;
2630         opt.init(dateTime);
2631         QRect arrowRect = dateTime->style()->subControlRect(QStyle::CC_ComboBox, &opt,
2632                                                             QStyle::SC_ComboBoxArrow, dateTime);
2633         arrowRect.moveTo(dateTime->mapToGlobal(arrowRect .topLeft()));
2634         if (arrowRect.contains(event->globalPos()) || rect().contains(event->pos()))
2635             setAttribute(Qt::WA_NoMouseReplay);
2636     }
2637     QWidget::mousePressEvent(event);
2638 }
2639
2640 void QCalendarPopup::mouseReleaseEvent(QMouseEvent*)
2641 {
2642     emit resetButton();
2643 }
2644
2645 bool QCalendarPopup::event(QEvent *event)
2646 {
2647     if (event->type() == QEvent::KeyPress) {
2648         QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
2649         if (keyEvent->key()== Qt::Key_Escape)
2650             dateChanged = false;
2651     }
2652     return QWidget::event(event);
2653 }
2654
2655 void QCalendarPopup::dateSelectionChanged()
2656 {
2657     dateChanged = true;
2658     emit newDateSelected(verifyCalendarInstance()->selectedDate());
2659 }
2660 void QCalendarPopup::dateSelected(const QDate &date)
2661 {
2662     dateChanged = true;
2663     emit activated(date);
2664     close();
2665 }
2666
2667 void QCalendarPopup::hideEvent(QHideEvent *)
2668 {
2669     emit resetButton();
2670     if (!dateChanged)
2671         emit hidingCalendar(oldDate);
2672 }
2673
2674 QT_END_NAMESPACE
2675 #include "moc_qdatetimeedit.cpp"
2676
2677 #endif // QT_NO_DATETIMEEDIT