/****************************************************************************
**
** Copyright (C) 2010 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 <math.h>
#include <private/qdatetimeedit_p.h>
#include <qabstractspinbox.h>
#include <qapplication.h>
#include <qdatetimeedit.h>
#include <qdesktopwidget.h>
#include <qdebug.h>
#include <qevent.h>
#include <qlineedit.h>
#include <private/qlineedit_p.h>
#include <qlocale.h>
#include <qpainter.h>
#include <qlayout.h>
#include <qset.h>
#include <qstyle.h>
#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<QDateTimeEditPrivate*>(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<typename C> 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<int>(w, fm.width(s));
s = d->textFromValue(d->maximum) + QLatin1String(" ");
w = qMax<int>(w, fm.width(s));
if (d->specialValueText.size()) {
s = d->specialValueText;
w = qMax<int>(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; i<d->sectionNodes.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<sectionNodes.size(); ++i) {
const int tmp = sectionPos(i);
if (pos < tmp + sectionSize(i)) {
return (pos < tmp ? -1 : i);
}
}
return -1;
}
/*!
\internal
Returns the closest section of index \a index. Searches forward
for a section if \a forward is true. Otherwise searches backwards.
*/
int QDateTimeEditPrivate::closestSection(int pos, bool forward) const
{
Q_ASSERT(pos >= 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<sectionNodes.size(); ++i) {
const int tmp = sectionPos(sectionNodes.at(i));
if (pos < tmp + sectionSize(i)) {
if (pos < tmp && !forward) {
return i-1;
}
return i;
} else if (i == sectionNodes.size() - 1 && pos > 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; i<max; ++i) {
const QChar ic = input.at(i);
const QChar sc = specialValueText.at(i);
if (ic != sc) {
if (sc.toLower() == ic.toLower()) {
changeCase = true;
} else {
break;
}
}
}
if (i == max) {
state = specialValueText.size() == input.size() ? QValidator::Acceptable : QValidator::Intermediate;
if (changeCase) {
input = specialValueText.left(max);
}
return minimum.toDateTime();
}
}
StateNode tmp = parse(input, position, value.toDateTime(), fixup);
input = tmp.input;
state = QValidator::State(int(tmp.state));
if (state == QValidator::Acceptable) {
if (tmp.conflicts && conflictGuard != tmp.value) {
conflictGuard = tmp.value;
clearCache();
input = textFromValue(tmp.value);
updateCache(tmp.value, input);
conflictGuard.clear();
} else {
cachedText = input;
cachedState = state;
cachedValue = tmp.value;
}
} else {
clearCache();
}
return (tmp.value.isNull() ? getZeroVariant().toDateTime() : tmp.value);
}
/*!
\internal
*/
QString QDateTimeEditPrivate::textFromValue(const QVariant &f) const
{
Q_Q(const QDateTimeEdit);
return q->textFromDateTime(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<int>(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<int>(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; i<sectionNodes.size(); ++i) {
if (convertToPublic(sectionNodes.at(i).type) == s && index-- == 0) {
return i;
}
}
return NoSectionIndex;
}
int QDateTimeEditPrivate::absoluteIndex(const SectionNode &s) const
{
return sectionNodes.indexOf(s);
}
void QDateTimeEditPrivate::interpret(EmitPolicy ep)
{
Q_Q(QDateTimeEdit);
QString tmp = displayText();
int pos = edit->cursorPosition();
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<QVBoxLayout*>(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<QDateTimeEdit *>(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<QKeyEvent*>(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