summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Wu Won <kevin.wu-won@nokia.com>2010-08-27 10:31:56 +1000
committerKevin Wu Won <kevin.wu-won@nokia.com>2010-08-27 11:11:44 +1000
commit0276c2a8836026fc0bff763f6f08281fac2997d1 (patch)
tree49531ca7b9e77f2be3bcee65410afd27e916fdb3
parenta5cf107614bafb50e29234ae11051707d2014e5a (diff)
Add support for VTIMEZONE in QVersitOrganizerImporter
Added auto tests for it Added extra value to enum QOrganizerItemRecurrenceRule::Frequency = Invalid
-rw-r--r--src/organizer/engines/qorganizeritemmemorybackend.cpp59
-rw-r--r--src/organizer/qorganizeritemrecurrencerule.cpp5
-rw-r--r--src/organizer/qorganizeritemrecurrencerule.h1
-rw-r--r--src/versitorganizer/qversitorganizerimporter.cpp7
-rw-r--r--src/versitorganizer/qversitorganizerimporter_p.cpp73
-rw-r--r--src/versitorganizer/qversitorganizerimporter_p.h17
-rw-r--r--src/versitorganizer/timezones_p.cpp85
-rw-r--r--src/versitorganizer/timezones_p.h116
-rw-r--r--src/versitorganizer/versitorganizer.pro6
-rw-r--r--tests/auto/qversitorganizerimporter/tst_qversitorganizerimporter.cpp156
-rw-r--r--tests/auto/qversitorganizerimporter/tst_qversitorganizerimporter.h3
11 files changed, 481 insertions, 47 deletions
diff --git a/src/organizer/engines/qorganizeritemmemorybackend.cpp b/src/organizer/engines/qorganizeritemmemorybackend.cpp
index 10587bcc92..5332943bb3 100644
--- a/src/organizer/engines/qorganizeritemmemorybackend.cpp
+++ b/src/organizer/engines/qorganizeritemmemorybackend.cpp
@@ -200,11 +200,6 @@ QList<QDateTime> QOrganizerItemMemoryEngine::generateDateTimes(const QDateTime&
maxCount = qMin(maxCount, rrule.count());
QDateTime realPeriodEnd(periodEnd);
- if (!periodEnd.isValid()) {
- // If no endDateTime is given, we'll only generate items that occur within the next 4 years of periodStart.
- realPeriodEnd.setDate(periodStart.date().addDays(1461));
- realPeriodEnd.setTime(periodStart.time());
- }
if (rrule.endDate().isValid() && rrule.endDate() < realPeriodEnd.date())
realPeriodEnd.setDate(rrule.endDate());
@@ -308,6 +303,8 @@ void QOrganizerItemMemoryEngine::inferMissingCriteria(QOrganizerItemRecurrenceRu
break;
case QOrganizerItemRecurrenceRule::Daily:
break;
+ case QOrganizerItemRecurrenceRule::Invalid:
+ Q_ASSERT(false);
}
}
@@ -348,7 +345,7 @@ bool QOrganizerItemMemoryEngine::inIntervaledPeriod(const QDate& date, const QDa
int daysDelta = initialDate.daysTo(date);
return (daysDelta % interval == 0);
}
- default:
+ case QOrganizerItemRecurrenceRule::Invalid:
Q_ASSERT(false);
return true;
}
@@ -410,7 +407,7 @@ QDate QOrganizerItemMemoryEngine::firstDateInNextPeriod(const QDate& date, QOrga
case QOrganizerItemRecurrenceRule::Daily:
retn = retn.addDays(1);
return retn;
- default:
+ case QOrganizerItemRecurrenceRule::Invalid:
Q_ASSERT(false);
return retn;
}
@@ -478,7 +475,28 @@ QList<QOrganizerItem> QOrganizerItemMemoryEngine::itemInstances(const QOrganizer
// Also, should this also return the exception instances (ie, return any persistent instances with parent information == generator?)
// XXX TODO: in detail validation, ensure that the referenced parent Id exists...
- if (periodStart > periodEnd) {
+ QDateTime realPeriodStart(periodStart);
+ QDateTime realPeriodEnd(periodEnd);
+ QDateTime initialDateTime;
+ if (generator.type() == QOrganizerItemType::TypeEvent) {
+ QOrganizerEvent evt = generator;
+ initialDateTime = evt.startDateTime();
+ } else if (generator.type() == QOrganizerItemType::TypeTodo) {
+ QOrganizerTodo todo = generator;
+ initialDateTime = todo.startDateTime();
+ } else {
+ // erm... not a recurring item in our schema...
+ return QList<QOrganizerItem>() << generator;
+ }
+
+ if (initialDateTime > realPeriodStart)
+ realPeriodStart = initialDateTime;
+ if (!periodEnd.isValid()) {
+ // If no endDateTime is given, we'll only generate items that occur within the next 4 years of realPeriodStart.
+ realPeriodEnd.setDate(realPeriodStart.date().addDays(1461));
+ realPeriodEnd.setTime(realPeriodStart.time());
+ }
+ if (realPeriodStart > realPeriodEnd) {
*error = QOrganizerItemManager::BadArgumentError;
return QList<QOrganizerItem>();
}
@@ -504,24 +522,12 @@ QList<QOrganizerItem> QOrganizerItemMemoryEngine::itemInstances(const QOrganizer
upperBound = instance.dueDateTime();
}
- if ((lowerBound.isNull() || lowerBound > periodStart) && (upperBound.isNull() || upperBound < periodEnd)) {
+ if ((lowerBound.isNull() || lowerBound > realPeriodStart) && (upperBound.isNull() || upperBound < realPeriodEnd)) {
// this occurrence fulfils the criteria.
retn.append(currException);
}
}
- QDateTime initialDateTime;
- if (generator.type() == QOrganizerItemType::TypeEvent) {
- QOrganizerEvent evt = generator;
- initialDateTime = evt.startDateTime();
- } else if (generator.type() == QOrganizerItemType::TypeTodo) {
- QOrganizerTodo todo = generator;
- initialDateTime = todo.startDateTime();
- } else {
- // erm... not a recurring item in our schema...
- return QList<QOrganizerItem>() << generator;
- }
-
// then, generate the required (unchanged) instances from the generator.
// before doing that, we have to find out all of the exception dates.
QList<QDate> xdates;
@@ -530,9 +536,10 @@ QList<QOrganizerItem> QOrganizerItemMemoryEngine::itemInstances(const QOrganizer
}
QList<QOrganizerItemRecurrenceRule> xrules = recur.exceptionRules();
foreach (const QOrganizerItemRecurrenceRule& xrule, xrules) {
- if ((xrule.endDate().isNull()) || (xrule.endDate() >= periodStart.date())) {
+ if (xrule.frequency() != QOrganizerItemRecurrenceRule::Invalid
+ && ((xrule.endDate().isNull()) || (xrule.endDate() >= realPeriodStart.date()))) {
// we cannot skip it, since it applies in the given time period.
- QList<QDateTime> xdatetimes = generateDateTimes(initialDateTime, xrule, periodStart, periodEnd, 50); // max count of 50 is arbitrary...
+ QList<QDateTime> xdatetimes = generateDateTimes(initialDateTime, xrule, realPeriodStart, realPeriodEnd, 50); // max count of 50 is arbitrary...
foreach (const QDateTime& xdatetime, xdatetimes) {
xdates += xdatetime.date();
}
@@ -541,14 +548,16 @@ QList<QOrganizerItem> QOrganizerItemMemoryEngine::itemInstances(const QOrganizer
// now generate a list of rdates (from the recurrenceDates and recurrenceRules)
QList<QDateTime> rdates;
+ rdates += initialDateTime;
foreach (const QDate& rdate, recur.recurrenceDates()) {
rdates += QDateTime(rdate, initialDateTime.time());
}
QList<QOrganizerItemRecurrenceRule> rrules = recur.recurrenceRules();
foreach (const QOrganizerItemRecurrenceRule& rrule, rrules) {
- if ((rrule.endDate().isNull()) || (rrule.endDate() >= periodStart.date())) {
+ if (rrule.frequency() != QOrganizerItemRecurrenceRule::Invalid
+ && ((rrule.endDate().isNull()) || (rrule.endDate() >= realPeriodStart.date()))) {
// we cannot skip it, since it applies in the given time period.
- rdates += generateDateTimes(initialDateTime, rrule, periodStart, periodEnd, 50); // max count of 50 is arbitrary...
+ rdates += generateDateTimes(initialDateTime, rrule, realPeriodStart, realPeriodEnd, 50); // max count of 50 is arbitrary...
}
}
diff --git a/src/organizer/qorganizeritemrecurrencerule.cpp b/src/organizer/qorganizeritemrecurrencerule.cpp
index 2dc9abf41c..ad156ef5a2 100644
--- a/src/organizer/qorganizeritemrecurrencerule.cpp
+++ b/src/organizer/qorganizeritemrecurrencerule.cpp
@@ -80,6 +80,7 @@ Q_DEFINE_LATIN1_CONSTANT(QOrganizerItemRecurrenceRule::FieldWeekStart, "WeekStar
/*!
* \enum QOrganizerItemRecurrenceRule::Frequency
+ * \value Invalid Signifies that the entire rrule is invalid.
* \value Daily
* \value Weekly
* \value Monthly
@@ -145,14 +146,14 @@ void QOrganizerItemRecurrenceRule::setFrequency(Frequency freq)
}
/*!
- * Returns the frequency with which the item recurs. The default frequency is 1.
+ * Returns the frequency with which the item recurs. The default frequency is Invalid.
*/
QOrganizerItemRecurrenceRule::Frequency QOrganizerItemRecurrenceRule::frequency() const
{
if (d->m_variantValues.contains(FieldFrequency))
return static_cast<Frequency>(d->m_variantValues.value(FieldFrequency).toInt());
else
- return Weekly;
+ return Invalid;
}
/*! Sets the "count" condition of the recurrence rule to \a count. If an end-date was previously
diff --git a/src/organizer/qorganizeritemrecurrencerule.h b/src/organizer/qorganizeritemrecurrencerule.h
index 700aa14942..32b94a04e8 100644
--- a/src/organizer/qorganizeritemrecurrencerule.h
+++ b/src/organizer/qorganizeritemrecurrencerule.h
@@ -134,6 +134,7 @@ public:
// enums
enum Frequency {
+ Invalid,
Daily,
Weekly,
Monthly,
diff --git a/src/versitorganizer/qversitorganizerimporter.cpp b/src/versitorganizer/qversitorganizerimporter.cpp
index 8984a6431f..6036cbb4c2 100644
--- a/src/versitorganizer/qversitorganizerimporter.cpp
+++ b/src/versitorganizer/qversitorganizerimporter.cpp
@@ -161,8 +161,11 @@ bool QVersitOrganizerImporter::importDocument(const QVersitDocument& document)
if (d->importDocument(subDocument, &item, &error)) {
d->mItems.append(item);
} else {
- d->mErrors.insert(documentIndex, error);
- ok = false;
+ // importDocument can return false with no error if it's a non-document component
+ if (error != QVersitOrganizerImporter::NoError) {
+ d->mErrors.insert(documentIndex, error);
+ ok = false;
+ }
}
documentIndex++;
}
diff --git a/src/versitorganizer/qversitorganizerimporter_p.cpp b/src/versitorganizer/qversitorganizerimporter_p.cpp
index 1eb744a9f2..9946a6212c 100644
--- a/src/versitorganizer/qversitorganizerimporter_p.cpp
+++ b/src/versitorganizer/qversitorganizerimporter_p.cpp
@@ -88,7 +88,9 @@ bool QVersitOrganizerImporterPrivate::importDocument(
} else if (document.componentType() == QLatin1String("VJOURNAL")) {
item->setType(QOrganizerItemType::TypeJournal);
} else if (document.componentType() == QLatin1String("VTIMEZONE")) {
- // TODO
+ mTimeZones.addTimeZone(importTimeZone(document));
+ *error = QVersitOrganizerImporter::NoError;
+ return false;
} else {
*error = QVersitOrganizerImporter::InvalidDocumentError;
return false;
@@ -411,14 +413,17 @@ bool QVersitOrganizerImporterPrivate::createJournalEntryDateTime(
* time zone (returned as a UTC datetime). Returns an invalid QDateTime if the string cannot be
* parsed.
*/
-QDateTime QVersitOrganizerImporterPrivate::parseDateTime(const QVersitProperty& property)
+QDateTime QVersitOrganizerImporterPrivate::parseDateTime(const QVersitProperty& property) const
{
- QDateTime datetime = parseDateTime(property.value());
- if (datetime.isValid() && datetime.timeSpec() == Qt::LocalTime && mTimeZoneHandler) {
+ QDateTime datetime(parseDateTime(property.value()));
+ if (datetime.isValid() && datetime.timeSpec() == Qt::LocalTime) {
QMultiHash<QString, QString> params = property.parameters();
QString tzid = params.value(QLatin1String("TZID"));
if (!tzid.isEmpty()) {
- datetime = mTimeZoneHandler->convertTimeZoneToUtc(datetime, tzid);
+ if (tzid.at(0) == QLatin1Char('/') && mTimeZoneHandler)
+ datetime = mTimeZoneHandler->convertTimeZoneToUtc(datetime, tzid);
+ else
+ datetime = mTimeZones.convert(datetime, tzid);
}
}
return datetime;
@@ -427,7 +432,7 @@ QDateTime QVersitOrganizerImporterPrivate::parseDateTime(const QVersitProperty&
/*! Parses \a str as an ISO 8601 datetime in basic format, either in UTC timezone or floating
* timezone. Returns an invalid QDateTime if the string cannot be parsed.
*/
-QDateTime QVersitOrganizerImporterPrivate::parseDateTime(QString str)
+QDateTime QVersitOrganizerImporterPrivate::parseDateTime(QString str) const
{
bool utc = str.endsWith(QLatin1Char('Z'), Qt::CaseInsensitive);
if (utc)
@@ -464,7 +469,7 @@ bool QVersitOrganizerImporterPrivate::createRecurrenceRule(
* Parses an iCalendar recurrence rule string \a str and puts the result in \a rule.
* Return true on success, false on failure.
*/
-bool QVersitOrganizerImporterPrivate::parseRecurRule(const QString& str, QOrganizerItemRecurrenceRule* rule)
+bool QVersitOrganizerImporterPrivate::parseRecurRule(const QString& str, QOrganizerItemRecurrenceRule* rule) const
{
QStringList parts = str.split(QLatin1Char(';'));
if (parts.size() == 0)
@@ -503,7 +508,7 @@ bool QVersitOrganizerImporterPrivate::parseRecurRule(const QString& str, QOrgani
* \a key is the part of the fragment before the equals sign and \a value is the part after.
*/
void QVersitOrganizerImporterPrivate::parseRecurFragment(const QString& key, const QString& value,
- QOrganizerItemRecurrenceRule* rule)
+ QOrganizerItemRecurrenceRule* rule) const
{
if (key == QLatin1String("INTERVAL")) {
bool ok;
@@ -597,7 +602,7 @@ void QVersitOrganizerImporterPrivate::parseRecurFragment(const QString& key, con
* Parses and returns a comma-separated list of integers. Only non-zero values between \a min and
* \a max (inclusive) are added
*/
-QList<int> QVersitOrganizerImporterPrivate::parseIntList(const QString& str, int min, int max)
+QList<int> QVersitOrganizerImporterPrivate::parseIntList(const QString& str, int min, int max) const
{
QList<int> values;
QStringList parts = str.split(QLatin1Char(','));
@@ -615,7 +620,7 @@ QList<int> QVersitOrganizerImporterPrivate::parseIntList(const QString& str, int
* Parses an iCalendar two-character string representing a day of week and returns an int
* corresponding to Qt::DayOfWeek. Returns -1 on parse failure.
*/
-int QVersitOrganizerImporterPrivate::parseDayOfWeek(const QString& str)
+int QVersitOrganizerImporterPrivate::parseDayOfWeek(const QString& str) const
{
if (str == QLatin1String("MO")) {
return Qt::Monday;
@@ -892,3 +897,51 @@ QString Duration::nextToken(QString* str)
return QString(); // null QString
}
}
+
+TimeZone QVersitOrganizerImporterPrivate::importTimeZone(const QVersitDocument& document) const
+{
+ TimeZone timeZone;
+ foreach (const QVersitProperty& property, document.properties()) {
+ if (property.name() == QLatin1String("TZID") && !property.value().isEmpty()) {
+ timeZone.setTzid(property.value());
+ }
+ }
+ foreach (const QVersitDocument& subDocument, document.subDocuments()) {
+ timeZone.addPhase(importTimeZonePhase(subDocument));
+ }
+ return timeZone;
+}
+
+TimeZonePhase QVersitOrganizerImporterPrivate::importTimeZonePhase(const QVersitDocument& document) const
+{
+ TimeZonePhase phase;
+ phase.setStandard(document.componentType() == QLatin1String("STANDARD"));
+
+ foreach (const QVersitProperty& property, document.properties()) {
+ if (property.name() == QLatin1String("TZOFFSETTO")) {
+ QString value(property.value());
+ if (value.size() == 5
+ && (value.at(0) == QLatin1Char('+') || value.at(0) == QLatin1Char('-'))
+ && value.at(1).isDigit()
+ && value.at(2).isDigit()
+ && value.at(3).isDigit()
+ && value.at(4).isDigit()) {
+ phase.setUtcOffset((value.at(0) == QLatin1Char('+') ? 1 : -1) * ( // deal with sign
+ value.mid(1, 2).toInt() * 3600 // hours part
+ + value.mid(3, 2).toInt() * 60 // minutes part
+ ));
+ }
+ } else if (property.name() == QLatin1String("DTSTART")) {
+ QDateTime dt(parseDateTime(property.value()));
+ if (dt.isValid() && dt.timeSpec() == Qt::LocalTime) {
+ phase.setStartDateTime(dt);
+ }
+ } else if (property.name() == QLatin1String("RRULE")) {
+ QOrganizerItemRecurrenceRule rrule;
+ if (parseRecurRule(property.value(), &rrule)) {
+ phase.setRecurrenceRule(rrule);
+ }
+ }
+ }
+ return phase;
+}
diff --git a/src/versitorganizer/qversitorganizerimporter_p.h b/src/versitorganizer/qversitorganizerimporter_p.h
index c4911dbb94..0b4a85fb45 100644
--- a/src/versitorganizer/qversitorganizerimporter_p.h
+++ b/src/versitorganizer/qversitorganizerimporter_p.h
@@ -57,6 +57,7 @@
#include "qorganizeritemrecurrence.h"
#include "qversitorganizerhandler.h"
#include "qversittimezonehandler.h"
+#include "timezones_p.h"
QTM_BEGIN_NAMESPACE
class QOrganizerItem;
@@ -169,18 +170,18 @@ private:
const QVersitProperty& property,
QOrganizerItem* item,
QList<QOrganizerItemDetail>* updatedDetails);
- QDateTime parseDateTime(const QVersitProperty& property);
- QDateTime parseDateTime(QString str);
+ QDateTime parseDateTime(const QVersitProperty& property) const;
+ QDateTime parseDateTime(QString str) const;
bool createRecurrenceRule(
const QVersitProperty& property,
QOrganizerItem* item,
QList<QOrganizerItemDetail>* updatedDetails);
- bool parseRecurRule(const QString& str, QOrganizerItemRecurrenceRule* rule);
+ bool parseRecurRule(const QString& str, QOrganizerItemRecurrenceRule* rule) const;
void parseRecurFragment(const QString& key, const QString& value,
- QOrganizerItemRecurrenceRule* rule);
- QList<int> parseIntList(const QString& str, int min, int max);
- int parseDayOfWeek(const QString& str);
+ QOrganizerItemRecurrenceRule* rule) const;
+ QList<int> parseIntList(const QString& str, int min, int max) const;
+ int parseDayOfWeek(const QString& str) const;
bool createRecurrenceDates(
const QVersitProperty& property,
@@ -202,8 +203,12 @@ private:
QOrganizerItem* item,
QList<QOrganizerItemDetail>* updatedDetails);
+ TimeZone importTimeZone(const QVersitDocument& document) const;
+ TimeZonePhase importTimeZonePhase(const QVersitDocument& document) const;
+
// versit property name -> <definition name, field name>:
QMap<QString, QPair<QString, QString> > mPropertyMappings;
+ TimeZones mTimeZones;
};
QTM_END_NAMESPACE
diff --git a/src/versitorganizer/timezones_p.cpp b/src/versitorganizer/timezones_p.cpp
new file mode 100644
index 0000000000..341f0511a0
--- /dev/null
+++ b/src/versitorganizer/timezones_p.cpp
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $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 "timezones_p.h"
+#include "qtorganizer.h"
+#include <QDateTime>
+
+QOrganizerItemManager* TimeZone::getManager()
+{
+ static QOrganizerItemManager* manager(new QOrganizerItemManager());
+ return manager;
+}
+
+QDateTime TimeZone::convert(const QDateTime& dateTime) const
+{
+ Q_ASSERT(isValid());
+ QOrganizerItemManager* manager = getManager();
+ int offset;
+ QDateTime latestPhase;
+ foreach(const TimeZonePhase& phase, mPhases) {
+ QOrganizerEvent event;
+ event.setStartDateTime(phase.startDateTime());
+ event.setRecurrenceRules(QList<QOrganizerItemRecurrenceRule>() << phase.recurrenceRule());
+ QList<QOrganizerItem> occurrences =
+ manager->itemInstances(event, phase.startDateTime(), dateTime, 500);
+ if (!occurrences.isEmpty()) {
+ QDateTime phaseStart(static_cast<QOrganizerEventOccurrence>(occurrences.last()).startDateTime());
+ if (phaseStart > latestPhase) {
+ latestPhase = phaseStart;
+ offset = phase.utcOffset();
+ }
+ }
+ }
+ QDateTime retn(dateTime);
+ retn.setTimeSpec(Qt::UTC);
+ return retn.addSecs(-offset);
+}
+
+QDateTime TimeZones::convert(const QDateTime& dateTime, const QString& tzid) const
+{
+ if (!mTimeZones.contains(tzid))
+ return QDateTime();
+ TimeZone tz = mTimeZones.value(tzid);
+ if (!tz.isValid())
+ return QDateTime();
+ return tz.convert(dateTime);
+}
diff --git a/src/versitorganizer/timezones_p.h b/src/versitorganizer/timezones_p.h
new file mode 100644
index 0000000000..600400fc88
--- /dev/null
+++ b/src/versitorganizer/timezones_p.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $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$
+**
+****************************************************************************/
+
+#ifndef TIMEZONES_P_H
+#define TIMEZONES_P_H
+
+#include <QDateTime>
+#include <QHash>
+#include "qorganizeritemrecurrencerule.h"
+
+QTM_BEGIN_NAMESPACE
+class QOrganizerItemManager;
+QTM_END_NAMESPACE
+
+QTM_USE_NAMESPACE
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+class TimeZonePhase {
+ public:
+ TimeZonePhase() : mStandard(true), mUtcOffset(100000) {} // invalid offset
+ void setStandard(bool standard) { mStandard = standard; }
+ bool isStandard() const { return mStandard; }
+ void setUtcOffset(int offset) { mUtcOffset = offset; }
+ int utcOffset() const { return mUtcOffset; }
+ void setStartDateTime(const QDateTime& dateTime) { mStartDateTime = dateTime; }
+ QDateTime startDateTime() const { return mStartDateTime; }
+ void setRecurrenceRule(const QOrganizerItemRecurrenceRule& rrule) { mRecurrenceRule = rrule; }
+ QOrganizerItemRecurrenceRule recurrenceRule() const { return mRecurrenceRule; }
+ bool isValid() const {
+ return mStartDateTime.isValid() && mUtcOffset < 86400 && mUtcOffset > -86400;
+ }
+ private:
+ bool mStandard; // true for STANDARD, false for DAYLIGHT
+ int mUtcOffset; // in seconds, the offset to apply after mStartDateTime
+ QDateTime mStartDateTime; // local time, when the phase comes into effect
+ QOrganizerItemRecurrenceRule mRecurrenceRule;
+};
+
+class TimeZone {
+ public:
+ QDateTime convert(const QDateTime& dateTime) const;
+ void setTzid(const QString& tzid) { mTzid = tzid; }
+ QString tzid() const { return mTzid; }
+ void addPhase(const TimeZonePhase& phase) { mPhases.append(phase); }
+ bool isValid() const {
+ foreach (const TimeZonePhase& phase, mPhases) {
+ if (!phase.isValid()) return false;
+ }
+ return !mPhases.isEmpty();
+ }
+
+ private:
+ static QOrganizerItemManager* getManager();
+ QString mTzid;
+ QList<TimeZonePhase> mPhases;
+};
+
+class TimeZones {
+ public:
+ QDateTime convert(const QDateTime& dateTime, const QString& tzid) const;
+ void addTimeZone(const TimeZone& timezone) {
+ if (!timezone.tzid().isEmpty())
+ mTimeZones.insert(timezone.tzid(), timezone);
+ }
+ private:
+ QHash<QString, TimeZone> mTimeZones;
+};
+
+#endif
diff --git a/src/versitorganizer/versitorganizer.pro b/src/versitorganizer/versitorganizer.pro
index 960d042c92..1a5cfa247e 100644
--- a/src/versitorganizer/versitorganizer.pro
+++ b/src/versitorganizer/versitorganizer.pro
@@ -30,7 +30,8 @@ PRIVATE_HEADERS += \
qversitorganizerexporter_p.h \
qversitorganizerimporter_p.h \
qversitorganizerdefs_p.h \
- qversitorganizerpluginloader_p.h
+ qversitorganizerpluginloader_p.h \
+ timezones_p.h
# Implementation
SOURCES += \
@@ -39,7 +40,8 @@ SOURCES += \
qversitorganizerimporter.cpp \
qversitorganizerimporter_p.cpp \
qversitorganizerhandler.cpp \
- qversitorganizerpluginloader_p.cpp
+ qversitorganizerpluginloader_p.cpp \
+ timezones_p.cpp
HEADERS += \
$$PUBLIC_HEADERS \
diff --git a/tests/auto/qversitorganizerimporter/tst_qversitorganizerimporter.cpp b/tests/auto/qversitorganizerimporter/tst_qversitorganizerimporter.cpp
index f4f3007d79..8291baa843 100644
--- a/tests/auto/qversitorganizerimporter/tst_qversitorganizerimporter.cpp
+++ b/tests/auto/qversitorganizerimporter/tst_qversitorganizerimporter.cpp
@@ -769,4 +769,160 @@ void tst_QVersitOrganizerImporter::testImportTodoProperties_data()
}
}
+void tst_QVersitOrganizerImporter::testTimeZones()
+{
+ QFETCH(QString, tzid);
+ QFETCH(QVersitDocument, timezoneSpec);
+ QFETCH(QString, datetimeString);
+ QFETCH(QDateTime, expected);
+
+ QVersitDocument document(QVersitDocument::ICalendar20Type);
+ document.setComponentType(QLatin1String("VCALENDAR"));
+ if (!tzid.isEmpty()) {
+ document.addSubDocument(timezoneSpec);
+ }
+ QVersitDocument vevent(QVersitDocument::ICalendar20Type);
+ vevent.setComponentType(QLatin1String("VEVENT"));
+ QVersitProperty property;
+ property.setName(QLatin1String("DTSTART"));
+ property.setValue(datetimeString);
+ if (!tzid.isEmpty()) {
+ property.insertParameter(QLatin1String("TZID"), tzid);
+ }
+ vevent.addProperty(property);
+ document.addSubDocument(vevent);
+
+ QVersitOrganizerImporter importer;
+ QVERIFY(importer.importDocument(document));
+ QVERIFY(importer.errors().isEmpty());
+ QList<QOrganizerItem> items = importer.items();
+ QCOMPARE(items.size(), 1);
+
+ QOrganizerEvent event = static_cast<QOrganizerEvent>(items.first());
+ QCOMPARE(event.type(), QString(QLatin1String(QOrganizerItemType::TypeEvent)));
+ QDateTime actualDatetime = event.startDateTime();
+ QCOMPARE(actualDatetime, expected);
+ QCOMPARE(actualDatetime.timeSpec(), expected.timeSpec());
+}
+
+void tst_QVersitOrganizerImporter::testTimeZones_data()
+{
+ QTest::addColumn<QString>("tzid"); // set this to empty if you don't want to associate a tzid
+ QTest::addColumn<QVersitDocument>("timezoneSpec");
+ QTest::addColumn<QString>("datetimeString");
+ QTest::addColumn<QDateTime>("expected");
+
+ QVersitDocument vtimezone(QVersitDocument::ICalendar20Type);
+ vtimezone.setComponentType(QLatin1String("VTIMEZONE"));
+ QTest::newRow("utc") << QString() << QVersitDocument(QVersitDocument::ICalendar20Type)
+ << QString::fromAscii("20100102T030405Z")
+ << QDateTime(QDate(2010, 1, 2), QTime(3, 4, 5), Qt::UTC);
+
+ QTest::newRow("floating") << QString() << QVersitDocument(QVersitDocument::ICalendar20Type)
+ << QString::fromAscii("20100102T030405")
+ << QDateTime(QDate(2010, 1, 2), QTime(3, 4, 5), Qt::LocalTime);
+
+ {
+ QVersitDocument vtimezone(QVersitDocument::ICalendar20Type);
+ vtimezone.setComponentType(QLatin1String("VTIMEZONE"));
+
+ QVersitProperty property;
+ property.setName(QLatin1String("TZID"));
+ property.setValue(QLatin1String("Asia/Singapore"));
+ vtimezone.addProperty(property);
+ property.setName(QLatin1String("X-LIC-LOCATION"));
+ property.setValue(QLatin1String("Asia/Singapore"));
+ vtimezone.addProperty(property);
+
+ QVersitDocument standard(QVersitDocument::ICalendar20Type);
+ standard.setComponentType(QLatin1String("STANDARD"));
+ property.setName(QLatin1String("TZOFFSETFROM"));
+ property.setValue(QLatin1String("+0800"));
+ standard.addProperty(property);
+ property.setName(QLatin1String("TZOFFSETTO"));
+ property.setValue(QLatin1String("+0800"));
+ standard.addProperty(property);
+ property.setName(QLatin1String("TZNAME"));
+ property.setValue(QLatin1String("EST"));
+ standard.addProperty(property);
+ property.setName(QLatin1String("DTSTART"));
+ property.setValue(QLatin1String("19700101T000000"));
+ standard.addProperty(property);
+ vtimezone.addSubDocument(standard);
+
+ QTest::newRow("no dst") << QString::fromAscii("Asia/Singapore")
+ << vtimezone << QString::fromAscii("20100102T100405")
+ << QDateTime(QDate(2010, 1, 2), QTime(2, 4, 5), Qt::UTC);
+ }
+
+ {
+ QVersitDocument vtimezone(QVersitDocument::ICalendar20Type);
+ vtimezone.setComponentType(QLatin1String("VTIMEZONE"));
+
+ QVersitProperty property;
+ property.setName(QLatin1String("TZID"));
+ property.setValue(QLatin1String("Australia/Sydney"));
+ vtimezone.addProperty(property);
+ property.setName(QLatin1String("X-LIC-LOCATION"));
+ property.setValue(QLatin1String("Australia/Sydney"));
+ vtimezone.addProperty(property);
+
+ QVersitDocument standard(QVersitDocument::ICalendar20Type);
+ standard.setComponentType(QLatin1String("STANDARD"));
+ property.setName(QLatin1String("TZOFFSETFROM"));
+ property.setValue(QLatin1String("+1100"));
+ standard.addProperty(property);
+ property.setName(QLatin1String("TZOFFSETTO"));
+ property.setValue(QLatin1String("+1000"));
+ standard.addProperty(property);
+ property.setName(QLatin1String("TZNAME"));
+ property.setValue(QLatin1String("EST"));
+ standard.addProperty(property);
+ property.setName(QLatin1String("DTSTART"));
+ property.setValue(QLatin1String("19700405T030000"));
+ standard.addProperty(property);
+ property.setName(QLatin1String("RRULE"));
+ property.setValue(QLatin1String("FREQ=YEARLY;BYMONTH=4;BYDAY=1SU"));
+ standard.addProperty(property);
+ vtimezone.addSubDocument(standard);
+
+ QVersitDocument daylight(QVersitDocument::ICalendar20Type);
+ daylight.setComponentType(QLatin1String("DAYLIGHT"));
+ property.setName(QLatin1String("TZOFFSETFROM"));
+ property.setValue(QLatin1String("+1000"));
+ daylight.addProperty(property);
+ property.setName(QLatin1String("TZOFFSETTO"));
+ property.setValue(QLatin1String("+1100"));
+ daylight.addProperty(property);
+ property.setName(QLatin1String("TZNAME"));
+ property.setValue(QLatin1String("EST"));
+ daylight.addProperty(property);
+ property.setName(QLatin1String("DTSTART"));
+ property.setValue(QLatin1String("19701004T020000"));
+ daylight.addProperty(property);
+ property.setName(QLatin1String("RRULE"));
+ property.setValue(QLatin1String("FREQ=YEARLY;BYMONTH=10;BYDAY=1SU"));
+ daylight.addProperty(property);
+ vtimezone.addSubDocument(daylight);
+
+ QTest::newRow("dst area in standard time") << QString::fromAscii("Australia/Sydney")
+ << vtimezone << QString::fromAscii("20100502T100405")
+ << QDateTime(QDate(2010, 5, 2), QTime(0, 4, 5), Qt::UTC);
+
+ QTest::newRow("dst") << QString::fromAscii("Australia/Sydney")
+ << vtimezone << QString::fromAscii("20100102T100405")
+ << QDateTime(QDate(2010, 1, 1), QTime(23, 4, 5), Qt::UTC);
+ }
+
+ {
+ QVersitDocument vtimezone(QVersitDocument::ICalendar20Type);
+ vtimezone.setComponentType(QLatin1String("VTIMEZONE"));
+
+ QVersitProperty property;
+ property.setName(QLatin1String("TZID"));
+ property.setValue(QLatin1String("test"));
+ vtimezone.addProperty(property);
+ }
+}
+
QTEST_MAIN(tst_QVersitOrganizerImporter)
diff --git a/tests/auto/qversitorganizerimporter/tst_qversitorganizerimporter.h b/tests/auto/qversitorganizerimporter/tst_qversitorganizerimporter.h
index f7096c9d8e..e3987471a9 100644
--- a/tests/auto/qversitorganizerimporter/tst_qversitorganizerimporter.h
+++ b/tests/auto/qversitorganizerimporter/tst_qversitorganizerimporter.h
@@ -64,6 +64,9 @@ private slots:
void testImportTodoProperties();
void testImportTodoProperties_data();
+
+ void testTimeZones();
+ void testTimeZones_data();
};
#endif