KPublicTransport

stopoverquerymodel.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 "stopoverquerymodel.h"
8#include "abstractquerymodel_p.h"
9#include "logging.h"
10#include "datatypes/stopoverutil_p.h"
11
12#include <KPublicTransport/Attribution>
13#include <KPublicTransport/Manager>
14#include <KPublicTransport/Stopover>
15#include <KPublicTransport/StopoverReply>
16
17#include <QDateTime>
18#include <QDebug>
19
20using namespace KPublicTransport;
21
22namespace KPublicTransport {
23class StopoverQueryModelPrivate : public AbstractQueryModelPrivate
24{
25public:
26 void doQuery() override;
27 void doClearResults() override;
28 void mergeResults(const std::vector<Stopover> &newDepartures);
29
30 std::vector<Stopover> m_departures;
31
32 StopoverRequest m_request;
33 StopoverRequest m_nextRequest;
34 StopoverRequest m_prevRequest;
35
36 Q_DECLARE_PUBLIC(StopoverQueryModel)
37};
38}
39
40void StopoverQueryModelPrivate::doQuery()
41{
43 if (!m_manager || !m_request.isValid()) {
44 return;
45 }
46
47 setLoading(true);
48 m_nextRequest = {};
49 m_prevRequest = {};
50 Q_EMIT q->canQueryPrevNextChanged();
51
52 auto reply = m_manager->queryStopover(m_request);
53 monitorReply(reply);
55 if (reply->error() == KPublicTransport::StopoverReply::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 StopoverQueryModelPrivate::doClearResults()
67{
68 m_departures.clear();
69}
70
71void StopoverQueryModelPrivate::mergeResults(const std::vector<Stopover> &newDepartures)
72{
74 for (const auto &dep : newDepartures) {
75 auto it = std::lower_bound(m_departures.begin(), m_departures.end(), dep, [this](const auto &lhs, const auto &rhs) {
76 return StopoverUtil::timeLessThan(m_request, lhs, rhs);
77 });
78
79 bool found = false;
80 while (it != m_departures.end() && StopoverUtil::timeEqual(m_request, dep, *it)) {
81 if (Stopover::isSame(dep, *it)) {
82 *it = Stopover::merge(*it, dep);
83 found = true;
84 const auto row = std::distance(m_departures.begin(), it);
85 const auto idx = q->index(row, 0);
86 Q_EMIT q->dataChanged(idx, idx);
87 break;
88 } else {
89 ++it;
90 }
91 }
92 if (found) {
93 continue;
94 }
95
96 const auto row = std::distance(m_departures.begin(), it);
97 q->beginInsertRows({}, row, row);
98 m_departures.insert(it, dep);
99 q->endInsertRows();
100 }
101}
102
103
104StopoverQueryModel::StopoverQueryModel(QObject *parent)
105 : AbstractQueryModel(new StopoverQueryModelPrivate, parent)
106{
107 connect(this, &AbstractQueryModel::loadingChanged, this, &StopoverQueryModel::canQueryPrevNextChanged);
108}
109
110StopoverQueryModel::~StopoverQueryModel() = default;
111
113{
114 Q_D(const StopoverQueryModel);
115 return d->m_request;
116}
117
118void StopoverQueryModel::setRequest(const StopoverRequest &req)
119{
121 d->m_request = req;
122 Q_EMIT requestChanged();
123 d->query();
124}
125
127{
128 Q_D(const StopoverQueryModel);
129 return !d->m_loading && !d->m_departures.empty() && d->m_nextRequest.isValid();
130}
131
133{
135 if (!canQueryNext()) {
136 qCWarning(Log) << "Cannot query next journeys";
137 return;
138 }
139
140 d->setLoading(true);
141 auto reply = d->m_manager->queryStopover(d->m_nextRequest);
142 d->monitorReply(reply);
145 if (reply->error() == KPublicTransport::StopoverReply::NoError) {
146 d->m_nextRequest = reply->nextRequest();
147 } else {
148 d->m_nextRequest = {};
149 }
150 Q_EMIT canQueryPrevNextChanged();
151 });
152 QObject::connect(reply, &KPublicTransport::StopoverReply::updated, this, [reply, this]() {
154 d->mergeResults(reply->takeResult());
155 });
156}
157
159{
160 Q_D(const StopoverQueryModel);
161 return !d->m_loading && !d->m_departures.empty() && d->m_prevRequest.isValid();
162}
163
165{
167 if (!canQueryPrevious()) {
168 qCWarning(Log) << "Cannot query previous journeys";
169 return;
170 }
171
172 d->setLoading(true);
173 auto reply = d->m_manager->queryStopover(d->m_prevRequest);
174 d->monitorReply(reply);
177 if (reply->error() == KPublicTransport::StopoverReply::NoError) {
178 d->m_prevRequest = reply->previousRequest();
179 } else {
180 d->m_prevRequest = {};
181 }
182 Q_EMIT canQueryPrevNextChanged();
183 });
184 QObject::connect(reply, &KPublicTransport::StopoverReply::updated, this, [reply, this]() {
186 d->mergeResults(reply->takeResult());
187 });
188}
189
190int StopoverQueryModel::rowCount(const QModelIndex& parent) const
191{
192 Q_D(const StopoverQueryModel);
193 if (parent.isValid()) {
194 return 0;
195 }
196 return d->m_departures.size();
197}
198
199QVariant StopoverQueryModel::data(const QModelIndex& index, int role) const
200{
201 Q_D(const StopoverQueryModel);
202 if (!index.isValid()) {
203 return {};
204 }
205
206 switch (role) {
207 case DepartureRole:
208 return QVariant::fromValue(d->m_departures[index.row()]);
209 }
210
211 return {};
212}
213
214QHash<int, QByteArray> StopoverQueryModel::roleNames() const
215{
217 r.insert(DepartureRole, "departure");
218 return r;
219}
220
221const std::vector<Stopover>& StopoverQueryModel::departures() const
222{
223 Q_D(const StopoverQueryModel);
224 return d->m_departures;
225}
226
227#include "moc_stopoverquerymodel.moc"
Common base class for query models, do not use directly.
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
Model representing arrival or departure query results.
bool canQueryNext
Whether querying for later departures is possible.
KPublicTransport::StopoverRequest request
Specify the actual departure query.
Q_INVOKABLE void queryNext()
Search for later journeys.
bool canQueryPrevious
Whether querying for earlier journey is possible.
Q_INVOKABLE void queryPrevious()
Search for earlier journeys.
const std::vector< Stopover > & departures() const
The current model content.
Describes an arrival or departure search.
bool isValid() const
Returns true if this is a valid request, ie.
static Stopover merge(const Stopover &lhs, const Stopover &rhs)
Merge two departure instances.
Definition stopover.cpp:189
static bool isSame(const Stopover &lhs, const Stopover &rhs)
Checks if to instances refer to the same departure (which does not necessarily mean they are exactly ...
Definition stopover.cpp:159
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 Tue Mar 26 2024 11:13:06 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.