KPublicTransport

stopoverreply.cpp
1 /*
2  SPDX-FileCopyrightText: 2018 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "stopoverreply.h"
8 #include "logging.h"
9 #include "reply_p.h"
10 #include "requestcontext_p.h"
11 #include "stopoverrequest.h"
12 #include "backends/abstractbackend.h"
13 #include "backends/cache.h"
14 #include "datatypes/stopoverutil_p.h"
15 
16 #include <KPublicTransport/Stopover>
17 
18 #include <QNetworkReply>
19 
20 using namespace KPublicTransport;
21 
22 namespace KPublicTransport {
23 class StopoverReplyPrivate : public ReplyPrivate {
24 public:
25  void finalizeResult() override;
26  bool needToWaitForAssets() const override;
27 
28  StopoverRequest request;
29  StopoverRequest nextRequest;
30  StopoverRequest prevRequest;
31  std::vector<Stopover> result;
32 };
33 }
34 
35 void StopoverReplyPrivate::finalizeResult()
36 {
37  if (result.empty()) {
38  return;
39  }
41  errorMsg.clear();
42 
43  std::sort(result.begin(), result.end(), [this](const auto &lhs, const auto &rhs) {
44  return StopoverUtil::timeLessThan(request, lhs, rhs);
45  });
46 
47  for (auto it = result.begin(); it != result.end(); ++it) {
48  for (auto mergeIt = it + 1; mergeIt != result.end();) {
49  if (!StopoverUtil::timeEqual(request, (*it), (*mergeIt))) {
50  break;
51  }
52 
53  if (Stopover::isSame(*it, *mergeIt)) {
54  *it = Stopover::merge(*it, *mergeIt);
55  mergeIt = result.erase(mergeIt);
56  } else {
57  ++mergeIt;
58  }
59  }
60  }
61 
62  nextRequest.purgeLoops(request);
63  prevRequest.purgeLoops(request);
64 }
65 
66 bool StopoverReplyPrivate::needToWaitForAssets() const
67 {
68  return request.downloadAssets();
69 }
70 
71 StopoverReply::StopoverReply(const StopoverRequest &req, QObject *parent)
72  : Reply(new StopoverReplyPrivate, parent)
73 {
74  Q_D(StopoverReply);
75  d->request = req;
76  d->nextRequest = req;
77  d->prevRequest = req;
78 }
79 
80 StopoverReply::~StopoverReply() = default;
81 
83 {
84  Q_D(const StopoverReply);
85  return d->request;
86 }
87 
88 const std::vector<Stopover>& StopoverReply::result() const
89 {
90  Q_D(const StopoverReply);
91  return d->result;
92 }
93 
94 std::vector<Stopover>&& StopoverReply::takeResult()
95 {
96  Q_D(StopoverReply);
97  return std::move(d->result);
98 }
99 
100 void StopoverReply::addResult(const AbstractBackend *backend, std::vector<Stopover> &&res)
101 {
102  Q_D(StopoverReply);
103  // update context for next/prev requests
104  // do this first, before res gets moved from below
105  if (d->request.mode() == StopoverRequest::QueryDeparture && !res.empty()) {
106  // we create a context for later queries here in any case, since we can emulate that generically without backend support
107  auto context = d->nextRequest.context(backend);
108  context.type = RequestContext::Next;
109  for (const auto &dep : res) {
110  context.dateTime = std::max(context.dateTime, dep.scheduledDepartureTime());
111  }
112  d->nextRequest.setContext(backend, std::move(context));
113  }
114 
115  // if this is a backend with a static timezone, apply this to the result
116  if (backend->timeZone().isValid()) {
117  for (auto &dep : res) {
118  StopoverUtil::applyTimeZone(dep, backend->timeZone());
119  }
120  }
121 
122  // augment line information
123  for (auto &dep : res) {
124  StopoverUtil::applyMetaData(dep, request().downloadAssets());
125  }
126 
127  // apply static attributions if @p backend contributed to the results
128  addAttribution(backend->attribution());
129 
130  // cache negative hits, positive ones are too short-lived
131  if (res.empty()) {
132  Cache::addNegativeDepartureCacheEntry(backend->backendId(), request().cacheKey());
133  }
134 
135  if (d->result.empty()) {
136  d->result = std::move(res);
137  } else {
138  d->result.insert(d->result.end(), res.begin(), res.end());
139  }
140 
141  d->pendingOps--;
142  d->emitUpdated(this);
143  d->emitFinishedIfDone(this);
144 }
145 
147 {
148  Q_D(const StopoverReply);
149  if (d->nextRequest.contexts().empty()) {
150  return {};
151  }
152  return d->nextRequest;
153 }
154 
156 {
157  Q_D(const StopoverReply);
158  if (d->prevRequest.contexts().empty()) {
159  return {};
160  }
161  return d->prevRequest;
162 }
163 
164 void StopoverReply::setNextContext(const AbstractBackend *backend, const QVariant &data)
165 {
166  Q_D(StopoverReply);
167  auto context = d->nextRequest.context(backend);
168  context.type = RequestContext::Next;
169  context.backendData = data;
170  d->nextRequest.setContext(backend, std::move(context));
171 }
172 
173 void StopoverReply::setPreviousContext(const AbstractBackend *backend, const QVariant &data)
174 {
175  Q_D(StopoverReply);
176  auto context = d->prevRequest.context(backend);
177  context.type = RequestContext::Previous;
178  context.backendData = data;
179  d->prevRequest.setContext(backend, std::move(context));
180 }
181 
182 void StopoverReply::addError(const AbstractBackend *backend, Reply::Error error, const QString &errorMsg)
183 {
184  if (error == Reply::NotFoundError) {
185  Cache::addNegativeDepartureCacheEntry(backend->backendId(), request().cacheKey());
186  } else {
187  qCDebug(Log) << backend->backendId() << error << errorMsg;
188  }
189  Reply::addError(error, errorMsg);
190 }
Departure or arrival query reply.
Definition: stopoverreply.h:22
Query operations and data types for accessing realtime public transport information from online servi...
Definition: attribution.cpp:16
std::vector< Stopover > && takeResult()
Returns the found arrival or departure information for moving elsewhere.
QString cacheKey() const
Unique string representation used for caching results.
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:152
StopoverRequest nextRequest() const
Returns a request object for querying departures following the ones returned by this reply...
const std::vector< Stopover > & result() const
Returns the found arrival or departure information.
void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
The requested journey/departure/place could not be found.
Definition: reply.h:34
Describes an arrival or departure search.
Error
Error types.
Definition: reply.h:31
Nothing went wrong.
Definition: reply.h:32
StopoverRequest request() const
The request this is the reply for.
static Stopover merge(const Stopover &lhs, const Stopover &rhs)
Merge two departure instances.
Definition: stopover.cpp:182
StopoverRequest previousRequest() const
Returns a request object for querying departures preceding the ones returned by this reply...
Query response base class.
Definition: reply.h:24
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Fri Oct 15 2021 23:07:28 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.