diff --git a/src/calendarhandler.cpp b/src/calendarhandler.cpp index b79b9bf..061ff7d 100644 --- a/src/calendarhandler.cpp +++ b/src/calendarhandler.cpp @@ -1,310 +1,305 @@ /* Copyright (c) 2017 Volker Krause 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 "config-kitinerary.h" #include "calendarhandler.h" #include "jsonlddocument.h" #include "logging.h" #include "mergeutil.h" #include "sortutil.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_KCAL #include #include #include #endif #ifdef HAVE_KCONTACTS #include #endif #include #include #include #include using namespace KItinerary; #ifdef HAVE_KCAL using namespace KCalCore; static void fillFlightReservation(const QVector &reservations, const KCalCore::Event::Ptr &event); template static void fillTripReservation(const Res &reservation, const KCalCore::Event::Ptr &event); static void fillTrainReservation(const TrainReservation &reservation, const KCalCore::Event::Ptr &event); static void fillBusReservation(const BusReservation &reservation, const KCalCore::Event::Ptr &event); static void fillLodgingReservation(const LodgingReservation &reservation, const KCalCore::Event::Ptr &event); static void fillGeoPosition(const QVariant &place, const KCalCore::Event::Ptr &event); #endif QSharedPointer CalendarHandler::findEvent(const QSharedPointer &calendar, const QVariant &reservation) { #ifdef HAVE_KCAL if (!JsonLd::canConvert(reservation)) { return {}; } - auto bookingRef = JsonLd::convert(reservation).reservationNumber(); - if (bookingRef.isEmpty()) { - return {}; - } - bookingRef.prepend(QLatin1String("KIT-")); const auto dt = SortUtil::startDateTime(reservation).date(); const auto events = calendar->events(dt); for (const auto &event : events) { - if (!event->uid().startsWith(bookingRef)) { + if (!event->uid().startsWith(QLatin1String("KIT-"))) { continue; } const auto otherRes = CalendarHandler::reservationsForEvent(event); for (const auto &other : otherRes) { if (MergeUtil::isSame(other, reservation)) { return event; } } } #else Q_UNUSED(calendar); Q_UNUSED(reservation); #endif return {}; } QVector CalendarHandler::reservationsForEvent(const QSharedPointer &event) { #ifdef HAVE_KCAL const auto payload = event->customProperty("KITINERARY", "RESERVATION").toUtf8(); const auto json = QJsonDocument::fromJson(payload).array(); return JsonLdDocument::fromJson(json); #else Q_UNUSED(event); return {}; #endif } QVariant CalendarHandler::reservationForEvent(const QSharedPointer &event) { const auto v = reservationsForEvent(event); return v.isEmpty() ? QVariant() : v.at(0); } void CalendarHandler::fillEvent(const QVector &reservations, const QSharedPointer &event) { if (reservations.isEmpty()) { return; } #ifdef HAVE_KCAL // TODO pass reservationS into all functions below for multi-traveler support const auto reservation = reservations.at(0); const int typeId = reservation.userType(); if (typeId == qMetaTypeId()) { fillFlightReservation(reservations, event); } else if (typeId == qMetaTypeId()) { fillLodgingReservation(reservation.value(), event); } else if (typeId == qMetaTypeId()) { fillTrainReservation(reservation.value(), event); } else if (typeId == qMetaTypeId()) { fillBusReservation(reservation.value(), event); } else { return; } if (!event->uid().startsWith(QLatin1String("KIT-"))) { event->setUid(QLatin1String("KIT-") + event->uid()); } const auto payload = QJsonDocument(JsonLdDocument::toJson(reservations)).toJson(QJsonDocument::Compact); event->setCustomProperty("KITINERARY", "RESERVATION", QString::fromUtf8(payload)); #else Q_UNUSED(event); #endif } void CalendarHandler::fillEvent(const QVariant &reservation, const QSharedPointer &event) { fillEvent(QVector{reservation}, event); } #ifdef HAVE_KCAL static void fillFlightReservation(const QVector &reservations, const KCalCore::Event::Ptr &event) { const auto flight = reservations.at(0).value().reservationFor().value(); const auto airline = flight.airline(); const auto depPort = flight.departureAirport(); const auto arrPort = flight.arrivalAirport(); const QString flightNumber = airline.iataCode() + QLatin1Char(' ') + flight.flightNumber(); event->setSummary(i18n("Flight %1 from %2 to %3", flightNumber, depPort.iataCode(), arrPort.iataCode())); event->setLocation(depPort.name()); fillGeoPosition(depPort, event); event->setDtStart(flight.departureTime()); event->setDtEnd(flight.arrivalTime()); event->setAllDay(false); const auto boardingTime = flight.boardingTime(); const auto departureGate = flight.departureGate(); if (boardingTime.isValid()) { const auto startOffset = Duration(event->dtStart(), boardingTime); const auto existinAlarms = event->alarms(); const auto it = std::find_if(existinAlarms.begin(), existinAlarms.end(), [startOffset](const Alarm::Ptr &other) { return other->startOffset() == startOffset; }); if (it == existinAlarms.end()) { Alarm::Ptr alarm(new Alarm(event.data())); alarm->setStartOffset(Duration(event->dtStart(), boardingTime)); if (departureGate.isEmpty()) { alarm->setDisplayAlarm(i18n("Boarding for flight %1", flightNumber)); } else { alarm->setDisplayAlarm(i18n("Boarding for flight %1 at gate %2", flightNumber, departureGate)); } alarm->setEnabled(true); event->addAlarm(alarm); } } QStringList desc; if (boardingTime.isValid()) { desc.push_back(i18n("Boarding time: %1", QLocale().toString(boardingTime.time(), QLocale::ShortFormat))); } if (!departureGate.isEmpty()) { desc.push_back(i18n("Departure gate: %1", departureGate)); } for (const auto r : reservations) { const auto reservation = r.value(); const auto person = reservation.underName().value(); if (!person.name().isEmpty()) { desc.push_back(person.name()); } if (!reservation.boardingGroup().isEmpty()) { desc.push_back(i18n("Boarding group: %1", reservation.boardingGroup())); } if (!reservation.airplaneSeat().isEmpty()) { desc.push_back(i18n("Seat: %1", reservation.airplaneSeat())); } if (!reservation.reservationNumber().isEmpty()) { desc.push_back(i18n("Booking reference: %1", reservation.reservationNumber())); } event->setDescription(desc.join(QLatin1Char('\n'))); } } template static void fillTripReservation(const Res &reservation, const KCalCore::Event::Ptr &event) { const auto trip = reservation.reservationFor().template value(); const auto depStation = trip.departureStation(); event->setLocation(depStation.name()); fillGeoPosition(depStation, event); event->setDtStart(trip.departureTime()); event->setDtEnd(trip.arrivalTime()); event->setAllDay(false); QStringList desc; if (!trip.departurePlatform().isEmpty()) { desc.push_back(i18n("Departure platform: %1", trip.departurePlatform())); } const auto ticket = reservation.reservedTicket().template value(); const auto seat = ticket.ticketedSeat(); if (!seat.seatSection().isEmpty()) { desc.push_back(i18n("Coach: %1", seat.seatSection())); } if (!seat.seatNumber().isEmpty()) { desc.push_back(i18n("Seat: %1", seat.seatNumber())); } if (!trip.arrivalPlatform().isEmpty()) { desc.push_back(i18n("Arrival platform: %1", trip.arrivalPlatform())); } if (!reservation.reservationNumber().isEmpty()) { desc.push_back(i18n("Booking reference: %1", reservation.reservationNumber())); } event->setDescription(desc.join(QLatin1Char('\n'))); } static void fillTrainReservation(const TrainReservation &reservation, const KCalCore::Event::Ptr &event) { const auto trip = reservation.reservationFor().value(); const auto depStation = trip.departureStation(); const auto arrStation = trip.arrivalStation(); event->setSummary(i18n("Train %1 from %2 to %3", trip.trainNumber(), depStation.name(), arrStation.name())); fillTripReservation(reservation, event); } static void fillBusReservation(const BusReservation &reservation, const KCalCore::Event::Ptr &event) { const auto trip = reservation.reservationFor().value(); const auto depStation = trip.departureStation(); const auto arrStation = trip.arrivalStation(); event->setSummary(i18n("Bus %1 from %2 to %3", trip.busNumber(), depStation.name(), arrStation.name())); fillTripReservation(reservation, event); } static void fillLodgingReservation(const LodgingReservation &reservation, const KCalCore::Event::Ptr &event) { const auto lodgingBusiness = reservation.reservationFor().value(); const auto address = lodgingBusiness.address(); event->setSummary(i18n("Hotel reservation: %1", lodgingBusiness.name())); #ifdef HAVE_KCONTACTS event->setLocation(i18nc(", , ", "%1, %2 %3, %4", address.streetAddress(), address.postalCode(), address.addressLocality(), KContacts::Address::ISOtoCountry(address.addressCountry()))); #endif fillGeoPosition(lodgingBusiness, event); event->setDtStart(QDateTime(reservation.checkinTime().date(), QTime())); event->setDtEnd(QDateTime(reservation.checkoutTime().date(), QTime())); event->setAllDay(true); event->setDescription(i18n("Check-in: %1\nCheck-out: %2\nBooking reference: %3", QLocale().toString(reservation.checkinTime().time(), QLocale::ShortFormat), QLocale().toString(reservation.checkoutTime().time(), QLocale::ShortFormat), reservation.reservationNumber())); event->setTransparency(Event::Transparent); } static void fillGeoPosition(const QVariant &place, const KCalCore::Event::Ptr &event) { if (!JsonLd::canConvert(place)) { return; } const auto geo = JsonLd::convert(place).geo(); if (!geo.isValid()) { return; } event->setHasGeo(true); event->setGeoLatitude(geo.latitude()); event->setGeoLongitude(geo.longitude()); } #endif