Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[nemo-qml-plugin-calendar] Add timezone bindings for events. Contribu…
…tes to TJC#81380
  • Loading branch information
dcaliste committed Aug 25, 2020
1 parent 884f815 commit 4391e71
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 18 deletions.
48 changes: 46 additions & 2 deletions src/calendarevent.cpp
Expand Up @@ -64,12 +64,56 @@ QString CalendarEvent::description() const

QDateTime CalendarEvent::startTime() const
{
return mManager->getEvent(mUniqueId, mRecurrenceId).startTime.dateTime();
// Cannot use KDateTime::dateTime() here because it is handling UTC
// spec in a different manner than other specs. If UTC, the QDateTime
// will be in UTC also and the UI will convert it to local when displaying
// the time, while in every other case, it set the QDateTime in
// local zone.
const KDateTime kdt = mManager->getEvent(mUniqueId, mRecurrenceId).startTime;
return QDateTime(kdt.date(), kdt.time());
}

QDateTime CalendarEvent::endTime() const
{
return mManager->getEvent(mUniqueId, mRecurrenceId).endTime.dateTime();
const KDateTime kdt = mManager->getEvent(mUniqueId, mRecurrenceId).endTime;
return QDateTime(kdt.date(), kdt.time());
}

static CalendarEvent::TimeSpec toTimeSpec(const KDateTime &dt)
{
switch (dt.timeType()) {
case (KDateTime::ClockTime):
return CalendarEvent::SpecClockTime;
case (KDateTime::LocalZone):
return CalendarEvent::SpecLocalZone;
case (KDateTime::TimeZone):
return CalendarEvent::SpecTimeZone;
case (KDateTime::UTC):
return CalendarEvent::SpecUtc;
default:
// Ignore other time types.
return CalendarEvent::SpecLocalZone;
}
}

CalendarEvent::TimeSpec CalendarEvent::startTimeSpec() const
{
return toTimeSpec(mManager->getEvent(mUniqueId, mRecurrenceId).startTime);
}

CalendarEvent::TimeSpec CalendarEvent::endTimeSpec() const
{
return toTimeSpec(mManager->getEvent(mUniqueId, mRecurrenceId).endTime);
}

QString CalendarEvent::startTimeZone() const
{
return mManager->getEvent(mUniqueId, mRecurrenceId).startTime.timeZone().name();
}

QString CalendarEvent::endTimeZone() const
{
return mManager->getEvent(mUniqueId, mRecurrenceId).endTime.timeZone().name();
}

