KPublicTransport

stopoverquerymodel.cpp
1 /*
2  SPDX-FileCopyrightText: 2019 Volker Krause <[email protected]>
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 
20 using namespace KPublicTransport;
21 
22 namespace KPublicTransport {
23 class StopoverQueryModelPrivate : public AbstractQueryModelPrivate
24 {
25 public:
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 
40 void StopoverQueryModelPrivate::doQuery()
41 {
42  Q_Q(StopoverQueryModel);
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 
66 void StopoverQueryModelPrivate::doClearResults()
67 {
68  m_departures.clear();
69 }
70 
71 void StopoverQueryModelPrivate::mergeResults(const std::vector<Stopover> &newDepartures)
72 {
73  Q_Q(StopoverQueryModel);
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 
104 StopoverQueryModel::StopoverQueryModel(QObject *parent)
105  : AbstractQueryModel(new StopoverQueryModelPrivate, parent)
106 {
107  connect(this, &AbstractQueryModel::loadingChanged, this, &StopoverQueryModel::canQueryPrevNextChanged);
108 }
109 
110 StopoverQueryModel::~StopoverQueryModel() = default;
111 
112 StopoverRequest StopoverQueryModel::request() const
113 {
114  Q_D(const StopoverQueryModel);
115  return d->m_request;
116 }
117 
118 void StopoverQueryModel::setRequest(const StopoverRequest &req)
119 {
120  Q_D(StopoverQueryModel);
121  d->m_request = req;
122  Q_EMIT requestChanged();
123  d->query();
124 }
125 
126 bool StopoverQueryModel::canQueryNext() const
127 {
128  Q_D(const StopoverQueryModel);
129  return !d->m_loading && !d->m_departures.empty() && d->m_nextRequest.isValid();
130 }
131 
133 {
134  Q_D(StopoverQueryModel);
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);
143  QObject::connect(reply, &KPublicTransport::StopoverReply::finished, this, [reply, this] {
144  Q_D(StopoverQueryModel);
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]() {
153  Q_D(StopoverQueryModel);
154  d->mergeResults(reply->takeResult());
155  });
156 }
157 
158 bool StopoverQueryModel::canQueryPrevious() const
159 {
160  Q_D(const StopoverQueryModel);
161  return !d->m_loading && !d->m_departures.empty() && d->m_prevRequest.isValid();
162 }
163 
165 {
166  Q_D(StopoverQueryModel);
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);
175  QObject::connect(reply, &KPublicTransport::StopoverReply::finished, this, [reply, this] {
176  Q_D(StopoverQueryModel);
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]() {
185  Q_D(StopoverQueryModel);
186  d->mergeResults(reply->takeResult());
187  });
188 }
189 
190 int 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 
199 QVariant 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 
214 QHash<int, QByteArray> StopoverQueryModel::roleNames() const
215 {
217  r.insert(DepartureRole, "departure");
218  return r;
219 }
220 
221 const std::vector<Stopover>& StopoverQueryModel::departures() const
222 {
223  Q_D(const StopoverQueryModel);
224  return d->m_departures;
225 }
226 
227 #include "moc_stopoverquerymodel.moc"
const std::vector< Stopover > & departures() const
The current model content.
Query operations and data types for accessing realtime public transport information from online servi...
Definition: attribution.cpp:16
virtual QHash< int, QByteArray > roleNames() const const
void finished()
Emitted whenever the corresponding search has been completed.
Model representing arrival or departure query results.
Q_INVOKABLE void queryPrevious()
Search for earlier journeys.
void updated()
Emitted whenever new results are available, even before the search has been completed.
bool isValid() const const
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
Definition: location.h:16
int row() const const
Q_INVOKABLE void queryNext()
Search for later journeys.
Describes an arrival or departure search.
QVariant fromValue(const T &value)
Nothing went wrong.
Definition: reply.h:32
Common base class for query models, do not use directly.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
static Stopover merge(const Stopover &lhs, const Stopover &rhs)
Merge two departure instances.
Definition: stopover.cpp:182
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.