source: trunk/src/gui/widgets/qdatetimeedit.cpp@ 348

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

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

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