KPublicTransport

vehiclelayoutquerymodel.cpp
1 /*
2  SPDX-FileCopyrightText: 2019 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "vehiclelayoutquerymodel.h"
8 #include "abstractquerymodel_p.h"
9 
10 #include <KPublicTransport/Attribution>
11 #include <KPublicTransport/Vehicle>
12 #include <KPublicTransport/VehicleLayoutReply>
13 #include <KPublicTransport/Manager>
14 
15 #include <QDebug>
16 
17 using namespace KPublicTransport;
18 
19 namespace KPublicTransport {
20 class VehicleLayoutQueryModelPrivate : public AbstractQueryModelPrivate
21 {
22 public:
23  void doQuery() override;
24  void doClearResults() override;
25 
26  void interpolatePlatformPositionsFromSectionName();
27  template <typename Iter>
28  void interpolatePlatformPositionsFromSectionName(Iter begin, Iter end);
29 
30  VehicleLayoutRequest m_request;
31  Stopover m_stopover;
32 
33  Q_DECLARE_PUBLIC(VehicleLayoutQueryModel)
34 };
35 }
36 
37 void VehicleLayoutQueryModelPrivate::doQuery()
38 {
40  if (!m_manager || !m_request.isValid()) {
41  return;
42  }
43 
44  // if the request already contains useful information, let's use those already
45  q->beginResetModel();
46  m_stopover = m_request.stopover();
47  q->endResetModel();
48  Q_EMIT q->contentChanged();
49 
50  setLoading(true);
51  auto reply = m_manager->queryVehicleLayout(m_request);
52  monitorReply(reply);
55  q->beginResetModel();
56  m_stopover = reply->stopover();
57  if (!m_stopover.platformLayout().isEmpty() && !m_stopover.vehicleLayout().isEmpty()
58  && !m_stopover.vehicleLayout().hasPlatformPositions() && m_stopover.vehicleLayout().hasPlatformSectionNames()) {
59  interpolatePlatformPositionsFromSectionName();
60  }
61  q->endResetModel();
62  Q_EMIT q->contentChanged();
63  });
64 }
65 
66 void VehicleLayoutQueryModelPrivate::doClearResults()
67 {
68  m_stopover = {};
70  Q_EMIT q->contentChanged();
71 }
72 
73 void VehicleLayoutQueryModelPrivate::interpolatePlatformPositionsFromSectionName()
74 {
75  auto vehicle = m_stopover.vehicleLayout();
76  auto vehicleSections = vehicle.takeSections();
77  const auto startSection = vehicleSections.front().platformSectionName();
78  const auto endSection = vehicleSections.back().platformSectionName();
79 
80  for (const auto &sec : m_stopover.platformLayout().sections()) {
81  if (sec.name() == startSection) {
82  interpolatePlatformPositionsFromSectionName(vehicleSections.begin(), vehicleSections.end());
83  break;
84  } else if (sec.name() == endSection) {
85  interpolatePlatformPositionsFromSectionName(vehicleSections.rbegin(), vehicleSections.rend());
86  break;
87  }
88  }
89 
90  vehicle.setSections(std::move(vehicleSections));
91  m_stopover.setVehicleLayout(std::move(vehicle));
92 }
93 
94 template<typename Iter>
95 void VehicleLayoutQueryModelPrivate::interpolatePlatformPositionsFromSectionName(Iter begin, Iter end)
96 {
97  auto rangeBegin = begin, rangeEnd = begin;
98  float minLength = 1.0;
99  while (rangeBegin != end) {
100  while (rangeEnd != end && (*rangeBegin).platformSectionName() == (*rangeEnd).platformSectionName()) {
101  ++rangeEnd;
102  }
103 
104  const auto platformIt = std::find_if(m_stopover.platformLayout().sections().begin(), m_stopover.platformLayout().sections().end(), [&rangeBegin](const auto &p) {
105  return p.name() == (*rangeBegin).platformSectionName();
106  });
107  if (platformIt == m_stopover.platformLayout().sections().end()) {
108  qWarning() << "Failed to find platform section" << (*rangeBegin).platformSectionName();
109  return;
110  }
111 
112  auto l = ((*platformIt).end() - (*platformIt).begin()) / std::distance(rangeBegin, rangeEnd);
113  minLength = std::min(minLength, l);
114 
115  if (rangeEnd == end) { // trailing coaches, don't scale them to the full section
116  l = minLength;
117  }
118 
119  auto pos = (*platformIt).begin();
120  for (auto it = rangeBegin; it != rangeEnd; ++it) {
121  (*it).setPlatformPositionBegin(pos);
122  (*it).setPlatformPositionEnd(pos + l);
123  pos += l;
124  }
125 
126  rangeBegin = rangeEnd;
127  }
128 
129  // fix-up leading coaches to not fill up the entire platform section
130  rangeEnd = std::find_if(begin, end, [&begin](const auto &p) {
131  return p.platformSectionName() != (*begin).platformSectionName();
132  });
133  auto pos = (*std::prev(rangeEnd)).platformPositionEnd() - std::distance(begin, rangeEnd) * minLength;
134  for (auto it = begin; it != rangeEnd; ++it) {
135  (*it).setPlatformPositionBegin(pos);
136  (*it).setPlatformPositionEnd(pos + minLength);
137  pos += minLength;
138  }
139 }
140 
141 
142 VehicleLayoutQueryModel::VehicleLayoutQueryModel(QObject* parent)
143  : AbstractQueryModel(new VehicleLayoutQueryModelPrivate, parent)
144 {
145 }
146 
147 VehicleLayoutQueryModel::~VehicleLayoutQueryModel() = default;
148 
149 VehicleLayoutRequest VehicleLayoutQueryModel::request() const
150 {
151  Q_D(const VehicleLayoutQueryModel);
152  return d->m_request;
153 }
154 
155 void VehicleLayoutQueryModel::setRequest(const VehicleLayoutRequest &req)
156 {
158  d->m_request = req;
159  Q_EMIT requestChanged();
160  d->query();
161 }
162 
163 Vehicle VehicleLayoutQueryModel::vehicle() const
164 {
165  return stopover().vehicleLayout();
166 }
167 
168 Platform VehicleLayoutQueryModel::platform() const
169 {
170  return stopover().platformLayout();
171 }
172 
173 Stopover VehicleLayoutQueryModel::stopover() const
174 {
175  Q_D(const VehicleLayoutQueryModel);
176  return d->m_stopover;
177 }
178 
179 int VehicleLayoutQueryModel::rowCount(const QModelIndex &parent) const
180 {
181  Q_D(const VehicleLayoutQueryModel);
182  if (parent.isValid()) {
183  return 0;
184  }
185  return d->m_stopover.vehicleLayout().sections().size();
186 }
187 
188 QVariant VehicleLayoutQueryModel::data(const QModelIndex &index, int role) const
189 {
190  Q_D(const VehicleLayoutQueryModel);
191  if (!index.isValid()) {
192  return {};
193  }
194 
195  switch (role) {
196  case VehicleSectionRole:
197  return QVariant::fromValue(d->m_stopover.vehicleLayout().sections()[index.row()]);
198  }
199 
200  return {};
201 }
202 
203 QHash<int, QByteArray> VehicleLayoutQueryModel::roleNames() const
204 {
206  r.insert(VehicleSectionRole, "vehicleSection");
207  return r;
208 }
209 
210 #include "moc_vehiclelayoutquerymodel.moc"
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.
bool isValid() const const
Definition: location.h:16
int row() const const
Information about the vehicle used on a journey.
Definition: vehicle.h:140
Describes a query for vehicle layout information.
QVariant fromValue(const T &value)
Information about an arrival and/or departure of a vehicle at a stop area.
Definition: stopover.h:25
Information about the layout of a station platform.
Definition: platform.h:44
Model for retrieving vehicle and platform layout query results.
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)
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.