diff options
Diffstat (limited to 'src/widgets/widgets/qdatetimeedit.cpp')
-rw-r--r-- | src/widgets/widgets/qdatetimeedit.cpp | 272 |
1 files changed, 164 insertions, 108 deletions
diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp index 5e61a87fd7..a9b5babde5 100644 --- a/src/widgets/widgets/qdatetimeedit.cpp +++ b/src/widgets/widgets/qdatetimeedit.cpp @@ -16,9 +16,6 @@ #include <qset.h> #include <qstyle.h> #include <qstylepainter.h> -#if QT_CONFIG(timezone) -#include <QTimeZone> -#endif #include <algorithm> @@ -190,8 +187,8 @@ QDateTimeEdit::QDateTimeEdit(QTime time, QWidget *parent) \internal */ QDateTimeEdit::QDateTimeEdit(const QVariant &var, QMetaType::Type parserType, QWidget *parent) - : QAbstractSpinBox(*new QDateTimeEditPrivate( - parserType == QMetaType::QDateTime ? Qt::LocalTime : Qt::UTC), + : QAbstractSpinBox(*new QDateTimeEditPrivate(parserType == QMetaType::QDateTime + ? QTimeZone::LocalTime : QTimeZone::UTC), parent) { Q_D(QDateTimeEdit); @@ -210,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 @@ -222,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 @@ -235,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(); @@ -272,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(); } } @@ -306,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 { @@ -317,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); @@ -363,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)); } @@ -405,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); } @@ -439,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); } @@ -475,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() @@ -517,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() @@ -554,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() @@ -593,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() @@ -634,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())); } } @@ -673,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)); } } @@ -957,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); } } @@ -996,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(); } } @@ -1297,6 +1347,7 @@ void QDateTimeEdit::focusInEvent(QFocusEvent *event) case Qt::ActiveWindowFocusReason: if (oldHasHadFocus) return; + break; case Qt::ShortcutFocusReason: case Qt::TabFocusReason: default: @@ -1389,7 +1440,7 @@ void QDateTimeEdit::stepBy(int steps) d->updateCache(d->value, d->displayText()); d->setSelected(d->currentSectionIndex); - d->updateTimeSpec(); + d->updateTimeZone(); } /*! @@ -1448,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); - } } @@ -1597,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); } @@ -1667,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); } @@ -1703,54 +1750,42 @@ QDateEdit::~QDateEdit() */ -QDateTimeEditPrivate::QDateTimeEditPrivate(Qt::TimeSpec timeSpec) +QDateTimeEditPrivate::QDateTimeEditPrivate(const QTimeZone &zone) : QDateTimeParser(QMetaType::QDateTime, QDateTimeParser::DateTimeEdit, QCalendar()), - spec(timeSpec) + timeZone(zone) { fixday = true; type = QMetaType::QDateTime; currentSectionIndex = FirstSectionIndex; first.pos = 0; - minimum = QDATETIMEEDIT_COMPAT_DATE_MIN.startOfDay(spec); - maximum = QDATETIMEEDIT_DATE_MAX.endOfDay(spec); + minimum = QDATETIMEEDIT_COMPAT_DATE_MIN.startOfDay(timeZone); + maximum = QDATETIMEEDIT_DATE_MAX.endOfDay(timeZone); readLocaleSettings(); } -QDateTime QDateTimeEditPrivate::convertTimeSpec(const QDateTime &datetime) +QDateTime QDateTimeEditPrivate::convertTimeZone(const QDateTime &datetime) { - 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 datetime.toTimeZone(timeZone); } -// FIXME: architecturaly incompatible with OffsetFromUTC or TimeZone as spec (QTBUG-80417). -void QDateTimeEditPrivate::updateTimeSpec() +QDateTime QDateTimeEditPrivate::dateTimeValue(QDate date, QTime time) const { - minimum = minimum.toDateTime().toTimeSpec(spec); - maximum = maximum.toDateTime().toTimeSpec(spec); - value = value.toDateTime().toTimeSpec(spec); + return QDateTime(date, time, timeZone); +} + +void QDateTimeEditPrivate::updateTimeZone() +{ + 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); } } } @@ -1785,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 @@ -1830,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); } @@ -1997,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; @@ -2044,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); } @@ -2114,17 +2172,16 @@ QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) c 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. @@ -2220,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); } /*! @@ -2257,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; @@ -2315,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()))); @@ -2422,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); } @@ -2439,7 +2495,7 @@ void QDateTimeEditPrivate::interpret(EmitPolicy ep) || currentSectionIndex < 0 || !(fieldInfo(currentSectionIndex) & AllowPartial))) { setValue(value, ep); - updateTimeSpec(); + updateTimeZone(); } else { QAbstractSpinBoxPrivate::interpret(ep); } @@ -2480,22 +2536,22 @@ 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("dd/MM/yyyy"_L1); break; case QMetaType::QDateTime: value = var; - updateTimeSpec(); + updateTimeZone(); q->setDisplayFormat(defaultDateTimeFormat); if (sectionNodes.isEmpty()) // ### safeguard for broken locale 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("hh:mm:ss"_L1); @@ -2573,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) |