File indexing completed on 2025-02-02 05:02:27
0001 /* 0002 SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org> 0003 SPDX-License-Identifier: LGPL-2.0-or-later 0004 */ 0005 0006 #include "calendarimportmodel.h" 0007 0008 #include <KItinerary/Event> 0009 #include <KItinerary/ExtractorEngine> 0010 #include <KItinerary/ExtractorPostprocessor> 0011 #include <KItinerary/ExtractorValidator> 0012 #include <KItinerary/JsonLdDocument> 0013 #include <KItinerary/Reservation> 0014 #include <KItinerary/Visit> 0015 0016 #include <QDebug> 0017 #include <QJsonArray> 0018 0019 CalendarImportModel::CalendarImportModel(QObject *parent) 0020 : QAbstractListModel(parent) 0021 { 0022 qRegisterMetaType<QVector<QVariant>>(); 0023 } 0024 0025 CalendarImportModel::~CalendarImportModel() = default; 0026 0027 KCalendarCore::Calendar* CalendarImportModel::calendar() const 0028 { 0029 return m_calendar; 0030 } 0031 0032 void CalendarImportModel::setCalendar(KCalendarCore::Calendar *calendar) 0033 { 0034 if (m_calendar == calendar) { 0035 return; 0036 } 0037 0038 if (m_calendar) { 0039 disconnect(m_calendar, nullptr, this, nullptr); 0040 } 0041 0042 m_calendar = calendar; 0043 Q_EMIT calendarChanged(); 0044 if (!m_calendar) { 0045 return; 0046 } 0047 0048 if (!m_calendar->isLoading()) { 0049 reload(); 0050 } else { 0051 connect(m_calendar, &KCalendarCore::Calendar::isLoadingChanged, this, &CalendarImportModel::reload); 0052 } 0053 } 0054 0055 QVector<QVariant> CalendarImportModel::selectedReservations() const 0056 { 0057 QVector<QVariant> res; 0058 for (const auto &ev : m_events) { 0059 if (!ev.selected) { 0060 continue; 0061 } 0062 std::copy(ev.data.begin(), ev.data.end(), std::back_inserter(res)); 0063 } 0064 return res; 0065 } 0066 0067 int CalendarImportModel::rowCount(const QModelIndex &parent) const 0068 { 0069 if (parent.isValid()) { 0070 return 0; 0071 } 0072 0073 return m_events.size(); 0074 } 0075 0076 QVariant CalendarImportModel::data(const QModelIndex &index, int role) const 0077 { 0078 using namespace KItinerary; 0079 if (!checkIndex(index)) { 0080 return {}; 0081 } 0082 0083 const auto &ev = m_events[index.row()]; 0084 switch (role) { 0085 case TitleRole: 0086 return ev.event->summary(); 0087 case SubtitleRole: 0088 return QLocale().toString(ev.event->dtStart()); 0089 case IconNameRole: 0090 if (!ev.data.isEmpty()) { 0091 const auto res = ev.data.at(0); 0092 if (JsonLd::isA<FlightReservation>(res)) { 0093 return QStringLiteral("qrc:///images/flight.svg"); 0094 } 0095 if (JsonLd::isA<TrainReservation>(res)) { 0096 return QStringLiteral("qrc:///images/train.svg"); 0097 } 0098 if (JsonLd::isA<BusReservation>(res)) { 0099 return QStringLiteral("qrc:///images/bus.svg"); 0100 } 0101 if (JsonLd::isA<BoatReservation>(res)) { 0102 return QStringLiteral("qrc:///images/ferry.svg"); 0103 } 0104 if (JsonLd::isA<LodgingReservation>(res)) { 0105 return QStringLiteral("go-home-symbolic"); 0106 } 0107 if (JsonLd::isA<FoodEstablishmentReservation>(res)) { 0108 return QStringLiteral("qrc:///images/foodestablishment.svg"); 0109 } 0110 if (JsonLd::isA<RentalCarReservation>(res)) { 0111 return QStringLiteral("qrc:///images/car.svg"); 0112 } 0113 } 0114 return QStringLiteral("meeting-attending"); 0115 case ReservationsRole: 0116 return QVariant::fromValue(ev.data); 0117 case SelectedRole: 0118 return ev.selected; 0119 } 0120 0121 return {}; 0122 } 0123 0124 bool CalendarImportModel::setData(const QModelIndex &index, const QVariant &value, int role) 0125 { 0126 auto &ev = m_events[index.row()]; 0127 switch (role) { 0128 case SelectedRole: 0129 ev.selected = value.toBool(); 0130 Q_EMIT dataChanged(index, index); 0131 Q_EMIT hasSelectionChanged(); 0132 return true; 0133 } 0134 return false; 0135 } 0136 0137 QHash<int, QByteArray> CalendarImportModel::roleNames() const 0138 { 0139 auto n = QAbstractListModel::roleNames(); 0140 n.insert(TitleRole, "title"); 0141 n.insert(SubtitleRole, "subtitle"); 0142 n.insert(IconNameRole, "iconName"); 0143 n.insert(ReservationsRole, "reservations"); 0144 n.insert(SelectedRole, "selected"); 0145 return n; 0146 } 0147 0148 bool CalendarImportModel::hasSelection() const 0149 { 0150 return std::any_of(m_events.begin(), m_events.end(), [](const auto &ev) { return ev.selected; }); 0151 } 0152 0153 void CalendarImportModel::reload() 0154 { 0155 beginResetModel(); 0156 m_events.clear(); 0157 0158 KItinerary::ExtractorEngine extractorEngine; 0159 extractorEngine.setHints(KItinerary::ExtractorEngine::ExtractGenericIcalEvents); 0160 0161 KItinerary::ExtractorValidator validator; 0162 validator.setAcceptedTypes< 0163 KItinerary::BoatReservation, 0164 KItinerary::BusReservation, 0165 KItinerary::Event, 0166 KItinerary::EventReservation, 0167 KItinerary::FlightReservation, 0168 KItinerary::FoodEstablishmentReservation, 0169 KItinerary::LodgingReservation, 0170 KItinerary::RentalCarReservation, 0171 KItinerary::TrainReservation, 0172 KItinerary::TouristAttractionVisit 0173 >(); 0174 0175 auto calEvents = m_calendar->events(today().addDays(-5), today().addDays(180)); 0176 calEvents = m_calendar->sortEvents(std::move(calEvents), KCalendarCore::EventSortStartDate, KCalendarCore::SortDirectionAscending); 0177 for (const auto &ev : std::as_const(calEvents)) { 0178 extractorEngine.clear(); 0179 extractorEngine.setContent(QVariant::fromValue(ev), u"internal/event"); 0180 KItinerary::ExtractorPostprocessor postProc; 0181 postProc.process(KItinerary::JsonLdDocument::fromJson(extractorEngine.extract())); 0182 auto res = postProc.result(); 0183 res.erase(std::remove_if(res.begin(), res.end(), [&validator](const auto &elem) { return !validator.isValidElement(elem); }), res.end()); 0184 if (res.empty()) { 0185 continue; 0186 } 0187 0188 const auto isReservation = !KItinerary::JsonLd::isA<KItinerary::Event>(res.at(0)); 0189 m_events.push_back({ev, res, isReservation}); 0190 } 0191 0192 endResetModel(); 0193 0194 Q_EMIT hasSelectionChanged(); 0195 } 0196 0197 QDate CalendarImportModel::today() const 0198 { 0199 if (Q_UNLIKELY(m_todayOverride.isValid())) { 0200 return m_todayOverride; 0201 } 0202 return QDate::currentDate(); 0203 } 0204 0205 #include "moc_calendarimportmodel.cpp"