KPublicTransport

journeyrequest.cpp
1 /*
2  SPDX-FileCopyrightText: 2018 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "journeyrequest.h"
8 #include "requestcontext_p.h"
9 #include "datatypes/datatypes_p.h"
10 #include "datatypes/json_p.h"
11 #include "datatypes/locationutil_p.h"
12 
13 #include <KPublicTransport/Location>
14 
15 #include <QCryptographicHash>
16 #include <QDateTime>
17 #include <QDebug>
18 #include <QMetaEnum>
19 #include <QSharedData>
20 
21 #include <unordered_map>
22 
23 using namespace KPublicTransport;
24 
25 enum { JourneyCacheTimeResolution = 60 }; // in seconds
26 
27 namespace KPublicTransport {
28 class JourneyRequestPrivate : public QSharedData {
29 public:
30  Location from;
31  Location to;
32  QDateTime dateTime;
33  std::vector<RequestContext> contexts;
34  QStringList backendIds;
36  JourneySection::Modes modes = JourneySection::PublicTransport | JourneySection::RentedVehicle;
37  int maximumResults = 12;
38  bool downloadAssets = false;
39  bool includeIntermediateStops = true;
40  bool includePaths = false;
41 
42  std::vector<IndividualTransport> accessModes = { {IndividualTransport::Walk} };
43  std::vector<IndividualTransport> egressModes = { {IndividualTransport::Walk} };
44 };
45 }
46 
47 KPUBLICTRANSPORT_MAKE_GADGET(JourneyRequest)
48 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneyRequest, Location, from, setFrom)
49 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneyRequest, Location, to, setTo)
50 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneyRequest, JourneyRequest::DateTimeMode, dateTimeMode, setDateTimeMode)
51 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneyRequest, bool, downloadAssets, setDownloadAssets)
52 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneyRequest, JourneySection::Modes, modes, setModes)
53 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneyRequest, int, maximumResults, setMaximumResults)
54 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneyRequest, bool, includeIntermediateStops, setIncludeIntermediateStops)
55 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneyRequest, bool, includePaths, setIncludePaths)
56 
57 JourneyRequest::JourneyRequest(const Location &from, const Location &to)
58  : d(new JourneyRequestPrivate)
59 {
60  d->from = from;
61  d->to = to;
62 }
63 
65 {
66  return !d->to.isEmpty() && !d->from.isEmpty();
67 }
68 
70 {
71  if (!d->dateTime.isValid()) {
72  d->dateTime = QDateTime::currentDateTime();
73  }
74  return d->dateTime;
75 }
76 
77 void JourneyRequest::setDateTime(const QDateTime& dt)
78 {
79  d.detach();
80  d->dateTime = dt;
81 }
82 
84 {
85  d.detach();
86  d->dateTime = dt;
87  d->dateTimeMode = Departure;
88 }
89 
91 {
92  d.detach();
93  d->dateTime = dt;
94  d->dateTimeMode = Arrival;
95 }
96 
97 RequestContext JourneyRequest::context(const AbstractBackend *backend) const
98 {
99  const auto it = std::lower_bound(d->contexts.begin(), d->contexts.end(), backend);
100  if (it != d->contexts.end() && (*it).backend == backend) {
101  return *it;
102  }
103 
104  RequestContext context;
105  context.backend = backend;
106  return context;
107 }
108 
109 const std::vector<RequestContext>& JourneyRequest::contexts() const
110 {
111  return d->contexts;
112 }
113 
114 void JourneyRequest::setContext(const AbstractBackend *backend, RequestContext &&context)
115 {
116  d.detach();
117  const auto it = std::lower_bound(d->contexts.begin(), d->contexts.end(), backend);
118  if (it != d->contexts.end() && (*it).backend == backend) {
119  (*it) = std::move(context);
120  } else {
121  d->contexts.insert(it, std::move(context));
122  }
123 }
124 
125 void JourneyRequest::purgeLoops(const JourneyRequest &baseRequest)
126 {
127  RequestContext::purgeLoops(d->contexts, baseRequest.contexts());
128 }
129 
130 QJsonObject JourneyRequest::toJson(const KPublicTransport::JourneyRequest &req)
131 {
132  auto obj = Json::toJson(req);
133  obj.insert(QLatin1String("from"), Location::toJson(req.from()));
134  obj.insert(QLatin1String("to"), Location::toJson(req.to()));
135  obj.insert(QLatin1String("accessModes"), IndividualTransport::toJson(req.accessModes()));
136  obj.insert(QLatin1String("egressModes"), IndividualTransport::toJson(req.egressModes()));
137  return obj;
138 }
139 
141 {
142  return d->backendIds;
143 }
144 
146 {
147  d.detach();
148  d->backendIds = backendIds;
149 }
150 
151 template <typename T>
152 static QVariantList toVariantList(const std::vector<T> &v)
153 {
154  QVariantList l;
155  l.reserve(v.size());
156  std::transform(v.begin(), v.end(), std::back_inserter(l), &QVariant::fromValue<T>);
157  return l;
158 }
159 
160 const std::vector<IndividualTransport>& JourneyRequest::accessModes() const
161 {
162  return d->accessModes;
163 }
164 
165 QVariantList JourneyRequest::accessModesVariant() const
166 {
167  return toVariantList(d->accessModes);
168 }
169 
170 void JourneyRequest::setAccessModes(std::vector<IndividualTransport> &&accessModes)
171 {
172  d.detach();
173  d->accessModes = std::move(accessModes);
174 }
175 
176 void JourneyRequest::setAccessModes(const QVariantList &accessModesVariant)
177 {
178  d.detach();
179  d->accessModes = IndividualTransport::fromVariant(accessModesVariant);
180 }
181 
182 const std::vector<IndividualTransport>& JourneyRequest::egressModes() const
183 {
184  return d->egressModes;
185 }
186 
187 QVariantList JourneyRequest::egressModesVariant() const
188 {
189  return toVariantList(d->egressModes);
190 }
191 
192 void JourneyRequest::setEgressModes(std::vector<IndividualTransport>&& egressModes)
193 {
194  d.detach();
195  d->egressModes = std::move(egressModes);
196 }
197 
198 void JourneyRequest::setEgressModes(const QVariantList &egressModesVariant)
199 {
200  d.detach();
201  d->egressModes = IndividualTransport::fromVariant(egressModesVariant);
202 }
203 
205 {
207  hash.addData(QByteArray::number(d->dateTime.toSecsSinceEpoch() / JourneyCacheTimeResolution));
208  hash.addData(LocationUtil::cacheKey(d->from).toUtf8());
209  hash.addData(LocationUtil::cacheKey(d->to).toUtf8());
210  hash.addData(d->dateTimeMode == JourneyRequest::Arrival ? "A" : "D", 1);
211  hash.addData(QMetaEnum::fromType<JourneySection::Mode>().valueToKeys(d->modes));
212  hash.addData(QByteArray::number(d->maximumResults));
213  hash.addData(d->includeIntermediateStops ? "I" : "-");
214  hash.addData(d->includePaths ? "P" : "-");
215 
216  hash.addData("ACCESS");
217  for (const auto &it : d->accessModes) {
218  hash.addData(QMetaEnum::fromType<IndividualTransport::Mode>().valueToKey(it.mode()));
219  hash.addData(QMetaEnum::fromType<IndividualTransport::Qualifier>().valueToKey(it.qualifier()));
220  }
221 
222  hash.addData("EGRESS");
223  for (const auto &it : d->accessModes) {
224  hash.addData(QMetaEnum::fromType<IndividualTransport::Mode>().valueToKey(it.mode()));
225  hash.addData(QMetaEnum::fromType<IndividualTransport::Qualifier>().valueToKey(it.qualifier()));
226  }
227 
228  return QString::fromUtf8(hash.result().toHex());
229 }
230 
231 static bool hasTakeBikeMode(const std::vector<IndividualTransport> &modes)
232 {
233  return std::any_of(modes.begin(), modes.end(), [](const auto &it) {
234  return it.mode() == IndividualTransport::Bike && it.qualifier() == IndividualTransport::None;
235  });
236 }
237 
238 void JourneyRequest::validate() const
239 {
240  // remove invalid access/egress modes
241  d->accessModes.erase(std::remove_if(d->accessModes.begin(), d->accessModes.end(), [](const auto &it) {
242  return (it.mode() == IndividualTransport::Car && it.qualifier() == IndividualTransport::None)
243  || it.qualifier() == IndividualTransport::Pickup;
244  }), d->accessModes.end());
245  d->egressModes.erase(std::remove_if(d->egressModes.begin(), d->egressModes.end(), [](const auto &it) {
246  return (it.mode() == IndividualTransport::Car && it.qualifier() == IndividualTransport::None)
247  || it.qualifier() == IndividualTransport::Dropoff
248  || it.qualifier() == IndividualTransport::Park;
249  }), d->egressModes.end());
250 
251  // taking a bike on public transport needs to be symmetric
252  const auto hasTakeBikeAccess = hasTakeBikeMode(d->accessModes);
253  const auto hasTakeBikeEgress = hasTakeBikeMode(d->egressModes);
254  if (hasTakeBikeAccess && !hasTakeBikeEgress) {
255  d->egressModes.push_back({ IndividualTransport::Bike });
256  } else if (!hasTakeBikeAccess && hasTakeBikeEgress) {
257  d->egressModes.erase(std::remove_if(d->egressModes.begin(), d->egressModes.end(), [](const auto &it) {
258  return it.mode() == IndividualTransport::Bike && it.qualifier() == IndividualTransport::None;
259  }), d->egressModes.end());
260  }
261 
262  // access/egress modes must not be empty
263  if (d->accessModes.empty()) {
264  d->accessModes = {{IndividualTransport::Walk}};
265  }
266  if (d->egressModes.empty()) {
267  d->egressModes = {{IndividualTransport::Walk}};
268  }
269 }
270 
271 #include "moc_journeyrequest.cpp"
for access legs, vehicle is parked before taking public transport.
Query operations and data types for accessing realtime public transport information from online servi...
Definition: attribution.cpp:16
QStringList backendIds() const
Identifiers of the backends that should be queried.
QByteArray toHex() const const
for access legs: vehicle is not taken onto public transport but also doesn&#39;t need parking ...
void setEgressModes(std::vector< IndividualTransport > &&egressModes)
Sets the requested egress modes.
dateTime() represents the desired departure time.
bool isValid() const
Returns true if this is a valid request, that is, it has enough parameters set to perform a query...
free floating or dock-based rental bike service, electric scooters, car sharing services, ie. any vehicle you drive yourself but that isn&#39;t your own
Definition: journey.h:45
QString cacheKey() const
Unique string representation used for caching results.
not applicable, or bike is taken on public transport legs.
A segment of a journey plan.
Definition: journey.h:31
KPublicTransport::Location from
The starting point of the journey search.
QDateTime dateTime
Date/time at which the journey should start/end.
for egress legs: vehicle is available at the last public transport leg
void setArrivalTime(const QDateTime &dt)
Sets the desired arrival time.
QString fromUtf8(const char *str, int size)
const std::vector< IndividualTransport > & accessModes() const
Requested access modes.
QVariantList accessModes
Access modes.
QByteArray number(int n, int base)
void addData(const char *data, int length)
const std::vector< IndividualTransport > & egressModes() const
Requested egress modes.
QVariantList egressModes
Egress modes.
QDateTime currentDateTime()
void setDepartureTime(const QDateTime &dt)
Set the desired departure time.
static QJsonObject toJson(const IndividualTransport &it)
Serializes one object to JSON.
Stopover Departure
Deprecated, use Stopover.
Definition: departure.h:18
void setAccessModes(std::vector< IndividualTransport > &&accessModes)
Sets the requested access modes.
static QJsonObject toJson(const Location &loc)
Serializes one Location object to JSON.
Definition: location.cpp:444
static std::vector< IndividualTransport > fromVariant(const QVariantList &v)
QByteArray result() const const
dateTime() represents the desired arriva time.
void setBackendIds(const QStringList &backendIds)
Set identifiers of backends that should be queried.
Describes a journey search.
KPublicTransport::Location to
The journey destination.
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.