KPublicTransport

journeyquerymodel.cpp
1 /*
2  SPDX-FileCopyrightText: 2019 Volker Krause <[email protected]>
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/JourneyRequest>
16 #include <KPublicTransport/Manager>
17 
18 #include <QDebug>
19 
20 using namespace KPublicTransport;
21 
22 namespace KPublicTransport {
23 class JourneyQueryModelPrivate : public AbstractQueryModelPrivate
24 {
25 public:
26  void doQuery() override;
27  void doClearResults() override;
28  void mergeResults(const std::vector<Journey> &newJourneys);
29 
30  std::vector<Journey> m_journeys;
31 
32  JourneyRequest m_request;
33  JourneyRequest m_nextRequest;
34  JourneyRequest m_prevRequest;
35 
36  Q_DECLARE_PUBLIC(JourneyQueryModel)
37 };
38 }
39 
40 void JourneyQueryModelPrivate::doQuery()
41 {
42  Q_Q(JourneyQueryModel);
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->queryJourney(m_request);
53  monitorReply(reply);
55  Q_Q(JourneyQueryModel);
56  if (reply->error() == KPublicTransport::JourneyReply::NoError) {
57  m_nextRequest = reply->nextRequest();
58  m_prevRequest = reply->previousRequest();
59  Q_EMIT q->canQueryPrevNextChanged();
60  }
61  });
62  QObject::connect(reply, &KPublicTransport::JourneyReply::updated, q, [reply, this]() {
63  mergeResults(reply->takeResult());
64  });
65 }
66 
67 void JourneyQueryModelPrivate::doClearResults()
68 {
69  m_journeys.clear();
70 }
71 
72 void JourneyQueryModelPrivate::mergeResults(const std::vector<Journey> &newJourneys)
73 {
74  Q_Q(JourneyQueryModel);
75  for (const auto &jny : newJourneys) {
76  auto it = std::lower_bound(m_journeys.begin(), m_journeys.end(), jny, JourneyUtil::firstTransportDepartureLessThan);
77 
78  bool found = false;
79  while (it != m_journeys.end() && JourneyUtil::firstTransportDepartureEqual(jny, *it)) {
80  if (Journey::isSame(jny, *it)) {
81  *it = Journey::merge(*it, jny);
82  found = true;
83  const auto row = std::distance(m_journeys.begin(), it);
84  const auto idx = q->index(row, 0);
85  Q_EMIT q->dataChanged(idx, idx);
86  break;
87  } else {
88  ++it;
89  }
90  }
91  if (found) {
92  continue;
93  }
94 
95  const auto row = std::distance(m_journeys.begin(), it);
96  q->beginInsertRows({}, row, row);
97  m_journeys.insert(it, jny);
98  q->endInsertRows();
99  }
100 }
101 
102 
103 JourneyQueryModel::JourneyQueryModel(QObject *parent)
104  : AbstractQueryModel(new JourneyQueryModelPrivate, parent)
105 {
106  connect(this, &AbstractQueryModel::loadingChanged, this, &JourneyQueryModel::canQueryPrevNextChanged);
107 }
108 
109 JourneyQueryModel::~JourneyQueryModel() = default;
110 
111 JourneyRequest JourneyQueryModel::request() const
112 {
113  Q_D(const JourneyQueryModel);
114  return d->m_request;
115 }
116 
118 {
119  Q_D(JourneyQueryModel);
120  d->m_request = req;
121  Q_EMIT requestChanged();
122  d->query();
123 }
124 
125 bool JourneyQueryModel::canQueryNext() const
126 {
127  Q_D(const JourneyQueryModel);
128  return !d->m_loading && !d->m_journeys.empty() && d->m_nextRequest.isValid();
129 }
130 
132 {
133  Q_D(JourneyQueryModel);
134  if (!canQueryNext()) {
135  qCWarning(Log) << "Cannot query next journeys";
136  return;
137  }
138 
139  d->setLoading(true);
140  auto reply = d->m_manager->queryJourney(d->m_nextRequest);
141  d->monitorReply(reply);
142  QObject::connect(reply, &KPublicTransport::JourneyReply::finished, this, [reply, this] {
143  Q_D(JourneyQueryModel);
144  if (reply->error() == KPublicTransport::JourneyReply::NoError) {
145  d->m_nextRequest = reply->nextRequest();
146  } else {
147  d->m_nextRequest = {};
148  }
149  Q_EMIT canQueryPrevNextChanged();
150  });
151  QObject::connect(reply, &KPublicTransport::JourneyReply::updated, this, [reply, this]() {
152  Q_D(JourneyQueryModel);
153  d->mergeResults(reply->takeResult());
154  });
155 }
156 
157 bool JourneyQueryModel::canQueryPrevious() const
158 {
159  Q_D(const JourneyQueryModel);
160  return !d->m_loading && !d->m_journeys.empty() && d->m_prevRequest.isValid();
161 }
162 
164 {
165  Q_D(JourneyQueryModel);
166  if (!canQueryPrevious()) {
167  qCWarning(Log) << "Cannot query previous journeys";
168  return;
169  }
170 
171  d->setLoading(true);
172  auto reply = d->m_manager->queryJourney(d->m_prevRequest);
173  d->monitorReply(reply);
174  QObject::connect(reply, &KPublicTransport::JourneyReply::finished, this, [reply, this] {
175  Q_D(JourneyQueryModel);
176  if (reply->error() == KPublicTransport::JourneyReply::NoError) {
177  d->m_prevRequest = reply->previousRequest();
178  } else {
179  d->m_prevRequest = {};
180  }
181  Q_EMIT canQueryPrevNextChanged();
182  });
183  QObject::connect(reply, &KPublicTransport::JourneyReply::updated, this, [reply, this]() {
184  Q_D(JourneyQueryModel);
185  d->mergeResults(reply->takeResult());
186  });
187 }
188 
189 int JourneyQueryModel::rowCount(const QModelIndex& parent) const
190 {
191  Q_D(const JourneyQueryModel);
192  if (parent.isValid()) {
193  return 0;
194  }
195  return d->m_journeys.size();
196 }
197 
198 QVariant JourneyQueryModel::data(const QModelIndex& index, int role) const
199 {
200  Q_D(const JourneyQueryModel);
201  if (!index.isValid()) {
202  return {};
203  }
204 
205  const auto jny = d->m_journeys[index.row()];
206  switch (role) {
207  case JourneyRole:
208  return QVariant::fromValue(jny);
209  case ScheduledDepartureTime:
210  return jny.scheduledDepartureTime();
211  case ScheduledArrivalTime:
212  return jny.scheduledArrivalTime();
213  }
214 
215  return {};
216 }
217 
218 QHash<int, QByteArray> JourneyQueryModel::roleNames() const
219 {
221  r.insert(JourneyRole, "journey");
222  r.insert(ScheduledDepartureTime, "scheduledDepartureTime");
223  r.insert(ScheduledArrivalTime, "scheduledArrivalTime");
224  return r;
225 }
226 
227 const std::vector<Journey>& JourneyQueryModel::journeys() const
228 {
229  Q_D(const JourneyQueryModel);
230  return d->m_journeys;
231 }
232 
233 #include "moc_journeyquerymodel.cpp"
Query operations and data types for accessing realtime public transport information from online servi...
Definition: attribution.cpp:16
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:619
virtual QHash< int, QByteArray > roleNames() const const
void finished()
Emitted whenever the corresponding search has been completed.
static Journey merge(const Journey &lhs, const Journey &rhs)
Merge two instances.
Definition: journey.cpp:651
void updated()
Emitted whenever new results are available, even before the search has been completed.
bool isValid() const const
Definition: location.h:16
Q_INVOKABLE void queryNext()
Search for later journeys.
const std::vector< Journey > & journeys() const
The current model content.
int row() const const
Model representing journey query results.
QVariant fromValue(const T &value)
Q_INVOKABLE void queryPrevious()
Search for earlier journeys.
Nothing went wrong.
Definition: reply.h:32
Common base class for query models, do not use directly.
Describes a journey search.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setRequest(const JourneyRequest &req)
Specify the actual journey query.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 23 2021 23:05:21 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.