Warning, file /pim/kitinerary/src/lib/calendarhandler.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2017 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "config-kitinerary.h" 0008 #include "calendarhandler.h" 0009 #include "jsonlddocument.h" 0010 #include "locationutil_p.h" 0011 #include "logging.h" 0012 #include "mergeutil.h" 0013 #include "sortutil.h" 0014 0015 #include <KItinerary/BoatTrip> 0016 #include <KItinerary/BusTrip> 0017 #include <KItinerary/Event> 0018 #include <KItinerary/Flight> 0019 #include <KItinerary/Organization> 0020 #include <KItinerary/Person> 0021 #include <KItinerary/Place> 0022 #include <KItinerary/RentalCar> 0023 #include <KItinerary/Reservation> 0024 #include <KItinerary/Ticket> 0025 #include <KItinerary/TrainTrip> 0026 #include <KItinerary/Visit> 0027 0028 #include <KCalendarCore/Alarm> 0029 #include <KCalendarCore/Calendar> 0030 #include <KCalendarCore/Event> 0031 0032 #include <KContacts/Address> 0033 0034 #include <KLocalizedString> 0035 0036 #include <QDateTime> 0037 #include <QJsonArray> 0038 #include <QJsonDocument> 0039 0040 using namespace KItinerary; 0041 0042 static QString formatAddress(const PostalAddress &addr) 0043 { 0044 return LocationUtil::toAddress(addr).formatted(KContacts::AddressFormatStyle::MultiLineInternational); 0045 } 0046 0047 static QString formatAddressSingleLine(const PostalAddress &addr) 0048 { 0049 return LocationUtil::toAddress(addr).formatted(KContacts::AddressFormatStyle::SingleLineInternational); 0050 } 0051 0052 using namespace KCalendarCore; 0053 static void fillFlightReservation(const QList<QVariant> &reservations, 0054 const KCalendarCore::Event::Ptr &event); 0055 static void fillTrainReservation(const TrainReservation &reservation, const KCalendarCore::Event::Ptr &event); 0056 static void fillBusReservation(const BusReservation &reservation, const KCalendarCore::Event::Ptr &event); 0057 static void fillBoatReservation(const BoatReservation &reservation, const KCalendarCore::Event::Ptr &event); 0058 static void fillLodgingReservation(const QList<QVariant> &reservations, 0059 const KCalendarCore::Event::Ptr &event); 0060 static void fillEvent(const KItinerary::Event &ev, const KCalendarCore::Event::Ptr &event); 0061 static void fillEventReservation(const QList<QVariant> &reservations, 0062 const KCalendarCore::Event::Ptr &event); 0063 static void fillGeoPosition(const QVariant &place, const KCalendarCore::Event::Ptr &event); 0064 static void fillFoodReservation(const FoodEstablishmentReservation &reservation, const KCalendarCore::Event::Ptr &event); 0065 static void fillRentalCarReservation(const RentalCarReservation &reservation, const KCalendarCore::Event::Ptr &event); 0066 static void fillTaxiReservation(const TaxiReservation &reservation, const KCalendarCore::Event::Ptr &event); 0067 0068 QList<QSharedPointer<KCalendarCore::Event>> CalendarHandler::findEvents( 0069 const QSharedPointer<KCalendarCore::Calendar> &calendar, 0070 const QVariant &reservation) { 0071 return findEvents(calendar.data(), reservation); 0072 } 0073 0074 QList<QSharedPointer<KCalendarCore::Event>> 0075 CalendarHandler::findEvents(KCalendarCore::Calendar *calendar, 0076 const QVariant &reservation) { 0077 if (!(JsonLd::canConvert<Reservation>(reservation) || JsonLd::canConvert<KItinerary::Event>(reservation)) || !calendar) { 0078 return {}; 0079 } 0080 0081 QList<KCalendarCore::Event::Ptr> events; 0082 QList<KCalendarCore::Event::Ptr> results; 0083 const auto startDt = SortUtil::startDateTime(reservation); 0084 const auto endDt = SortUtil::endDateTime(reservation); 0085 if (startDt.isValid() && endDt.isValid() && startDt == startDt.date().startOfDay(startDt.timeZone()) 0086 && std::abs(endDt.secsTo(endDt.date().endOfDay(endDt.timeZone()))) <= 1) { 0087 // looks like an all day event, don't adjust for timezones in that case 0088 events = calendar->events(startDt.date()); 0089 } else if (startDt.isValid()) { 0090 // we know the exact day to search at 0091 events = calendar->events(startDt.toTimeZone(calendar->timeZone()).date()); 0092 } else if (JsonLd::canConvert<Reservation>(reservation)) { 0093 // for minimal cancellations, we need to search in a larger range 0094 const auto res = JsonLd::convert<Reservation>(reservation); 0095 if (!res.modifiedTime().isValid() || res.reservationStatus() != Reservation::ReservationCancelled) { 0096 return {}; 0097 } 0098 const auto date = res.modifiedTime().toTimeZone(calendar->timeZone()).date(); 0099 events = calendar->events(date, date.addDays(180)); 0100 } 0101 0102 for (const auto &event : events) { 0103 if (!event->uid().startsWith(QLatin1StringView("KIT-"))) { 0104 continue; 0105 } 0106 const auto otherRes = CalendarHandler::reservationsForEvent(event); 0107 for (const auto &other : otherRes) { 0108 if (MergeUtil::isSame(other, reservation)) { 0109 results.push_back(event); 0110 } 0111 } 0112 } 0113 0114 return results; 0115 } 0116 0117 QList<QVariant> CalendarHandler::reservationsForEvent( 0118 const QSharedPointer<KCalendarCore::Event> &event) { 0119 const auto payload = event->customProperty("KITINERARY", "RESERVATION").toUtf8(); 0120 const auto json = QJsonDocument::fromJson(payload).array(); 0121 return JsonLdDocument::fromJson(json); 0122 } 0123 0124 bool CalendarHandler::canCreateEvent(const QVariant &reservation) 0125 { 0126 if (JsonLd::isA<FlightReservation>(reservation)) { 0127 const auto f = reservation.value<FlightReservation>().reservationFor().value<Flight>(); 0128 if (f.departureTime().isValid() && f.arrivalTime().isValid()) { 0129 return true; 0130 } 0131 } 0132 return SortUtil::startDateTime(reservation).isValid(); 0133 } 0134 0135 void CalendarHandler::fillEvent( 0136 const QList<QVariant> &reservations, 0137 const QSharedPointer<KCalendarCore::Event> &event) { 0138 if (reservations.isEmpty()) { 0139 return; 0140 } 0141 0142 // TODO pass reservationS into all functions below for multi-traveler support 0143 const auto &reservation = reservations.at(0); 0144 const int typeId = reservation.userType(); 0145 if (typeId == qMetaTypeId<FlightReservation>()) { 0146 fillFlightReservation(reservations, event); 0147 } else if (typeId == qMetaTypeId<LodgingReservation>()) { 0148 fillLodgingReservation(reservations, event); 0149 } else if (typeId == qMetaTypeId<TrainReservation>()) { 0150 fillTrainReservation(reservation.value<TrainReservation>(), event); 0151 } else if (typeId == qMetaTypeId<BusReservation>()) { 0152 fillBusReservation(reservation.value<BusReservation>(), event); 0153 } else if (typeId == qMetaTypeId<BoatReservation>()) { 0154 fillBoatReservation(reservation.value<BoatReservation>(), event); 0155 } else if (JsonLd::isA<EventReservation>(reservation)) { 0156 fillEventReservation(reservations, event); 0157 } else if (JsonLd::isA<Event>(reservation)) { 0158 fillEvent(reservation.value<KItinerary::Event>(), event); 0159 } else if (JsonLd::isA<FoodEstablishmentReservation>(reservation)) { 0160 fillFoodReservation(reservation.value<FoodEstablishmentReservation>(), event); 0161 } else if (JsonLd::isA<RentalCarReservation>(reservation)) { 0162 fillRentalCarReservation(reservation.value<RentalCarReservation>(), event); 0163 } else if (JsonLd::isA<TaxiReservation>(reservation)) { 0164 fillTaxiReservation(reservation.value<TaxiReservation>(), event); 0165 } else { 0166 return; 0167 } 0168 0169 if (JsonLd::canConvert<Reservation>(reservation) && JsonLd::convert<Reservation>(reservation).reservationStatus() == Reservation::ReservationCancelled) { 0170 event->setTransparency(KCalendarCore::Event::Transparent); 0171 event->setSummary(i18nc("canceled train/flight/loading reservation", "Canceled: %1", event->summary())); 0172 event->clearAlarms(); 0173 } 0174 0175 if (!event->uid().startsWith(QLatin1StringView("KIT-"))) { 0176 event->setUid(QLatin1StringView("KIT-") + event->uid()); 0177 } 0178 0179 const auto payload = QJsonDocument(JsonLdDocument::toJson(reservations)).toJson(QJsonDocument::Compact); 0180 event->setCustomProperty("KITINERARY", "RESERVATION", QString::fromUtf8(payload)); 0181 } 0182 0183 static QString airportDisplayCode(const Airport &airport) 0184 { 0185 return airport.iataCode().isEmpty() ? airport.name() : airport.iataCode(); 0186 } 0187 0188 static void fillFlightReservation(const QList<QVariant> &reservations, 0189 const KCalendarCore::Event::Ptr &event) { 0190 const auto flight = reservations.at(0).value<FlightReservation>().reservationFor().value<Flight>(); 0191 const auto airline = flight.airline(); 0192 const auto depPort = flight.departureAirport(); 0193 const auto arrPort = flight.arrivalAirport(); 0194 0195 const QString flightNumber = airline.iataCode() + QLatin1Char(' ') + flight.flightNumber(); 0196 0197 event->setSummary(i18n("Flight %1 from %2 to %3", flightNumber, airportDisplayCode(depPort), airportDisplayCode(arrPort))); 0198 event->setLocation(depPort.name()); 0199 fillGeoPosition(depPort, event); 0200 event->setDtStart(flight.departureTime()); 0201 event->setDtEnd(flight.arrivalTime()); 0202 event->setAllDay(false); 0203 0204 const auto boardingTime = flight.boardingTime(); 0205 const auto departureGate = flight.departureGate(); 0206 if (boardingTime.isValid()) { 0207 const auto startOffset = Duration(event->dtStart(), boardingTime); 0208 const auto existinAlarms = event->alarms(); 0209 const auto it = std::find_if(existinAlarms.begin(), existinAlarms.end(), [startOffset](const Alarm::Ptr &other) { 0210 return other->startOffset() == startOffset; 0211 }); 0212 if (it == existinAlarms.end()) { 0213 Alarm::Ptr alarm(new Alarm(event.data())); 0214 alarm->setStartOffset(Duration(event->dtStart(), boardingTime)); 0215 if (departureGate.isEmpty()) { 0216 alarm->setDisplayAlarm(i18n("Boarding for flight %1", flightNumber)); 0217 } else { 0218 alarm->setDisplayAlarm(i18n("Boarding for flight %1 at gate %2", flightNumber, departureGate)); 0219 } 0220 alarm->setEnabled(true); 0221 event->addAlarm(alarm); 0222 } 0223 } 0224 0225 QStringList desc; 0226 if (boardingTime.isValid()) { 0227 desc.push_back(i18n("Boarding time: %1", QLocale().toString(boardingTime.time(), QLocale::ShortFormat))); 0228 } 0229 if (!departureGate.isEmpty()) { 0230 desc.push_back(i18nc("flight departure gate", "Departure gate: %1", departureGate)); 0231 } 0232 0233 for (const auto &r : reservations) { 0234 const auto reservation = r.value<FlightReservation>(); 0235 const auto person = reservation.underName().value<KItinerary::Person>(); 0236 if (!person.name().isEmpty()) { 0237 desc.push_back(person.name()); 0238 } 0239 if (!reservation.boardingGroup().isEmpty()) { 0240 desc.push_back(i18n("Boarding group: %1", reservation.boardingGroup())); 0241 } 0242 if (!reservation.airplaneSeat().isEmpty()) { 0243 desc.push_back(i18n("Seat: %1", reservation.airplaneSeat())); 0244 } 0245 if (!reservation.reservationNumber().isEmpty()) { 0246 desc.push_back(i18n("Booking reference: %1", reservation.reservationNumber())); 0247 } 0248 } 0249 event->setDescription(desc.join(QLatin1Char('\n'))); 0250 } 0251 0252 static void fillTrainReservation(const TrainReservation &reservation, const KCalendarCore::Event::Ptr &event) 0253 { 0254 const auto trip = reservation.reservationFor().value<TrainTrip>(); 0255 const auto depStation = trip.departureStation(); 0256 const auto arrStation = trip.arrivalStation(); 0257 0258 event->setSummary(i18n("Train %1 from %2 to %3", trip.trainNumber(), depStation.name(), arrStation.name())); 0259 event->setLocation(depStation.name()); 0260 fillGeoPosition(depStation, event); 0261 event->setDtStart(trip.departureTime()); 0262 event->setDtEnd(trip.arrivalTime()); 0263 event->setAllDay(false); 0264 0265 QStringList desc; 0266 if (!trip.departurePlatform().isEmpty()) { 0267 desc.push_back(i18n("Departure platform: %1", trip.departurePlatform())); 0268 } 0269 const auto ticket = reservation.reservedTicket().value<Ticket>(); 0270 const auto seat = ticket.ticketedSeat(); 0271 if (!seat.seatSection().isEmpty()) { 0272 desc.push_back(i18n("Coach: %1", seat.seatSection())); 0273 } 0274 if (!seat.seatNumber().isEmpty()) { 0275 desc.push_back(i18n("Seat: %1", seat.seatNumber())); 0276 } 0277 if (!trip.arrivalPlatform().isEmpty()) { 0278 desc.push_back(i18n("Arrival platform: %1", trip.arrivalPlatform())); 0279 } 0280 if (!reservation.reservationNumber().isEmpty()) { 0281 desc.push_back(i18n("Booking reference: %1", reservation.reservationNumber())); 0282 } 0283 event->setDescription(desc.join(QLatin1Char('\n'))); 0284 } 0285 0286 static void fillBusReservation(const BusReservation &reservation, const KCalendarCore::Event::Ptr &event) 0287 { 0288 const auto trip = reservation.reservationFor().value<BusTrip>(); 0289 const auto depStation = trip.departureBusStop(); 0290 const auto arrStation = trip.arrivalBusStop(); 0291 0292 event->setSummary(i18n("Bus %1 from %2 to %3", trip.busNumber(), depStation.name(), arrStation.name())); 0293 event->setLocation(depStation.name()); 0294 fillGeoPosition(depStation, event); 0295 event->setDtStart(trip.departureTime()); 0296 event->setDtEnd(trip.arrivalTime()); 0297 event->setAllDay(false); 0298 0299 QStringList desc; 0300 const auto ticket = reservation.reservedTicket().value<Ticket>(); 0301 const auto seat = ticket.ticketedSeat(); 0302 if (!seat.seatNumber().isEmpty()) { 0303 desc.push_back(i18n("Seat: %1", seat.seatNumber())); 0304 } 0305 if (!reservation.reservationNumber().isEmpty()) { 0306 desc.push_back(i18n("Booking reference: %1", reservation.reservationNumber())); 0307 } 0308 event->setDescription(desc.join(QLatin1Char('\n'))); 0309 } 0310 0311 static void fillBoatReservation(const KItinerary::BoatReservation &reservation, const KCalendarCore::Event::Ptr &event) 0312 { 0313 const auto trip = reservation.reservationFor().value<BoatTrip>(); 0314 const auto depTerminal = trip.departureBoatTerminal(); 0315 const auto arrTerminal = trip.arrivalBoatTerminal(); 0316 0317 event->setSummary(i18n("Ferry from %1 to %2", depTerminal.name(), arrTerminal.name())); 0318 event->setLocation(depTerminal.name()); 0319 fillGeoPosition(depTerminal, event); 0320 event->setDtStart(trip.departureTime()); 0321 event->setDtEnd(trip.arrivalTime()); 0322 event->setAllDay(false); 0323 0324 QStringList desc; 0325 const auto ticket = reservation.reservedTicket().value<Ticket>(); 0326 if (!reservation.reservationNumber().isEmpty()) { 0327 desc.push_back(i18n("Booking reference: %1", reservation.reservationNumber())); 0328 } 0329 if (!ticket.ticketNumber().isEmpty() && ticket.ticketNumber() != reservation.reservationNumber()) { 0330 desc.push_back(i18n("Ticket number: %1", ticket.ticketNumber())); 0331 } 0332 event->setDescription(desc.join(QLatin1Char('\n'))); 0333 } 0334 0335 static void fillLodgingReservation(const QList<QVariant> &reservations, 0336 const KCalendarCore::Event::Ptr &event) { 0337 const auto reservation = reservations.at(0).value<LodgingReservation>(); 0338 const auto lodgingBusiness = reservation.reservationFor().value<LodgingBusiness>(); 0339 0340 event->setSummary(i18n("Hotel reservation: %1", lodgingBusiness.name())); 0341 event->setLocation(formatAddressSingleLine(lodgingBusiness.address())); 0342 fillGeoPosition(lodgingBusiness, event); 0343 0344 event->setDtStart(QDateTime(reservation.checkinTime().date(), QTime())); 0345 event->setDtEnd(QDateTime(reservation.checkoutTime().date(), QTime())); 0346 event->setAllDay(true); 0347 event->setTransparency(KCalendarCore::Event::Transparent); 0348 0349 QStringList desc; 0350 if (reservation.checkinTime().isValid()) { 0351 desc.push_back(i18n("Check-in: %1", QLocale().toString(reservation.checkinTime().time(), QLocale::ShortFormat))); 0352 } 0353 if (reservation.checkoutTime().isValid()) { 0354 desc.push_back(i18n("Check-out: %1", QLocale().toString(reservation.checkoutTime().time(), QLocale::ShortFormat))); 0355 } 0356 if (!lodgingBusiness.telephone().isEmpty()) { 0357 desc.push_back(i18n("Phone: %1", lodgingBusiness.telephone())); 0358 } 0359 if (!lodgingBusiness.email().isEmpty()) { 0360 desc.push_back(i18n("Email: %1", lodgingBusiness.email())); 0361 } 0362 if (!lodgingBusiness.url().isEmpty()) { 0363 desc.push_back(i18n("Website: %1", lodgingBusiness.url().toString())); 0364 } 0365 0366 for (const auto &r : reservations) { 0367 const auto reservation = r.value<LodgingReservation>(); 0368 const auto person = reservation.underName().value<KItinerary::Person>(); 0369 if (!person.name().isEmpty()) { 0370 desc.push_back(person.name()); 0371 } 0372 if (!reservation.reservationNumber().isEmpty()) { 0373 desc.push_back(i18n("Booking reference: %1", reservation.reservationNumber())); 0374 } 0375 } 0376 event->setDescription(desc.join(QLatin1Char('\n'))); 0377 } 0378 0379 static void fillEvent(const KItinerary::Event &ev, const KCalendarCore::Event::Ptr &event) 0380 { 0381 Place location; 0382 if (JsonLd::canConvert<Place>(ev.location())) { 0383 location = JsonLd::convert<Place>(ev.location()); 0384 } 0385 0386 event->setSummary(ev.name()); 0387 event->setLocation(location.name()); 0388 fillGeoPosition(location, event); 0389 event->setDtStart(ev.startDate()); 0390 if (ev.endDate().isValid()) { 0391 event->setDtEnd(ev.endDate()); 0392 // QDate::endOfDay adds 999ms, while endDate has that truncated 0393 event->setAllDay(ev.startDate() == ev.startDate().date().startOfDay(ev.startDate().timeZone()) 0394 && std::abs(ev.endDate().secsTo(ev.endDate().date().endOfDay(ev.endDate().timeZone()))) <= 1); 0395 if (event->allDay()) { 0396 event->setDtStart(QDateTime(event->dtStart().date(), QTime())); 0397 event->setDtEnd(QDateTime(event->dtEnd().date(), QTime())); 0398 } 0399 } else { 0400 event->setDtEnd(ev.startDate().addSecs(3600)); 0401 event->setAllDay(false); 0402 } 0403 0404 if (ev.doorTime().isValid()) { 0405 const auto startOffset = Duration(event->dtStart(), ev.doorTime()); 0406 const auto existinAlarms = event->alarms(); 0407 const auto it = std::find_if(existinAlarms.begin(), existinAlarms.end(), [startOffset](const Alarm::Ptr &other) { 0408 return other->startOffset() == startOffset; 0409 }); 0410 if (it == existinAlarms.end()) { 0411 Alarm::Ptr alarm(new Alarm(event.data())); 0412 alarm->setStartOffset(Duration(event->dtStart(), ev.doorTime())); 0413 alarm->setDisplayAlarm(i18n("Entrance for %1", ev.name())); 0414 alarm->setEnabled(true); 0415 event->addAlarm(alarm); 0416 } 0417 } 0418 0419 event->setDescription(formatAddress(location.address()) + QLatin1Char('\n')); 0420 } 0421 0422 static void fillEventReservation(const QList<QVariant> &reservations, 0423 const KCalendarCore::Event::Ptr &event) { 0424 const auto ev = reservations.at(0).value<EventReservation>().reservationFor().value<KItinerary::Event>(); 0425 fillEvent(ev, event); 0426 0427 QStringList desc = { event->description() }; 0428 for (const auto &r : reservations) { 0429 const auto reservation = r.value<EventReservation>(); 0430 const auto person = reservation.underName().value<KItinerary::Person>(); 0431 if (!person.name().isEmpty()) { 0432 desc.push_back(person.name()); 0433 } 0434 // TODO: add seat information if present 0435 if (!reservation.reservationNumber().isEmpty()) { 0436 desc.push_back(i18n("Booking reference: %1", reservation.reservationNumber())); 0437 } 0438 } 0439 event->setDescription(desc.join(QLatin1Char('\n'))); 0440 } 0441 0442 static void fillGeoPosition(const QVariant &place, const KCalendarCore::Event::Ptr &event) 0443 { 0444 if (!JsonLd::canConvert<Place>(place)) { 0445 return; 0446 } 0447 const auto geo = JsonLd::convert<Place>(place).geo(); 0448 if (!geo.isValid()) { 0449 return; 0450 } 0451 0452 event->setGeoLatitude(geo.latitude()); 0453 event->setGeoLongitude(geo.longitude()); 0454 } 0455 0456 static void fillFoodReservation(const FoodEstablishmentReservation &reservation, const KCalendarCore::Event::Ptr &event) 0457 { 0458 const auto foodEstablishment = reservation.reservationFor().value<FoodEstablishment>(); 0459 0460 event->setSummary(i18n("Restaurant reservation: %1", foodEstablishment.name())); 0461 event->setLocation(formatAddressSingleLine(foodEstablishment.address())); 0462 fillGeoPosition(foodEstablishment, event); 0463 0464 event->setDtStart(reservation.startTime()); 0465 auto endTime = reservation.endTime(); 0466 if (!endTime.isValid()) { 0467 endTime = reservation.startTime().addSecs(7200); // if we have no end time, let's assume 2h 0468 } 0469 event->setDtEnd(endTime); 0470 event->setAllDay(false); 0471 0472 QStringList desc; 0473 if (reservation.partySize() > 0) { 0474 desc.push_back(i18n("Number of people: %1", reservation.partySize())); 0475 } 0476 if (!reservation.reservationNumber().isEmpty()) { 0477 desc.push_back(i18n("Booking reference: %1", reservation.reservationNumber())); 0478 } 0479 const auto person = reservation.underName().value<KItinerary::Person>(); 0480 if (!person.name().isEmpty()) { 0481 desc.push_back(i18n("Under name: %1", person.name())); 0482 } 0483 event->setDescription(desc.join(QLatin1Char('\n'))); 0484 } 0485 0486 static void fillRentalCarReservation(const RentalCarReservation &reservation, const KCalendarCore::Event::Ptr &event) 0487 { 0488 const auto rentalCalPickup = reservation.pickupLocation(); 0489 const auto addressPickUp = rentalCalPickup.address(); 0490 const auto rentalCar = reservation.reservationFor().value<RentalCar>(); 0491 event->setSummary(i18n("Rental car reservation: %1", rentalCar.name())); 0492 event->setLocation(rentalCalPickup.name()); 0493 fillGeoPosition(rentalCalPickup, event); 0494 0495 event->setDtStart(reservation.pickupTime()); 0496 event->setDtEnd(reservation.dropoffTime()); 0497 event->setAllDay(false); 0498 event->setTransparency(KCalendarCore::Event::Transparent); 0499 0500 QStringList desc; 0501 if (!addressPickUp.isEmpty()) { 0502 desc.push_back(i18n("Pickup location: %1\n%2\n", rentalCalPickup.name(), formatAddress(addressPickUp))); 0503 } 0504 const auto dropOff = reservation.dropoffLocation(); 0505 if (!dropOff.name().isEmpty()) { 0506 desc.push_back(i18n("Dropoff location: %1\n%2\n", dropOff.name(), formatAddress(dropOff.address()))); 0507 } 0508 if (!reservation.reservationNumber().isEmpty()) { 0509 desc.push_back(i18n("Booking reference: %1", reservation.reservationNumber())); 0510 } 0511 const auto person = reservation.underName().value<KItinerary::Person>(); 0512 if (!person.name().isEmpty()) { 0513 desc.push_back(i18n("Under name: %1", person.name())); 0514 } 0515 0516 event->setDescription(desc.join(QLatin1Char('\n'))); 0517 } 0518 0519 static void fillTaxiReservation(const TaxiReservation &reservation, const KCalendarCore::Event::Ptr &event) 0520 { 0521 const auto taxiPickup = reservation.pickupLocation(); 0522 const auto addressPickUp = taxiPickup.address(); 0523 //TODO const auto rentalCar = reservation.reservationFor().value<RentalCar>(); 0524 //TODO event->setSummary(i18n("Rental Car reservation: %1", rentalCar.name())); 0525 event->setLocation(formatAddressSingleLine(addressPickUp)); 0526 fillGeoPosition(taxiPickup, event); 0527 0528 event->setDtStart(reservation.pickupTime()); 0529 //TODO event->setDtEnd(reservation.dropoffTime()); 0530 event->setAllDay(false); 0531 event->setTransparency(KCalendarCore::Event::Transparent); 0532 //TODO event->setSummary(i18n("Rent car reservation: %1", rentalCar.name())); 0533 const QString pickUpAddress = formatAddress(addressPickUp); 0534 0535 const QString description = i18n("Reservation reference: %1\nUnder name: %2\nPickup location: %3", 0536 reservation.reservationNumber(), 0537 reservation.underName().value<KItinerary::Person>().name(), 0538 pickUpAddress); 0539 0540 event->setDescription(description); 0541 } 0542