diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 117693c37..e4d228292 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,147 +1,146 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-kcalcore.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kcalcore.h ) ########### next target ############### bison_target(VersitParser ${CMAKE_CURRENT_SOURCE_DIR}/versit/vcc.y ${CMAKE_CURRENT_BINARY_DIR}/vcc-parser.c ) set(libversit_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/versit/vobject.c ${BISON_VersitParser_OUTPUTS} ) set(kcalcore_LIB_SRCS ${libversit_SRCS} alarm.cpp attachment.cpp attendee.cpp calendar.cpp calfilter.cpp calformat.cpp calstorage.cpp compat.cpp customproperties.cpp duration.cpp event.cpp exceptions.cpp filestorage.cpp freebusy.cpp freebusycache.cpp freebusyperiod.cpp icalformat.cpp icalformat_p.cpp icaltimezones.cpp incidence.cpp incidencebase.cpp journal.cpp memorycalendar.cpp occurrenceiterator.cpp period.cpp person.cpp recurrence.cpp recurrencerule.cpp schedulemessage.cpp sorting.cpp todo.cpp utils.cpp vcalformat.cpp visitor.cpp ) ecm_qt_declare_logging_category(kcalcore_LIB_SRCS HEADER kcalcore_debug.h IDENTIFIER KCALCORE_LOG CATEGORY_NAME org.kde.pim.kcalcore) add_library(KF5CalendarCore ${kcalcore_LIB_SRCS}) generate_export_header(KF5CalendarCore BASE_NAME kcalcore) add_library(KF5::CalendarCore ALIAS KF5CalendarCore) target_include_directories(KF5CalendarCore INTERFACE "$") target_include_directories(KF5CalendarCore PUBLIC "$") target_include_directories(KF5CalendarCore PUBLIC "$") target_link_libraries(KF5CalendarCore PUBLIC Qt5::Core PRIVATE KF5::KDELibs4Support ${LibIcal_LIBRARIES} ) if(HAVE_UUID_LIBRARY) target_link_libraries(KF5CalendarCore PRIVATE ${UUID_LIBRARY} ) endif() set_target_properties(KF5CalendarCore PROPERTIES VERSION ${KCALCORE_VERSION_STRING} SOVERSION ${KCALCORE_SOVERSION} EXPORT_NAME CalendarCore ) install(TARGETS KF5CalendarCore EXPORT KF5CalendarCoreTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) ########### Generate Headers ############### ecm_generate_headers(KCalCore_CamelCase_HEADERS HEADER_NAMES Alarm Attachment Attendee CalFilter CalFormat CalStorage Calendar CustomProperties Duration Event Exceptions # NOTE: Used to be called 'Exception' in KDE4 FileStorage FreeBusy FreeBusyCache FreeBusyPeriod ICalFormat Incidence IncidenceBase Journal MemoryCalendar OccurrenceIterator Period Person Recurrence RecurrenceRule ScheduleMessage SortableList Sorting Todo - Utils VCalFormat Visitor PREFIX KCalCore REQUIRED_HEADERS KCalCore_HEADERS ) ########### install files ############### install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kcalcore_export.h ${KCalCore_HEADERS} supertrait.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KCalCore/kcalcore COMPONENT Devel ) install(FILES ${KCalCore_CamelCase_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KCalCore/KCalCore COMPONENT Devel ) ecm_generate_pri_file(BASE_NAME KCalCore LIB_NAME KF5CalendarCore DEPS "Core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KCalCore/KCalCore) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/utils.cpp b/src/utils.cpp index 6f840ab45..f21b8016e 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,306 +1,267 @@ /* This file is part of the kcalcore library. Copyright (c) 2017 Daniel Vrátil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "utils.h" #include #include #include #include #include -QDateTime KCalCore::applySpec(const QDateTime &dt, const KDateTime::Spec &spec, bool isAllDay) -{ - if (isAllDay) { - QDateTime out; - switch (spec.type()) { - case KDateTime::UTC: - return QDateTime(dt.date(), QTime(), Qt::UTC); - case KDateTime::OffsetFromUTC: - return QDateTime(dt.date(), QTime(), Qt::OffsetFromUTC, spec.utcOffset()); - case KDateTime::TimeZone: - return QDateTime(dt.date(), QTime(), QTimeZone(spec.timeZone().name().toUtf8())); - case KDateTime::LocalZone: - case KDateTime::ClockTime: - return QDateTime(dt.date(), QTime(), Qt::LocalTime); - case KDateTime::Invalid: - return dt; - } - out.setTime({}); - return out; - } else { - switch (spec.type()) { - case KDateTime::UTC: - return dt.toTimeSpec(Qt::UTC); - case KDateTime::OffsetFromUTC: - return dt.toOffsetFromUtc(spec.utcOffset()); - case KDateTime::TimeZone: - return dt.toTimeZone(QTimeZone(spec.timeZone().name().toUtf8())); - case KDateTime::LocalZone: - case KDateTime::ClockTime: - return dt.toLocalTime(); - case KDateTime::Invalid: - return dt; - } - } - - Q_UNREACHABLE(); - return {}; -} - KDateTime::Spec KCalCore::zoneToSpec(const QTimeZone& zone) { if (!zone.isValid()) return KDateTime::Invalid; if (zone == QTimeZone::utc()) return KDateTime::UTC; if (zone == QTimeZone::systemTimeZone()) return KDateTime::LocalZone; if (zone.id().startsWith("UTC")) { return KDateTime::Spec(KDateTime::OffsetFromUTC, zone.offsetFromUtc(QDateTime::currentDateTimeUtc())); } else { return KSystemTimeZones::zone(QString::fromLatin1(zone.id())); } } namespace { QTimeZone resolveCustomTZ(const KTimeZone &ktz) { // First, let's try Microsoft const auto msIana = QTimeZone::windowsIdToDefaultIanaId(ktz.name().toUtf8()); if (!msIana.isEmpty()) { return QTimeZone(msIana); } int standardUtcOffset = 0; bool matched = false; const auto phases = ktz.phases(); for (const auto &phase : phases) { if (!phase.isDst()) { standardUtcOffset = phase.utcOffset(); matched = true; break; } } if (!matched) { standardUtcOffset = ktz.currentOffset(Qt::UTC); } const auto candidates = QTimeZone::availableTimeZoneIds(standardUtcOffset); QMap matchedCandidates; for (const auto &tzid : candidates) { const QTimeZone candidate(tzid); // This would be a fallback if (candidate.hasTransitions() != ktz.hasTransitions()) { matchedCandidates.insert(0, candidate); continue; } // Without transitions, we can't do any more precise matching, so just // accept this candidate and be done with it if (!candidate.hasTransitions() && !ktz.hasTransitions()) { return candidate; } // Calculate how many transitions this candidate shares with the ktz. // The candidate with the most matching transitions will win. const auto transitions = ktz.transitions(QDateTime(), QDateTime::currentDateTimeUtc()); int matchedTransitions = 0; for (auto it = transitions.rbegin(), end = transitions.rend(); it != end; ++it) { const auto &transition = *it; const QTimeZone::OffsetDataList candidateTransitions = candidate.transitions(transition.time(), transition.time()); if (candidateTransitions.isEmpty()) { continue; } const auto candidateTransition = candidateTransitions[0]; const auto abvs = transition.phase().abbreviations(); for (const auto &abv : abvs) { if (candidateTransition.abbreviation == QString::fromUtf8(abv)) { ++matchedTransitions; break; } } } matchedCandidates.insert(matchedTransitions, candidate); } if (!matchedCandidates.isEmpty()) { return matchedCandidates.value(matchedCandidates.lastKey()); } return {}; } } QTimeZone KCalCore::specToZone(const KDateTime::Spec &spec) { switch (spec.type()) { case KDateTime::Invalid: return QTimeZone(); case KDateTime::LocalZone: case KDateTime::ClockTime: return QTimeZone::systemTimeZone(); case KDateTime::UTC: return QTimeZone::utc(); default: { auto tz = QTimeZone(spec.timeZone().name().toUtf8()); if (!tz.isValid()) { tz = resolveCustomTZ(spec.timeZone()); qDebug() << "Resolved" << spec.timeZone().name() << "to" << tz.id(); } return tz; } } return QTimeZone::systemTimeZone(); } QDateTime KCalCore::k2q(const KDateTime &kdt) { if (kdt.isValid()) { return QDateTime(kdt.date(), kdt.time(), specToZone(kdt.timeSpec())); } else { return QDateTime(); } } KDateTime KCalCore::q2k(const QDateTime &qdt, bool allDay) { if (qdt.isValid()) { KDateTime kdt(qdt.date(), qdt.time(), zoneToSpec(qdt.timeZone())); kdt.setDateOnly(allDay && qdt.time() == QTime(0, 0, 0)); return kdt; } else { return KDateTime(); } } // To remain backwards compatible we need to (de)serialize QDateTime the way KDateTime // was (de)serialized void KCalCore::serializeQDateTimeAsKDateTime(QDataStream &out, const QDateTime &dt) { out << dt.date() << dt.time(); switch (dt.timeSpec()) { case Qt::UTC: out << static_cast('u'); break; case Qt::OffsetFromUTC: out << static_cast('o') << dt.offsetFromUtc(); break; case Qt::TimeZone: serializeQTimeZoneAsSpec(out, dt.timeZone()); break; case Qt::LocalTime: out << static_cast('c'); break; } const bool isDateOnly = dt.date().isValid() && !dt.time().isValid(); out << quint8(isDateOnly ? 0x01 : 0x00); } void KCalCore::deserializeKDateTimeAsQDateTime(QDataStream &in, QDateTime &dt) { QDate date; QTime time; quint8 ts, flags; in >> date >> time >> ts; switch (static_cast(ts)) { case 'u': dt = QDateTime(date, time, Qt::UTC); break; case 'o': { int offset; in >> offset; dt = QDateTime(date, time, Qt::OffsetFromUTC, offset); break; } case 'z': { QString tzid; in >> tzid; dt = QDateTime(date, time, QTimeZone(tzid.toUtf8())); break; } case 'c': dt = QDateTime(date, time, Qt::LocalTime); break; } // unused, we don't have a special handling for date-only QDateTime in >> flags; } void KCalCore::serializeQTimeZoneAsSpec(QDataStream &out, const QTimeZone& tz) { out << static_cast('z') << (tz.isValid() ? QString::fromUtf8(tz.id()) : QString()); } void KCalCore::deserializeSpecAsQTimeZone(QDataStream &in, QTimeZone &tz) { quint8 ts; in >> ts; switch (static_cast(ts)) { case 'u': tz = QTimeZone::utc(); return; case 'o': { int offset; in >> offset; tz = QTimeZone(offset); return; } case 'z': { QString tzid; in >> tzid; tz = QTimeZone(tzid.toUtf8()); return; } case 'c': tz = QTimeZone::systemTimeZone(); break; } } void KCalCore::serializeQDateTimeSortableList(QDataStream &out, const SortableList &list) { out << list.size(); for (const auto &i : list) { serializeQDateTimeAsKDateTime(out, i); } } void KCalCore::deserializeQDateTimeSortableList(QDataStream& in, SortableList& list) { int size; in >> size; list.clear(); list.reserve(size); for (int i = 0; i < size; ++i) { QDateTime dt; deserializeKDateTimeAsQDateTime(in, dt); list << dt; } } diff --git a/src/utils.h b/src/utils.h index 7a2d51251..1168439ea 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,66 +1,61 @@ /* This file is part of the kcalcore library. Copyright (c) 2017 Daniel Vrátil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KCALCORE_UTILS_H_ #define KCALCORE_UTILS_H_ #include "kcalcore_export.h" #include "sortablelist.h" #include #include class QDataStream; namespace KCalCore { // TODO: PORTING-helper only, remove once KDateTime is gone -/** - * Applies KDateTime::Spec to given QDateTime and returns a modified QDateTime - */ -QDateTime applySpec(const QDateTime &dt, const KDateTime::Spec &spec, bool isAllDay); - /** * Helpers to retain backwards compatibility of binary serialization. */ KCALCORE_EXPORT void serializeQDateTimeAsKDateTime(QDataStream &out, const QDateTime &dt); KCALCORE_EXPORT void deserializeKDateTimeAsQDateTime(QDataStream &in, QDateTime &dt); -KCALCORE_EXPORT void serializeQDateTimeSortableList(QDataStream &out, const SortableList &list); -KCALCORE_EXPORT void deserializeQDateTimeSortableList(QDataStream &in, SortableList &list); +void serializeQDateTimeSortableList(QDataStream &out, const SortableList &list); +void deserializeQDateTimeSortableList(QDataStream &in, SortableList &list); -KCALCORE_EXPORT void serializeQTimeZoneAsSpec(QDataStream &out, const QTimeZone &tz); -KCALCORE_EXPORT void deserializeSpecAsQTimeZone(QDataStream &in, QTimeZone &tz); +void serializeQTimeZoneAsSpec(QDataStream &out, const QTimeZone &tz); +void deserializeSpecAsQTimeZone(QDataStream &in, QTimeZone &tz); /** Convert a QTimeZone to a KDateTime::Spec */ -KCALCORE_EXPORT KDateTime::Spec zoneToSpec(const QTimeZone &zone); +KDateTime::Spec zoneToSpec(const QTimeZone &zone); /** Convert a QTimeZone to a KDateTime::Spec */ -KCALCORE_EXPORT QTimeZone specToZone(const KDateTime::Spec &spec); +QTimeZone specToZone(const KDateTime::Spec &spec); /** Convert KDateTime to QDateTime, correctly preserves timespec */ -KCALCORE_EXPORT QDateTime k2q(const KDateTime &kdt); -KCALCORE_EXPORT KDateTime q2k(const QDateTime &qdt, bool isAllDay = false); +QDateTime k2q(const KDateTime &kdt); +KDateTime q2k(const QDateTime &qdt, bool isAllDay = false); } #endif