summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleg Yadrov <oleg.yadrov@qt.io>2017-12-11 16:25:45 -0200
committerMitch Curtis <mitch.curtis@qt.io>2017-12-15 09:42:37 +0000
commit15c909f4170450cdbe01218a0d7cbea55b70fae5 (patch)
tree2d6488db691b6f006327510ae358f2e33b06c148
parent37592ad9c6df35bdd37609569963fe7361cdad85 (diff)
downloadqtquickcontrols-15c909f4170450cdbe01218a0d7cbea55b70fae5.tar.gz
Calendar: fix bug when NaN is displayed instead of date
I fixed a similar issue last year on the JavaScript side: 094ad30c94a72784449f43ef06d2172d644ab0fd At this time the same thing has been happening in C++. See QTBUG-54559 and the patch for a detailed explanation of the issue. In short, the problem with Calendar is that internally it uses QDate which does not keep information about time, whereas in the JavaScript world date is always combined with time. So, QDate(2017-10-15) is valid, but when during QDate -> JS Date transformation we add time to it (which defaults to midnight (00:00)), it becomes invalid in time zones where the Daylight Saving Time -> Standard Time transition takes place at midnight. To avoid switching the entire QQuickCalendarModel1 to using QDateTime, I modified its date(...) and dateAt(...) methods to return QDateTime with the time part always set to 12:00. That transformation required more changes in QQuickRangedDate1, because Calendar::selectedDate internally is QQuickRangedDate1::selectedDate, and I also had to fix "selected" property binding in the Base Calendar Style as it did take into account the time part of the date, which resulted in wrong behavior with my changes. Task-number: QTBUG-64068 Change-Id: Ia2f7703ff4e5811ef79438c97739da1d8001a7f5 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> Reviewed-by: J-P Nurmi <jpnurmi@qt.io>
-rw-r--r--src/controls/Private/qquickcalendarmodel.cpp8
-rw-r--r--src/controls/Private/qquickcalendarmodel_p.h2
-rw-r--r--src/controls/Private/qquickrangeddate.cpp12
-rw-r--r--src/controls/Private/qquickrangeddate_p.h24
-rw-r--r--src/controls/Styles/Base/CalendarStyle.qml4
-rw-r--r--tests/auto/controls/data/tst_calendar.qml29
-rw-r--r--tests/auto/controls/data/tst_rangeddate.qml5
7 files changed, 52 insertions, 32 deletions
diff --git a/src/controls/Private/qquickcalendarmodel.cpp b/src/controls/Private/qquickcalendarmodel.cpp
index 64d52f95..b2284c25 100644
--- a/src/controls/Private/qquickcalendarmodel.cpp
+++ b/src/controls/Private/qquickcalendarmodel.cpp
@@ -162,7 +162,7 @@ void QQuickCalendarModel1::setLocale(const QLocale &locale)
QVariant QQuickCalendarModel1::data(const QModelIndex &index, int role) const
{
if (role == DateRole)
- return mVisibleDates.at(index.row());
+ return QDateTime(mVisibleDates.at(index.row()), QTime(12, 0));
return QVariant();
}
@@ -181,9 +181,9 @@ QHash<int, QByteArray> QQuickCalendarModel1::roleNames() const
/*!
Returns the date at \a index, or an invalid date if \a index is invalid.
*/
-QDate QQuickCalendarModel1::dateAt(int index) const
+QDateTime QQuickCalendarModel1::dateAt(int index) const
{
- return index >= 0 && index < mVisibleDates.size() ? mVisibleDates.at(index) : QDate();
+ return index >= 0 && index < mVisibleDates.size() ? QDateTime(mVisibleDates.at(index), QTime(12, 0)) : QDateTime();
}
/*!
@@ -207,7 +207,7 @@ int QQuickCalendarModel1::indexAt(const QDate &date)
int QQuickCalendarModel1::weekNumberAt(int row) const
{
const int index = row * daysInAWeek;
- const QDate date = dateAt(index);
+ const QDate date = dateAt(index).date();
if (date.isValid())
return date.weekNumber();
return -1;
diff --git a/src/controls/Private/qquickcalendarmodel_p.h b/src/controls/Private/qquickcalendarmodel_p.h
index cb47c576..99ae9423 100644
--- a/src/controls/Private/qquickcalendarmodel_p.h
+++ b/src/controls/Private/qquickcalendarmodel_p.h
@@ -75,7 +75,7 @@ public:
QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
- Q_INVOKABLE QDate dateAt(int index) const;
+ Q_INVOKABLE QDateTime dateAt(int index) const;
Q_INVOKABLE int indexAt(const QDate &visibleDate);
Q_INVOKABLE int weekNumberAt(int row) const;
diff --git a/src/controls/Private/qquickrangeddate.cpp b/src/controls/Private/qquickrangeddate.cpp
index 231a798a..df7958ac 100644
--- a/src/controls/Private/qquickrangeddate.cpp
+++ b/src/controls/Private/qquickrangeddate.cpp
@@ -42,12 +42,12 @@
QT_BEGIN_NAMESPACE
// JavaScript Date > QDate conversion is not correct for large negative dates.
-Q_GLOBAL_STATIC_WITH_ARGS(const QDate, jsMinimumDate, (QDate(1, 1, 1)))
-Q_GLOBAL_STATIC_WITH_ARGS(const QDate, jsMaximumDate, (QDate(275759, 10, 25)))
+Q_GLOBAL_STATIC_WITH_ARGS(const QDateTime, jsMinimumDate, (QDateTime(QDate(1, 1, 1), QTime())))
+Q_GLOBAL_STATIC_WITH_ARGS(const QDateTime, jsMaximumDate, (QDateTime(QDate(275759, 10, 25), QTime())))
QQuickRangedDate1::QQuickRangedDate1() :
QObject(0),
- mDate(QDate::currentDate()),
+ mDate(QDateTime::currentDateTime()),
mMinimumDate(*jsMinimumDate),
mMaximumDate(*jsMaximumDate)
{
@@ -56,7 +56,7 @@ QQuickRangedDate1::QQuickRangedDate1() :
/*! \internal
\qmlproperty date QQuickRangedDate::date
*/
-void QQuickRangedDate1::setDate(const QDate &date)
+void QQuickRangedDate1::setDate(const QDateTime &date)
{
if (date == mDate)
return;
@@ -75,7 +75,7 @@ void QQuickRangedDate1::setDate(const QDate &date)
/*! \internal
\qmlproperty date QQuickRangedDate::minimumDate
*/
-void QQuickRangedDate1::setMinimumDate(const QDate &minimumDate)
+void QQuickRangedDate1::setMinimumDate(const QDateTime &minimumDate)
{
if (minimumDate == mMinimumDate)
return;
@@ -93,7 +93,7 @@ void QQuickRangedDate1::setMinimumDate(const QDate &minimumDate)
/*! \internal
\qmlproperty date QQuickRangedDate::maximumDate
*/
-void QQuickRangedDate1::setMaximumDate(const QDate &maximumDate)
+void QQuickRangedDate1::setMaximumDate(const QDateTime &maximumDate)
{
if (maximumDate == mMaximumDate)
return;
diff --git a/src/controls/Private/qquickrangeddate_p.h b/src/controls/Private/qquickrangeddate_p.h
index 6ac7bc12..836daa4c 100644
--- a/src/controls/Private/qquickrangeddate_p.h
+++ b/src/controls/Private/qquickrangeddate_p.h
@@ -49,23 +49,23 @@ QT_BEGIN_NAMESPACE
class QQuickRangedDate1 : public QObject
{
Q_OBJECT
- Q_PROPERTY(QDate date READ date WRITE setDate NOTIFY dateChanged RESET resetDate)
- Q_PROPERTY(QDate minimumDate READ minimumDate WRITE setMinimumDate NOTIFY minimumDateChanged RESET resetMinimumDate)
- Q_PROPERTY(QDate maximumDate READ maximumDate WRITE setMaximumDate NOTIFY maximumDateChanged RESET resetMaximumDate)
+ Q_PROPERTY(QDateTime date READ date WRITE setDate NOTIFY dateChanged RESET resetDate)
+ Q_PROPERTY(QDateTime minimumDate READ minimumDate WRITE setMinimumDate NOTIFY minimumDateChanged RESET resetMinimumDate)
+ Q_PROPERTY(QDateTime maximumDate READ maximumDate WRITE setMaximumDate NOTIFY maximumDateChanged RESET resetMaximumDate)
public:
QQuickRangedDate1();
~QQuickRangedDate1() {}
- QDate date() const { return mDate; }
- void setDate(const QDate &date);
+ QDateTime date() const { return mDate; }
+ void setDate(const QDateTime &date);
void resetDate() {}
- QDate minimumDate() const { return mMinimumDate; }
- void setMinimumDate(const QDate &minimumDate);
+ QDateTime minimumDate() const { return mMinimumDate; }
+ void setMinimumDate(const QDateTime &minimumDate);
void resetMinimumDate() {}
- QDate maximumDate() const { return mMaximumDate; }
- void setMaximumDate(const QDate &maximumDate);
+ QDateTime maximumDate() const { return mMaximumDate; }
+ void setMaximumDate(const QDateTime &maximumDate);
void resetMaximumDate() {}
Q_SIGNALS:
@@ -74,9 +74,9 @@ Q_SIGNALS:
void maximumDateChanged();
private:
- QDate mDate;
- QDate mMinimumDate;
- QDate mMaximumDate;
+ QDateTime mDate;
+ QDateTime mMinimumDate;
+ QDateTime mMaximumDate;
};
QT_END_NAMESPACE
diff --git a/src/controls/Styles/Base/CalendarStyle.qml b/src/controls/Styles/Base/CalendarStyle.qml
index 862c5f43..5999dcac 100644
--- a/src/controls/Styles/Base/CalendarStyle.qml
+++ b/src/controls/Styles/Base/CalendarStyle.qml
@@ -671,7 +671,9 @@ Style {
property QtObject styleData: QtObject {
readonly property alias index: delegateLoader.__index
- readonly property bool selected: control.selectedDate.getTime() === date.getTime()
+ readonly property bool selected: control.selectedDate.getFullYear() === date.getFullYear() &&
+ control.selectedDate.getMonth() === date.getMonth() &&
+ control.selectedDate.getDate() === date.getDate()
readonly property alias date: delegateLoader.__date
readonly property bool valid: delegateLoader.valid
// TODO: this will not be correct if the app is running when a new day begins.
diff --git a/tests/auto/controls/data/tst_calendar.qml b/tests/auto/controls/data/tst_calendar.qml
index 1185aca9..d47f62ba 100644
--- a/tests/auto/controls/data/tst_calendar.qml
+++ b/tests/auto/controls/data/tst_calendar.qml
@@ -129,7 +129,10 @@ Item {
compare(calendar.minimumDate, new Date(1, 0, 1));
compare(calendar.maximumDate, new Date(4000, 0, 1));
- compare(calendar.selectedDate, new Date(new Date().setHours(0, 0, 0, 0)));
+ var expectedDate = new Date();
+ compare(calendar.selectedDate.getFullYear(), expectedDate.getFullYear());
+ compare(calendar.selectedDate.getMonth(), expectedDate.getMonth());
+ compare(calendar.selectedDate.getDate(), expectedDate.getDate());
compare(calendar.frameVisible, true);
compare(calendar.dayOfWeekFormat, Locale.ShortFormat);
compare(calendar.__locale, Qt.locale());
@@ -406,7 +409,9 @@ Item {
expectedDate.setDate(expectedDate.getDate() + cellIndex);
mousePress(calendar, toPixelsX(day), toPixelsY(week), Qt.LeftButton);
- compare(calendar.selectedDate, expectedDate);
+ compare(calendar.selectedDate.getFullYear(), expectedDate.getFullYear());
+ compare(calendar.selectedDate.getMonth(), expectedDate.getMonth());
+ compare(calendar.selectedDate.getDate(), expectedDate.getDate());
compare(calendar.__panel.pressedCellIndex, cellIndex);
compare(pressedSignalSpy.count, 1);
compare(releasedSignalSpy.count, 0);
@@ -434,7 +439,9 @@ Item {
// Ensure released event does not trigger date selection.
calendar.selectedDate = startDate;
mousePress(calendar, toPixelsX(1), toPixelsY(0), Qt.LeftButton);
- compare(calendar.selectedDate, new Date(2012, 11, 31));
+ compare(calendar.selectedDate.getFullYear(), 2012);
+ compare(calendar.selectedDate.getMonth(), 11);
+ compare(calendar.selectedDate.getDate(), 31);
compare(calendar.__panel.pressedCellIndex, 1);
compare(pressedSignalSpy.count, 1);
compare(releasedSignalSpy.count, 0);
@@ -445,7 +452,9 @@ Item {
clickedSignalSpy.clear();
mouseRelease(calendar, toPixelsX(1), toPixelsY(0), Qt.LeftButton);
- compare(calendar.selectedDate, new Date(2012, 11, 31));
+ compare(calendar.selectedDate.getFullYear(), 2012);
+ compare(calendar.selectedDate.getMonth(), 11);
+ compare(calendar.selectedDate.getDate(), 31);
compare(calendar.__panel.pressedCellIndex, -1);
compare(pressedSignalSpy.count, 0);
compare(releasedSignalSpy.count, 1);
@@ -534,7 +543,9 @@ Item {
calendar.__locale = Qt.locale("en_GB");
calendar.selectedDate = new Date(2014, 11, 1);
mousePress(calendar, toPixelsX(0), toPixelsY(0), Qt.LeftButton);
- compare(calendar.selectedDate, new Date(2014, 10, 24));
+ compare(calendar.selectedDate.getFullYear(), 2014);
+ compare(calendar.selectedDate.getMonth(), 10);
+ compare(calendar.selectedDate.getDate(), 24);
mouseRelease(calendar, toPixelsX(0), toPixelsY(0), Qt.LeftButton);
}
@@ -585,7 +596,9 @@ Item {
function dragTo(cellX, cellY, expectedCellIndex, expectedDate) {
mouseMove(calendar, toPixelsX(cellX), toPixelsY(cellY));
- compare(calendar.selectedDate, expectedDate);
+ compare(calendar.selectedDate.getFullYear(), expectedDate.getFullYear());
+ compare(calendar.selectedDate.getMonth(), expectedDate.getMonth());
+ compare(calendar.selectedDate.getDate(), expectedDate.getDate());
compare(calendar.__panel.pressedCellIndex, expectedCellIndex);
compare(hoveredSignalSpy.count, 1);
compare(pressedSignalSpy.count, 1);
@@ -627,7 +640,9 @@ Item {
3 4 5 6 7 8 9 3 4 5 6 7 8 9 */
mousePress(calendar, toPixelsX(5), toPixelsY(0), Qt.LeftButton);
- compare(calendar.selectedDate, new Date(2014, 1, 1));
+ compare(calendar.selectedDate.getFullYear(), 2014);
+ compare(calendar.selectedDate.getMonth(), 1);
+ compare(calendar.selectedDate.getDate(), 1);
compare(calendar.__panel.pressedCellIndex, 5);
compare(pressedSignalSpy.count, 1);
compare(releasedSignalSpy.count, 0);
diff --git a/tests/auto/controls/data/tst_rangeddate.qml b/tests/auto/controls/data/tst_rangeddate.qml
index cad94eb4..a1874441 100644
--- a/tests/auto/controls/data/tst_rangeddate.qml
+++ b/tests/auto/controls/data/tst_rangeddate.qml
@@ -69,7 +69,10 @@ Item {
function test_defaultConstruction() {
// rangedDate.date should be the current date.
- compare(rangedDate.date.getTime(), new Date(Date.now()).setHours(0, 0, 0, 0));
+ var expectedDate = new Date();
+ compare(rangedDate.date.getFullYear(), expectedDate.getFullYear());
+ compare(rangedDate.date.getMonth(), expectedDate.getMonth());
+ compare(rangedDate.date.getDate(), expectedDate.getDate());
}
function test_minMax() {