KPublicTransport

journeyquerymodel.cpp
1/*
2 SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "journeyquerymodel.h"
8#include "abstractquerymodel_p.h"
9#include "logging.h"
10#include "../datatypes/journeyutil_p.h"
11
12#include <KPublicTransport/Attribution>
13#include <KPublicTransport/Journey>
14#include <KPublicTransport/JourneyReply>
15#include <KPublicTransport/Manager>
16
17#include <QDebug>
18
19using namespace KPublicTransport;
20
21namespace KPublicTransport {
22class JourneyQueryModelPrivate : public AbstractQueryModelPrivate
23{
24public:
25 void doQuery() override;
26 void doClearResults() override;
27 void mergeResults(const std::vector<Journey> &newJourneys);
28
29 std::vector<Journey> m_journeys;
30
31 JourneyRequest m_request;
32 JourneyRequest m_nextRequest;
33 JourneyRequest m_prevRequest;
34
35 Q_DECLARE_PUBLIC(JourneyQueryModel)
36};
37}
38
39void JourneyQueryModelPrivate::doQuery()
40{
42 if (!m_manager || !m_request.isValid()) {
43 return;
44 }
45
46 setLoading(true);
47 m_nextRequest = {};
48 m_prevRequest = {};
49 Q_EMIT q->canQueryPrevNextChanged();
50
51 auto reply = m_manager->queryJourney(m_request);
52 monitorReply(reply);
55 if (reply->error() == KPublicTransport::JourneyReply::NoError) {
56 m_nextRequest = reply->nextRequest();
57 m_prevRequest = reply->previousRequest();
58 Q_EMIT q->canQueryPrevNextChanged();
59 }
60 });
62 mergeResults(reply->takeResult());
63 });
64}
65
66void JourneyQueryModelPrivate::doClearResults()
67{
68 m_journeys.clear();
69}
70
71void JourneyQueryModelPrivate::mergeResults(const std::vector<Journey> &newJourneys)
72{
74 for (const auto &jny : newJourneys) {
75 auto it = std::lower_bound(m_journeys.begin(), m_journeys.end(), jny, JourneyUtil::firstTransportDepartureLessThan);
76
77 bool found = false;
78 while (it != m_journeys.end() && JourneyUtil::firstTransportDepartureEqual(jny, *it)) {
79 if (Journey::isSame(jny, *it)) {
80 *it = Journey::merge(*it, jny);
81 found = true;
82 const auto row = std::distance(m_journeys.begin(), it);
83 const auto idx = q->index(row, 0);
84 Q_EMIT q->dataChanged(idx, idx);
85 break;
86 } else {
87 ++it;
88 }
89 }
90 if (found) {
91 continue;
92 }
93
94 const auto row = std::distance(m_journeys.begin(), it);
95 q->beginInsertRows({}, row, row);
96 m_journeys.insert(it, jny);
97 q->endInsertRows();
98 }
99}
100
101
102JourneyQueryModel::JourneyQueryModel(QObject *parent)
103 : AbstractQueryModel(new JourneyQueryModelPrivate, parent)
104{
105 connect(this, &AbstractQueryModel::loadingChanged, this, &JourneyQueryModel::canQueryPrevNextChanged);
106}
107
108JourneyQueryModel::~JourneyQueryModel() = default;
109
111{
112 Q_D(const JourneyQueryModel);
113 return d->m_request;
114}
115
117{
119 d->m_request = req;
120 Q_EMIT requestChanged();
121 d->query();
122}
123
125{
126 Q_D(const JourneyQueryModel);
127 return !d->m_loading && !d->m_journeys.empty() && d->m_nextRequest.isValid();
128}
129
131{
133 if (!canQueryNext()) {
134 qCWarning(Log) << "Cannot query next journeys";
135 return;
136 }
137
138 d->setLoading(true);
139 auto reply = d->m_manager->queryJourney(d->m_nextRequest);
140 d->monitorReply(reply);
143 if (reply->error() == KPublicTransport::JourneyReply::NoError) {
144 d->m_nextRequest = reply->nextRequest();
145 } else {
146 d->m_nextRequest = {};
147 }
148 Q_EMIT canQueryPrevNextChanged();
149 });
150 QObject::connect(reply, &KPublicTransport::JourneyReply::updated, this, [reply, this]() {
152 d->mergeResults(reply->takeResult());
153 });
154}
155
157{
158 Q_D(const JourneyQueryModel);
159 return !d->m_loading && !d->m_journeys.empty() && d->m_prevRequest.isValid();
160}
161
163{
165 if (!canQueryPrevious()) {
166 qCWarning(Log) << "Cannot query previous journeys";
167 return;
168 }
169
170 d->setLoading(true);
171 auto reply = d->m_manager->queryJourney(d->m_prevRequest);
172 d->monitorReply(reply);
175 if (reply->error() == KPublicTransport::JourneyReply::NoError) {
176 d->m_prevRequest = reply->previousRequest();
177 } else {
178 d->m_prevRequest = {};
179 }
180 Q_EMIT canQueryPrevNextChanged();
181 });
182 QObject::connect(reply, &KPublicTransport::JourneyReply::updated, this, [reply, this]() {
184 d->mergeResults(reply->takeResult());
185 });
186}
187
188int JourneyQueryModel::rowCount(const QModelIndex& parent) const
189{
190 Q_D(const JourneyQueryModel);
191 if (parent.isValid()) {
192 return 0;
193 }
194 return d->m_journeys.size();
195}
196
197QVariant JourneyQueryModel::data(const QModelIndex& index, int role) const
198{
199 Q_D(const JourneyQueryModel);
200 if (!index.isValid()) {
201 return {};
202 }
203
204 const auto jny = d->m_journeys[index.row()];
205 switch (role) {
206 case JourneyRole:
207 return QVariant::fromValue(jny);
208 case ScheduledDepartureTime:
209 return jny.scheduledDepartureTime();
210 case ScheduledArrivalTime:
211 return jny.scheduledArrivalTime();
213 return jny.scheduledDepartureTime().date();
214 }
215
216 return {};
217}
218
219QHash<int, QByteArray> JourneyQueryModel::roleNames() const
220{
222 r.insert(JourneyRole, "journey");
223 r.insert(ScheduledDepartureTime, "scheduledDepartureTime");
224 r.insert(ScheduledArrivalTime, "scheduledArrivalTime");
225 r.insert(ScheduledDepartureDate, "scheduledDepartureDate");
226 return r;
227}
228
229const std::vector<Journey>& JourneyQueryModel::journeys() const
230{
231 Q_D(const JourneyQueryModel);
232 return d->m_journeys;
233}
234
235#include "moc_journeyquerymodel.cpp"
Common base class for query models, do not use directly.
Model representing journey query results.
void setRequest(const JourneyRequest &req)
Specify the actual journey query.
bool canQueryPrevious
Whether querying for earlier journey is possible.
bool canQueryNext
Whether querying for later journeys is possible.
const std::vector< Journey > & journeys() const
The current model content.
KPublicTransport::JourneyRequest request
Specify the requested journey.
@ ScheduledDepartureDate
Useful for creating sections.
Q_INVOKABLE void queryPrevious()
Search for earlier journeys.
Q_INVOKABLE void queryNext()
Search for later journeys.
Describes a journey search.
bool isValid() const
Returns true if this is a valid request, that is, it has enough parameters set to perform a query.
static bool isSame(const Journey &lhs, const Journey &rhs)
Checks if two instances refer to the same journey (which does not necessarily mean they are exactly e...
Definition journey.cpp:803
static Journey merge(const Journey &lhs, const Journey &rhs)
Merge two instances.
Definition journey.cpp:835
void finished()
Emitted whenever the corresponding search has been completed.
void updated()
Emitted whenever new results are available, even before the search has been completed.
@ NoError
Nothing went wrong.
Definition reply.h:32
Query operations and data types for accessing realtime public transport information from online servi...
virtual QHash< int, QByteArray > roleNames() const const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
bool isValid() const const
int row() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QVariant fromValue(T &&value)
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:07:52 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.