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