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

Last change on this file since 858 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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