bool CalendarEvent::allDay() const
Expand Down
14 changes: 12 additions & 2 deletions src/calendarevent.h
Expand Up @@ -44,14 +44,17 @@ class CalendarEvent : public QObject
{
Q_OBJECT
Q_ENUMS(Reminder)
Q_ENUMS(TimeSpec)
Q_ENUMS(Secrecy)
Q_ENUMS(Response)

Q_PROPERTY(QString displayLabel READ displayLabel NOTIFY displayLabelChanged)
Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
Q_PROPERTY(QDateTime startTime READ startTime NOTIFY startTimeChanged)
Q_PROPERTY(QDateTime endTime READ endTime NOTIFY endTimeChanged)
Q_PROPERTY(CalendarEvent::TimeSpec startTimeSpec READ startTimeSpec NOTIFY startTimeChanged)
Q_PROPERTY(CalendarEvent::TimeSpec endTimeSpec READ endTimeSpec NOTIFY endTimeChanged)
Q_PROPERTY(QString startTimeZone READ startTimeZone NOTIFY startTimeChanged)
Q_PROPERTY(QString endTimeZone READ endTimeZone NOTIFY endTimeChanged)
Q_PROPERTY(bool allDay READ allDay NOTIFY allDayChanged)
Q_PROPERTY(CalendarEvent::Recur recur READ recur NOTIFY recurChanged)
Q_PROPERTY(QDateTime recurEndDate READ recurEndDate NOTIFY recurEndDateChanged)
Expand Down Expand Up @@ -99,8 +102,11 @@ class CalendarEvent : public QObject

enum TimeSpec {
SpecLocalZone,
SpecClockTime
SpecClockTime,
SpecTimeZone,
SpecUtc
};
Q_ENUM(TimeSpec)

enum Secrecy {
SecrecyPublic,
Expand All @@ -122,6 +128,10 @@ class CalendarEvent : public QObject
QString description() const;
QDateTime startTime() const;
QDateTime endTime() const;
TimeSpec startTimeSpec() const;
TimeSpec endTimeSpec() const;
QString startTimeZone() const;
QString endTimeZone() const;
bool allDay() const;
Recur recur() const;
QDateTime recurEndDate() const;
Expand Down
33 changes: 21 additions & 12 deletions src/calendareventmodification.cpp
@@ -1,5 +1,6 @@
#include "calendareventmodification.h"
#include "calendarmanager.h"
#include <ksystemtimezone.h>

#include <QDebug>

Expand Down Expand Up @@ -54,14 +55,27 @@ QDateTime CalendarEventModification::startTime() const
return m_event.startTime.dateTime();
}

void CalendarEventModification::setStartTime(const QDateTime &startTime, int spec)
static KDateTime toKDateTime(const QDateTime &dt, int spec, const QString &timezone)
{
KDateTime::SpecType kSpec = KDateTime::LocalZone;
if (spec == CalendarEvent::SpecClockTime) {
kSpec = KDateTime::ClockTime;
if (spec == CalendarEvent::SpecTimeZone) {
KTimeZone tz = KSystemTimeZones::zone(timezone);
if (tz.isValid()) {
return KDateTime(dt, tz);
} else {
qWarning() << "Invalid zone name, falling back to local zone:" << timezone;
return KDateTime(dt, KDateTime::LocalZone);
}
} else if (spec == CalendarEvent::SpecClockTime) {
return KDateTime(dt, KDateTime::ClockTime);
} else if (spec == CalendarEvent::SpecUtc) {
return KDateTime(QDateTime(dt.date(), dt.time(), Qt::UTC));
}
return KDateTime(dt, KDateTime::LocalZone);
}

KDateTime time(startTime, kSpec);
void CalendarEventModification::setStartTime(const QDateTime &startTime, int spec, const QString &timezone)
{
const KDateTime time = toKDateTime(startTime, spec, timezone);
if (m_event.startTime != time) {
m_event.startTime = time;
emit startTimeChanged();
Expand All @@ -73,14 +87,9 @@ QDateTime CalendarEventModification::endTime() const
return m_event.endTime.dateTime();
}

void CalendarEventModification::setEndTime(const QDateTime &endTime, int spec)
void CalendarEventModification::setEndTime(const QDateTime &endTime, int spec, const QString &timezone)
{
KDateTime::SpecType kSpec = KDateTime::LocalZone;
if (spec == CalendarEvent::SpecClockTime) {
kSpec = KDateTime::ClockTime;
}
KDateTime time(endTime, kSpec);

const KDateTime time = toKDateTime(endTime, spec, timezone);
if (m_event.endTime != time) {
m_event.endTime = time;
emit endTimeChanged();
Expand Down
4 changes: 2 additions & 2 deletions src/calendareventmodification.h
Expand Up @@ -38,10 +38,10 @@ class CalendarEventModification : public QObject
void setDescription(const QString &description);

QDateTime startTime() const;
Q_INVOKABLE void setStartTime(const QDateTime &startTime, int spec);
Q_INVOKABLE void setStartTime(const QDateTime &startTime, int spec, const QString &timezone = QString());

QDateTime endTime() const;
Q_INVOKABLE void setEndTime(const QDateTime &endTime, int spec);
Q_INVOKABLE void setEndTime(const QDateTime &endTime, int spec, const QString &timezone = QString());

bool allDay() const;
void setAllDay(bool);
Expand Down
83 changes: 83 additions & 0 deletions tests/tst_calendarevent/tst_calendarevent.cpp
Expand Up @@ -24,6 +24,8 @@ private slots:

void modSetters();
void testSave();
void testTimeZone_data();
void testTimeZone();
void testRecurrenceException();
void testDate_data();
void testDate();
Expand Down Expand Up @@ -182,6 +184,13 @@ void tst_CalendarEvent::testSave()
QCOMPARE(eventB->endTime().toTime_t(), endTime.toTime_t());
QCOMPARE(eventB->startTime().toTime_t(), startTime.toTime_t());

QCOMPARE(eventB->endTime().timeSpec(), Qt::LocalTime);
QCOMPARE(eventB->startTime().timeSpec(), Qt::LocalTime);
QCOMPARE(eventB->endTimeSpec(), CalendarEvent::SpecTimeZone);
QCOMPARE(eventB->startTimeSpec(), CalendarEvent::SpecTimeZone);
QCOMPARE(eventB->endTimeZone().toUtf8(), endTime.timeZone().id());
QCOMPARE(eventB->startTimeZone().toUtf8(), startTime.timeZone().id());

QCOMPARE(eventB->allDay(), allDay);
QCOMPARE(eventB->description(), description);
QCOMPARE(eventB->displayLabel(), displayLabel);
Expand All @@ -196,6 +205,80 @@ void tst_CalendarEvent::testSave()
delete eventMod;
}

void tst_CalendarEvent::testTimeZone_data()
{
QTest::addColumn<CalendarEvent::TimeSpec>("spec");

QTest::newRow("clock time") << CalendarEvent::SpecClockTime;
QTest::newRow("local zone") << CalendarEvent::SpecLocalZone;
QTest::newRow("UTC") << CalendarEvent::SpecUtc;
QTest::newRow("time zone") << CalendarEvent::SpecTimeZone;
}

void tst_CalendarEvent::testTimeZone()
{
QFETCH(CalendarEvent::TimeSpec, spec);

CalendarEventModification *eventMod = calendarApi->createNewEvent();
QVERIFY(eventMod != 0);

QDateTime startTime = QDateTime(QDate(2020, 4, 8), QTime(16, 50));
if (spec == CalendarEvent::SpecTimeZone) {
// Using the system time zone, because agendamodels are looking for
// events in the same day in the system time zone.
eventMod->setStartTime(startTime, spec, QDateTime::currentDateTime().timeZone().id());
} else {
eventMod->setStartTime(startTime, spec);
}
QDateTime endTime = startTime.addSecs(3600);
if (spec == CalendarEvent::SpecTimeZone) {
eventMod->setEndTime(endTime, spec, QDateTime::currentDateTime().timeZone().id());
} else {
eventMod->setEndTime(endTime, spec);
}

QString uid;
bool ok = saveEvent(eventMod, &uid);
if (!ok) {
QFAIL("Failed to fetch new event uid");
}
QVERIFY(!uid.isEmpty());
mSavedEvents.insert(uid);

CalendarEventQuery query;
query.setUniqueId(uid);

for (int i = 0; i < 30; i++) {
if (query.event())
break;

QTest::qWait(100);
}
CalendarEvent *eventB = (CalendarEvent*) query.event();
QVERIFY(eventB != 0);

QCOMPARE(eventB->endTime(), endTime);
QCOMPARE(eventB->startTime(), startTime);

QCOMPARE(eventB->endTime().timeSpec(), Qt::LocalTime);
QCOMPARE(eventB->startTime().timeSpec(), Qt::LocalTime);
if (spec == CalendarEvent::SpecClockTime
|| spec == CalendarEvent::SpecUtc) {
QCOMPARE(eventB->endTimeSpec(), spec);
QCOMPARE(eventB->startTimeSpec(), spec);
} else {
QCOMPARE(eventB->endTimeSpec(), CalendarEvent::SpecTimeZone);
QCOMPARE(eventB->startTimeSpec(), CalendarEvent::SpecTimeZone);
QCOMPARE(eventB->endTimeZone().toUtf8(), endTime.timeZone().id());
QCOMPARE(eventB->startTimeZone().toUtf8(), startTime.timeZone().id());
}

calendarApi->remove(uid);
mSavedEvents.remove(uid);

delete eventMod;
}

void tst_CalendarEvent::testRecurrenceException()
{
CalendarEventModification *event = calendarApi->createNewEvent();
Expand Down

0 comments on commit 4391e71

Please sign in to comment.