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

Last change on this file since 769 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 76.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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 QDateTimeEdit
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 QDateTimeEdit
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 \sa calendarPopup
758*/
759void QDateTimeEdit::setCalendarWidget(QCalendarWidget *calendarWidget)
760{
761 Q_D(QDateTimeEdit);
762 if (!calendarWidget) {
763 qWarning("QDateTimeEdit::setCalendarWidget: Cannot set a null calendar widget");
764 return;
765 }
766
767 if (!d->calendarPopup) {
768 qWarning("QDateTimeEdit::setCalendarWidget: calendarPopup is set to false");
769 return;
770 }
771
772 if (!(d->display & QDateTimeParser::DateSectionMask)) {
773 qWarning("QDateTimeEdit::setCalendarWidget: no date sections specified");
774 return;
775 }
776 d->initCalendarPopup(calendarWidget);
777}
778
779
780/*!
781 \since 4.2
782
783 Selects \a section. If \a section doesn't exist in the currently
784 displayed sections this function does nothing. If \a section is
785 NoSection this function will unselect all text in the editor.
786 Otherwise this function will move the cursor and the current section
787 to the selected section.
788
789 \sa currentSection()
790*/
791
792void QDateTimeEdit::setSelectedSection(Section section)
793{
794 Q_D(QDateTimeEdit);
795 if (section == NoSection) {
796 d->edit->setSelection(d->edit->cursorPosition(), 0);
797 } else if (section & d->sections) {
798 if (currentSection() != section)
799 setCurrentSection(section);
800 d->setSelected(d->currentSectionIndex);
801 }
802}
803
804
805
806/*!
807 \fn QString QDateTimeEdit::sectionText(Section section) const
808
809 Returns the text from the given \a section.
810
811 \sa currentSection()
812*/
813
814QString QDateTimeEdit::sectionText(Section section) const
815{
816 Q_D(const QDateTimeEdit);
817 if (section == QDateTimeEdit::NoSection || !(section & d->sections)) {
818 return QString();
819 }
820
821 d->updateCache(d->value, d->displayText());
822 const int sectionIndex = d->absoluteIndex(section, 0);
823 return d->sectionText(sectionIndex);
824}
825
826/*!
827 \property QDateTimeEdit::displayFormat
828
829 \brief the format used to display the time/date of the date time edit
830
831 This format is the same as the one used described in QDateTime::toString()
832 and QDateTime::fromString()
833
834 Example format strings(assuming that the date is 2nd of July 1969):
835
836 \table
837 \header \i Format \i Result
838 \row \i dd.MM.yyyy \i 02.07.1969
839 \row \i MMM d yy \i Jul 2 69
840 \row \i MMMM d yy \i July 2 69
841 \endtable
842
843 Note that if you specify a two digit year, it will be interpreted
844 to be in the century in which the date time edit was initialized.
845 The default century is the 21 (2000-2099).
846
847 If you specify an invalid format the format will not be set.
848
849 \sa QDateTime::toString(), displayedSections()
850*/
851
852QString QDateTimeEdit::displayFormat() const
853{
854 Q_D(const QDateTimeEdit);
855 return isRightToLeft() ? d->unreversedFormat : d->displayFormat;
856}
857
858template<typename C> static inline C reverse(const C &l)
859{
860 C ret;
861 for (int i=l.size() - 1; i>=0; --i)
862 ret.append(l.at(i));
863 return ret;
864}
865
866void QDateTimeEdit::setDisplayFormat(const QString &format)
867{
868 Q_D(QDateTimeEdit);
869 if (d->parseFormat(format)) {
870 d->unreversedFormat.clear();
871 if (isRightToLeft()) {
872 d->unreversedFormat = format;
873 d->displayFormat.clear();
874 for (int i=d->sectionNodes.size() - 1; i>=0; --i) {
875 d->displayFormat += d->separators.at(i + 1);
876 d->displayFormat += d->sectionFormat(i);
877 }
878 d->displayFormat += d->separators.at(0);
879 d->separators = reverse(d->separators);
880 d->sectionNodes = reverse(d->sectionNodes);
881 }
882
883 d->formatExplicitlySet = true;
884 d->sections = d->convertSections(d->display);
885 d->clearCache();
886
887 d->currentSectionIndex = qMin(d->currentSectionIndex, d->sectionNodes.size() - 1);
888 const bool timeShown = (d->sections & TimeSections_Mask);
889 const bool dateShown = (d->sections & DateSections_Mask);
890 Q_ASSERT(dateShown || timeShown);
891 if (timeShown && !dateShown) {
892 setDateRange(d->value.toDate(), d->value.toDate());
893 } else if (dateShown && !timeShown) {
894 setTimeRange(QDATETIMEEDIT_TIME_MIN, QDATETIMEEDIT_TIME_MAX);
895 d->value = QDateTime(d->value.toDate(), QTime(), d->spec);
896 }
897 d->updateEdit();
898 d->_q_editorCursorPositionChanged(-1, 0);
899 }
900}
901
902/*!
903 \property QDateTimeEdit::calendarPopup
904 \brief the current calender pop-up showing mode.
905 \since 4.2
906
907 The calendar pop-up will be shown upon clicking the arrow button.
908 This property is valid only if there is a valid date display format.
909
910 \sa setDisplayFormat()
911*/
912
913bool QDateTimeEdit::calendarPopup() const
914{
915 Q_D(const QDateTimeEdit);
916 return d->calendarPopup;
917}
918
919void QDateTimeEdit::setCalendarPopup(bool enable)
920{
921 Q_D(QDateTimeEdit);
922 if (enable == d->calendarPopup)
923 return;
924 setAttribute(Qt::WA_MacShowFocusRect, !enable);
925 d->calendarPopup = enable;
926#ifdef QT_KEYPAD_NAVIGATION
927 if (!enable)
928 d->focusOnButton = false;
929#endif
930 d->updateEditFieldGeometry();
931 update();
932}
933
934/*!
935 \property QDateTimeEdit::timeSpec
936 \brief the current timespec used by the date time edit.
937 \since 4.4
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 d->edit->d_func()->control->setCursorBlinkPeriod(0);
1090 d->setSelected(0);
1091 }
1092 }
1093 return;
1094#endif
1095 case Qt::Key_Enter:
1096 case Qt::Key_Return:
1097 d->interpret(AlwaysEmit);
1098 d->setSelected(d->currentSectionIndex, true);
1099 event->ignore();
1100 emit editingFinished();
1101 return;
1102 default:
1103#ifdef QT_KEYPAD_NAVIGATION
1104 if (QApplication::keypadNavigationEnabled() && !hasEditFocus()
1105 && !event->text().isEmpty() && event->text().at(0).isLetterOrNumber()) {
1106 setEditFocus(true);
1107
1108 //hide cursor
1109 d->edit->d_func()->setCursorVisible(false);
1110 d->edit->d_func()->control->setCursorBlinkPeriod(0);
1111 d->setSelected(0);
1112 oldCurrent = 0;
1113 }
1114#endif
1115 if (!d->isSeparatorKey(event)) {
1116 inserted = select = !event->text().isEmpty() && event->text().at(0).isPrint()
1117 && !(event->modifiers() & ~(Qt::ShiftModifier|Qt::KeypadModifier));
1118 break;
1119 }
1120 case Qt::Key_Left:
1121 case Qt::Key_Right:
1122 if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) {
1123 if (
1124#ifdef QT_KEYPAD_NAVIGATION
1125 QApplication::keypadNavigationEnabled() && !hasEditFocus()
1126 || !QApplication::keypadNavigationEnabled() &&
1127#endif
1128 !(event->modifiers() & Qt::ControlModifier)) {
1129 select = false;
1130 break;
1131 }
1132#ifdef Q_WS_MAC
1133 else
1134#ifdef QT_KEYPAD_NAVIGATION
1135 if (!QApplication::keypadNavigationEnabled())
1136#endif
1137 {
1138 select = (event->modifiers() & Qt::ShiftModifier);
1139 break;
1140 }
1141#endif
1142 }
1143 // else fall through
1144 case Qt::Key_Backtab:
1145 case Qt::Key_Tab: {
1146 event->accept();
1147 if (d->specialValue()) {
1148 d->edit->setSelection(d->edit->cursorPosition(), 0);
1149 return;
1150 }
1151 const bool forward = event->key() != Qt::Key_Left && event->key() != Qt::Key_Backtab
1152 && (event->key() != Qt::Key_Tab || !(event->modifiers() & Qt::ShiftModifier));
1153#ifdef QT_KEYPAD_NAVIGATION
1154 int newSection = d->nextPrevSection(d->currentSectionIndex, forward);
1155 if (QApplication::keypadNavigationEnabled()) {
1156 if (d->focusOnButton) {
1157 newSection = forward ? 0 : d->sectionNodes.size() - 1;
1158 d->focusOnButton = false;
1159 update();
1160 } else if (newSection < 0 && select && d->calendarPopupEnabled()) {
1161 setSelectedSection(NoSection);
1162 d->focusOnButton = true;
1163 update();
1164 return;
1165 }
1166 }
1167 // only allow date/time sections to be selected.
1168 if (newSection & ~(QDateTimeParser::TimeSectionMask | QDateTimeParser::DateSectionMask))
1169 return;
1170#endif
1171 //key tab and backtab will be managed thrgout QWidget::event
1172 if (event->key() != Qt::Key_Backtab && event->key() != Qt::Key_Tab)
1173 focusNextPrevChild(forward);
1174
1175 return; }
1176 }
1177 QAbstractSpinBox::keyPressEvent(event);
1178 if (select && !(event->modifiers() & Qt::ShiftModifier) && !d->edit->hasSelectedText()) {
1179 if (inserted && d->sectionAt(d->edit->cursorPosition()) == QDateTimeParser::NoSectionIndex) {
1180 QString str = d->displayText();
1181 int pos = d->edit->cursorPosition();
1182 if (validate(str, pos) == QValidator::Acceptable
1183 && (d->sectionNodes.at(oldCurrent).count != 1
1184 || d->sectionMaxSize(oldCurrent) == d->sectionSize(oldCurrent)
1185 || d->skipToNextSection(oldCurrent, d->value.toDateTime(), d->sectionText(oldCurrent)))) {
1186 QDTEDEBUG << "Setting currentsection to"
1187 << d->closestSection(d->edit->cursorPosition(), true) << event->key()
1188 << oldCurrent << str;
1189 const int tmp = d->closestSection(d->edit->cursorPosition(), true);
1190 if (tmp >= 0)
1191 d->currentSectionIndex = tmp;
1192 }
1193 }
1194 if (d->currentSectionIndex != oldCurrent) {
1195 d->setSelected(d->currentSectionIndex);
1196 }
1197 }
1198 if (d->specialValue()) {
1199 d->edit->setSelection(d->edit->cursorPosition(), 0);
1200 }
1201}
1202
1203/*!
1204 \reimp
1205*/
1206
1207#ifndef QT_NO_WHEELEVENT
1208void QDateTimeEdit::wheelEvent(QWheelEvent *event)
1209{
1210 QAbstractSpinBox::wheelEvent(event);
1211}
1212#endif
1213
1214/*!
1215 \reimp
1216*/
1217
1218void QDateTimeEdit::focusInEvent(QFocusEvent *event)
1219{
1220 Q_D(QDateTimeEdit);
1221 QAbstractSpinBox::focusInEvent(event);
1222 QString *frm = 0;
1223 const int oldPos = d->edit->cursorPosition();
1224 if (!d->formatExplicitlySet) {
1225 if (d->displayFormat == d->defaultTimeFormat) {
1226 frm = &d->defaultTimeFormat;
1227 } else if (d->displayFormat == d->defaultDateFormat) {
1228 frm = &d->defaultDateFormat;
1229 } else if (d->displayFormat == d->defaultDateTimeFormat) {
1230 frm = &d->defaultDateTimeFormat;
1231 }
1232
1233 if (frm) {
1234 d->readLocaleSettings();
1235 if (d->displayFormat != *frm) {
1236 setDisplayFormat(*frm);
1237 d->formatExplicitlySet = false;
1238 d->edit->setCursorPosition(oldPos);
1239 }
1240 }
1241 }
1242 const bool oldHasHadFocus = d->hasHadFocus;
1243 d->hasHadFocus = true;
1244 bool first = true;
1245 switch (event->reason()) {
1246 case Qt::BacktabFocusReason:
1247 first = false;
1248 break;
1249 case Qt::MouseFocusReason:
1250 case Qt::PopupFocusReason:
1251 return;
1252 case Qt::ActiveWindowFocusReason:
1253 if (oldHasHadFocus)
1254 return;
1255 case Qt::ShortcutFocusReason:
1256 case Qt::TabFocusReason:
1257 default:
1258 break;
1259 }
1260 if (isRightToLeft())
1261 first = !first;
1262 d->updateEdit(); // needed to make it update specialValueText
1263
1264 d->setSelected(first ? 0 : d->sectionNodes.size() - 1);
1265}
1266
1267/*!
1268 \reimp
1269*/
1270
1271bool QDateTimeEdit::focusNextPrevChild(bool next)
1272{
1273 Q_D(QDateTimeEdit);
1274 const int newSection = d->nextPrevSection(d->currentSectionIndex, next);
1275 switch (d->sectionType(newSection)) {
1276 case QDateTimeParser::NoSection:
1277 case QDateTimeParser::FirstSection:
1278 case QDateTimeParser::LastSection:
1279 return QAbstractSpinBox::focusNextPrevChild(next);
1280 default:
1281 d->edit->deselect();
1282 d->edit->setCursorPosition(d->sectionPos(newSection));
1283 QDTEDEBUG << d->sectionPos(newSection);
1284 d->setSelected(newSection, true);
1285 return false;
1286 }
1287}
1288
1289/*!
1290 \reimp
1291*/
1292
1293void QDateTimeEdit::stepBy(int steps)
1294{
1295 Q_D(QDateTimeEdit);
1296#ifdef QT_KEYPAD_NAVIGATION
1297 // with keypad navigation and not editFocus, left right change the date/time by a fixed amount.
1298 if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
1299 // if date based, shift by day. else shift by 15min
1300 if (d->sections & DateSections_Mask) {
1301 setDateTime(dateTime().addDays(steps));
1302 } else {
1303 int minutes = time().hour()*60 + time().minute();
1304 int blocks = minutes/15;
1305 blocks += steps;
1306 /* rounding involved */
1307 if (minutes % 15) {
1308 if (steps < 0) {
1309 blocks += 1; // do one less step;
1310 }
1311 }
1312
1313 minutes = blocks * 15;
1314
1315 /* need to take wrapping into account */
1316 if (!d->wrapping) {
1317 int max_minutes = d->maximum.toTime().hour()*60 + d->maximum.toTime().minute();
1318 int min_minutes = d->minimum.toTime().hour()*60 + d->minimum.toTime().minute();
1319
1320 if (minutes >= max_minutes) {
1321 setTime(maximumTime());
1322 return;
1323 } else if (minutes <= min_minutes) {
1324 setTime(minimumTime());
1325 return;
1326 }
1327 }
1328 setTime(QTime(minutes/60, minutes%60));
1329 }
1330 return;
1331 }
1332#endif
1333 // don't optimize away steps == 0. This is the only way to select
1334 // the currentSection in Qt 4.1.x
1335 if (d->specialValue() && displayedSections() != AmPmSection) {
1336 for (int i=0; i<d->sectionNodes.size(); ++i) {
1337 if (d->sectionType(i) != QDateTimeParser::AmPmSection) {
1338 d->currentSectionIndex = i;
1339 break;
1340 }
1341 }
1342 }
1343 d->setValue(d->stepBy(d->currentSectionIndex, steps, false), EmitIfChanged);
1344 d->updateCache(d->value, d->displayText());
1345
1346 d->setSelected(d->currentSectionIndex);
1347 d->updateTimeSpec();
1348}
1349
1350/*!
1351 This virtual function is used by the date time edit whenever it
1352 needs to display \a dateTime.
1353
1354 If you reimplement this, you may also need to reimplement validate().
1355
1356 \sa dateTimeFromText(), validate()
1357*/
1358QString QDateTimeEdit::textFromDateTime(const QDateTime &dateTime) const
1359{
1360 Q_D(const QDateTimeEdit);
1361 return locale().toString(dateTime, d->displayFormat);
1362}
1363
1364
1365/*!
1366 Returns an appropriate datetime for the given \a text.
1367
1368 This virtual function is used by the datetime edit whenever it
1369 needs to interpret text entered by the user as a value.
1370
1371 \sa textFromDateTime(), validate()
1372*/
1373QDateTime QDateTimeEdit::dateTimeFromText(const QString &text) const
1374{
1375 Q_D(const QDateTimeEdit);
1376 QString copy = text;
1377 int pos = d->edit->cursorPosition();
1378 QValidator::State state = QValidator::Acceptable;
1379 return d->validateAndInterpret(copy, pos, state);
1380}
1381
1382/*!
1383 \reimp
1384*/
1385
1386QValidator::State QDateTimeEdit::validate(QString &text, int &pos) const
1387{
1388 Q_D(const QDateTimeEdit);
1389 QValidator::State state;
1390 d->validateAndInterpret(text, pos, state);
1391 return state;
1392}
1393
1394/*!
1395 \reimp
1396*/
1397
1398
1399void QDateTimeEdit::fixup(QString &input) const
1400{
1401 Q_D(const QDateTimeEdit);
1402 QValidator::State state;
1403 int copy = d->edit->cursorPosition();
1404
1405 d->validateAndInterpret(input, copy, state, true);
1406}
1407
1408
1409/*!
1410 \reimp
1411*/
1412
1413QDateTimeEdit::StepEnabled QDateTimeEdit::stepEnabled() const
1414{
1415 Q_D(const QDateTimeEdit);
1416 if (d->readOnly)
1417 return StepEnabled(0);
1418 if (d->specialValue()) {
1419 return (d->minimum == d->maximum ? StepEnabled(0) : StepEnabled(StepUpEnabled));
1420 }
1421
1422 QAbstractSpinBox::StepEnabled ret = 0;
1423
1424#ifdef QT_KEYPAD_NAVIGATION
1425 if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
1426 if (d->wrapping)
1427 return StepEnabled(StepUpEnabled | StepDownEnabled);
1428 // 3 cases. date, time, datetime. each case look
1429 // at just the relavant component.
1430 QVariant max, min, val;
1431 if (!(d->sections & DateSections_Mask)) {
1432 // time only, no date
1433 max = d->maximum.toTime();
1434 min = d->minimum.toTime();
1435 val = d->value.toTime();
1436 } else if (!(d->sections & TimeSections_Mask)) {
1437 // date only, no time
1438 max = d->maximum.toDate();
1439 min = d->minimum.toDate();
1440 val = d->value.toDate();
1441 } else {
1442 // both
1443 max = d->maximum;
1444 min = d->minimum;
1445 val = d->value;
1446 }
1447 if (val != min)
1448 ret |= QAbstractSpinBox::StepDownEnabled;
1449 if (val != max)
1450 ret |= QAbstractSpinBox::StepUpEnabled;
1451 return ret;
1452 }
1453#endif
1454 switch (d->sectionType(d->currentSectionIndex)) {
1455 case QDateTimeParser::NoSection:
1456 case QDateTimeParser::FirstSection:
1457 case QDateTimeParser::LastSection: return 0;
1458 default: break;
1459 }
1460 if (d->wrapping)
1461 return StepEnabled(StepDownEnabled|StepUpEnabled);
1462
1463 QVariant v = d->stepBy(d->currentSectionIndex, 1, true);
1464 if (v != d->value) {
1465 ret |= QAbstractSpinBox::StepUpEnabled;
1466 }
1467 v = d->stepBy(d->currentSectionIndex, -1, true);
1468 if (v != d->value) {
1469 ret |= QAbstractSpinBox::StepDownEnabled;
1470 }
1471
1472 return ret;
1473}
1474
1475
1476/*!
1477 \reimp
1478*/
1479
1480void QDateTimeEdit::mousePressEvent(QMouseEvent *event)
1481{
1482 Q_D(QDateTimeEdit);
1483 if (!d->calendarPopupEnabled()) {
1484 QAbstractSpinBox::mousePressEvent(event);
1485 return;
1486 }
1487 d->updateHoverControl(event->pos());
1488 if (d->hoverControl == QStyle::SC_ComboBoxArrow) {
1489 event->accept();
1490 if (d->readOnly) {
1491 return;
1492 }
1493 d->updateArrow(QStyle::State_Sunken);
1494 d->initCalendarPopup();
1495 d->positionCalendarPopup();
1496 //Show the calendar
1497 d->monthCalendar->show();
1498 } else {
1499 QAbstractSpinBox::mousePressEvent(event);
1500 }
1501}
1502
1503/*!
1504 \class QTimeEdit
1505 \brief The QTimeEdit class provides a widget for editing times based on
1506 the QDateTimeEdit widget.
1507
1508 \ingroup basicwidgets
1509
1510
1511 Many of the properties and functions provided by QTimeEdit are implemented in
1512 QDateTimeEdit. The following properties are most relevant to users of this
1513 class:
1514
1515 \list
1516 \o \l{QDateTimeEdit::time}{time} holds the date displayed by the widget.
1517 \o \l{QDateTimeEdit::minimumTime}{minimumTime} defines the minimum (earliest) time
1518 that can be set by the user.
1519 \o \l{QDateTimeEdit::maximumTime}{maximumTime} defines the maximum (latest) time
1520 that can be set by the user.
1521 \o \l{QDateTimeEdit::displayFormat}{displayFormat} contains a string that is used
1522 to format the time displayed in the widget.
1523 \endlist
1524
1525 \table 100%
1526 \row \o \inlineimage windowsxp-timeedit.png Screenshot of a Windows XP style time editing widget
1527 \o A time editing widget shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
1528 \row \o \inlineimage macintosh-timeedit.png Screenshot of a Macintosh style time editing widget
1529 \o A time editing widget shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
1530 \row \o \inlineimage plastique-timeedit.png Screenshot of a Plastique style time editing widget
1531 \o A time editing widget shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
1532 \endtable
1533
1534 \sa QDateEdit, QDateTimeEdit
1535*/
1536
1537/*!
1538 Constructs an empty time editor with a \a parent.
1539*/
1540
1541
1542QTimeEdit::QTimeEdit(QWidget *parent)
1543 : QDateTimeEdit(QDATETIMEEDIT_TIME_MIN, QVariant::Time, parent)
1544{
1545}
1546
1547/*!
1548 Constructs an empty time editor with a \a parent. The time is set
1549 to \a time.
1550*/
1551
1552QTimeEdit::QTimeEdit(const QTime &time, QWidget *parent)
1553 : QDateTimeEdit(time, QVariant::Time, parent)
1554{
1555}
1556
1557/*!
1558 \property QTimeEdit::time
1559 \brief the QTime that is shown in the widget
1560
1561 By default, this property contains a time of 00:00:00 and 0 milliseconds.
1562*/
1563
1564
1565/*!
1566 \class QDateEdit
1567 \brief The QDateEdit class provides a widget for editing dates based on
1568 the QDateTimeEdit widget.
1569
1570 \ingroup basicwidgets
1571
1572
1573 Many of the properties and functions provided by QDateEdit are implemented in
1574 QDateTimeEdit. The following properties are most relevant to users of this
1575 class:
1576
1577 \list
1578 \o \l{QDateTimeEdit::date}{date} holds the date displayed by the widget.
1579 \o \l{QDateTimeEdit::minimumDate}{minimumDate} defines the minimum (earliest)
1580 date that can be set by the user.
1581 \o \l{QDateTimeEdit::maximumDate}{maximumDate} defines the maximum (latest) date
1582 that can be set by the user.
1583 \o \l{QDateTimeEdit::displayFormat}{displayFormat} contains a string that is used
1584 to format the date displayed in the widget.
1585 \endlist
1586
1587 \table 100%
1588 \row \o \inlineimage windowsxp-dateedit.png Screenshot of a Windows XP style date editing widget
1589 \o A date editing widget shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
1590 \row \o \inlineimage macintosh-dateedit.png Screenshot of a Macintosh style date editing widget
1591 \o A date editing widget shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
1592 \row \o \inlineimage plastique-dateedit.png Screenshot of a Plastique style date editing widget
1593 \o A date editing widget shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
1594 \endtable
1595
1596 \sa QTimeEdit, QDateTimeEdit
1597*/
1598
1599/*!
1600 Constructs an empty date editor with a \a parent.
1601*/
1602
1603QDateEdit::QDateEdit(QWidget *parent)
1604 : QDateTimeEdit(QDATETIMEEDIT_DATE_INITIAL, QVariant::Date, parent)
1605{
1606}
1607
1608/*!
1609 Constructs an empty date editor with a \a parent. The date is set
1610 to \a date.
1611*/
1612
1613QDateEdit::QDateEdit(const QDate &date, QWidget *parent)
1614 : QDateTimeEdit(date, QVariant::Date, parent)
1615{
1616}
1617
1618/*!
1619 \property QDateEdit::date
1620 \brief the QDate that is shown in the widget
1621
1622 By default, this property contains a date referring to January 1, 2000.
1623*/
1624
1625
1626// --- QDateTimeEditPrivate ---
1627
1628/*!
1629 \internal
1630 Constructs a QDateTimeEditPrivate object
1631*/
1632
1633
1634QDateTimeEditPrivate::QDateTimeEditPrivate()
1635 : QDateTimeParser(QVariant::DateTime, QDateTimeParser::DateTimeEdit)
1636{
1637 hasHadFocus = false;
1638 formatExplicitlySet = false;
1639 cacheGuard = false;
1640 fixday = true;
1641 type = QVariant::DateTime;
1642 sections = 0;
1643 cachedDay = -1;
1644 currentSectionIndex = FirstSectionIndex;
1645
1646 first.type = FirstSection;
1647 last.type = LastSection;
1648 none.type = NoSection;
1649 first.pos = 0;
1650 last.pos = -1;
1651 none.pos = -1;
1652 sections = 0;
1653 calendarPopup = false;
1654 minimum = QDATETIMEEDIT_COMPAT_DATETIME_MIN;
1655 maximum = QDATETIMEEDIT_DATETIME_MAX;
1656 arrowState = QStyle::State_None;
1657 monthCalendar = 0;
1658 readLocaleSettings();
1659
1660#ifdef QT_KEYPAD_NAVIGATION
1661 focusOnButton = false;
1662#endif
1663}
1664
1665void QDateTimeEditPrivate::updateTimeSpec()
1666{
1667 minimum = minimum.toDateTime().toTimeSpec(spec);
1668 maximum = maximum.toDateTime().toTimeSpec(spec);
1669 value = value.toDateTime().toTimeSpec(spec);
1670}
1671
1672void QDateTimeEditPrivate::updateEdit()
1673{
1674 const QString newText = (specialValue() ? specialValueText : textFromValue(value));
1675 if (newText == displayText())
1676 return;
1677 int selsize = edit->selectedText().size();
1678 const bool sb = edit->blockSignals(true);
1679
1680 edit->setText(newText);
1681
1682 if (!specialValue()
1683#ifdef QT_KEYPAD_NAVIGATION
1684 && !(QApplication::keypadNavigationEnabled() && !edit->hasEditFocus())
1685#endif
1686 ) {
1687 int cursor = sectionPos(currentSectionIndex);
1688 QDTEDEBUG << "cursor is " << cursor << currentSectionIndex;
1689 cursor = qBound(0, cursor, displayText().size());
1690 QDTEDEBUG << cursor;
1691 if (selsize > 0) {
1692 edit->setSelection(cursor, selsize);
1693 QDTEDEBUG << cursor << selsize;
1694 } else {
1695 edit->setCursorPosition(cursor);
1696 QDTEDEBUG << cursor;
1697
1698 }
1699 }
1700 edit->blockSignals(sb);
1701}
1702
1703
1704/*!
1705 \internal
1706
1707 Selects the section \a s. If \a forward is false selects backwards.
1708*/
1709
1710void QDateTimeEditPrivate::setSelected(int sectionIndex, bool forward)
1711{
1712 if (specialValue()
1713#ifdef QT_KEYPAD_NAVIGATION
1714 || (QApplication::keypadNavigationEnabled() && !edit->hasEditFocus())
1715#endif
1716 ) {
1717 edit->selectAll();
1718 } else {
1719 const SectionNode &node = sectionNode(sectionIndex);
1720 if (node.type == NoSection || node.type == LastSection || node.type == FirstSection)
1721 return;
1722
1723 updateCache(value, displayText());
1724 const int size = sectionSize(sectionIndex);
1725 if (forward) {
1726 edit->setSelection(sectionPos(node), size);
1727 } else {
1728 edit->setSelection(sectionPos(node) + size, -size);
1729 }
1730 }
1731}
1732
1733/*!
1734 \internal
1735
1736 Returns the section at index \a index or NoSection if there are no sections there.
1737*/
1738
1739int QDateTimeEditPrivate::sectionAt(int pos) const
1740{
1741 if (pos < separators.first().size()) {
1742 return (pos == 0 ? FirstSectionIndex : NoSectionIndex);
1743 } else if (displayText().size() - pos < separators.last().size() + 1) {
1744 if (separators.last().size() == 0) {
1745 return sectionNodes.count() - 1;
1746 }
1747 return (pos == displayText().size() ? LastSectionIndex : NoSectionIndex);
1748 }
1749 updateCache(value, displayText());
1750
1751 for (int i=0; i<sectionNodes.size(); ++i) {
1752 const int tmp = sectionPos(i);
1753 if (pos < tmp + sectionSize(i)) {
1754 return (pos < tmp ? -1 : i);
1755 }
1756 }
1757 return -1;
1758}
1759
1760/*!
1761 \internal
1762
1763 Returns the closest section of index \a index. Searches forward
1764 for a section if \a forward is true. Otherwise searches backwards.
1765*/
1766
1767int QDateTimeEditPrivate::closestSection(int pos, bool forward) const
1768{
1769 Q_ASSERT(pos >= 0);
1770 if (pos < separators.first().size()) {
1771 return forward ? 0 : FirstSectionIndex;
1772 } else if (displayText().size() - pos < separators.last().size() + 1) {
1773 return forward ? LastSectionIndex : sectionNodes.size() - 1;
1774 }
1775 updateCache(value, displayText());
1776 for (int i=0; i<sectionNodes.size(); ++i) {
1777 const int tmp = sectionPos(sectionNodes.at(i));
1778 if (pos < tmp + sectionSize(i)) {
1779 if (pos < tmp && !forward) {
1780 return i-1;
1781 }
1782 return i;
1783 } else if (i == sectionNodes.size() - 1 && pos > tmp) {
1784 return i;
1785 }
1786 }
1787 qWarning("QDateTimeEdit: Internal Error: closestSection returned NoSection");
1788 return NoSectionIndex;
1789}
1790
1791/*!
1792 \internal
1793
1794 Returns a copy of the section that is before or after \a current, depending on \a forward.
1795*/
1796
1797int QDateTimeEditPrivate::nextPrevSection(int current, bool forward) const
1798{
1799 Q_Q(const QDateTimeEdit);
1800 if (q->isRightToLeft())
1801 forward = !forward;
1802
1803 switch (current) {
1804 case FirstSectionIndex: return forward ? 0 : FirstSectionIndex;
1805 case LastSectionIndex: return (forward ? LastSectionIndex : sectionNodes.size() - 1);
1806 case NoSectionIndex: return FirstSectionIndex;
1807 default: break;
1808 }
1809 Q_ASSERT(current >= 0 && current < sectionNodes.size());
1810
1811 current += (forward ? 1 : -1);
1812 if (current >= sectionNodes.size()) {
1813 return LastSectionIndex;
1814 } else if (current < 0) {
1815 return FirstSectionIndex;
1816 }
1817
1818 return current;
1819}
1820
1821/*!
1822 \internal
1823
1824 Clears the text of section \a s.
1825*/
1826
1827void QDateTimeEditPrivate::clearSection(int index)
1828{
1829 const QLatin1Char space(' ');
1830 int cursorPos = edit->cursorPosition();
1831 bool blocked = edit->blockSignals(true);
1832 QString t = edit->text();
1833 const int pos = sectionPos(index);
1834 if (pos == -1) {
1835 qWarning("QDateTimeEdit: Internal error (%s:%d)", __FILE__, __LINE__);
1836 return;
1837 }
1838 const int size = sectionSize(index);
1839 t.replace(pos, size, QString().fill(space, size));
1840 edit->setText(t);
1841 edit->setCursorPosition(cursorPos);
1842 QDTEDEBUG << cursorPos;
1843
1844 edit->blockSignals(blocked);
1845}
1846
1847
1848/*!
1849 \internal
1850
1851 updates the cached values
1852*/
1853
1854void QDateTimeEditPrivate::updateCache(const QVariant &val, const QString &str) const
1855{
1856 if (val != cachedValue || str != cachedText || cacheGuard) {
1857 cacheGuard = true;
1858 QString copy = str;
1859 int unused = edit->cursorPosition();
1860 QValidator::State unusedState;
1861 validateAndInterpret(copy, unused, unusedState);
1862 cacheGuard = false;
1863 }
1864}
1865
1866/*!
1867 \internal
1868
1869 parses and validates \a input
1870*/
1871
1872QDateTime QDateTimeEditPrivate::validateAndInterpret(QString &input, int &position,
1873 QValidator::State &state, bool fixup) const
1874{
1875 if (input.isEmpty()) {
1876 if (sectionNodes.size() == 1 || !specialValueText.isEmpty()) {
1877 state = QValidator::Intermediate;
1878 } else {
1879 state = QValidator::Invalid;
1880 }
1881 return getZeroVariant().toDateTime();
1882 } else if (cachedText == input && !fixup) {
1883 state = cachedState;
1884 return cachedValue.toDateTime();
1885 } else if (!specialValueText.isEmpty()) {
1886 bool changeCase = false;
1887 const int max = qMin(specialValueText.size(), input.size());
1888 int i;
1889 for (i=0; i<max; ++i) {
1890 const QChar ic = input.at(i);
1891 const QChar sc = specialValueText.at(i);
1892 if (ic != sc) {
1893 if (sc.toLower() == ic.toLower()) {
1894 changeCase = true;
1895 } else {
1896 break;
1897 }
1898 }
1899 }
1900 if (i == max) {
1901 state = specialValueText.size() == input.size() ? QValidator::Acceptable : QValidator::Intermediate;
1902 if (changeCase) {
1903 input = specialValueText.left(max);
1904 }
1905 return minimum.toDateTime();
1906 }
1907 }
1908 StateNode tmp = parse(input, position, value.toDateTime(), fixup);
1909 input = tmp.input;
1910 state = QValidator::State(int(tmp.state));
1911 if (state == QValidator::Acceptable) {
1912 if (tmp.conflicts && conflictGuard != tmp.value) {
1913 conflictGuard = tmp.value;
1914 clearCache();
1915 input = textFromValue(tmp.value);
1916 updateCache(tmp.value, input);
1917 conflictGuard.clear();
1918 } else {
1919 cachedText = input;
1920 cachedState = state;
1921 cachedValue = tmp.value;
1922 }
1923 } else {
1924 clearCache();
1925 }
1926 return (tmp.value.isNull() ? getZeroVariant().toDateTime() : tmp.value);
1927}
1928
1929
1930/*!
1931 \internal
1932*/
1933
1934QString QDateTimeEditPrivate::textFromValue(const QVariant &f) const
1935{
1936 Q_Q(const QDateTimeEdit);
1937 return q->textFromDateTime(f.toDateTime());
1938}
1939
1940/*!
1941 \internal
1942
1943 This function's name is slightly confusing; it is not to be confused
1944 with QAbstractSpinBox::valueFromText().
1945*/
1946
1947QVariant QDateTimeEditPrivate::valueFromText(const QString &f) const
1948{
1949 Q_Q(const QDateTimeEdit);
1950 return q->dateTimeFromText(f).toTimeSpec(spec);
1951}
1952
1953
1954/*!
1955 \internal
1956
1957 Internal function called by QDateTimeEdit::stepBy(). Also takes a
1958 Section for which section to step on and a bool \a test for
1959 whether or not to modify the internal cachedDay variable. This is
1960 necessary because the function is called from the const function
1961 QDateTimeEdit::stepEnabled() as well as QDateTimeEdit::stepBy().
1962*/
1963
1964QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) const
1965{
1966 Q_Q(const QDateTimeEdit);
1967 QDateTime v = value.toDateTime();
1968 QString str = displayText();
1969 int pos = edit->cursorPosition();
1970 const SectionNode sn = sectionNode(sectionIndex);
1971
1972 int val;
1973 // to make sure it behaves reasonably when typing something and then stepping in non-tracking mode
1974 if (!test && pendingEmit) {
1975 if (q->validate(str, pos) != QValidator::Acceptable) {
1976 v = value.toDateTime();
1977 } else {
1978 v = q->dateTimeFromText(str);
1979 }
1980 val = getDigit(v, sectionIndex);
1981 } else {
1982 val = getDigit(v, sectionIndex);
1983 }
1984
1985 val += steps;
1986
1987 const int min = absoluteMin(sectionIndex);
1988 const int max = absoluteMax(sectionIndex, value.toDateTime());
1989
1990 if (val < min) {
1991 val = (wrapping ? max - (min - val) + 1 : min);
1992 } else if (val > max) {
1993 val = (wrapping ? min + val - max - 1 : max);
1994 }
1995
1996
1997 const int oldDay = v.date().day();
1998
1999 setDigit(v, sectionIndex, val);
2000 // if this sets year or month it will make
2001 // sure that days are lowered if needed.
2002
2003 const QDateTime minimumDateTime = minimum.toDateTime();
2004 const QDateTime maximumDateTime = maximum.toDateTime();
2005 // changing one section should only modify that section, if possible
2006 if (sn.type != AmPmSection && (v < minimumDateTime || v > maximumDateTime)) {
2007 const int localmin = getDigit(minimumDateTime, sectionIndex);
2008 const int localmax = getDigit(maximumDateTime, sectionIndex);
2009
2010 if (wrapping) {
2011 // just because we hit the roof in one direction, it
2012 // doesn't mean that we hit the floor in the other
2013 if (steps > 0) {
2014 setDigit(v, sectionIndex, min);
2015 if (!(sn.type & (DaySection|DayOfWeekSection)) && sections & DateSectionMask) {
2016 const int daysInMonth = v.date().daysInMonth();
2017 if (v.date().day() < oldDay && v.date().day() < daysInMonth) {
2018 const int adds = qMin(oldDay, daysInMonth);
2019 v = v.addDays(adds - v.date().day());
2020 }
2021 }
2022
2023 if (v < minimumDateTime) {
2024 setDigit(v, sectionIndex, localmin);
2025 if (v < minimumDateTime)
2026 setDigit(v, sectionIndex, localmin + 1);
2027 }
2028 } else {
2029 setDigit(v, sectionIndex, max);
2030 if (!(sn.type & (DaySection|DayOfWeekSection)) && sections & DateSectionMask) {
2031 const int daysInMonth = v.date().daysInMonth();
2032 if (v.date().day() < oldDay && v.date().day() < daysInMonth) {
2033 const int adds = qMin(oldDay, daysInMonth);
2034 v = v.addDays(adds - v.date().day());
2035 }
2036 }
2037
2038 if (v > maximumDateTime) {
2039 setDigit(v, sectionIndex, localmax);
2040 if (v > maximumDateTime)
2041 setDigit(v, sectionIndex, localmax - 1);
2042 }
2043 }
2044 } else {
2045 setDigit(v, sectionIndex, (steps > 0 ? localmax : localmin));
2046 }
2047 }
2048 if (!test && oldDay != v.date().day() && !(sn.type & (DaySection|DayOfWeekSection))) {
2049 // this should not happen when called from stepEnabled
2050 cachedDay = qMax<int>(oldDay, cachedDay);
2051 }
2052
2053 if (v < minimumDateTime) {
2054 if (wrapping) {
2055 QDateTime t = v;
2056 setDigit(t, sectionIndex, steps < 0 ? max : min);
2057 bool mincmp = (t >= minimumDateTime);
2058 bool maxcmp = (t <= maximumDateTime);
2059 if (!mincmp || !maxcmp) {
2060 setDigit(t, sectionIndex, getDigit(steps < 0
2061 ? maximumDateTime
2062 : minimumDateTime, sectionIndex));
2063 mincmp = (t >= minimumDateTime);
2064 maxcmp = (t <= maximumDateTime);
2065 }
2066 if (mincmp && maxcmp) {
2067 v = t;
2068 }
2069 } else {
2070 v = value.toDateTime();
2071 }
2072 } else if (v > maximumDateTime) {
2073 if (wrapping) {
2074 QDateTime t = v;
2075 setDigit(t, sectionIndex, steps > 0 ? min : max);
2076 bool mincmp = (t >= minimumDateTime);
2077 bool maxcmp = (t <= maximumDateTime);
2078 if (!mincmp || !maxcmp) {
2079 setDigit(t, sectionIndex, getDigit(steps > 0 ?
2080 minimumDateTime :
2081 maximumDateTime, sectionIndex));
2082 mincmp = (t >= minimumDateTime);
2083 maxcmp = (t <= maximumDateTime);
2084 }
2085 if (mincmp && maxcmp) {
2086 v = t;
2087 }
2088 } else {
2089 v = value.toDateTime();
2090 }
2091 }
2092
2093 const QDateTime ret = bound(v, value, steps).toDateTime().toTimeSpec(spec);
2094 return ret;
2095}
2096
2097/*!
2098 \internal
2099*/
2100
2101void QDateTimeEditPrivate::emitSignals(EmitPolicy ep, const QVariant &old)
2102{
2103 Q_Q(QDateTimeEdit);
2104 if (ep == NeverEmit) {
2105 return;
2106 }
2107 pendingEmit = false;
2108
2109 const bool dodate = value.toDate().isValid() && (sections & DateSectionMask);
2110 const bool datechanged = (ep == AlwaysEmit || old.toDate() != value.toDate());
2111 const bool dotime = value.toTime().isValid() && (sections & TimeSectionMask);
2112 const bool timechanged = (ep == AlwaysEmit || old.toTime() != value.toTime());
2113
2114 updateCache(value, displayText());
2115
2116 syncCalendarWidget();
2117 if (datechanged || timechanged)
2118 emit q->dateTimeChanged(value.toDateTime());
2119 if (dodate && datechanged)
2120 emit q->dateChanged(value.toDate());
2121 if (dotime && timechanged)
2122 emit q->timeChanged(value.toTime());
2123
2124}
2125
2126/*!
2127 \internal
2128*/
2129
2130void QDateTimeEditPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos)
2131{
2132 if (ignoreCursorPositionChanged || specialValue())
2133 return;
2134 const QString oldText = displayText();
2135 updateCache(value, oldText);
2136
2137 const bool allowChange = !edit->hasSelectedText();
2138 const bool forward = oldpos <= newpos;
2139 ignoreCursorPositionChanged = true;
2140 int s = sectionAt(newpos);
2141 if (s == NoSectionIndex && forward && newpos > 0) {
2142 s = sectionAt(newpos - 1);
2143 }
2144
2145 int c = newpos;
2146
2147 const int selstart = edit->selectionStart();
2148 const int selSection = sectionAt(selstart);
2149 const int l = selSection != -1 ? sectionSize(selSection) : 0;
2150
2151 if (s == NoSectionIndex) {
2152 if (l > 0 && selstart == sectionPos(selSection) && edit->selectedText().size() == l) {
2153 s = selSection;
2154 if (allowChange)
2155 setSelected(selSection, true);
2156 c = -1;
2157 } else {
2158 int closest = closestSection(newpos, forward);
2159 c = sectionPos(closest) + (forward ? 0 : qMax<int>(0, sectionSize(closest)));
2160
2161 if (allowChange) {
2162 edit->setCursorPosition(c);
2163 QDTEDEBUG << c;
2164 }
2165 s = closest;
2166 }
2167 }
2168
2169 if (allowChange && currentSectionIndex != s) {
2170 interpret(EmitIfChanged);
2171 }
2172 if (c == -1) {
2173 setSelected(s, true);
2174 } else if (!edit->hasSelectedText()) {
2175 if (oldpos < newpos) {
2176 edit->setCursorPosition(displayText().size() - (oldText.size() - c));
2177 } else {
2178 edit->setCursorPosition(c);
2179 }
2180 }
2181
2182 QDTEDEBUG << "currentSectionIndex is set to" << sectionName(sectionType(s))
2183 << oldpos << newpos
2184 << "was" << sectionName(sectionType(currentSectionIndex));
2185
2186 currentSectionIndex = s;
2187 Q_ASSERT_X(currentSectionIndex < sectionNodes.size(),
2188 "QDateTimeEditPrivate::_q_editorCursorPositionChanged()",
2189 qPrintable(QString::fromAscii("Internal error (%1 %2)").
2190 arg(currentSectionIndex).
2191 arg(sectionNodes.size())));
2192
2193 ignoreCursorPositionChanged = false;
2194}
2195
2196/*!
2197 \internal
2198
2199 Try to get the format from the local settings
2200*/
2201void QDateTimeEditPrivate::readLocaleSettings()
2202{
2203 const QLocale loc;
2204 defaultTimeFormat = loc.timeFormat(QLocale::ShortFormat);
2205 defaultDateFormat = loc.dateFormat(QLocale::ShortFormat);
2206 defaultDateTimeFormat = loc.dateTimeFormat(QLocale::ShortFormat);
2207}
2208
2209QDateTimeEdit::Section QDateTimeEditPrivate::convertToPublic(QDateTimeParser::Section s)
2210{
2211 switch (s & ~Internal) {
2212 case AmPmSection: return QDateTimeEdit::AmPmSection;
2213 case MSecSection: return QDateTimeEdit::MSecSection;
2214 case SecondSection: return QDateTimeEdit::SecondSection;
2215 case MinuteSection: return QDateTimeEdit::MinuteSection;
2216 case DayOfWeekSection:
2217 case DaySection: return QDateTimeEdit::DaySection;
2218 case MonthSection: return QDateTimeEdit::MonthSection;
2219 case YearSection2Digits:
2220 case YearSection: return QDateTimeEdit::YearSection;
2221 case Hour12Section:
2222 case Hour24Section: return QDateTimeEdit::HourSection;
2223 case FirstSection:
2224 case NoSection:
2225 case LastSection: break;
2226 }
2227 return QDateTimeEdit::NoSection;
2228}
2229
2230QDateTimeEdit::Sections QDateTimeEditPrivate::convertSections(QDateTimeParser::Sections s)
2231{
2232 QDateTimeEdit::Sections ret = 0;
2233 if (s & QDateTimeParser::MSecSection)
2234 ret |= QDateTimeEdit::MSecSection;
2235 if (s & QDateTimeParser::SecondSection)
2236 ret |= QDateTimeEdit::SecondSection;
2237 if (s & QDateTimeParser::MinuteSection)
2238 ret |= QDateTimeEdit::MinuteSection;
2239 if (s & (QDateTimeParser::Hour24Section|QDateTimeParser::Hour12Section))
2240 ret |= QDateTimeEdit::HourSection;
2241 if (s & QDateTimeParser::AmPmSection)
2242 ret |= QDateTimeEdit::AmPmSection;
2243 if (s & (QDateTimeParser::DaySection|QDateTimeParser::DayOfWeekSection))
2244 ret |= QDateTimeEdit::DaySection;
2245 if (s & QDateTimeParser::MonthSection)
2246 ret |= QDateTimeEdit::MonthSection;
2247 if (s & (QDateTimeParser::YearSection|QDateTimeParser::YearSection2Digits))
2248 ret |= QDateTimeEdit::YearSection;
2249
2250 return ret;
2251}
2252
2253/*!
2254 \reimp
2255*/
2256
2257void QDateTimeEdit::paintEvent(QPaintEvent *event)
2258{
2259 Q_D(QDateTimeEdit);
2260 if (!d->calendarPopupEnabled()) {
2261 QAbstractSpinBox::paintEvent(event);
2262 return;
2263 }
2264
2265 QStyleOptionSpinBox opt;
2266 initStyleOption(&opt);
2267
2268 QStyleOptionComboBox optCombo;
2269
2270 optCombo.init(this);
2271 optCombo.editable = true;
2272 optCombo.frame = opt.frame;
2273 optCombo.subControls = opt.subControls;
2274 optCombo.activeSubControls = opt.activeSubControls;
2275 optCombo.state = opt.state;
2276 if (d->readOnly) {
2277 optCombo.state &= ~QStyle::State_Enabled;
2278 }
2279
2280 QPainter p(this);
2281 style()->drawComplexControl(QStyle::CC_ComboBox, &optCombo, &p, this);
2282}
2283
2284QString QDateTimeEditPrivate::getAmPmText(AmPm ap, Case cs) const
2285{
2286 if (ap == AmText) {
2287 return (cs == UpperCase ? QDateTimeEdit::tr("AM") : QDateTimeEdit::tr("am"));
2288 } else {
2289 return (cs == UpperCase ? QDateTimeEdit::tr("PM") : QDateTimeEdit::tr("pm"));
2290 }
2291}
2292
2293int QDateTimeEditPrivate::absoluteIndex(QDateTimeEdit::Section s, int index) const
2294{
2295 for (int i=0; i<sectionNodes.size(); ++i) {
2296 if (convertToPublic(sectionNodes.at(i).type) == s && index-- == 0) {
2297 return i;
2298 }
2299 }
2300 return NoSectionIndex;
2301}
2302
2303int QDateTimeEditPrivate::absoluteIndex(const SectionNode &s) const
2304{
2305 return sectionNodes.indexOf(s);
2306}
2307
2308void QDateTimeEditPrivate::interpret(EmitPolicy ep)
2309{
2310 Q_Q(QDateTimeEdit);
2311 QString tmp = displayText();
2312 int pos = edit->cursorPosition();
2313 const QValidator::State state = q->validate(tmp, pos);
2314 if (state != QValidator::Acceptable
2315 && correctionMode == QAbstractSpinBox::CorrectToPreviousValue
2316 && (state == QValidator::Invalid || !(fieldInfo(currentSectionIndex) & AllowPartial))) {
2317 setValue(value, ep);
2318 updateTimeSpec();
2319 } else {
2320 QAbstractSpinBoxPrivate::interpret(ep);
2321 }
2322}
2323
2324void QDateTimeEditPrivate::clearCache() const
2325{
2326 QAbstractSpinBoxPrivate::clearCache();
2327 cachedDay = -1;
2328}
2329
2330/*!
2331 Initialize \a option with the values from this QDataTimeEdit. This method
2332 is useful for subclasses when they need a QStyleOptionSpinBox, but don't want
2333 to fill in all the information themselves.
2334
2335 \sa QStyleOption::initFrom()
2336*/
2337void QDateTimeEdit::initStyleOption(QStyleOptionSpinBox *option) const
2338{
2339 if (!option)
2340 return;
2341
2342 Q_D(const QDateTimeEdit);
2343 QAbstractSpinBox::initStyleOption(option);
2344 if (d->calendarPopupEnabled()) {
2345 option->subControls = QStyle::SC_ComboBoxFrame | QStyle::SC_ComboBoxEditField
2346 | QStyle::SC_ComboBoxArrow;
2347 if (d->arrowState == QStyle::State_Sunken)
2348 option->state |= QStyle::State_Sunken;
2349 else
2350 option->state &= ~QStyle::State_Sunken;
2351 }
2352}
2353
2354void QDateTimeEditPrivate::init(const QVariant &var)
2355{
2356 Q_Q(QDateTimeEdit);
2357 switch (var.type()) {
2358 case QVariant::Date:
2359 value = QDateTime(var.toDate(), QDATETIMEEDIT_TIME_MIN);
2360 q->setDisplayFormat(defaultDateFormat);
2361 if (sectionNodes.isEmpty()) // ### safeguard for broken locale
2362 q->setDisplayFormat(QLatin1String("dd/MM/yyyy"));
2363 break;
2364 case QVariant::DateTime:
2365 value = var;
2366 q->setDisplayFormat(defaultDateTimeFormat);
2367 if (sectionNodes.isEmpty()) // ### safeguard for broken locale
2368 q->setDisplayFormat(QLatin1String("dd/MM/yyyy hh:mm:ss"));
2369 break;
2370 case QVariant::Time:
2371 value = QDateTime(QDATETIMEEDIT_DATE_INITIAL, var.toTime());
2372 q->setDisplayFormat(defaultTimeFormat);
2373 if (sectionNodes.isEmpty()) // ### safeguard for broken locale
2374 q->setDisplayFormat(QLatin1String("hh:mm:ss"));
2375 break;
2376 default:
2377 Q_ASSERT_X(0, "QDateTimeEditPrivate::init", "Internal error");
2378 break;
2379 }
2380#ifdef QT_KEYPAD_NAVIGATION
2381 if (QApplication::keypadNavigationEnabled())
2382 q->setCalendarPopup(true);
2383#endif
2384 updateTimeSpec();
2385 q->setInputMethodHints(Qt::ImhPreferNumbers);
2386 setLayoutItemMargins(QStyle::SE_DateTimeEditLayoutItem);
2387}
2388
2389void QDateTimeEditPrivate::_q_resetButton()
2390{
2391 updateArrow(QStyle::State_None);
2392}
2393
2394void QDateTimeEditPrivate::updateArrow(QStyle::StateFlag state)
2395{
2396 Q_Q(QDateTimeEdit);
2397
2398 if (arrowState == state)
2399 return;
2400 arrowState = state;
2401 if (arrowState != QStyle::State_None)
2402 buttonState |= Mouse;
2403 else {
2404 buttonState = 0;
2405 hoverControl = QStyle::SC_ComboBoxFrame;
2406 }
2407 q->update();
2408}
2409
2410/*!
2411 \internal
2412 Returns the hover control at \a pos.
2413 This will update the hoverRect and hoverControl.
2414*/
2415QStyle::SubControl QDateTimeEditPrivate::newHoverControl(const QPoint &pos)
2416{
2417 if (!calendarPopupEnabled())
2418 return QAbstractSpinBoxPrivate::newHoverControl(pos);
2419
2420 Q_Q(QDateTimeEdit);
2421
2422 QStyleOptionComboBox optCombo;
2423 optCombo.init(q);
2424 optCombo.editable = true;
2425 optCombo.subControls = QStyle::SC_All;
2426 hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &optCombo, pos, q);
2427 return hoverControl;
2428}
2429
2430void QDateTimeEditPrivate::updateEditFieldGeometry()
2431{
2432 if (!calendarPopupEnabled()) {
2433 QAbstractSpinBoxPrivate::updateEditFieldGeometry();
2434 return;
2435 }
2436
2437 Q_Q(QDateTimeEdit);
2438
2439 QStyleOptionComboBox optCombo;
2440 optCombo.init(q);
2441 optCombo.editable = true;
2442 optCombo.subControls = QStyle::SC_ComboBoxEditField;
2443 edit->setGeometry(q->style()->subControlRect(QStyle::CC_ComboBox, &optCombo,
2444 QStyle::SC_ComboBoxEditField, q));
2445}
2446
2447QVariant QDateTimeEditPrivate::getZeroVariant() const
2448{
2449 Q_ASSERT(type == QVariant::DateTime);
2450 return QDateTime(QDATETIMEEDIT_DATE_INITIAL, QTime(), spec);
2451}
2452
2453void QDateTimeEditPrivate::setRange(const QVariant &min, const QVariant &max)
2454{
2455 QAbstractSpinBoxPrivate::setRange(min, max);
2456 syncCalendarWidget();
2457}
2458
2459
2460bool QDateTimeEditPrivate::isSeparatorKey(const QKeyEvent *ke) const
2461{
2462 if (!ke->text().isEmpty() && currentSectionIndex + 1 < sectionNodes.size() && currentSectionIndex >= 0) {
2463 if (fieldInfo(currentSectionIndex) & Numeric) {
2464 if (ke->text().at(0).isNumber())
2465 return false;
2466 } else if (ke->text().at(0).isLetterOrNumber()) {
2467 return false;
2468 }
2469 return separators.at(currentSectionIndex + 1).contains(ke->text());
2470 }
2471 return false;
2472}
2473
2474void QDateTimeEditPrivate::initCalendarPopup(QCalendarWidget *cw)
2475{
2476 Q_Q(QDateTimeEdit);
2477 if (!monthCalendar) {
2478 monthCalendar = new QCalendarPopup(q, cw);
2479 monthCalendar->setObjectName(QLatin1String("qt_datetimedit_calendar"));
2480 QObject::connect(monthCalendar, SIGNAL(newDateSelected(QDate)), q, SLOT(setDate(QDate)));
2481 QObject::connect(monthCalendar, SIGNAL(hidingCalendar(QDate)), q, SLOT(setDate(QDate)));
2482 QObject::connect(monthCalendar, SIGNAL(activated(QDate)), q, SLOT(setDate(QDate)));
2483 QObject::connect(monthCalendar, SIGNAL(activated(QDate)), monthCalendar, SLOT(close()));
2484 QObject::connect(monthCalendar, SIGNAL(resetButton()), q, SLOT(_q_resetButton()));
2485 } else if (cw) {
2486 monthCalendar->setCalendarWidget(cw);
2487 }
2488 syncCalendarWidget();
2489}
2490
2491void QDateTimeEditPrivate::positionCalendarPopup()
2492{
2493 Q_Q(QDateTimeEdit);
2494 QPoint pos = (q->layoutDirection() == Qt::RightToLeft) ? q->rect().bottomRight() : q->rect().bottomLeft();
2495 QPoint pos2 = (q->layoutDirection() == Qt::RightToLeft) ? q->rect().topRight() : q->rect().topLeft();
2496 pos = q->mapToGlobal(pos);
2497 pos2 = q->mapToGlobal(pos2);
2498 QSize size = monthCalendar->sizeHint();
2499 QRect screen = QApplication::desktop()->availableGeometry(pos);
2500 //handle popup falling "off screen"
2501 if (q->layoutDirection() == Qt::RightToLeft) {
2502 pos.setX(pos.x()-size.width());
2503 pos2.setX(pos2.x()-size.width());
2504 if (pos.x() < screen.left())
2505 pos.setX(qMax(pos.x(), screen.left()));
2506 else if (pos.x()+size.width() > screen.right())
2507 pos.setX(qMax(pos.x()-size.width(), screen.right()-size.width()));
2508 } else {
2509 if (pos.x()+size.width() > screen.right())
2510 pos.setX(screen.right()-size.width());
2511 pos.setX(qMax(pos.x(), screen.left()));
2512 }
2513 if (pos.y() + size.height() > screen.bottom())
2514 pos.setY(pos2.y() - size.height());
2515 else if (pos.y() < screen.top())
2516 pos.setY(screen.top());
2517 if (pos.y() < screen.top())
2518 pos.setY(screen.top());
2519 if (pos.y()+size.height() > screen.bottom())
2520 pos.setY(screen.bottom()-size.height());
2521 monthCalendar->move(pos);
2522}
2523
2524bool QDateTimeEditPrivate::calendarPopupEnabled() const
2525{
2526 return (calendarPopup && (sections & (DateSectionMask)));
2527}
2528
2529void QDateTimeEditPrivate::syncCalendarWidget()
2530{
2531 Q_Q(QDateTimeEdit);
2532 if (monthCalendar) {
2533 monthCalendar->setDateRange(q->minimumDate(), q->maximumDate());
2534 monthCalendar->setDate(q->date());
2535 }
2536}
2537
2538QCalendarPopup::QCalendarPopup(QWidget * parent, QCalendarWidget *cw)
2539 : QWidget(parent, Qt::Popup), calendar(0)
2540{
2541 setAttribute(Qt::WA_WindowPropagation);
2542
2543 dateChanged = false;
2544 if (!cw) {
2545 cw = new QCalendarWidget(this);
2546 cw->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
2547#ifdef QT_KEYPAD_NAVIGATION
2548 if (QApplication::keypadNavigationEnabled())
2549 cw->setHorizontalHeaderFormat(QCalendarWidget::SingleLetterDayNames);
2550#endif
2551 }
2552 setCalendarWidget(cw);
2553}
2554
2555void QCalendarPopup::setCalendarWidget(QCalendarWidget *cw)
2556{
2557 Q_ASSERT(cw);
2558 QVBoxLayout *widgetLayout = qobject_cast<QVBoxLayout*>(layout());
2559 if (!widgetLayout) {
2560 widgetLayout = new QVBoxLayout(this);
2561 widgetLayout->setMargin(0);
2562 widgetLayout->setSpacing(0);
2563 }
2564 delete calendar;
2565 calendar = cw;
2566 widgetLayout->addWidget(calendar);
2567
2568 connect(calendar, SIGNAL(activated(QDate)), this, SLOT(dateSelected(QDate)));
2569 connect(calendar, SIGNAL(clicked(QDate)), this, SLOT(dateSelected(QDate)));
2570 connect(calendar, SIGNAL(selectionChanged()), this, SLOT(dateSelectionChanged()));
2571
2572 calendar->setFocus();
2573}
2574
2575
2576void QCalendarPopup::setDate(const QDate &date)
2577{
2578 oldDate = date;
2579 calendar->setSelectedDate(date);
2580}
2581
2582void QCalendarPopup::setDateRange(const QDate &min, const QDate &max)
2583{
2584 calendar->setMinimumDate(min);
2585 calendar->setMaximumDate(max);
2586}
2587
2588void QCalendarPopup::mousePressEvent(QMouseEvent *event)
2589{
2590 QDateTimeEdit *dateTime = qobject_cast<QDateTimeEdit *>(parentWidget());
2591 if (dateTime) {
2592 QStyleOptionComboBox opt;
2593 opt.init(dateTime);
2594 QRect arrowRect = dateTime->style()->subControlRect(QStyle::CC_ComboBox, &opt,
2595 QStyle::SC_ComboBoxArrow, dateTime);
2596 arrowRect.moveTo(dateTime->mapToGlobal(arrowRect .topLeft()));
2597 if (arrowRect.contains(event->globalPos()) || rect().contains(event->pos()))
2598 setAttribute(Qt::WA_NoMouseReplay);
2599 }
2600 QWidget::mousePressEvent(event);
2601}
2602
2603void QCalendarPopup::mouseReleaseEvent(QMouseEvent*)
2604{
2605 emit resetButton();
2606}
2607
2608bool QCalendarPopup::event(QEvent *event)
2609{
2610 if (event->type() == QEvent::KeyPress) {
2611 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
2612 if (keyEvent->key()== Qt::Key_Escape)
2613 dateChanged = false;
2614 }
2615 return QWidget::event(event);
2616}
2617
2618void QCalendarPopup::dateSelectionChanged()
2619{
2620 dateChanged = true;
2621 emit newDateSelected(calendar->selectedDate());
2622}
2623void QCalendarPopup::dateSelected(const QDate &date)
2624{
2625 dateChanged = true;
2626 emit activated(date);
2627 close();
2628}
2629
2630void QCalendarPopup::hideEvent(QHideEvent *)
2631{
2632 emit resetButton();
2633 if (!dateChanged)
2634 emit hidingCalendar(oldDate);
2635}
2636
2637QT_END_NAMESPACE
2638#include "moc_qdatetimeedit.cpp"
2639
2640#endif // QT_NO_DATETIMEEDIT
Note: See TracBrowser for help on using the repository browser.