diff -r 000000000000 -r 1918ee327afb src/gui/widgets/qdatetimeedit.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gui/widgets/qdatetimeedit.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,2640 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef QT_NO_DATETIMEEDIT + +//#define QDATETIMEEDIT_QDTEDEBUG +#ifdef QDATETIMEEDIT_QDTEDEBUG +# define QDTEDEBUG qDebug() << QString::fromLatin1("%1:%2").arg(__FILE__).arg(__LINE__) +# define QDTEDEBUGN qDebug +#else +# define QDTEDEBUG if (false) qDebug() +# define QDTEDEBUGN if (false) qDebug +#endif + +QT_BEGIN_NAMESPACE + +// --- QDateTimeEdit --- + +/*! + \class QDateTimeEdit + \brief The QDateTimeEdit class provides a widget for editing dates and times. + + \ingroup basicwidgets + + + QDateTimeEdit allows the user to edit dates by using the keyboard or + the arrow keys to increase and decrease date and time values. The + arrow keys can be used to move from section to section within the + QDateTimeEdit box. Dates and times appear in accordance with the + format set; see setDisplayFormat(). + + \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 0 + + Here we've created a new QDateTimeEdit object initialized with + today's date, and restricted the valid date range to today plus or + minus 365 days. We've set the order to month, day, year. + + The minimum value for QDateTimeEdit is 14 September 1752, + and 2 January 4713BC for QDate. You can change this by calling + setMinimumDate(), setMaximumDate(), setMinimumTime(), + and setMaximumTime(). + + \section1 Using a Pop-up Calendar Widget + + QDateTimeEdit can be configured to allow a QCalendarWidget to be used + to select dates. This is enabled by setting the calendarPopup property. + Additionally, you can supply a custom calendar widget for use as the + calendar pop-up by calling the setCalendarWidget() function. The existing + calendar widget can be retrieved with calendarWidget(). + + \table 100% + \row \o \inlineimage windowsxp-datetimeedit.png Screenshot of a Windows XP style date time editing widget + \o A date time editing widget shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}. + \row \o \inlineimage macintosh-datetimeedit.png Screenshot of a Macintosh style date time editing widget + \o A date time editing widget shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}. + \row \o \inlineimage plastique-datetimeedit.png Screenshot of a Plastique style date time editing widget + \o A date time editing widget shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}. + \endtable + + \sa QDateEdit, QTimeEdit, QDate, QTime +*/ + +/*! + \enum QDateTimeEdit::Section + + \value NoSection + \value AmPmSection + \value MSecSection + \value SecondSection + \value MinuteSection + \value HourSection + \value DaySection + \value MonthSection + \value YearSection + \omitvalue DateSections_Mask + \omitvalue TimeSections_Mask +*/ + +/*! + \fn void QDateTimeEdit::dateTimeChanged(const QDateTime &datetime) + + This signal is emitted whenever the date or time is changed. The + new date and time is passed in \a datetime. +*/ + +/*! + \fn void QDateTimeEdit::timeChanged(const QTime &time) + + This signal is emitted whenever the time is changed. The new time + is passed in \a time. +*/ + +/*! + \fn void QDateTimeEdit::dateChanged(const QDate &date) + + This signal is emitted whenever the date is changed. The new date + is passed in \a date. +*/ + + +/*! + Constructs an empty date time editor with a \a parent. +*/ + +QDateTimeEdit::QDateTimeEdit(QWidget *parent) + : QAbstractSpinBox(*new QDateTimeEditPrivate, parent) +{ + Q_D(QDateTimeEdit); + d->init(QDateTime(QDATETIMEEDIT_DATE_INITIAL, QDATETIMEEDIT_TIME_MIN)); +} + +/*! + Constructs an empty date time editor with a \a parent. The value + is set to \a datetime. +*/ + +QDateTimeEdit::QDateTimeEdit(const QDateTime &datetime, QWidget *parent) + : QAbstractSpinBox(*new QDateTimeEditPrivate, parent) +{ + Q_D(QDateTimeEdit); + d->init(datetime.isValid() ? datetime : QDateTime(QDATETIMEEDIT_DATE_INITIAL, + QDATETIMEEDIT_TIME_MIN)); +} + +/*! + \fn QDateTimeEdit::QDateTimeEdit(const QDate &date, QWidget *parent) + + Constructs an empty date time editor with a \a parent. + The value is set to \a date. +*/ + +QDateTimeEdit::QDateTimeEdit(const QDate &date, QWidget *parent) + : QAbstractSpinBox(*new QDateTimeEditPrivate, parent) +{ + Q_D(QDateTimeEdit); + d->init(date.isValid() ? date : QDATETIMEEDIT_DATE_INITIAL); +} + +/*! + \fn QDateTimeEdit::QDateTimeEdit(const QTime &time, QWidget *parent) + + Constructs an empty date time editor with a \a parent. + The value is set to \a time. +*/ + +QDateTimeEdit::QDateTimeEdit(const QTime &time, QWidget *parent) + : QAbstractSpinBox(*new QDateTimeEditPrivate, parent) +{ + Q_D(QDateTimeEdit); + d->init(time.isValid() ? time : QDATETIMEEDIT_TIME_MIN); +} + +/*! + \internal +*/ + +QDateTimeEdit::QDateTimeEdit(const QVariant &var, QVariant::Type parserType, QWidget *parent) + : QAbstractSpinBox(*new QDateTimeEditPrivate, parent) +{ + Q_D(QDateTimeEdit); + d->parserType = parserType; + d->init(var); +} + +/*! + \property QDateTimeEdit::dateTime + \brief the QDateTime that is set in the QDateTimeEdit + + When setting this property the timespec of the QDateTimeEdit remains the same + and the timespec of the new QDateTime is ignored. + + By default, this property contains a date that refers to January 1, + 2000 and a time of 00:00:00 and 0 milliseconds. + + \sa date, time +*/ + +QDateTime QDateTimeEdit::dateTime() const +{ + Q_D(const QDateTimeEdit); + return d->value.toDateTime(); +} + +void QDateTimeEdit::setDateTime(const QDateTime &datetime) +{ + Q_D(QDateTimeEdit); + if (datetime.isValid()) { + d->clearCache(); + if (!(d->sections & DateSections_Mask)) + setDateRange(datetime.date(), datetime.date()); + d->setValue(QDateTime(datetime.date(), datetime.time(), d->spec), EmitIfChanged); + } +} + +/*! + \property QDateTimeEdit::date + \brief the QDate that is set in the QDateTimeEdit + + By default, this property contains a date that refers to January 1, 2000. + + \sa time, dateTime +*/ + +/*! + Returns the date of the date time edit. +*/ +QDate QDateTimeEdit::date() const +{ + Q_D(const QDateTimeEdit); + return d->value.toDate(); +} + +void QDateTimeEdit::setDate(const QDate &date) +{ + Q_D(QDateTimeEdit); + if (date.isValid()) { + if (!(d->sections & DateSections_Mask)) + setDateRange(date, date); + + d->clearCache(); + d->setValue(QDateTime(date, d->value.toTime(), d->spec), EmitIfChanged); + d->updateTimeSpec(); + } +} + +/*! + \property QDateTimeEdit::time + \brief the QTime that is set in the QDateTimeEdit + + By default, this property contains a time of 00:00:00 and 0 milliseconds. + + \sa date, dateTime +*/ + +/*! + Returns the time of the date time edit. +*/ +QTime QDateTimeEdit::time() const +{ + Q_D(const QDateTimeEdit); + return d->value.toTime(); +} + +void QDateTimeEdit::setTime(const QTime &time) +{ + Q_D(QDateTimeEdit); + if (time.isValid()) { + d->clearCache(); + d->setValue(QDateTime(d->value.toDate(), time, d->spec), EmitIfChanged); + } +} + + +/*! + \property QDateTimeEdit::minimumDateTime + \since 4.4 + + \brief the minimum datetime of the date time edit + + When setting this property the \l maximumDateTime() is adjusted if + necessary to ensure that the range remains valid. If the datetime is + not a valid QDateTime object, this function does nothing. + + The default minimumDateTime can be restored with + clearMinimumDateTime() + + By default, this property contains a date that refers to September 14, + 1752 and a time of 00:00:00 and 0 milliseconds. + + \sa maximumDateTime(), minimumTime(), maximumTime(), minimumDate(), + maximumDate(), setDateTimeRange(), setDateRange(), setTimeRange(), + clearMaximumDateTime(), clearMinimumDate(), + clearMaximumDate(), clearMinimumTime(), clearMaximumTime() +*/ + +QDateTime QDateTimeEdit::minimumDateTime() const +{ + Q_D(const QDateTimeEdit); + return d->minimum.toDateTime(); +} + +void QDateTimeEdit::clearMinimumDateTime() +{ + setMinimumDateTime(QDateTime(QDATETIMEEDIT_COMPAT_DATE_MIN, QDATETIMEEDIT_TIME_MIN)); +} + +void QDateTimeEdit::setMinimumDateTime(const QDateTime &dt) +{ + Q_D(QDateTimeEdit); + if (dt.isValid() && dt.date() >= QDATETIMEEDIT_DATE_MIN) { + const QDateTime m = dt.toTimeSpec(d->spec); + const QDateTime max = d->maximum.toDateTime(); + d->setRange(m, (max > m ? max : m)); + } +} + +/*! + \property QDateTimeEdit::maximumDateTime + \since 4.4 + + \brief the maximum datetime of the date time edit + + When setting this property the \l minimumDateTime() is adjusted if + necessary to ensure that the range remains valid. If the datetime is + not a valid QDateTime object, this function does nothing. + + The default maximumDateTime can be restored with + clearMaximumDateTime(). + + By default, this property contains a date that refers to 31 December, + 7999 and a time of 23:59:59 and 999 milliseconds. + + \sa minimumDateTime(), minimumTime(), maximumTime(), minimumDate(), + maximumDate(), setDateTimeRange(), setDateRange(), setTimeRange(), + clearMinimumDateTime(), clearMinimumDate(), + clearMaximumDate(), clearMinimumTime(), clearMaximumTime() +*/ + +QDateTime QDateTimeEdit::maximumDateTime() const +{ + Q_D(const QDateTimeEdit); + return d->maximum.toDateTime(); +} + +void QDateTimeEdit::clearMaximumDateTime() +{ + setMaximumDateTime(QDATETIMEEDIT_DATETIME_MAX); +} + +void QDateTimeEdit::setMaximumDateTime(const QDateTime &dt) +{ + Q_D(QDateTimeEdit); + if (dt.isValid() && dt.date() <= QDATETIMEEDIT_DATE_MAX) { + const QDateTime m = dt.toTimeSpec(d->spec); + const QDateTime min = d->minimum.toDateTime(); + d->setRange((min < m ? min : m), m); + } +} + + +/*! + Convenience function to set minimum and maximum date time with one + function call. + \since 4.4 + + \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 1 + + is analogous to: + + \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 2 + + If either \a min or \a max are not valid, this function does + nothing. + + \sa setMinimumDate(), maximumDate(), setMaximumDate(), + clearMinimumDate(), setMinimumTime(), maximumTime(), + setMaximumTime(), clearMinimumTime(), QDateTime::isValid() +*/ + +void QDateTimeEdit::setDateTimeRange(const QDateTime &min, const QDateTime &max) +{ + Q_D(QDateTimeEdit); + const QDateTime minimum = min.toTimeSpec(d->spec); + QDateTime maximum = max.toTimeSpec(d->spec); + if (min > max) + maximum = minimum; + d->setRange(minimum, maximum); +} + +/*! + \property QDateTimeEdit::minimumDate + + \brief the minimum date of the date time edit + + When setting this property the \l maximumDate is adjusted if + necessary, to ensure that the range remains valid. If the date is + not a valid QDate object, this function does nothing. + + By default, this property contains a date that refers to September 14, 1752. + The minimum date must be at least the first day in year 100, otherwise + setMinimumDate() has no effect. + + \sa minimumTime(), maximumTime(), setDateRange() +*/ + +QDate QDateTimeEdit::minimumDate() const +{ + Q_D(const QDateTimeEdit); + return d->minimum.toDate(); +} + +void QDateTimeEdit::setMinimumDate(const QDate &min) +{ + Q_D(QDateTimeEdit); + if (min.isValid() && min >= QDATETIMEEDIT_DATE_MIN) { + setMinimumDateTime(QDateTime(min, d->minimum.toTime(), d->spec)); + } +} + +void QDateTimeEdit::clearMinimumDate() +{ + setMinimumDate(QDATETIMEEDIT_COMPAT_DATE_MIN); +} + +/*! + \property QDateTimeEdit::maximumDate + + \brief the maximum date of the date time edit + + When setting this property the \l minimumDate is adjusted if + necessary to ensure that the range remains valid. If the date is + not a valid QDate object, this function does nothing. + + By default, this property contains a date that refers to December 31, 7999. + + \sa minimumDate, minimumTime, maximumTime, setDateRange() +*/ + +QDate QDateTimeEdit::maximumDate() const +{ + Q_D(const QDateTimeEdit); + return d->maximum.toDate(); +} + +void QDateTimeEdit::setMaximumDate(const QDate &max) +{ + Q_D(QDateTimeEdit); + if (max.isValid()) { + setMaximumDateTime(QDateTime(max, d->maximum.toTime(), d->spec)); + } +} + +void QDateTimeEdit::clearMaximumDate() +{ + setMaximumDate(QDATETIMEEDIT_DATE_MAX); +} + +/*! + \property QDateTimeEdit::minimumTime + + \brief the minimum time of the date time edit + + When setting this property the \l maximumTime is adjusted if + necessary, to ensure that the range remains valid. If the time is + not a valid QTime object, this function does nothing. + + By default, this property contains a time of 00:00:00 and 0 milliseconds. + + \sa maximumTime, minimumDate, maximumDate, setTimeRange() +*/ + +QTime QDateTimeEdit::minimumTime() const +{ + Q_D(const QDateTimeEdit); + return d->minimum.toTime(); +} + +void QDateTimeEdit::setMinimumTime(const QTime &min) +{ + Q_D(QDateTimeEdit); + if (min.isValid()) { + const QDateTime m(d->minimum.toDate(), min, d->spec); + setMinimumDateTime(m); + } +} + +void QDateTimeEdit::clearMinimumTime() +{ + setMinimumTime(QDATETIMEEDIT_TIME_MIN); +} + +/*! + \property QDateTimeEdit::maximumTime + + \brief the maximum time of the date time edit + + When setting this property, the \l minimumTime is adjusted if + necessary to ensure that the range remains valid. If the time is + not a valid QTime object, this function does nothing. + + By default, this property contains a time of 23:59:59 and 999 milliseconds. + + \sa minimumTime, minimumDate, maximumDate, setTimeRange() +*/ +QTime QDateTimeEdit::maximumTime() const +{ + Q_D(const QDateTimeEdit); + return d->maximum.toTime(); +} + +void QDateTimeEdit::setMaximumTime(const QTime &max) +{ + Q_D(QDateTimeEdit); + if (max.isValid()) { + const QDateTime m(d->maximum.toDate(), max); + setMaximumDateTime(m); + } +} + +void QDateTimeEdit::clearMaximumTime() +{ + setMaximumTime(QDATETIMEEDIT_TIME_MAX); +} + +/*! + Convenience function to set minimum and maximum date with one + function call. + + \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 3 + + is analogous to: + + \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 4 + + If either \a min or \a max are not valid, this function does + nothing. + + \sa setMinimumDate(), maximumDate(), setMaximumDate(), + clearMinimumDate(), setMinimumTime(), maximumTime(), + setMaximumTime(), clearMinimumTime(), QDate::isValid() +*/ + +void QDateTimeEdit::setDateRange(const QDate &min, const QDate &max) +{ + Q_D(QDateTimeEdit); + if (min.isValid() && max.isValid()) { + setDateTimeRange(QDateTime(min, d->minimum.toTime(), d->spec), + QDateTime(max, d->maximum.toTime(), d->spec)); + } +} + +/*! + Convenience function to set minimum and maximum time with one + function call. + + \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 5 + + is analogous to: + + \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 6 + + If either \a min or \a max are not valid, this function does + nothing. + + \sa setMinimumDate(), maximumDate(), setMaximumDate(), + clearMinimumDate(), setMinimumTime(), maximumTime(), + setMaximumTime(), clearMinimumTime(), QTime::isValid() +*/ + +void QDateTimeEdit::setTimeRange(const QTime &min, const QTime &max) +{ + Q_D(QDateTimeEdit); + if (min.isValid() && max.isValid()) { + setDateTimeRange(QDateTime(d->minimum.toDate(), min, d->spec), + QDateTime(d->maximum.toDate(), max, d->spec)); + } +} + +/*! + \property QDateTimeEdit::displayedSections + + \brief the currently displayed fields of the date time edit + + Returns a bit set of the displayed sections for this format. + \a setDisplayFormat(), displayFormat() +*/ + +QDateTimeEdit::Sections QDateTimeEdit::displayedSections() const +{ + Q_D(const QDateTimeEdit); + return d->sections; +} + +/*! + \property QDateTimeEdit::currentSection + + \brief the current section of the spinbox + \a setCurrentSection() +*/ + +QDateTimeEdit::Section QDateTimeEdit::currentSection() const +{ + Q_D(const QDateTimeEdit); +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled() && d->focusOnButton) + return NoSection; +#endif + return d->convertToPublic(d->sectionType(d->currentSectionIndex)); +} + +void QDateTimeEdit::setCurrentSection(Section section) +{ + Q_D(QDateTimeEdit); + if (section == NoSection || !(section & d->sections)) + return; + + d->updateCache(d->value, d->displayText()); + const int size = d->sectionNodes.size(); + int index = d->currentSectionIndex + 1; + for (int i=0; i<2; ++i) { + while (index < size) { + if (d->convertToPublic(d->sectionType(index)) == section) { + d->edit->setCursorPosition(d->sectionPos(index)); + QDTEDEBUG << d->sectionPos(index); + return; + } + ++index; + } + index = 0; + } +} + +/*! + \since 4.3 + + Returns the Section at \a index. + + If the format is 'yyyy/MM/dd', sectionAt(0) returns YearSection, + sectionAt(1) returns MonthSection, and sectionAt(2) returns + YearSection, +*/ + +QDateTimeEdit::Section QDateTimeEdit::sectionAt(int index) const +{ + Q_D(const QDateTimeEdit); + if (index < 0 || index >= d->sectionNodes.size()) + return NoSection; + return d->convertToPublic(d->sectionType(index)); +} + +/*! + \since 4.3 + + \property QDateTimeEdit::sectionCount + + \brief the number of sections displayed. + If the format is 'yyyy/yy/yyyy', sectionCount returns 3 +*/ + +int QDateTimeEdit::sectionCount() const +{ + Q_D(const QDateTimeEdit); + return d->sectionNodes.size(); +} + + +/*! + \since 4.3 + + \property QDateTimeEdit::currentSectionIndex + + \brief the current section index of the spinbox + + If the format is 'yyyy/MM/dd', the displayText is '2001/05/21' and + the cursorPosition is 5 currentSectionIndex returns 1. If the + cursorPosition is 3 currentSectionIndex is 0 etc. + + \a setCurrentSection() + \sa currentSection() +*/ + +int QDateTimeEdit::currentSectionIndex() const +{ + Q_D(const QDateTimeEdit); + return d->currentSectionIndex; +} + +void QDateTimeEdit::setCurrentSectionIndex(int index) +{ + Q_D(QDateTimeEdit); + if (index < 0 || index >= d->sectionNodes.size()) + return; + d->edit->setCursorPosition(d->sectionPos(index)); +} + +/*! + \since 4.4 + + \brief Returns the calendar widget for the editor if calendarPopup is + set to true and (sections() & DateSections_Mask) != 0. + + This function creates and returns a calendar widget if none has been set. +*/ + + +QCalendarWidget *QDateTimeEdit::calendarWidget() const +{ + Q_D(const QDateTimeEdit); + if (!d->calendarPopup || !(d->sections & QDateTimeParser::DateSectionMask)) + return 0; + if (!d->monthCalendar) { + const_cast(d)->initCalendarPopup(); + } + return d->monthCalendar->calendarWidget(); +} + +/*! + \since 4.4 + + Sets the given \a calendarWidget as the widget to be used for the calendar + pop-up. The editor does not automatically take ownership of the calendar widget. + + \sa calendarPopup +*/ +void QDateTimeEdit::setCalendarWidget(QCalendarWidget *calendarWidget) +{ + Q_D(QDateTimeEdit); + if (!calendarWidget) { + qWarning("QDateTimeEdit::setCalendarWidget: Cannot set a null calendar widget"); + return; + } + + if (!d->calendarPopup) { + qWarning("QDateTimeEdit::setCalendarWidget: calendarPopup is set to false"); + return; + } + + if (!(d->display & QDateTimeParser::DateSectionMask)) { + qWarning("QDateTimeEdit::setCalendarWidget: no date sections specified"); + return; + } + d->initCalendarPopup(calendarWidget); +} + + +/*! + \since 4.2 + + Selects \a section. If \a section doesn't exist in the currently + displayed sections this function does nothing. If \a section is + NoSection this function will unselect all text in the editor. + Otherwise this function will move the cursor and the current section + to the selected section. + + \sa currentSection() +*/ + +void QDateTimeEdit::setSelectedSection(Section section) +{ + Q_D(QDateTimeEdit); + if (section == NoSection) { + d->edit->setSelection(d->edit->cursorPosition(), 0); + } else if (section & d->sections) { + if (currentSection() != section) + setCurrentSection(section); + d->setSelected(d->currentSectionIndex); + } +} + + + +/*! + \fn QString QDateTimeEdit::sectionText(Section section) const + + Returns the text from the given \a section. + + \sa currentSection() +*/ + +QString QDateTimeEdit::sectionText(Section section) const +{ + Q_D(const QDateTimeEdit); + if (section == QDateTimeEdit::NoSection || !(section & d->sections)) { + return QString(); + } + + d->updateCache(d->value, d->displayText()); + const int sectionIndex = d->absoluteIndex(section, 0); + return d->sectionText(sectionIndex); +} + +/*! + \property QDateTimeEdit::displayFormat + + \brief the format used to display the time/date of the date time edit + + This format is the same as the one used described in QDateTime::toString() + and QDateTime::fromString() + + Example format strings(assuming that the date is 2nd of July 1969): + + \table + \header \i Format \i Result + \row \i dd.MM.yyyy \i 02.07.1969 + \row \i MMM d yy \i Jul 2 69 + \row \i MMMM d yy \i July 2 69 + \endtable + + Note that if you specify a two digit year, it will be interpreted + to be in the century in which the date time edit was initialized. + The default century is the 21 (2000-2099). + + If you specify an invalid format the format will not be set. + + \sa QDateTime::toString(), displayedSections() +*/ + +QString QDateTimeEdit::displayFormat() const +{ + Q_D(const QDateTimeEdit); + return isRightToLeft() ? d->unreversedFormat : d->displayFormat; +} + +template static inline C reverse(const C &l) +{ + C ret; + for (int i=l.size() - 1; i>=0; --i) + ret.append(l.at(i)); + return ret; +} + +void QDateTimeEdit::setDisplayFormat(const QString &format) +{ + Q_D(QDateTimeEdit); + if (d->parseFormat(format)) { + d->unreversedFormat.clear(); + if (isRightToLeft()) { + d->unreversedFormat = format; + d->displayFormat.clear(); + for (int i=d->sectionNodes.size() - 1; i>=0; --i) { + d->displayFormat += d->separators.at(i + 1); + d->displayFormat += d->sectionFormat(i); + } + d->displayFormat += d->separators.at(0); + d->separators = reverse(d->separators); + d->sectionNodes = reverse(d->sectionNodes); + } + + d->formatExplicitlySet = true; + d->sections = d->convertSections(d->display); + d->clearCache(); + + d->currentSectionIndex = qMin(d->currentSectionIndex, d->sectionNodes.size() - 1); + const bool timeShown = (d->sections & TimeSections_Mask); + const bool dateShown = (d->sections & DateSections_Mask); + Q_ASSERT(dateShown || timeShown); + if (timeShown && !dateShown) { + setDateRange(d->value.toDate(), d->value.toDate()); + } else if (dateShown && !timeShown) { + setTimeRange(QDATETIMEEDIT_TIME_MIN, QDATETIMEEDIT_TIME_MAX); + d->value = QDateTime(d->value.toDate(), QTime(), d->spec); + } + d->updateEdit(); + d->_q_editorCursorPositionChanged(-1, 0); + } +} + +/*! + \property QDateTimeEdit::calendarPopup + \brief the current calender pop-up showing mode. + \since 4.2 + + The calendar pop-up will be shown upon clicking the arrow button. + This property is valid only if there is a valid date display format. + + \sa setDisplayFormat() +*/ + +bool QDateTimeEdit::calendarPopup() const +{ + Q_D(const QDateTimeEdit); + return d->calendarPopup; +} + +void QDateTimeEdit::setCalendarPopup(bool enable) +{ + Q_D(QDateTimeEdit); + if (enable == d->calendarPopup) + return; + setAttribute(Qt::WA_MacShowFocusRect, !enable); + d->calendarPopup = enable; +#ifdef QT_KEYPAD_NAVIGATION + if (!enable) + d->focusOnButton = false; +#endif + d->updateEditFieldGeometry(); + update(); +} + +/*! + \property QDateTimeEdit::timeSpec + \brief the current timespec used by the date time edit. + \since 4.4 +*/ + +Qt::TimeSpec QDateTimeEdit::timeSpec() const +{ + Q_D(const QDateTimeEdit); + return d->spec; +} + +void QDateTimeEdit::setTimeSpec(Qt::TimeSpec spec) +{ + Q_D(QDateTimeEdit); + if (spec != d->spec) { + d->spec = spec; + d->updateTimeSpec(); + } +} + +/*! + \reimp +*/ + +QSize QDateTimeEdit::sizeHint() const +{ + Q_D(const QDateTimeEdit); + if (d->cachedSizeHint.isEmpty()) { + ensurePolished(); + + const QFontMetrics fm(fontMetrics()); + int h = d->edit->sizeHint().height(); + int w = 0; + QString s; + s = d->textFromValue(d->minimum) + QLatin1String(" "); + w = qMax(w, fm.width(s)); + s = d->textFromValue(d->maximum) + QLatin1String(" "); + w = qMax(w, fm.width(s)); + if (d->specialValueText.size()) { + s = d->specialValueText; + w = qMax(w, fm.width(s)); + } + w += 2; // cursor blinking space + + QSize hint(w, h); + +#ifdef Q_WS_MAC + if (d->calendarPopupEnabled()) { + QStyleOptionComboBox opt; + d->cachedSizeHint = style()->sizeFromContents(QStyle::CT_ComboBox, &opt, hint, this); + } else { +#else + { +#endif + QSize extra(35, 6); + QStyleOptionSpinBox opt; + initStyleOption(&opt); + opt.rect.setSize(hint + extra); + extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt, + QStyle::SC_SpinBoxEditField, this).size(); + // get closer to final result by repeating the calculation + opt.rect.setSize(hint + extra); + extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt, + QStyle::SC_SpinBoxEditField, this).size(); + hint += extra; + + opt.rect = rect(); + d->cachedSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this) + .expandedTo(QApplication::globalStrut()); + } + + d->cachedMinimumSizeHint = d->cachedSizeHint; + // essentially make minimumSizeHint return the same as sizeHint for datetimeedits + } + return d->cachedSizeHint; +} + +/*! + \reimp +*/ + +bool QDateTimeEdit::event(QEvent *event) +{ + Q_D(QDateTimeEdit); + switch (event->type()) { + case QEvent::ApplicationLayoutDirectionChange: { + const bool was = d->formatExplicitlySet; + const QString oldFormat = d->displayFormat; + d->displayFormat.clear(); + setDisplayFormat(oldFormat); + d->formatExplicitlySet = was; + break; } + case QEvent::LocaleChange: + d->updateEdit(); + break; + case QEvent::StyleChange: +#ifdef Q_WS_MAC + case QEvent::MacSizeChange: +#endif + d->setLayoutItemMargins(QStyle::SE_DateTimeEditLayoutItem); + break; + default: + break; + } + return QAbstractSpinBox::event(event); +} + +/*! + \reimp +*/ + +void QDateTimeEdit::clear() +{ + Q_D(QDateTimeEdit); + d->clearSection(d->currentSectionIndex); +} +/*! + \reimp +*/ + +void QDateTimeEdit::keyPressEvent(QKeyEvent *event) +{ + Q_D(QDateTimeEdit); + int oldCurrent = d->currentSectionIndex; + bool select = true; + bool inserted = false; + + switch (event->key()) { +#ifdef QT_KEYPAD_NAVIGATION + case Qt::Key_NumberSign: //shortcut to popup calendar + if (QApplication::keypadNavigationEnabled() && d->calendarPopupEnabled()) { + d->initCalendarPopup(); + d->positionCalendarPopup(); + d->monthCalendar->show(); + return; + } + break; + case Qt::Key_Select: + if (QApplication::keypadNavigationEnabled()) { + if (hasEditFocus()) { + if (d->focusOnButton) { + d->initCalendarPopup(); + d->positionCalendarPopup(); + d->monthCalendar->show(); + d->focusOnButton = false; + return; + } + setEditFocus(false); + selectAll(); + } else { + setEditFocus(true); + + //hide cursor + d->edit->d_func()->setCursorVisible(false); + d->edit->d_func()->control->setCursorBlinkPeriod(0); + d->setSelected(0); + } + } + return; +#endif + case Qt::Key_Enter: + case Qt::Key_Return: + d->interpret(AlwaysEmit); + d->setSelected(d->currentSectionIndex, true); + event->ignore(); + emit editingFinished(); + return; + default: +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled() && !hasEditFocus() + && !event->text().isEmpty() && event->text().at(0).isLetterOrNumber()) { + setEditFocus(true); + + //hide cursor + d->edit->d_func()->setCursorVisible(false); + d->edit->d_func()->control->setCursorBlinkPeriod(0); + d->setSelected(0); + oldCurrent = 0; + } +#endif + if (!d->isSeparatorKey(event)) { + inserted = select = !event->text().isEmpty() && event->text().at(0).isPrint() + && !(event->modifiers() & ~(Qt::ShiftModifier|Qt::KeypadModifier)); + break; + } + case Qt::Key_Left: + case Qt::Key_Right: + if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) { + if ( +#ifdef QT_KEYPAD_NAVIGATION + QApplication::keypadNavigationEnabled() && !hasEditFocus() + || !QApplication::keypadNavigationEnabled() && +#endif + !(event->modifiers() & Qt::ControlModifier)) { + select = false; + break; + } +#ifdef Q_WS_MAC + else +#ifdef QT_KEYPAD_NAVIGATION + if (!QApplication::keypadNavigationEnabled()) +#endif + { + select = (event->modifiers() & Qt::ShiftModifier); + break; + } +#endif + } + // else fall through + case Qt::Key_Backtab: + case Qt::Key_Tab: { + event->accept(); + if (d->specialValue()) { + d->edit->setSelection(d->edit->cursorPosition(), 0); + return; + } + const bool forward = event->key() != Qt::Key_Left && event->key() != Qt::Key_Backtab + && (event->key() != Qt::Key_Tab || !(event->modifiers() & Qt::ShiftModifier)); +#ifdef QT_KEYPAD_NAVIGATION + int newSection = d->nextPrevSection(d->currentSectionIndex, forward); + if (QApplication::keypadNavigationEnabled()) { + if (d->focusOnButton) { + newSection = forward ? 0 : d->sectionNodes.size() - 1; + d->focusOnButton = false; + update(); + } else if (newSection < 0 && select && d->calendarPopupEnabled()) { + setSelectedSection(NoSection); + d->focusOnButton = true; + update(); + return; + } + } + // only allow date/time sections to be selected. + if (newSection & ~(QDateTimeParser::TimeSectionMask | QDateTimeParser::DateSectionMask)) + return; +#endif + //key tab and backtab will be managed thrgout QWidget::event + if (event->key() != Qt::Key_Backtab && event->key() != Qt::Key_Tab) + focusNextPrevChild(forward); + + return; } + } + QAbstractSpinBox::keyPressEvent(event); + if (select && !(event->modifiers() & Qt::ShiftModifier) && !d->edit->hasSelectedText()) { + if (inserted && d->sectionAt(d->edit->cursorPosition()) == QDateTimeParser::NoSectionIndex) { + QString str = d->displayText(); + int pos = d->edit->cursorPosition(); + if (validate(str, pos) == QValidator::Acceptable + && (d->sectionNodes.at(oldCurrent).count != 1 + || d->sectionMaxSize(oldCurrent) == d->sectionSize(oldCurrent) + || d->skipToNextSection(oldCurrent, d->value.toDateTime(), d->sectionText(oldCurrent)))) { + QDTEDEBUG << "Setting currentsection to" + << d->closestSection(d->edit->cursorPosition(), true) << event->key() + << oldCurrent << str; + const int tmp = d->closestSection(d->edit->cursorPosition(), true); + if (tmp >= 0) + d->currentSectionIndex = tmp; + } + } + if (d->currentSectionIndex != oldCurrent) { + d->setSelected(d->currentSectionIndex); + } + } + if (d->specialValue()) { + d->edit->setSelection(d->edit->cursorPosition(), 0); + } +} + +/*! + \reimp +*/ + +#ifndef QT_NO_WHEELEVENT +void QDateTimeEdit::wheelEvent(QWheelEvent *event) +{ + QAbstractSpinBox::wheelEvent(event); +} +#endif + +/*! + \reimp +*/ + +void QDateTimeEdit::focusInEvent(QFocusEvent *event) +{ + Q_D(QDateTimeEdit); + QAbstractSpinBox::focusInEvent(event); + QString *frm = 0; + const int oldPos = d->edit->cursorPosition(); + if (!d->formatExplicitlySet) { + if (d->displayFormat == d->defaultTimeFormat) { + frm = &d->defaultTimeFormat; + } else if (d->displayFormat == d->defaultDateFormat) { + frm = &d->defaultDateFormat; + } else if (d->displayFormat == d->defaultDateTimeFormat) { + frm = &d->defaultDateTimeFormat; + } + + if (frm) { + d->readLocaleSettings(); + if (d->displayFormat != *frm) { + setDisplayFormat(*frm); + d->formatExplicitlySet = false; + d->edit->setCursorPosition(oldPos); + } + } + } + const bool oldHasHadFocus = d->hasHadFocus; + d->hasHadFocus = true; + bool first = true; + switch (event->reason()) { + case Qt::BacktabFocusReason: + first = false; + break; + case Qt::MouseFocusReason: + case Qt::PopupFocusReason: + return; + case Qt::ActiveWindowFocusReason: + if (oldHasHadFocus) + return; + case Qt::ShortcutFocusReason: + case Qt::TabFocusReason: + default: + break; + } + if (isRightToLeft()) + first = !first; + d->updateEdit(); // needed to make it update specialValueText + + d->setSelected(first ? 0 : d->sectionNodes.size() - 1); +} + +/*! + \reimp +*/ + +bool QDateTimeEdit::focusNextPrevChild(bool next) +{ + Q_D(QDateTimeEdit); + const int newSection = d->nextPrevSection(d->currentSectionIndex, next); + switch (d->sectionType(newSection)) { + case QDateTimeParser::NoSection: + case QDateTimeParser::FirstSection: + case QDateTimeParser::LastSection: + return QAbstractSpinBox::focusNextPrevChild(next); + default: + d->edit->deselect(); + d->edit->setCursorPosition(d->sectionPos(newSection)); + QDTEDEBUG << d->sectionPos(newSection); + d->setSelected(newSection, true); + return false; + } +} + +/*! + \reimp +*/ + +void QDateTimeEdit::stepBy(int steps) +{ + Q_D(QDateTimeEdit); +#ifdef QT_KEYPAD_NAVIGATION + // with keypad navigation and not editFocus, left right change the date/time by a fixed amount. + if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) { + // if date based, shift by day. else shift by 15min + if (d->sections & DateSections_Mask) { + setDateTime(dateTime().addDays(steps)); + } else { + int minutes = time().hour()*60 + time().minute(); + int blocks = minutes/15; + blocks += steps; + /* rounding involved */ + if (minutes % 15) { + if (steps < 0) { + blocks += 1; // do one less step; + } + } + + minutes = blocks * 15; + + /* need to take wrapping into account */ + if (!d->wrapping) { + int max_minutes = d->maximum.toTime().hour()*60 + d->maximum.toTime().minute(); + int min_minutes = d->minimum.toTime().hour()*60 + d->minimum.toTime().minute(); + + if (minutes >= max_minutes) { + setTime(maximumTime()); + return; + } else if (minutes <= min_minutes) { + setTime(minimumTime()); + return; + } + } + setTime(QTime(minutes/60, minutes%60)); + } + return; + } +#endif + // don't optimize away steps == 0. This is the only way to select + // the currentSection in Qt 4.1.x + if (d->specialValue() && displayedSections() != AmPmSection) { + for (int i=0; isectionNodes.size(); ++i) { + if (d->sectionType(i) != QDateTimeParser::AmPmSection) { + d->currentSectionIndex = i; + break; + } + } + } + d->setValue(d->stepBy(d->currentSectionIndex, steps, false), EmitIfChanged); + d->updateCache(d->value, d->displayText()); + + d->setSelected(d->currentSectionIndex); + d->updateTimeSpec(); +} + +/*! + This virtual function is used by the date time edit whenever it + needs to display \a dateTime. + + If you reimplement this, you may also need to reimplement validate(). + + \sa dateTimeFromText(), validate() +*/ +QString QDateTimeEdit::textFromDateTime(const QDateTime &dateTime) const +{ + Q_D(const QDateTimeEdit); + return locale().toString(dateTime, d->displayFormat); +} + + +/*! + Returns an appropriate datetime for the given \a text. + + This virtual function is used by the datetime edit whenever it + needs to interpret text entered by the user as a value. + + \sa textFromDateTime(), validate() +*/ +QDateTime QDateTimeEdit::dateTimeFromText(const QString &text) const +{ + Q_D(const QDateTimeEdit); + QString copy = text; + int pos = d->edit->cursorPosition(); + QValidator::State state = QValidator::Acceptable; + return d->validateAndInterpret(copy, pos, state); +} + +/*! + \reimp +*/ + +QValidator::State QDateTimeEdit::validate(QString &text, int &pos) const +{ + Q_D(const QDateTimeEdit); + QValidator::State state; + d->validateAndInterpret(text, pos, state); + return state; +} + +/*! + \reimp +*/ + + +void QDateTimeEdit::fixup(QString &input) const +{ + Q_D(const QDateTimeEdit); + QValidator::State state; + int copy = d->edit->cursorPosition(); + + d->validateAndInterpret(input, copy, state, true); +} + + +/*! + \reimp +*/ + +QDateTimeEdit::StepEnabled QDateTimeEdit::stepEnabled() const +{ + Q_D(const QDateTimeEdit); + if (d->readOnly) + return StepEnabled(0); + if (d->specialValue()) { + return (d->minimum == d->maximum ? StepEnabled(0) : StepEnabled(StepUpEnabled)); + } + + QAbstractSpinBox::StepEnabled ret = 0; + +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) { + if (d->wrapping) + return StepEnabled(StepUpEnabled | StepDownEnabled); + // 3 cases. date, time, datetime. each case look + // at just the relavant component. + QVariant max, min, val; + if (!(d->sections & DateSections_Mask)) { + // time only, no date + max = d->maximum.toTime(); + min = d->minimum.toTime(); + val = d->value.toTime(); + } else if (!(d->sections & TimeSections_Mask)) { + // date only, no time + max = d->maximum.toDate(); + min = d->minimum.toDate(); + val = d->value.toDate(); + } else { + // both + max = d->maximum; + min = d->minimum; + val = d->value; + } + if (val != min) + ret |= QAbstractSpinBox::StepDownEnabled; + if (val != max) + ret |= QAbstractSpinBox::StepUpEnabled; + return ret; + } +#endif + switch (d->sectionType(d->currentSectionIndex)) { + case QDateTimeParser::NoSection: + case QDateTimeParser::FirstSection: + case QDateTimeParser::LastSection: return 0; + default: break; + } + if (d->wrapping) + return StepEnabled(StepDownEnabled|StepUpEnabled); + + QVariant v = d->stepBy(d->currentSectionIndex, 1, true); + if (v != d->value) { + ret |= QAbstractSpinBox::StepUpEnabled; + } + v = d->stepBy(d->currentSectionIndex, -1, true); + if (v != d->value) { + ret |= QAbstractSpinBox::StepDownEnabled; + } + + return ret; +} + + +/*! + \reimp +*/ + +void QDateTimeEdit::mousePressEvent(QMouseEvent *event) +{ + Q_D(QDateTimeEdit); + if (!d->calendarPopupEnabled()) { + QAbstractSpinBox::mousePressEvent(event); + return; + } + d->updateHoverControl(event->pos()); + if (d->hoverControl == QStyle::SC_ComboBoxArrow) { + event->accept(); + if (d->readOnly) { + return; + } + d->updateArrow(QStyle::State_Sunken); + d->initCalendarPopup(); + d->positionCalendarPopup(); + //Show the calendar + d->monthCalendar->show(); + } else { + QAbstractSpinBox::mousePressEvent(event); + } +} + +/*! + \class QTimeEdit + \brief The QTimeEdit class provides a widget for editing times based on + the QDateTimeEdit widget. + + \ingroup basicwidgets + + + Many of the properties and functions provided by QTimeEdit are implemented in + QDateTimeEdit. The following properties are most relevant to users of this + class: + + \list + \o \l{QDateTimeEdit::time}{time} holds the date displayed by the widget. + \o \l{QDateTimeEdit::minimumTime}{minimumTime} defines the minimum (earliest) time + that can be set by the user. + \o \l{QDateTimeEdit::maximumTime}{maximumTime} defines the maximum (latest) time + that can be set by the user. + \o \l{QDateTimeEdit::displayFormat}{displayFormat} contains a string that is used + to format the time displayed in the widget. + \endlist + + \table 100% + \row \o \inlineimage windowsxp-timeedit.png Screenshot of a Windows XP style time editing widget + \o A time editing widget shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}. + \row \o \inlineimage macintosh-timeedit.png Screenshot of a Macintosh style time editing widget + \o A time editing widget shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}. + \row \o \inlineimage plastique-timeedit.png Screenshot of a Plastique style time editing widget + \o A time editing widget shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}. + \endtable + + \sa QDateEdit, QDateTimeEdit +*/ + +/*! + Constructs an empty time editor with a \a parent. +*/ + + +QTimeEdit::QTimeEdit(QWidget *parent) + : QDateTimeEdit(QDATETIMEEDIT_TIME_MIN, QVariant::Time, parent) +{ +} + +/*! + Constructs an empty time editor with a \a parent. The time is set + to \a time. +*/ + +QTimeEdit::QTimeEdit(const QTime &time, QWidget *parent) + : QDateTimeEdit(time, QVariant::Time, parent) +{ +} + +/*! + \property QTimeEdit::time + \brief the QTime that is shown in the widget + + By default, this property contains a time of 00:00:00 and 0 milliseconds. +*/ + + +/*! + \class QDateEdit + \brief The QDateEdit class provides a widget for editing dates based on + the QDateTimeEdit widget. + + \ingroup basicwidgets + + + Many of the properties and functions provided by QDateEdit are implemented in + QDateTimeEdit. The following properties are most relevant to users of this + class: + + \list + \o \l{QDateTimeEdit::date}{date} holds the date displayed by the widget. + \o \l{QDateTimeEdit::minimumDate}{minimumDate} defines the minimum (earliest) + date that can be set by the user. + \o \l{QDateTimeEdit::maximumDate}{maximumDate} defines the maximum (latest) date + that can be set by the user. + \o \l{QDateTimeEdit::displayFormat}{displayFormat} contains a string that is used + to format the date displayed in the widget. + \endlist + + \table 100% + \row \o \inlineimage windowsxp-dateedit.png Screenshot of a Windows XP style date editing widget + \o A date editing widget shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}. + \row \o \inlineimage macintosh-dateedit.png Screenshot of a Macintosh style date editing widget + \o A date editing widget shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}. + \row \o \inlineimage plastique-dateedit.png Screenshot of a Plastique style date editing widget + \o A date editing widget shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}. + \endtable + + \sa QTimeEdit, QDateTimeEdit +*/ + +/*! + Constructs an empty date editor with a \a parent. +*/ + +QDateEdit::QDateEdit(QWidget *parent) + : QDateTimeEdit(QDATETIMEEDIT_DATE_INITIAL, QVariant::Date, parent) +{ +} + +/*! + Constructs an empty date editor with a \a parent. The date is set + to \a date. +*/ + +QDateEdit::QDateEdit(const QDate &date, QWidget *parent) + : QDateTimeEdit(date, QVariant::Date, parent) +{ +} + +/*! + \property QDateEdit::date + \brief the QDate that is shown in the widget + + By default, this property contains a date referring to January 1, 2000. +*/ + + +// --- QDateTimeEditPrivate --- + +/*! + \internal + Constructs a QDateTimeEditPrivate object +*/ + + +QDateTimeEditPrivate::QDateTimeEditPrivate() + : QDateTimeParser(QVariant::DateTime, QDateTimeParser::DateTimeEdit) +{ + hasHadFocus = false; + formatExplicitlySet = false; + cacheGuard = false; + fixday = true; + type = QVariant::DateTime; + sections = 0; + cachedDay = -1; + currentSectionIndex = FirstSectionIndex; + + first.type = FirstSection; + last.type = LastSection; + none.type = NoSection; + first.pos = 0; + last.pos = -1; + none.pos = -1; + sections = 0; + calendarPopup = false; + minimum = QDATETIMEEDIT_COMPAT_DATETIME_MIN; + maximum = QDATETIMEEDIT_DATETIME_MAX; + arrowState = QStyle::State_None; + monthCalendar = 0; + readLocaleSettings(); + +#ifdef QT_KEYPAD_NAVIGATION + focusOnButton = false; +#endif +} + +void QDateTimeEditPrivate::updateTimeSpec() +{ + minimum = minimum.toDateTime().toTimeSpec(spec); + maximum = maximum.toDateTime().toTimeSpec(spec); + value = value.toDateTime().toTimeSpec(spec); +} + +void QDateTimeEditPrivate::updateEdit() +{ + const QString newText = (specialValue() ? specialValueText : textFromValue(value)); + if (newText == displayText()) + return; + int selsize = edit->selectedText().size(); + const bool sb = edit->blockSignals(true); + + edit->setText(newText); + + if (!specialValue() +#ifdef QT_KEYPAD_NAVIGATION + && !(QApplication::keypadNavigationEnabled() && !edit->hasEditFocus()) +#endif + ) { + int cursor = sectionPos(currentSectionIndex); + QDTEDEBUG << "cursor is " << cursor << currentSectionIndex; + cursor = qBound(0, cursor, displayText().size()); + QDTEDEBUG << cursor; + if (selsize > 0) { + edit->setSelection(cursor, selsize); + QDTEDEBUG << cursor << selsize; + } else { + edit->setCursorPosition(cursor); + QDTEDEBUG << cursor; + + } + } + edit->blockSignals(sb); +} + + +/*! + \internal + + Selects the section \a s. If \a forward is false selects backwards. +*/ + +void QDateTimeEditPrivate::setSelected(int sectionIndex, bool forward) +{ + if (specialValue() +#ifdef QT_KEYPAD_NAVIGATION + || (QApplication::keypadNavigationEnabled() && !edit->hasEditFocus()) +#endif + ) { + edit->selectAll(); + } else { + const SectionNode &node = sectionNode(sectionIndex); + if (node.type == NoSection || node.type == LastSection || node.type == FirstSection) + return; + + updateCache(value, displayText()); + const int size = sectionSize(sectionIndex); + if (forward) { + edit->setSelection(sectionPos(node), size); + } else { + edit->setSelection(sectionPos(node) + size, -size); + } + } +} + +/*! + \internal + + Returns the section at index \a index or NoSection if there are no sections there. +*/ + +int QDateTimeEditPrivate::sectionAt(int pos) const +{ + if (pos < separators.first().size()) { + return (pos == 0 ? FirstSectionIndex : NoSectionIndex); + } else if (displayText().size() - pos < separators.last().size() + 1) { + if (separators.last().size() == 0) { + return sectionNodes.count() - 1; + } + return (pos == displayText().size() ? LastSectionIndex : NoSectionIndex); + } + updateCache(value, displayText()); + + for (int i=0; i= 0); + if (pos < separators.first().size()) { + return forward ? 0 : FirstSectionIndex; + } else if (displayText().size() - pos < separators.last().size() + 1) { + return forward ? LastSectionIndex : sectionNodes.size() - 1; + } + updateCache(value, displayText()); + for (int i=0; i tmp) { + return i; + } + } + qWarning("QDateTimeEdit: Internal Error: closestSection returned NoSection"); + return NoSectionIndex; +} + +/*! + \internal + + Returns a copy of the section that is before or after \a current, depending on \a forward. +*/ + +int QDateTimeEditPrivate::nextPrevSection(int current, bool forward) const +{ + Q_Q(const QDateTimeEdit); + if (q->isRightToLeft()) + forward = !forward; + + switch (current) { + case FirstSectionIndex: return forward ? 0 : FirstSectionIndex; + case LastSectionIndex: return (forward ? LastSectionIndex : sectionNodes.size() - 1); + case NoSectionIndex: return FirstSectionIndex; + default: break; + } + Q_ASSERT(current >= 0 && current < sectionNodes.size()); + + current += (forward ? 1 : -1); + if (current >= sectionNodes.size()) { + return LastSectionIndex; + } else if (current < 0) { + return FirstSectionIndex; + } + + return current; +} + +/*! + \internal + + Clears the text of section \a s. +*/ + +void QDateTimeEditPrivate::clearSection(int index) +{ + const QLatin1Char space(' '); + int cursorPos = edit->cursorPosition(); + bool blocked = edit->blockSignals(true); + QString t = edit->text(); + const int pos = sectionPos(index); + if (pos == -1) { + qWarning("QDateTimeEdit: Internal error (%s:%d)", __FILE__, __LINE__); + return; + } + const int size = sectionSize(index); + t.replace(pos, size, QString().fill(space, size)); + edit->setText(t); + edit->setCursorPosition(cursorPos); + QDTEDEBUG << cursorPos; + + edit->blockSignals(blocked); +} + + +/*! + \internal + + updates the cached values +*/ + +void QDateTimeEditPrivate::updateCache(const QVariant &val, const QString &str) const +{ + if (val != cachedValue || str != cachedText || cacheGuard) { + cacheGuard = true; + QString copy = str; + int unused = edit->cursorPosition(); + QValidator::State unusedState; + validateAndInterpret(copy, unused, unusedState); + cacheGuard = false; + } +} + +/*! + \internal + + parses and validates \a input +*/ + +QDateTime QDateTimeEditPrivate::validateAndInterpret(QString &input, int &position, + QValidator::State &state, bool fixup) const +{ + if (input.isEmpty()) { + if (sectionNodes.size() == 1 || !specialValueText.isEmpty()) { + state = QValidator::Intermediate; + } else { + state = QValidator::Invalid; + } + return getZeroVariant().toDateTime(); + } else if (cachedText == input && !fixup) { + state = cachedState; + return cachedValue.toDateTime(); + } else if (!specialValueText.isEmpty()) { + bool changeCase = false; + const int max = qMin(specialValueText.size(), input.size()); + int i; + for (i=0; itextFromDateTime(f.toDateTime()); +} + +/*! + \internal + + This function's name is slightly confusing; it is not to be confused + with QAbstractSpinBox::valueFromText(). +*/ + +QVariant QDateTimeEditPrivate::valueFromText(const QString &f) const +{ + Q_Q(const QDateTimeEdit); + return q->dateTimeFromText(f).toTimeSpec(spec); +} + + +/*! + \internal + + Internal function called by QDateTimeEdit::stepBy(). Also takes a + Section for which section to step on and a bool \a test for + whether or not to modify the internal cachedDay variable. This is + necessary because the function is called from the const function + QDateTimeEdit::stepEnabled() as well as QDateTimeEdit::stepBy(). +*/ + +QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) const +{ + Q_Q(const QDateTimeEdit); + QDateTime v = value.toDateTime(); + QString str = displayText(); + int pos = edit->cursorPosition(); + const SectionNode sn = sectionNode(sectionIndex); + + int val; + // to make sure it behaves reasonably when typing something and then stepping in non-tracking mode + if (!test && pendingEmit) { + if (q->validate(str, pos) != QValidator::Acceptable) { + v = value.toDateTime(); + } else { + v = q->dateTimeFromText(str); + } + val = getDigit(v, sectionIndex); + } else { + val = getDigit(v, sectionIndex); + } + + val += steps; + + const int min = absoluteMin(sectionIndex); + const int max = absoluteMax(sectionIndex, value.toDateTime()); + + if (val < min) { + val = (wrapping ? max - (min - val) + 1 : min); + } else if (val > max) { + val = (wrapping ? min + val - max - 1 : max); + } + + + const int oldDay = v.date().day(); + + setDigit(v, sectionIndex, val); + // if this sets year or month it will make + // sure that days are lowered if needed. + + const QDateTime minimumDateTime = minimum.toDateTime(); + const QDateTime maximumDateTime = maximum.toDateTime(); + // changing one section should only modify that section, if possible + if (sn.type != AmPmSection && (v < minimumDateTime || v > maximumDateTime)) { + const int localmin = getDigit(minimumDateTime, sectionIndex); + const int localmax = getDigit(maximumDateTime, sectionIndex); + + if (wrapping) { + // just because we hit the roof in one direction, it + // doesn't mean that we hit the floor in the other + if (steps > 0) { + setDigit(v, sectionIndex, min); + if (!(sn.type & (DaySection|DayOfWeekSection)) && sections & DateSectionMask) { + const int daysInMonth = v.date().daysInMonth(); + if (v.date().day() < oldDay && v.date().day() < daysInMonth) { + const int adds = qMin(oldDay, daysInMonth); + v = v.addDays(adds - v.date().day()); + } + } + + if (v < minimumDateTime) { + setDigit(v, sectionIndex, localmin); + if (v < minimumDateTime) + setDigit(v, sectionIndex, localmin + 1); + } + } else { + setDigit(v, sectionIndex, max); + if (!(sn.type & (DaySection|DayOfWeekSection)) && sections & DateSectionMask) { + const int daysInMonth = v.date().daysInMonth(); + if (v.date().day() < oldDay && v.date().day() < daysInMonth) { + const int adds = qMin(oldDay, daysInMonth); + v = v.addDays(adds - v.date().day()); + } + } + + if (v > maximumDateTime) { + setDigit(v, sectionIndex, localmax); + if (v > maximumDateTime) + setDigit(v, sectionIndex, localmax - 1); + } + } + } else { + setDigit(v, sectionIndex, (steps > 0 ? localmax : localmin)); + } + } + if (!test && oldDay != v.date().day() && !(sn.type & (DaySection|DayOfWeekSection))) { + // this should not happen when called from stepEnabled + cachedDay = qMax(oldDay, cachedDay); + } + + if (v < minimumDateTime) { + if (wrapping) { + QDateTime t = v; + setDigit(t, sectionIndex, steps < 0 ? max : min); + bool mincmp = (t >= minimumDateTime); + bool maxcmp = (t <= maximumDateTime); + if (!mincmp || !maxcmp) { + setDigit(t, sectionIndex, getDigit(steps < 0 + ? maximumDateTime + : minimumDateTime, sectionIndex)); + mincmp = (t >= minimumDateTime); + maxcmp = (t <= maximumDateTime); + } + if (mincmp && maxcmp) { + v = t; + } + } else { + v = value.toDateTime(); + } + } else if (v > maximumDateTime) { + if (wrapping) { + QDateTime t = v; + setDigit(t, sectionIndex, steps > 0 ? min : max); + bool mincmp = (t >= minimumDateTime); + bool maxcmp = (t <= maximumDateTime); + if (!mincmp || !maxcmp) { + setDigit(t, sectionIndex, getDigit(steps > 0 ? + minimumDateTime : + maximumDateTime, sectionIndex)); + mincmp = (t >= minimumDateTime); + maxcmp = (t <= maximumDateTime); + } + if (mincmp && maxcmp) { + v = t; + } + } else { + v = value.toDateTime(); + } + } + + const QDateTime ret = bound(v, value, steps).toDateTime().toTimeSpec(spec); + return ret; +} + +/*! + \internal +*/ + +void QDateTimeEditPrivate::emitSignals(EmitPolicy ep, const QVariant &old) +{ + Q_Q(QDateTimeEdit); + if (ep == NeverEmit) { + return; + } + pendingEmit = false; + + const bool dodate = value.toDate().isValid() && (sections & DateSectionMask); + const bool datechanged = (ep == AlwaysEmit || old.toDate() != value.toDate()); + const bool dotime = value.toTime().isValid() && (sections & TimeSectionMask); + const bool timechanged = (ep == AlwaysEmit || old.toTime() != value.toTime()); + + updateCache(value, displayText()); + + syncCalendarWidget(); + if (datechanged || timechanged) + emit q->dateTimeChanged(value.toDateTime()); + if (dodate && datechanged) + emit q->dateChanged(value.toDate()); + if (dotime && timechanged) + emit q->timeChanged(value.toTime()); + +} + +/*! + \internal +*/ + +void QDateTimeEditPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos) +{ + if (ignoreCursorPositionChanged || specialValue()) + return; + const QString oldText = displayText(); + updateCache(value, oldText); + + const bool allowChange = !edit->hasSelectedText(); + const bool forward = oldpos <= newpos; + ignoreCursorPositionChanged = true; + int s = sectionAt(newpos); + if (s == NoSectionIndex && forward && newpos > 0) { + s = sectionAt(newpos - 1); + } + + int c = newpos; + + const int selstart = edit->selectionStart(); + const int selSection = sectionAt(selstart); + const int l = selSection != -1 ? sectionSize(selSection) : 0; + + if (s == NoSectionIndex) { + if (l > 0 && selstart == sectionPos(selSection) && edit->selectedText().size() == l) { + s = selSection; + if (allowChange) + setSelected(selSection, true); + c = -1; + } else { + int closest = closestSection(newpos, forward); + c = sectionPos(closest) + (forward ? 0 : qMax(0, sectionSize(closest))); + + if (allowChange) { + edit->setCursorPosition(c); + QDTEDEBUG << c; + } + s = closest; + } + } + + if (allowChange && currentSectionIndex != s) { + interpret(EmitIfChanged); + } + if (c == -1) { + setSelected(s, true); + } else if (!edit->hasSelectedText()) { + if (oldpos < newpos) { + edit->setCursorPosition(displayText().size() - (oldText.size() - c)); + } else { + edit->setCursorPosition(c); + } + } + + QDTEDEBUG << "currentSectionIndex is set to" << sectionName(sectionType(s)) + << oldpos << newpos + << "was" << sectionName(sectionType(currentSectionIndex)); + + currentSectionIndex = s; + Q_ASSERT_X(currentSectionIndex < sectionNodes.size(), + "QDateTimeEditPrivate::_q_editorCursorPositionChanged()", + qPrintable(QString::fromAscii("Internal error (%1 %2)"). + arg(currentSectionIndex). + arg(sectionNodes.size()))); + + ignoreCursorPositionChanged = false; +} + +/*! + \internal + + Try to get the format from the local settings +*/ +void QDateTimeEditPrivate::readLocaleSettings() +{ + const QLocale loc; + defaultTimeFormat = loc.timeFormat(QLocale::ShortFormat); + defaultDateFormat = loc.dateFormat(QLocale::ShortFormat); + defaultDateTimeFormat = loc.dateTimeFormat(QLocale::ShortFormat); +} + +QDateTimeEdit::Section QDateTimeEditPrivate::convertToPublic(QDateTimeParser::Section s) +{ + switch (s & ~Internal) { + case AmPmSection: return QDateTimeEdit::AmPmSection; + case MSecSection: return QDateTimeEdit::MSecSection; + case SecondSection: return QDateTimeEdit::SecondSection; + case MinuteSection: return QDateTimeEdit::MinuteSection; + case DayOfWeekSection: + case DaySection: return QDateTimeEdit::DaySection; + case MonthSection: return QDateTimeEdit::MonthSection; + case YearSection2Digits: + case YearSection: return QDateTimeEdit::YearSection; + case Hour12Section: + case Hour24Section: return QDateTimeEdit::HourSection; + case FirstSection: + case NoSection: + case LastSection: break; + } + return QDateTimeEdit::NoSection; +} + +QDateTimeEdit::Sections QDateTimeEditPrivate::convertSections(QDateTimeParser::Sections s) +{ + QDateTimeEdit::Sections ret = 0; + if (s & QDateTimeParser::MSecSection) + ret |= QDateTimeEdit::MSecSection; + if (s & QDateTimeParser::SecondSection) + ret |= QDateTimeEdit::SecondSection; + if (s & QDateTimeParser::MinuteSection) + ret |= QDateTimeEdit::MinuteSection; + if (s & (QDateTimeParser::Hour24Section|QDateTimeParser::Hour12Section)) + ret |= QDateTimeEdit::HourSection; + if (s & QDateTimeParser::AmPmSection) + ret |= QDateTimeEdit::AmPmSection; + if (s & (QDateTimeParser::DaySection|QDateTimeParser::DayOfWeekSection)) + ret |= QDateTimeEdit::DaySection; + if (s & QDateTimeParser::MonthSection) + ret |= QDateTimeEdit::MonthSection; + if (s & (QDateTimeParser::YearSection|QDateTimeParser::YearSection2Digits)) + ret |= QDateTimeEdit::YearSection; + + return ret; +} + +/*! + \reimp +*/ + +void QDateTimeEdit::paintEvent(QPaintEvent *event) +{ + Q_D(QDateTimeEdit); + if (!d->calendarPopupEnabled()) { + QAbstractSpinBox::paintEvent(event); + return; + } + + QStyleOptionSpinBox opt; + initStyleOption(&opt); + + QStyleOptionComboBox optCombo; + + optCombo.init(this); + optCombo.editable = true; + optCombo.frame = opt.frame; + optCombo.subControls = opt.subControls; + optCombo.activeSubControls = opt.activeSubControls; + optCombo.state = opt.state; + if (d->readOnly) { + optCombo.state &= ~QStyle::State_Enabled; + } + + QPainter p(this); + style()->drawComplexControl(QStyle::CC_ComboBox, &optCombo, &p, this); +} + +QString QDateTimeEditPrivate::getAmPmText(AmPm ap, Case cs) const +{ + if (ap == AmText) { + return (cs == UpperCase ? QDateTimeEdit::tr("AM") : QDateTimeEdit::tr("am")); + } else { + return (cs == UpperCase ? QDateTimeEdit::tr("PM") : QDateTimeEdit::tr("pm")); + } +} + +int QDateTimeEditPrivate::absoluteIndex(QDateTimeEdit::Section s, int index) const +{ + for (int i=0; icursorPosition(); + const QValidator::State state = q->validate(tmp, pos); + if (state != QValidator::Acceptable + && correctionMode == QAbstractSpinBox::CorrectToPreviousValue + && (state == QValidator::Invalid || !(fieldInfo(currentSectionIndex) & AllowPartial))) { + setValue(value, ep); + updateTimeSpec(); + } else { + QAbstractSpinBoxPrivate::interpret(ep); + } +} + +void QDateTimeEditPrivate::clearCache() const +{ + QAbstractSpinBoxPrivate::clearCache(); + cachedDay = -1; +} + +/*! + Initialize \a option with the values from this QDataTimeEdit. This method + is useful for subclasses when they need a QStyleOptionSpinBox, but don't want + to fill in all the information themselves. + + \sa QStyleOption::initFrom() +*/ +void QDateTimeEdit::initStyleOption(QStyleOptionSpinBox *option) const +{ + if (!option) + return; + + Q_D(const QDateTimeEdit); + QAbstractSpinBox::initStyleOption(option); + if (d->calendarPopupEnabled()) { + option->subControls = QStyle::SC_ComboBoxFrame | QStyle::SC_ComboBoxEditField + | QStyle::SC_ComboBoxArrow; + if (d->arrowState == QStyle::State_Sunken) + option->state |= QStyle::State_Sunken; + else + option->state &= ~QStyle::State_Sunken; + } +} + +void QDateTimeEditPrivate::init(const QVariant &var) +{ + Q_Q(QDateTimeEdit); + switch (var.type()) { + case QVariant::Date: + value = QDateTime(var.toDate(), QDATETIMEEDIT_TIME_MIN); + q->setDisplayFormat(defaultDateFormat); + if (sectionNodes.isEmpty()) // ### safeguard for broken locale + q->setDisplayFormat(QLatin1String("dd/MM/yyyy")); + break; + case QVariant::DateTime: + value = var; + q->setDisplayFormat(defaultDateTimeFormat); + if (sectionNodes.isEmpty()) // ### safeguard for broken locale + q->setDisplayFormat(QLatin1String("dd/MM/yyyy hh:mm:ss")); + break; + case QVariant::Time: + value = QDateTime(QDATETIMEEDIT_DATE_INITIAL, var.toTime()); + q->setDisplayFormat(defaultTimeFormat); + if (sectionNodes.isEmpty()) // ### safeguard for broken locale + q->setDisplayFormat(QLatin1String("hh:mm:ss")); + break; + default: + Q_ASSERT_X(0, "QDateTimeEditPrivate::init", "Internal error"); + break; + } +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled()) + q->setCalendarPopup(true); +#endif + updateTimeSpec(); + q->setInputMethodHints(Qt::ImhPreferNumbers); + setLayoutItemMargins(QStyle::SE_DateTimeEditLayoutItem); +} + +void QDateTimeEditPrivate::_q_resetButton() +{ + updateArrow(QStyle::State_None); +} + +void QDateTimeEditPrivate::updateArrow(QStyle::StateFlag state) +{ + Q_Q(QDateTimeEdit); + + if (arrowState == state) + return; + arrowState = state; + if (arrowState != QStyle::State_None) + buttonState |= Mouse; + else { + buttonState = 0; + hoverControl = QStyle::SC_ComboBoxFrame; + } + q->update(); +} + +/*! + \internal + Returns the hover control at \a pos. + This will update the hoverRect and hoverControl. +*/ +QStyle::SubControl QDateTimeEditPrivate::newHoverControl(const QPoint &pos) +{ + if (!calendarPopupEnabled()) + return QAbstractSpinBoxPrivate::newHoverControl(pos); + + Q_Q(QDateTimeEdit); + + QStyleOptionComboBox optCombo; + optCombo.init(q); + optCombo.editable = true; + optCombo.subControls = QStyle::SC_All; + hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &optCombo, pos, q); + return hoverControl; +} + +void QDateTimeEditPrivate::updateEditFieldGeometry() +{ + if (!calendarPopupEnabled()) { + QAbstractSpinBoxPrivate::updateEditFieldGeometry(); + return; + } + + Q_Q(QDateTimeEdit); + + QStyleOptionComboBox optCombo; + optCombo.init(q); + optCombo.editable = true; + optCombo.subControls = QStyle::SC_ComboBoxEditField; + edit->setGeometry(q->style()->subControlRect(QStyle::CC_ComboBox, &optCombo, + QStyle::SC_ComboBoxEditField, q)); +} + +QVariant QDateTimeEditPrivate::getZeroVariant() const +{ + Q_ASSERT(type == QVariant::DateTime); + return QDateTime(QDATETIMEEDIT_DATE_INITIAL, QTime(), spec); +} + +void QDateTimeEditPrivate::setRange(const QVariant &min, const QVariant &max) +{ + QAbstractSpinBoxPrivate::setRange(min, max); + syncCalendarWidget(); +} + + +bool QDateTimeEditPrivate::isSeparatorKey(const QKeyEvent *ke) const +{ + if (!ke->text().isEmpty() && currentSectionIndex + 1 < sectionNodes.size() && currentSectionIndex >= 0) { + if (fieldInfo(currentSectionIndex) & Numeric) { + if (ke->text().at(0).isNumber()) + return false; + } else if (ke->text().at(0).isLetterOrNumber()) { + return false; + } + return separators.at(currentSectionIndex + 1).contains(ke->text()); + } + return false; +} + +void QDateTimeEditPrivate::initCalendarPopup(QCalendarWidget *cw) +{ + Q_Q(QDateTimeEdit); + if (!monthCalendar) { + monthCalendar = new QCalendarPopup(q, cw); + monthCalendar->setObjectName(QLatin1String("qt_datetimedit_calendar")); + QObject::connect(monthCalendar, SIGNAL(newDateSelected(QDate)), q, SLOT(setDate(QDate))); + QObject::connect(monthCalendar, SIGNAL(hidingCalendar(QDate)), q, SLOT(setDate(QDate))); + QObject::connect(monthCalendar, SIGNAL(activated(QDate)), q, SLOT(setDate(QDate))); + QObject::connect(monthCalendar, SIGNAL(activated(QDate)), monthCalendar, SLOT(close())); + QObject::connect(monthCalendar, SIGNAL(resetButton()), q, SLOT(_q_resetButton())); + } else if (cw) { + monthCalendar->setCalendarWidget(cw); + } + syncCalendarWidget(); +} + +void QDateTimeEditPrivate::positionCalendarPopup() +{ + Q_Q(QDateTimeEdit); + QPoint pos = (q->layoutDirection() == Qt::RightToLeft) ? q->rect().bottomRight() : q->rect().bottomLeft(); + QPoint pos2 = (q->layoutDirection() == Qt::RightToLeft) ? q->rect().topRight() : q->rect().topLeft(); + pos = q->mapToGlobal(pos); + pos2 = q->mapToGlobal(pos2); + QSize size = monthCalendar->sizeHint(); + QRect screen = QApplication::desktop()->availableGeometry(pos); + //handle popup falling "off screen" + if (q->layoutDirection() == Qt::RightToLeft) { + pos.setX(pos.x()-size.width()); + pos2.setX(pos2.x()-size.width()); + if (pos.x() < screen.left()) + pos.setX(qMax(pos.x(), screen.left())); + else if (pos.x()+size.width() > screen.right()) + pos.setX(qMax(pos.x()-size.width(), screen.right()-size.width())); + } else { + if (pos.x()+size.width() > screen.right()) + pos.setX(screen.right()-size.width()); + pos.setX(qMax(pos.x(), screen.left())); + } + if (pos.y() + size.height() > screen.bottom()) + pos.setY(pos2.y() - size.height()); + else if (pos.y() < screen.top()) + pos.setY(screen.top()); + if (pos.y() < screen.top()) + pos.setY(screen.top()); + if (pos.y()+size.height() > screen.bottom()) + pos.setY(screen.bottom()-size.height()); + monthCalendar->move(pos); +} + +bool QDateTimeEditPrivate::calendarPopupEnabled() const +{ + return (calendarPopup && (sections & (DateSectionMask))); +} + +void QDateTimeEditPrivate::syncCalendarWidget() +{ + Q_Q(QDateTimeEdit); + if (monthCalendar) { + monthCalendar->setDateRange(q->minimumDate(), q->maximumDate()); + monthCalendar->setDate(q->date()); + } +} + +QCalendarPopup::QCalendarPopup(QWidget * parent, QCalendarWidget *cw) + : QWidget(parent, Qt::Popup), calendar(0) +{ + setAttribute(Qt::WA_WindowPropagation); + + dateChanged = false; + if (!cw) { + cw = new QCalendarWidget(this); + cw->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader); +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled()) + cw->setHorizontalHeaderFormat(QCalendarWidget::SingleLetterDayNames); +#endif + } + setCalendarWidget(cw); +} + +void QCalendarPopup::setCalendarWidget(QCalendarWidget *cw) +{ + Q_ASSERT(cw); + QVBoxLayout *widgetLayout = qobject_cast(layout()); + if (!widgetLayout) { + widgetLayout = new QVBoxLayout(this); + widgetLayout->setMargin(0); + widgetLayout->setSpacing(0); + } + delete calendar; + calendar = cw; + widgetLayout->addWidget(calendar); + + connect(calendar, SIGNAL(activated(QDate)), this, SLOT(dateSelected(QDate))); + connect(calendar, SIGNAL(clicked(QDate)), this, SLOT(dateSelected(QDate))); + connect(calendar, SIGNAL(selectionChanged()), this, SLOT(dateSelectionChanged())); + + calendar->setFocus(); +} + + +void QCalendarPopup::setDate(const QDate &date) +{ + oldDate = date; + calendar->setSelectedDate(date); +} + +void QCalendarPopup::setDateRange(const QDate &min, const QDate &max) +{ + calendar->setMinimumDate(min); + calendar->setMaximumDate(max); +} + +void QCalendarPopup::mousePressEvent(QMouseEvent *event) +{ + QDateTimeEdit *dateTime = qobject_cast(parentWidget()); + if (dateTime) { + QStyleOptionComboBox opt; + opt.init(dateTime); + QRect arrowRect = dateTime->style()->subControlRect(QStyle::CC_ComboBox, &opt, + QStyle::SC_ComboBoxArrow, dateTime); + arrowRect.moveTo(dateTime->mapToGlobal(arrowRect .topLeft())); + if (arrowRect.contains(event->globalPos()) || rect().contains(event->pos())) + setAttribute(Qt::WA_NoMouseReplay); + } + QWidget::mousePressEvent(event); +} + +void QCalendarPopup::mouseReleaseEvent(QMouseEvent*) +{ + emit resetButton(); +} + +bool QCalendarPopup::event(QEvent *event) +{ + if (event->type() == QEvent::KeyPress) { + QKeyEvent *keyEvent = static_cast(event); + if (keyEvent->key()== Qt::Key_Escape) + dateChanged = false; + } + return QWidget::event(event); +} + +void QCalendarPopup::dateSelectionChanged() +{ + dateChanged = true; + emit newDateSelected(calendar->selectedDate()); +} +void QCalendarPopup::dateSelected(const QDate &date) +{ + dateChanged = true; + emit activated(date); + close(); +} + +void QCalendarPopup::hideEvent(QHideEvent *) +{ + emit resetButton(); + if (!dateChanged) + emit hidingCalendar(oldDate); +} + +QT_END_NAMESPACE +#include "moc_qdatetimeedit.cpp" + +#endif // QT_NO_DATETIMEEDIT