diff options
Diffstat (limited to 'src/widgets/widgets/qdatetimeedit.cpp')
-rw-r--r-- | src/widgets/widgets/qdatetimeedit.cpp | 393 |
1 files changed, 219 insertions, 174 deletions
diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp index e57d1f9db5..a9b5babde5 100644 --- a/src/widgets/widgets/qdatetimeedit.cpp +++ b/src/widgets/widgets/qdatetimeedit.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWidgets module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include <private/qapplication_p.h> #include <private/qdatetimeedit_p.h> @@ -51,9 +15,7 @@ #include <qlayout.h> #include <qset.h> #include <qstyle.h> -#if QT_CONFIG(timezone) -#include <QTimeZone> -#endif +#include <qstylepainter.h> #include <algorithm> @@ -68,6 +30,8 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + // --- QDateTimeEdit --- /*! @@ -223,7 +187,9 @@ QDateTimeEdit::QDateTimeEdit(QTime time, QWidget *parent) \internal */ QDateTimeEdit::QDateTimeEdit(const QVariant &var, QMetaType::Type parserType, QWidget *parent) - : QAbstractSpinBox(*new QDateTimeEditPrivate, parent) + : QAbstractSpinBox(*new QDateTimeEditPrivate(parserType == QMetaType::QDateTime + ? QTimeZone::LocalTime : QTimeZone::UTC), + parent) { Q_D(QDateTimeEdit); d->parserType = parserType; @@ -241,8 +207,8 @@ QDateTimeEdit::~QDateTimeEdit() \property QDateTimeEdit::dateTime \brief The QDateTime that is set in the QDateTimeEdit. - When setting this property, the new QDateTime is converted to the timespec of - the QDateTimeEdit, which thus remains unchanged. + When setting this property, the new QDateTime is converted to the time system + of the QDateTimeEdit, which thus remains unchanged. By default, this property is set to the start of 2000 CE. It can only be set to a valid QDateTime value. If any operation causes this property to have an @@ -253,7 +219,7 @@ QDateTimeEdit::~QDateTimeEdit() widget's date-range to start and end on the date of the new value of this property. - \sa date, time, minimumDateTime, maximumDateTime + \sa date, time, minimumDateTime, maximumDateTime, timeZone */ QDateTime QDateTimeEdit::dateTime() const @@ -266,8 +232,8 @@ void QDateTimeEdit::setDateTime(const QDateTime &datetime) { Q_D(QDateTimeEdit); if (datetime.isValid()) { - QDateTime when = d->convertTimeSpec(datetime); - Q_ASSERT(when.timeSpec() == d->spec); + QDateTime when = d->convertTimeZone(datetime); + Q_ASSERT(when.timeRepresentation() == d->timeZone); d->clearCache(); const QDate date = when.date(); @@ -303,14 +269,10 @@ void QDateTimeEdit::setDate(QDate date) setDateRange(date, date); d->clearCache(); - QDateTime when(date, d->value.toTime(), d->spec); - // The specified time might not exist on the specified day, - // i.e. the time is in the gap a spring-forward jumps over. - if (!when.isValid()) - when = QDateTime::fromMSecsSinceEpoch(when.toMSecsSinceEpoch(), d->spec); + QDateTime when = d->dateTimeValue(date, d->value.toTime()); Q_ASSERT(when.isValid()); d->setValue(when, EmitIfChanged); - d->updateTimeSpec(); + d->updateTimeZone(); } } @@ -337,10 +299,16 @@ void QDateTimeEdit::setTime(QTime time) Q_D(QDateTimeEdit); if (time.isValid()) { d->clearCache(); - d->setValue(QDateTime(d->value.toDate(), time, d->spec), EmitIfChanged); + d->setValue(d->dateTimeValue(d->value.toDate(), time), EmitIfChanged); } } +/*! + \since 5.14 + Report the calendar system in use by this widget. + + \sa setCalendar() +*/ QCalendar QDateTimeEdit::calendar() const { @@ -348,6 +316,16 @@ QCalendar QDateTimeEdit::calendar() const return d->calendar; } +/*! + \since 5.14 + Set \a calendar as the calendar system to be used by this widget. + + The widget can use any supported calendar system. + By default, it uses the Gregorian calendar. + + \sa calendar() +*/ + void QDateTimeEdit::setCalendar(QCalendar calendar) { Q_D(QDateTimeEdit); @@ -394,7 +372,7 @@ 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 m = dt.toTimeZone(d->timeZone); const QDateTime max = d->maximum.toDateTime(); d->setRange(m, (max > m ? max : m)); } @@ -436,7 +414,7 @@ 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 m = dt.toTimeZone(d->timeZone); const QDateTime min = d->minimum.toDateTime(); d->setRange((min < m ? min : m), m); } @@ -470,8 +448,8 @@ void QDateTimeEdit::setDateTimeRange(const QDateTime &min, const QDateTime &max) { Q_D(QDateTimeEdit); // FIXME: does none of the range checks applied to setMin/setMax methods ! - const QDateTime minimum = min.toTimeSpec(d->spec); - const QDateTime maximum = (min > max ? minimum : max.toTimeSpec(d->spec)); + const QDateTime minimum = min.toTimeZone(d->timeZone); + const QDateTime maximum = (min > max ? minimum : max.toTimeZone(d->timeZone)); d->setRange(minimum, maximum); } @@ -506,9 +484,8 @@ QDate QDateTimeEdit::minimumDate() const void QDateTimeEdit::setMinimumDate(QDate min) { Q_D(QDateTimeEdit); - if (min.isValid() && min >= QDATETIMEEDIT_DATE_MIN) { - setMinimumDateTime(QDateTime(min, d->minimum.toTime(), d->spec)); - } + if (min.isValid() && min >= QDATETIMEEDIT_DATE_MIN) + setMinimumDateTime(d->dateTimeValue(min, d->minimum.toTime())); } void QDateTimeEdit::clearMinimumDate() @@ -548,7 +525,7 @@ void QDateTimeEdit::setMaximumDate(QDate max) { Q_D(QDateTimeEdit); if (max.isValid()) - setMaximumDateTime(QDateTime(max, d->maximum.toTime(), d->spec)); + setMaximumDateTime(d->dateTimeValue(max, d->maximum.toTime())); } void QDateTimeEdit::clearMaximumDate() @@ -585,10 +562,8 @@ QTime QDateTimeEdit::minimumTime() const void QDateTimeEdit::setMinimumTime(QTime min) { Q_D(QDateTimeEdit); - if (min.isValid()) { - const QDateTime m(d->minimum.toDate(), min, d->spec); - setMinimumDateTime(m); - } + if (min.isValid()) + setMinimumDateTime(d->dateTimeValue(d->minimum.toDate(), min)); } void QDateTimeEdit::clearMinimumTime() @@ -624,10 +599,8 @@ QTime QDateTimeEdit::maximumTime() const void QDateTimeEdit::setMaximumTime(QTime max) { Q_D(QDateTimeEdit); - if (max.isValid()) { - const QDateTime m(d->maximum.toDate(), max, d->spec); - setMaximumDateTime(m); - } + if (max.isValid()) + setMaximumDateTime(d->dateTimeValue(d->maximum.toDate(), max)); } void QDateTimeEdit::clearMaximumTime() @@ -665,8 +638,8 @@ void QDateTimeEdit::setDateRange(QDate min, 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)); + setDateTimeRange(d->dateTimeValue(min, d->minimum.toTime()), + d->dateTimeValue(max, d->maximum.toTime())); } } @@ -704,8 +677,8 @@ void QDateTimeEdit::setTimeRange(QTime min, 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)); + setDateTimeRange(d->dateTimeValue(d->minimum.toDate(), min), + d->dateTimeValue(d->maximum.toDate(), max)); } } @@ -988,10 +961,10 @@ void QDateTimeEdit::setDisplayFormat(const QString &format) } } else if (dateShown && !timeShown) { setTimeRange(QDATETIMEEDIT_TIME_MIN, QDATETIMEEDIT_TIME_MAX); - d->value = QDateTime(d->value.toDate(), QTime(), d->spec); + d->value = d->value.toDate().startOfDay(d->timeZone); } d->updateEdit(); - d->_q_editorCursorPositionChanged(-1, 0); + d->editorCursorPositionChanged(-1, 0); } } @@ -1027,24 +1000,70 @@ void QDateTimeEdit::setCalendarPopup(bool enable) update(); } +#if QT_DEPRECATED_SINCE(6, 10) /*! \property QDateTimeEdit::timeSpec - \brief The current timespec used by the date time edit. \since 4.4 + \deprecated[6.10] Use QDateTimeEdit::timeZone instead. + \brief The current timespec used by the date time edit. + + Since Qt 6.7 this is an indirect accessor for the timeZone property. + + \sa QDateTimeEdit::timeZone */ Qt::TimeSpec QDateTimeEdit::timeSpec() const { Q_D(const QDateTimeEdit); - return d->spec; + return d->timeZone.timeSpec(); } void QDateTimeEdit::setTimeSpec(Qt::TimeSpec spec) { Q_D(QDateTimeEdit); - if (spec != d->spec) { - d->spec = spec; - d->updateTimeSpec(); + if (spec != d->timeZone.timeSpec()) { + switch (spec) { + case Qt::UTC: + setTimeZone(QTimeZone::UTC); + break; + case Qt::LocalTime: + setTimeZone(QTimeZone::LocalTime); + break; + default: + qWarning() << "Ignoring attempt to set time-spec" << spec + << "which needs ancillary data: see setTimeZone()"; + return; + } + } +} +#endif // 6.10 deprecation + +// TODO: enable user input to control timeZone, when the format includes it. +/*! + \property QDateTimeEdit::timeZone + \since 6.7 + \brief The current timezone used by the datetime editing widget + + If the datetime format in use includes a timezone indicator - that is, a + \c{t}, \c{tt}, \c{ttt} or \c{tttt} format specifier - the user's input is + re-expressed in this timezone whenever it is parsed, overriding any timezone + the user may have specified. + + \sa QDateTimeEdit::displayFormat +*/ + +QTimeZone QDateTimeEdit::timeZone() const +{ + Q_D(const QDateTimeEdit); + return d->timeZone; +} + +void QDateTimeEdit::setTimeZone(const QTimeZone &zone) +{ + Q_D(QDateTimeEdit); + if (zone != d->timeZone) { + d->timeZone = zone; + d->updateTimeZone(); } } @@ -1062,9 +1081,9 @@ QSize QDateTimeEdit::sizeHint() const int h = d->edit->sizeHint().height(); int w = 0; QString s; - s = d->textFromValue(d->minimum) + QLatin1Char(' '); + s = d->textFromValue(d->minimum) + u' '; w = qMax<int>(w, fm.horizontalAdvance(s)); - s = d->textFromValue(d->maximum) + QLatin1Char(' '); + s = d->textFromValue(d->maximum) + u' '; w = qMax<int>(w, fm.horizontalAdvance(s)); if (d->specialValueText.size()) { s = d->specialValueText; @@ -1295,9 +1314,9 @@ void QDateTimeEdit::focusInEvent(QFocusEvent *event) { Q_D(QDateTimeEdit); QAbstractSpinBox::focusInEvent(event); - QString *frm = nullptr; const int oldPos = d->edit->cursorPosition(); if (!d->formatExplicitlySet) { + QString *frm = nullptr; if (d->displayFormat == d->defaultTimeFormat) { frm = &d->defaultTimeFormat; } else if (d->displayFormat == d->defaultDateFormat) { @@ -1328,6 +1347,7 @@ void QDateTimeEdit::focusInEvent(QFocusEvent *event) case Qt::ActiveWindowFocusReason: if (oldHasHadFocus) return; + break; case Qt::ShortcutFocusReason: case Qt::TabFocusReason: default: @@ -1420,7 +1440,7 @@ void QDateTimeEdit::stepBy(int steps) d->updateCache(d->value, d->displayText()); d->setSelected(d->currentSectionIndex); - d->updateTimeSpec(); + d->updateTimeZone(); } /*! @@ -1479,15 +1499,11 @@ void QDateTimeEdit::fixup(QString &input) const int copy = d->edit->cursorPosition(); QDateTime value = d->validateAndInterpret(input, copy, state, true); - /* - String was valid, but the datetime still is not; use the time that - has the same distance from epoch. - CorrectToPreviousValue correction is handled by QAbstractSpinBox. - */ - if (!value.isValid() && d->correctionMode == QAbstractSpinBox::CorrectToNearestValue) { - value = QDateTime::fromMSecsSinceEpoch(value.toMSecsSinceEpoch(), value.timeSpec()); + // CorrectToPreviousValue correction is handled by QAbstractSpinBox. + // The value might not match the input if the input represents a date-time + // skipped over by its time representation, such as a spring-forward. + if (d->correctionMode == QAbstractSpinBox::CorrectToNearestValue) input = textFromDateTime(value); - } } @@ -1511,7 +1527,7 @@ QDateTimeEdit::StepEnabled QDateTimeEdit::stepEnabled() const if (d->wrapping) return StepEnabled(StepUpEnabled | StepDownEnabled); // 3 cases. date, time, datetime. each case look - // at just the relavant component. + // at just the relevant component. QVariant max, min, val; if (!(d->sections & DateSections_Mask)) { // time only, no date @@ -1628,7 +1644,7 @@ QTimeEdit::QTimeEdit(QWidget *parent) */ QTimeEdit::QTimeEdit(QTime time, QWidget *parent) - : QDateTimeEdit(time, QMetaType::QTime, parent) + : QDateTimeEdit(time.isValid() ? time : QDATETIMEEDIT_TIME_MIN, QMetaType::QTime, parent) { connect(this, &QTimeEdit::timeChanged, this, &QTimeEdit::userTimeChanged); } @@ -1698,7 +1714,7 @@ QDateEdit::QDateEdit(QWidget *parent) */ QDateEdit::QDateEdit(QDate date, QWidget *parent) - : QDateTimeEdit(date, QMetaType::QDate, parent) + : QDateTimeEdit(date.isValid() ? date : QDATETIMEEDIT_DATE_INITIAL, QMetaType::QDate, parent) { connect(this, &QDateEdit::dateChanged, this, &QDateEdit::userDateChanged); } @@ -1734,65 +1750,42 @@ QDateEdit::~QDateEdit() */ -QDateTimeEditPrivate::QDateTimeEditPrivate() - : QDateTimeParser(QMetaType::QDateTime, QDateTimeParser::DateTimeEdit, QCalendar()) +QDateTimeEditPrivate::QDateTimeEditPrivate(const QTimeZone &zone) + : QDateTimeParser(QMetaType::QDateTime, QDateTimeParser::DateTimeEdit, QCalendar()), + timeZone(zone) { - hasHadFocus = false; - formatExplicitlySet = false; - cacheGuard = false; fixday = true; type = QMetaType::QDateTime; - sections = { }; - cachedDay = -1; currentSectionIndex = FirstSectionIndex; first.pos = 0; - calendarPopup = false; - minimum = QDATETIMEEDIT_COMPAT_DATE_MIN.startOfDay(); - maximum = QDATETIMEEDIT_DATE_MAX.endOfDay(); - arrowState = QStyle::State_None; - monthCalendar = nullptr; + minimum = QDATETIMEEDIT_COMPAT_DATE_MIN.startOfDay(timeZone); + maximum = QDATETIMEEDIT_DATE_MAX.endOfDay(timeZone); readLocaleSettings(); +} -#ifdef QT_KEYPAD_NAVIGATION - focusOnButton = false; -#endif +QDateTime QDateTimeEditPrivate::convertTimeZone(const QDateTime &datetime) +{ + return datetime.toTimeZone(timeZone); } -QDateTime QDateTimeEditPrivate::convertTimeSpec(const QDateTime &datetime) +QDateTime QDateTimeEditPrivate::dateTimeValue(QDate date, QTime time) const { - Q_ASSERT(value.toDateTime().timeSpec() == spec); - switch (spec) { - case Qt::UTC: - return datetime.toUTC(); - case Qt::LocalTime: - return datetime.toLocalTime(); - case Qt::OffsetFromUTC: - return datetime.toOffsetFromUtc(value.toDateTime().offsetFromUtc()); - case Qt::TimeZone: -#if QT_CONFIG(timezone) - return datetime.toTimeZone(value.toDateTime().timeZone()); -#else - qWarning("QDateTimeEdit: Internal: enable timezone feature to support Qt::TimeZone"); - return datetime; -#endif - } - Q_UNREACHABLE(); + return QDateTime(date, time, timeZone); } -// FIXME: architecturaly incompatible with OffsetFromUTC or TimeZone as spec (QTBUG-80417). -void QDateTimeEditPrivate::updateTimeSpec() +void QDateTimeEditPrivate::updateTimeZone() { - minimum = minimum.toDateTime().toTimeSpec(spec); - maximum = maximum.toDateTime().toTimeSpec(spec); - value = value.toDateTime().toTimeSpec(spec); + minimum = minimum.toDateTime().toTimeZone(timeZone); + maximum = maximum.toDateTime().toTimeZone(timeZone); + value = value.toDateTime().toTimeZone(timeZone); // time zone changes can lead to 00:00:00 becomes 01:00:00 and 23:59:59 becomes 00:59:59 (invalid range) const bool dateShown = (sections & QDateTimeEdit::DateSections_Mask); if (!dateShown) { if (minimum.toTime() >= maximum.toTime()){ - minimum = value.toDate().startOfDay(spec); - maximum = value.toDate().endOfDay(spec); + minimum = value.toDate().startOfDay(timeZone); + maximum = value.toDate().endOfDay(timeZone); } } } @@ -1827,6 +1820,27 @@ void QDateTimeEditPrivate::updateEdit() } } +QDateTime QDateTimeEditPrivate::getMinimum() const +{ + if (keyboardTracking) + return minimum.toDateTime(); + + if (timeZone.timeSpec() == Qt::LocalTime) + return QDateTimeParser::getMinimum(); + + return QDATETIMEEDIT_DATE_MIN.startOfDay(timeZone); +} + +QDateTime QDateTimeEditPrivate::getMaximum() const +{ + if (keyboardTracking) + return maximum.toDateTime(); + + if (timeZone.timeSpec() == Qt::LocalTime) + return QDateTimeParser::getMaximum(); + + return QDATETIMEEDIT_DATE_MAX.endOfDay(timeZone); +} /*! \internal @@ -1872,7 +1886,7 @@ int QDateTimeEditPrivate::sectionAt(int pos) const const int textSize = text.size(); if (textSize - pos < separators.last().size() + 1) { if (separators.last().size() == 0) { - return sectionNodes.count() - 1; + return sectionNodes.size() - 1; } return (pos == textSize ? LastSectionIndex : NoSectionIndex); } @@ -1958,7 +1972,7 @@ int QDateTimeEditPrivate::nextPrevSection(int current, bool forward) const void QDateTimeEditPrivate::clearSection(int index) { - const QLatin1Char space(' '); + const auto space = u' '; int cursorPos = edit->cursorPosition(); const QSignalBlocker blocker(edit); QString t = edit->text(); @@ -2039,8 +2053,10 @@ QDateTime QDateTimeEditPrivate::validateAndInterpret(QString &input, int &positi StateNode tmp = parse(input, position, value.toDateTime(), fixup); // Take note of any corrections imposed during parsing: input = m_text; - // Impose this widget's spec: - tmp.value = tmp.value.toTimeSpec(spec); + // TODO: if the format specifies time-zone, update timeZone to match the + // parsed text; but we're in const context, so can't - QTBUG-118393. + // Impose this widget's time system: + tmp.value = tmp.value.toTimeZone(timeZone); // ... but that might turn a valid datetime into an invalid one: if (!tmp.value.isValid() && tmp.state == Acceptable) tmp.state = Intermediate; @@ -2086,7 +2102,7 @@ QString QDateTimeEditPrivate::textFromValue(const QVariant &f) const QVariant QDateTimeEditPrivate::valueFromText(const QString &f) const { Q_Q(const QDateTimeEdit); - return q->dateTimeFromText(f).toTimeSpec(spec); + return q->dateTimeFromText(f).toTimeZone(timeZone); } @@ -2113,30 +2129,59 @@ QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) c v = q->dateTimeFromText(str); int 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); + if (sn.type & DayOfWeekSectionMask) { + // Must take locale's first day of week into account when *not* + // wrapping; min and max don't help us. +#ifndef QT_ALWAYS_WRAP_WEEKDAY // (documentation, not an actual define) + if (!wrapping) { + /* It's not clear this is ever really a desirable behavior. + + It refuses to step backwards from the first day of the week or + forwards from the day before, only allowing day-of-week stepping + from start to end of one week. That's strictly what non-wrapping + behavior must surely mean, when put in locale-neutral terms. + + It is, however, likely that users would prefer the "more natural" + behavior of cycling through the week. + */ + const int first = int(locale().firstDayOfWeek()); // Mon = 1 through 7 = Sun + val = qBound(val < first ? first - 7 : first, + val + steps, + val < first ? first - 1 : first + 6); + } else +#endif + { + val += steps; + } + + // Restore to range from 1 through 7: + val = val % 7; + if (val <= 0) + val += 7; + } else { + val += steps; + const int span = max - min + 1; + if (val < min) + val = wrapping ? val + span : min; + else if (val > max) + val = wrapping ? val - span : max; } const int oldDay = v.date().day(calendar); - setDigit(v, sectionIndex, val); /* - Stepping into a daylight saving time that doesn't exist, - so use the time that has the same distance from epoch. + Stepping into a daylight saving time that doesn't exist (setDigit() is + true when date and time are valid, even if the date-time returned + isn't), so use the time that has the same distance from epoch. */ - if (!v.isValid()) { - auto msecsSinceEpoch = v.toMSecsSinceEpoch(); + if (setDigit(v, sectionIndex, val) && getDigit(v, sectionIndex) != val + && sn.type & HourSectionMask && steps < 0) { // decreasing from e.g 3am to 2am would get us back to 3am, but we want 1am - if (steps < 0 && sn.type & HourSectionMask) - msecsSinceEpoch -= 3600 * 1000; - v = QDateTime::fromMSecsSinceEpoch(msecsSinceEpoch, v.timeSpec()); + auto msecsSinceEpoch = v.toMSecsSinceEpoch() - 3600 * 1000; + v = QDateTime::fromMSecsSinceEpoch(msecsSinceEpoch, v.timeRepresentation()); } // if this sets year or month it will make // sure that days are lowered if needed. @@ -2144,7 +2189,8 @@ QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) c 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)) { + if (sn.type != AmPmSection && !(sn.type & DayOfWeekSectionMask) + && (v < minimumDateTime || v > maximumDateTime)) { const int localmin = getDigit(minimumDateTime, sectionIndex); const int localmax = getDigit(maximumDateTime, sectionIndex); @@ -2231,8 +2277,7 @@ QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) c } } - const QDateTime ret = bound(v, value, steps).toDateTime().toTimeSpec(spec); - return ret; + return bound(v, value, steps).toDateTime().toTimeZone(timeZone); } /*! @@ -2268,7 +2313,7 @@ void QDateTimeEditPrivate::emitSignals(EmitPolicy ep, const QVariant &old) \internal */ -void QDateTimeEditPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos) +void QDateTimeEditPrivate::editorCursorPositionChanged(int oldpos, int newpos) { if (ignoreCursorPositionChanged || specialValue()) return; @@ -2326,7 +2371,7 @@ void QDateTimeEditPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos currentSectionIndex = s; Q_ASSERT_X(currentSectionIndex < sectionNodes.size(), - "QDateTimeEditPrivate::_q_editorCursorPositionChanged()", + "QDateTimeEditPrivate::editorCursorPositionChanged()", qPrintable(QString::fromLatin1("Internal error (%1 %2)"). arg(currentSectionIndex). arg(sectionNodes.size()))); @@ -2419,8 +2464,8 @@ void QDateTimeEdit::paintEvent(QPaintEvent *event) optCombo.state &= ~QStyle::State_Enabled; } - QPainter p(this); - style()->drawComplexControl(QStyle::CC_ComboBox, &optCombo, &p, this); + QStylePainter p(this); + p.drawComplexControl(QStyle::CC_ComboBox, optCombo); } int QDateTimeEditPrivate::absoluteIndex(QDateTimeEdit::Section s, int index) const @@ -2433,7 +2478,7 @@ int QDateTimeEditPrivate::absoluteIndex(QDateTimeEdit::Section s, int index) con return NoSectionIndex; } -int QDateTimeEditPrivate::absoluteIndex(const SectionNode &s) const +int QDateTimeEditPrivate::absoluteIndex(SectionNode s) const { return sectionNodes.indexOf(s); } @@ -2450,7 +2495,7 @@ void QDateTimeEditPrivate::interpret(EmitPolicy ep) || currentSectionIndex < 0 || !(fieldInfo(currentSectionIndex) & AllowPartial))) { setValue(value, ep); - updateTimeSpec(); + updateTimeZone(); } else { QAbstractSpinBoxPrivate::interpret(ep); } @@ -2491,25 +2536,25 @@ void QDateTimeEditPrivate::init(const QVariant &var) Q_Q(QDateTimeEdit); switch (var.userType()) { case QMetaType::QDate: - value = var.toDate().startOfDay(); - updateTimeSpec(); + value = var.toDate().startOfDay(timeZone); + updateTimeZone(); q->setDisplayFormat(defaultDateFormat); if (sectionNodes.isEmpty()) // ### safeguard for broken locale - q->setDisplayFormat(QLatin1String("dd/MM/yyyy")); + q->setDisplayFormat("dd/MM/yyyy"_L1); break; case QMetaType::QDateTime: value = var; - updateTimeSpec(); + updateTimeZone(); q->setDisplayFormat(defaultDateTimeFormat); if (sectionNodes.isEmpty()) // ### safeguard for broken locale - q->setDisplayFormat(QLatin1String("dd/MM/yyyy hh:mm:ss")); + q->setDisplayFormat("dd/MM/yyyy hh:mm:ss"_L1); break; case QMetaType::QTime: - value = QDateTime(QDATETIMEEDIT_DATE_INITIAL, var.toTime()); - updateTimeSpec(); + value = dateTimeValue(QDATETIMEEDIT_DATE_INITIAL, var.toTime()); + updateTimeZone(); q->setDisplayFormat(defaultTimeFormat); if (sectionNodes.isEmpty()) // ### safeguard for broken locale - q->setDisplayFormat(QLatin1String("hh:mm:ss")); + q->setDisplayFormat("hh:mm:ss"_L1); break; default: Q_ASSERT_X(0, "QDateTimeEditPrivate::init", "Internal error"); @@ -2584,7 +2629,7 @@ void QDateTimeEditPrivate::updateEditFieldGeometry() QVariant QDateTimeEditPrivate::getZeroVariant() const { Q_ASSERT(type == QMetaType::QDateTime); - return QDateTime(QDATETIMEEDIT_DATE_INITIAL, QTime(), spec); + return QDATETIMEEDIT_DATE_INITIAL.startOfDay(timeZone); } void QDateTimeEditPrivate::setRange(const QVariant &min, const QVariant &max) @@ -2613,7 +2658,7 @@ void QDateTimeEditPrivate::initCalendarPopup(QCalendarWidget *cw) Q_Q(QDateTimeEdit); if (!monthCalendar) { monthCalendar = new QCalendarPopup(q, cw, calendar); - monthCalendar->setObjectName(QLatin1String("qt_datetimedit_calendar")); + monthCalendar->setObjectName("qt_datetimedit_calendar"_L1); 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))); |