File indexing completed on 2024-05-12 04:42:52
0001 /* 0002 SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "journeyquerymodel.h" 0008 #include "abstractquerymodel_p.h" 0009 #include "logging.h" 0010 #include "../datatypes/journeyutil_p.h" 0011 0012 #include <KPublicTransport/Attribution> 0013 #include <KPublicTransport/Journey> 0014 #include <KPublicTransport/JourneyReply> 0015 #include <KPublicTransport/Manager> 0016 0017 #include <QDebug> 0018 0019 using namespace KPublicTransport; 0020 0021 namespace KPublicTransport { 0022 class JourneyQueryModelPrivate : public AbstractQueryModelPrivate 0023 { 0024 public: 0025 void doQuery() override; 0026 void doClearResults() override; 0027 void mergeResults(const std::vector<Journey> &newJourneys); 0028 0029 std::vector<Journey> m_journeys; 0030 0031 JourneyRequest m_request; 0032 JourneyRequest m_nextRequest; 0033 JourneyRequest m_prevRequest; 0034 0035 Q_DECLARE_PUBLIC(JourneyQueryModel) 0036 }; 0037 } 0038 0039 void JourneyQueryModelPrivate::doQuery() 0040 { 0041 Q_Q(JourneyQueryModel); 0042 if (!m_manager || !m_request.isValid()) { 0043 return; 0044 } 0045 0046 setLoading(true); 0047 m_nextRequest = {}; 0048 m_prevRequest = {}; 0049 Q_EMIT q->canQueryPrevNextChanged(); 0050 0051 auto reply = m_manager->queryJourney(m_request); 0052 monitorReply(reply); 0053 QObject::connect(reply, &KPublicTransport::JourneyReply::finished, q, [reply, this] { 0054 Q_Q(JourneyQueryModel); 0055 if (reply->error() == KPublicTransport::JourneyReply::NoError) { 0056 m_nextRequest = reply->nextRequest(); 0057 m_prevRequest = reply->previousRequest(); 0058 Q_EMIT q->canQueryPrevNextChanged(); 0059 } 0060 }); 0061 QObject::connect(reply, &KPublicTransport::JourneyReply::updated, q, [reply, this]() { 0062 mergeResults(reply->takeResult()); 0063 }); 0064 } 0065 0066 void JourneyQueryModelPrivate::doClearResults() 0067 { 0068 m_journeys.clear(); 0069 } 0070 0071 void JourneyQueryModelPrivate::mergeResults(const std::vector<Journey> &newJourneys) 0072 { 0073 Q_Q(JourneyQueryModel); 0074 for (const auto &jny : newJourneys) { 0075 auto it = std::lower_bound(m_journeys.begin(), m_journeys.end(), jny, JourneyUtil::firstTransportDepartureLessThan); 0076 0077 bool found = false; 0078 while (it != m_journeys.end() && JourneyUtil::firstTransportDepartureEqual(jny, *it)) { 0079 if (Journey::isSame(jny, *it)) { 0080 *it = Journey::merge(*it, jny); 0081 found = true; 0082 const auto row = std::distance(m_journeys.begin(), it); 0083 const auto idx = q->index(row, 0); 0084 Q_EMIT q->dataChanged(idx, idx); 0085 break; 0086 } else { 0087 ++it; 0088 } 0089 } 0090 if (found) { 0091 continue; 0092 } 0093 0094 const auto row = std::distance(m_journeys.begin(), it); 0095 q->beginInsertRows({}, row, row); 0096 m_journeys.insert(it, jny); 0097 q->endInsertRows(); 0098 } 0099 } 0100 0101 0102 JourneyQueryModel::JourneyQueryModel(QObject *parent) 0103 : AbstractQueryModel(new JourneyQueryModelPrivate, parent) 0104 { 0105 connect(this, &AbstractQueryModel::loadingChanged, this, &JourneyQueryModel::canQueryPrevNextChanged); 0106 } 0107 0108 JourneyQueryModel::~JourneyQueryModel() = default; 0109 0110 JourneyRequest JourneyQueryModel::request() const 0111 { 0112 Q_D(const JourneyQueryModel); 0113 return d->m_request; 0114 } 0115 0116 void JourneyQueryModel::setRequest(const JourneyRequest &req) 0117 { 0118 Q_D(JourneyQueryModel); 0119 d->m_request = req; 0120 Q_EMIT requestChanged(); 0121 d->query(); 0122 } 0123 0124 bool JourneyQueryModel::canQueryNext() const 0125 { 0126 Q_D(const JourneyQueryModel); 0127 return !d->m_loading && !d->m_journeys.empty() && d->m_nextRequest.isValid(); 0128 } 0129 0130 void JourneyQueryModel::queryNext() 0131 { 0132 Q_D(JourneyQueryModel); 0133 if (!canQueryNext()) { 0134 qCWarning(Log) << "Cannot query next journeys"; 0135 return; 0136 } 0137 0138 d->setLoading(true); 0139 auto reply = d->m_manager->queryJourney(d->m_nextRequest); 0140 d->monitorReply(reply); 0141 QObject::connect(reply, &KPublicTransport::JourneyReply::finished, this, [reply, this] { 0142 Q_D(JourneyQueryModel); 0143 if (reply->error() == KPublicTransport::JourneyReply::NoError) { 0144 d->m_nextRequest = reply->nextRequest(); 0145 } else { 0146 d->m_nextRequest = {}; 0147 } 0148 Q_EMIT canQueryPrevNextChanged(); 0149 }); 0150 QObject::connect(reply, &KPublicTransport::JourneyReply::updated, this, [reply, this]() { 0151 Q_D(JourneyQueryModel); 0152 d->mergeResults(reply->takeResult()); 0153 }); 0154 } 0155 0156 bool JourneyQueryModel::canQueryPrevious() const 0157 { 0158 Q_D(const JourneyQueryModel); 0159 return !d->m_loading && !d->m_journeys.empty() && d->m_prevRequest.isValid(); 0160 } 0161 0162 void JourneyQueryModel::queryPrevious() 0163 { 0164 Q_D(JourneyQueryModel); 0165 if (!canQueryPrevious()) { 0166 qCWarning(Log) << "Cannot query previous journeys"; 0167 return; 0168 } 0169 0170 d->setLoading(true); 0171 auto reply = d->m_manager->queryJourney(d->m_prevRequest); 0172 d->monitorReply(reply); 0173 QObject::connect(reply, &KPublicTransport::JourneyReply::finished, this, [reply, this] { 0174 Q_D(JourneyQueryModel); 0175 if (reply->error() == KPublicTransport::JourneyReply::NoError) { 0176 d->m_prevRequest = reply->previousRequest(); 0177 } else { 0178 d->m_prevRequest = {}; 0179 } 0180 Q_EMIT canQueryPrevNextChanged(); 0181 }); 0182 QObject::connect(reply, &KPublicTransport::JourneyReply::updated, this, [reply, this]() { 0183 Q_D(JourneyQueryModel); 0184 d->mergeResults(reply->takeResult()); 0185 }); 0186 } 0187 0188 int JourneyQueryModel::rowCount(const QModelIndex& parent) const 0189 { 0190 Q_D(const JourneyQueryModel); 0191 if (parent.isValid()) { 0192 return 0; 0193 } 0194 return d->m_journeys.size(); 0195 } 0196 0197 QVariant JourneyQueryModel::data(const QModelIndex& index, int role) const 0198 { 0199 Q_D(const JourneyQueryModel); 0200 if (!index.isValid()) { 0201 return {}; 0202 } 0203 0204 const auto jny = d->m_journeys[index.row()]; 0205 switch (role) { 0206 case JourneyRole: 0207 return QVariant::fromValue(jny); 0208 case ScheduledDepartureTime: 0209 return jny.scheduledDepartureTime(); 0210 case ScheduledArrivalTime: 0211 return jny.scheduledArrivalTime(); 0212 } 0213 0214 return {}; 0215 } 0216 0217 QHash<int, QByteArray> JourneyQueryModel::roleNames() const 0218 { 0219 auto r = QAbstractListModel::roleNames(); 0220 r.insert(JourneyRole, "journey"); 0221 r.insert(ScheduledDepartureTime, "scheduledDepartureTime"); 0222 r.insert(ScheduledArrivalTime, "scheduledArrivalTime"); 0223 return r; 0224 } 0225 0226 const std::vector<Journey>& JourneyQueryModel::journeys() const 0227 { 0228 Q_D(const JourneyQueryModel); 0229 return d->m_journeys; 0230 } 0231 0232 #include "moc_journeyquerymodel.cpp"