diff --git a/src/publictransport/backends/hafasmgateparser.cpp b/src/publictransport/backends/hafasmgateparser.cpp index 1344da8..d373a20 100644 --- a/src/publictransport/backends/hafasmgateparser.cpp +++ b/src/publictransport/backends/hafasmgateparser.cpp @@ -1,330 +1,334 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "hafasmgateparser.h" #include "logging.h" #include #include #include #include #include #include #include #include #include using namespace KPublicTransport; HafasMgateParser::HafasMgateParser() = default; HafasMgateParser::~HafasMgateParser() = default; void HafasMgateParser::setLineModeMap(std::unordered_map &&modeMap) { m_lineModeMap = std::move(modeMap); } void HafasMgateParser::setLocationIdentifierType(const QString &idType) { m_locIdType = idType; } static std::vector parseIcos(const QJsonArray &icoL) { std::vector icos; icos.reserve(icoL.size()); for (const auto &icoV : icoL) { const auto icoObj = icoV.toObject(); Ico ico; const auto fg = icoObj.value(QLatin1String("fg")).toObject(); if (!fg.isEmpty()) { ico.fg = QColor(fg.value(QLatin1String("r")).toInt(), fg.value(QLatin1String("g")).toInt(), fg.value(QLatin1String("b")).toInt()); } const auto bg = icoObj.value(QLatin1String("bg")).toObject(); if (!bg.isEmpty()) { ico.bg = QColor(bg.value(QLatin1String("r")).toInt(), bg.value(QLatin1String("g")).toInt(), bg.value(QLatin1String("b")).toInt()); } icos.push_back(ico); } return icos; } std::vector HafasMgateParser::parseLocations(const QJsonArray &locL) const { std::vector locs; locs.reserve(locL.size()); for (const auto &locV : locL) { const auto locObj = locV.toObject(); Location loc; loc.setName(locObj.value(QLatin1String("name")).toString()); loc.setIdentifier(m_locIdType, locObj.value(QLatin1String("extId")).toString()); const auto coordObj = locObj.value(QLatin1String("crd")).toObject(); loc.setCoordinate(coordObj.value(QLatin1String("y")).toDouble() / 1000000.0, coordObj.value(QLatin1String("x")).toDouble() / 1000000.0); locs.push_back(loc); } return locs; } std::vector HafasMgateParser::parseLines(const QJsonArray &prodL, const std::vector &icos) const { std::vector lines; lines.reserve(prodL.size()); for (const auto &prodV : prodL) { const auto prodObj = prodV.toObject(); Line line; line.setName(prodObj.value(QLatin1String("name")).toString()); const auto prodCode = prodObj.value(QLatin1String("cls")).toInt(); const auto lineModeIt = m_lineModeMap.find(prodCode); if (lineModeIt != m_lineModeMap.end()) { line.setMode((*lineModeIt).second); } else { qCDebug(Log) << "Encountered unknown line type:" << prodCode << line.name(); } const auto icoIdx = prodObj.value(QLatin1String("icoX")).toInt(); if ((unsigned int)icoIdx < icos.size()) { line.setColor(icos[icoIdx].bg); line.setTextColor(icos[icoIdx].fg); } lines.push_back(line); } return lines; } std::vector HafasMgateParser::parseStationBoardResponse(const QJsonObject &obj) const { const auto commonObj = obj.value(QLatin1String("common")).toObject(); const auto icos = parseIcos(commonObj.value(QLatin1String("icoL")).toArray()); const auto locs = parseLocations(commonObj.value(QLatin1String("locL")).toArray()); const auto lines = parseLines(commonObj.value(QLatin1String("prodL")).toArray(), icos); std::vector res; const auto jnyL = obj.value(QLatin1String("jnyL")).toArray(); res.reserve(jnyL.size()); for (const auto &jny : jnyL) { const auto jnyObj = jny.toObject(); const auto stbStop = jnyObj.value(QLatin1String("stbStop")).toObject(); Route route; route.setDirection(jnyObj.value(QLatin1String("dirTxt")).toString()); const auto lineIdx = jnyObj.value(QLatin1String("prodX")).toInt(); if ((unsigned int)lineIdx < lines.size()) { route.setLine(lines[lineIdx]); } Departure dep; dep.setRoute(route); const auto dateStr = jnyObj.value(QLatin1String("date")).toString(); dep.setScheduledDepartureTime(QDateTime::fromString(dateStr + stbStop.value(QLatin1String("dTimeS")).toString(), QLatin1String("yyyyMMddhhmmss"))); const auto dTimeR = stbStop.value(QLatin1String("dTimeR")).toString(); if (!dTimeR.isEmpty()) { dep.setExpectedDepartureTime(QDateTime::fromString(dateStr + dTimeR, QLatin1String("yyyyMMddhhmmss"))); } dep.setScheduledArrivalTime(QDateTime::fromString(dateStr + stbStop.value(QLatin1String("aTimeS")).toString(), QLatin1String("yyyyMMddhhmmss"))); const auto aTimeR = stbStop.value(QLatin1String("aTimeR")).toString(); if (!aTimeR.isEmpty()) { dep.setExpectedArrivalTime(QDateTime::fromString(dateStr + aTimeR, QLatin1String("yyyyMMddhhmmss"))); } dep.setScheduledPlatform(stbStop.value(QLatin1String("dPlatfS")).toString()); dep.setExpectedPlatform(stbStop.value(QLatin1String("dPlatfR")).toString()); if (dep.scheduledPlatform().isEmpty()) { dep.setScheduledPlatform(stbStop.value(QLatin1String("aPlatfS")).toString()); } if (dep.expectedPlatform().isEmpty()) { dep.setExpectedPlatform(stbStop.value(QLatin1String("aPlatfR")).toString()); } const auto locIdx = stbStop.value(QLatin1String("locX")).toInt(); if ((unsigned int)locIdx < locs.size()) { dep.setStopPoint(locs[locIdx]); } res.push_back(dep); } return res; } bool HafasMgateParser::parseError(const QJsonObject& obj) const { if (obj.value(QLatin1String("err")).toString() != QLatin1String("OK")) { m_error = Reply::NotFoundError; m_errorMsg = obj.value(QLatin1String("errTxt")).toString(); return false; } m_error = Reply::NoError; m_errorMsg.clear(); return true; } std::vector HafasMgateParser::parseDepartures(const QByteArray &data) const { const auto topObj = QJsonDocument::fromJson(data).object(); //qDebug().noquote() << QJsonDocument(topObj).toJson(); const auto svcResL = topObj.value(QLatin1String("svcResL")).toArray(); for (const auto &v : svcResL) { const auto obj = v.toObject(); if (obj.value(QLatin1String("meth")).toString() == QLatin1String("StationBoard")) { if (parseError(obj)) { return parseStationBoardResponse(obj.value(QLatin1String("res")).toObject()); } return {}; } } return {}; } std::vector HafasMgateParser::parseLocations(const QByteArray &data) const { const auto topObj = QJsonDocument::fromJson(data).object(); const auto svcResL = topObj.value(QLatin1String("svcResL")).toArray(); for (const auto &v : svcResL) { const auto obj = v.toObject(); const auto meth = obj.value(QLatin1String("meth")).toString(); if (meth == QLatin1String("LocMatch") || meth == QLatin1String("LocGeoPos")) { if (parseError(obj)) { const auto resObj = obj.value(QLatin1String("res")).toObject(); if (resObj.contains(QLatin1String("locL"))) { return parseLocations(resObj.value(QLatin1String("locL")).toArray()); } if (resObj.contains(QLatin1String("match"))) { return parseLocations(resObj.value(QLatin1String("match")).toObject().value(QLatin1String("locL")).toArray()); } qCDebug(Log).noquote() << "Failed to parse location query response:" << QJsonDocument(obj).toJson(); return {}; } return {}; } } return {}; } std::vector HafasMgateParser::parseJourneys(const QByteArray &data) const { const auto topObj = QJsonDocument::fromJson(data).object(); // qDebug().noquote() << QJsonDocument(topObj).toJson(); const auto svcResL = topObj.value(QLatin1String("svcResL")).toArray(); for (const auto &v : svcResL) { const auto obj = v.toObject(); if (obj.value(QLatin1String("meth")).toString() == QLatin1String("TripSearch")) { if (parseError(obj)) { return parseTripSearch(obj.value(QLatin1String("res")).toObject()); } return {}; } } return {}; } std::vector HafasMgateParser::parseTripSearch(const QJsonObject &obj) const { const auto commonObj = obj.value(QLatin1String("common")).toObject(); const auto icos = parseIcos(commonObj.value(QLatin1String("icoL")).toArray()); const auto locs = parseLocations(commonObj.value(QLatin1String("locL")).toArray()); const auto lines = parseLines(commonObj.value(QLatin1String("prodL")).toArray(), icos); std::vector res; const auto outConL = obj.value(QLatin1String("outConL")).toArray(); res.reserve(outConL.size()); for (const auto &outConV: outConL) { const auto outCon = outConV.toObject(); const auto dateStr = outCon.value(QLatin1String("date")).toString(); const auto secL = outCon.value(QLatin1String("secL")).toArray(); std::vector sections; sections.reserve(secL.size()); for (const auto &secV : secL) { const auto secObj = secV.toObject(); JourneySection section; const auto dep = secObj.value(QLatin1String("dep")).toObject(); section.setScheduledDepartureTime(QDateTime::fromString(dateStr + dep.value(QLatin1String("dTimeS")).toString(), QLatin1String("yyyyMMddhhmmss"))); const auto dTimeR = dep.value(QLatin1String("dTimeR")).toString(); if (!dTimeR.isEmpty()) { section.setExpectedDepartureTime(QDateTime::fromString(dateStr + dTimeR, QLatin1String("yyyyMMddhhmmss"))); } auto locIdx = dep.value(QLatin1String("locX")).toInt(); if ((unsigned int)locIdx < locs.size()) { section.setFrom(locs[locIdx]); } + section.setScheduledDeparturePlatform(dep.value(QLatin1String("dPlatfS")).toString()); + section.setExpectedDeparturePlatform(dep.value(QLatin1String("dPlatfR")).toString()); const auto arr = secObj.value(QLatin1String("arr")).toObject(); section.setScheduledArrivalTime(QDateTime::fromString(dateStr + arr.value(QLatin1String("aTimeS")).toString(), QLatin1String("yyyyMMddhhmmss"))); const auto aTimeR = dep.value(QLatin1String("aTimeR")).toString(); if (!aTimeR.isEmpty()) { section.setExpectedArrivalTime(QDateTime::fromString(dateStr + aTimeR, QLatin1String("yyyyMMddhhmmss"))); } locIdx = arr.value(QLatin1String("locX")).toInt(); if ((unsigned int)locIdx < locs.size()) { section.setTo(locs[locIdx]); } + section.setScheduledArrivalPlatform(dep.value(QLatin1String("aPlatfS")).toString()); + section.setExpectedArrivalPlatform(dep.value(QLatin1String("aPlatfR")).toString()); const auto typeStr = secObj.value(QLatin1String("type")).toString(); if (typeStr == QLatin1String("JNY")) { section.setMode(JourneySection::PublicTransport); const auto jnyObj = secObj.value(QLatin1String("jny")).toObject(); Route route; route.setDirection(jnyObj.value(QLatin1String("dirTxt")).toString()); const auto lineIdx = jnyObj.value(QLatin1String("prodX")).toInt(); if ((unsigned int)lineIdx < lines.size()) { route.setLine(lines[lineIdx]); } section.setRoute(route); } else if (typeStr == QLatin1String("WALK")) { section.setMode(JourneySection::Walking); } sections.push_back(section); } Journey journey; journey.setSections(std::move(sections)); res.push_back(journey); } return res; } Reply::Error HafasMgateParser::error() const { return m_error; } QString HafasMgateParser::errorMessage() const { return m_errorMsg; } diff --git a/src/publictransport/datatypes/journey.cpp b/src/publictransport/datatypes/journey.cpp index 2dd39ea..d92c65f 100644 --- a/src/publictransport/datatypes/journey.cpp +++ b/src/publictransport/datatypes/journey.cpp @@ -1,217 +1,285 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "journey.h" #include "datatypes_p.h" #include using namespace KPublicTransport; namespace KPublicTransport { class JourneySectionPrivate : public QSharedData { public: JourneySection::Mode mode = JourneySection::Invalid; QDateTime scheduledDepartureTime; QDateTime expectedDepartureTime; QDateTime scheduledArrivalTime; QDateTime expectedArrivalTime; Location from; Location to; Route route; + QString scheduledDeparturePlatform; + QString expectedDeparturePlatform; + QString scheduledArrivalPlatform; + QString expectedArrivalPlatform; }; class JourneyPrivate : public QSharedData { public: std::vector sections; }; } KPUBLICTRANSPORT_MAKE_GADGET(JourneySection) JourneySection::Mode JourneySection::mode() const { return d->mode; } void JourneySection::setMode(JourneySection::Mode mode) { d.detach(); d->mode = mode; } QDateTime JourneySection::scheduledDepartureTime() const { return d->scheduledDepartureTime; } void JourneySection::setScheduledDepartureTime(const QDateTime &dt) { d.detach(); d->scheduledDepartureTime = dt; } QDateTime JourneySection::expectedDepartureTime() const { return d->expectedDepartureTime; } void JourneySection::setExpectedDepartureTime(const QDateTime &dt) { d.detach(); d->expectedDepartureTime = dt; } bool JourneySection::hasExpectedDepartureTime() const { return d->expectedDepartureTime.isValid(); } int JourneySection::departureDelay() const { if (hasExpectedDepartureTime()) { return d->scheduledDepartureTime.secsTo(d->expectedDepartureTime) / 60; } return 0; } QDateTime JourneySection::scheduledArrivalTime() const { return d->scheduledArrivalTime; } void JourneySection::setScheduledArrivalTime(const QDateTime &dt) { d.detach(); d->scheduledArrivalTime = dt; } QDateTime JourneySection::expectedArrivalTime() const { return d->expectedArrivalTime; } void JourneySection::setExpectedArrivalTime(const QDateTime &dt) { d.detach(); d->expectedArrivalTime = dt; } bool JourneySection::hasExpectedArrivalTime() const { return d->expectedArrivalTime.isValid(); } int JourneySection::arrivalDelay() const { if (hasExpectedArrivalTime()) { return d->scheduledArrivalTime.secsTo(d->expectedArrivalTime) / 60; } return 0; } int JourneySection::duration() const { return d->scheduledDepartureTime.secsTo(d->scheduledArrivalTime); } Location JourneySection::from() const { return d->from; } void JourneySection::setFrom(const Location &from) { d.detach(); d->from = from; } Location JourneySection::to() const { return d->to; } void JourneySection::setTo(const Location &to) { d.detach(); d->to = to; } Route JourneySection::route() const { return d->route; } void JourneySection::setRoute(const Route &route) { d.detach(); d->route = route; } +QString JourneySection::scheduledDeparturePlatform() const +{ + return d->scheduledDeparturePlatform; +} + +void JourneySection::setScheduledDeparturePlatform(const QString &platform) +{ + d.detach(); + d->scheduledDeparturePlatform = platform; +} + +QString JourneySection::expectedDeparturePlatform() const +{ + return d->expectedDeparturePlatform; +} + +void JourneySection::setExpectedDeparturePlatform(const QString &platform) +{ + d.detach(); + d->expectedDeparturePlatform = platform; +} + +bool JourneySection::hasExpectedDeparturePlatform() const +{ + return !d->expectedDeparturePlatform.isEmpty(); +} + +bool JourneySection::departurePlatformChanged() const +{ + return hasExpectedDeparturePlatform() && d->expectedDeparturePlatform != d->scheduledDeparturePlatform; +} + +QString JourneySection::scheduledArrivalPlatform() const +{ + return d->scheduledArrivalPlatform; +} + +void JourneySection::setScheduledArrivalPlatform(const QString &platform) +{ + d.detach(); + d->scheduledArrivalPlatform = platform; +} + +QString JourneySection::expectedArrivalPlatform() const +{ + return d->expectedArrivalPlatform; +} + +void JourneySection::setExpectedArrivalPlatform(const QString &platform) +{ + d.detach(); + d->expectedArrivalPlatform = platform; +} + +bool JourneySection::hasExpectedArrivalPlatform() const +{ + return !d->expectedArrivalPlatform.isEmpty(); +} + +bool JourneySection::arrivalPlatformChanged() const +{ + return hasExpectedArrivalPlatform() && d->scheduledArrivalPlatform != d->expectedArrivalPlatform; +} + KPUBLICTRANSPORT_MAKE_GADGET(Journey) const std::vector& Journey::sections() const { return d->sections; } std::vector&& Journey::takeSections() { return std::move(d->sections); } void Journey::setSections(std::vector &§ions) { d.detach(); d->sections = std::move(sections); } QVariantList Journey::sectionsVariant() const { QVariantList l; l.reserve(d->sections.size()); std::transform(d->sections.begin(), d->sections.end(), std::back_inserter(l), [](const auto &sec) { return QVariant::fromValue(sec); }); return l; } QDateTime Journey::scheduledDepartureTime() const { if (!d->sections.empty()) { return d->sections.front().scheduledDepartureTime(); } return {}; } QDateTime Journey::scheduledArrivalTime() const { if (!d->sections.empty()) { return d->sections.back().scheduledArrivalTime(); } return {}; } int Journey::duration() const { return scheduledDepartureTime().secsTo(scheduledArrivalTime()); } #include "moc_journey.cpp" diff --git a/src/publictransport/datatypes/journey.h b/src/publictransport/datatypes/journey.h index e70dcc3..4b51205 100644 --- a/src/publictransport/datatypes/journey.h +++ b/src/publictransport/datatypes/journey.h @@ -1,145 +1,175 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef KPUBLICTRANSPORT_JOURNEY_H #define KPUBLICTRANSPORT_JOURNEY_H #include "datatypes.h" #include "line.h" #include "location.h" #include #include namespace KPublicTransport { class JourneySectionPrivate; /** A segment of a journey plan. */ class JourneySection { KPUBLICTRANSPORT_GADGET(JourneySection) /** Mode of transport for this section. */ Q_PROPERTY(Mode mode READ mode WRITE setMode) /** Planned departure time. */ Q_PROPERTY(QDateTime scheduledDepartureTime READ scheduledDepartureTime WRITE setScheduledDepartureTime) /** Actual departure time, if available. * Set to invalid to indicate real-time data is not available. */ Q_PROPERTY(QDateTime expectedDepartureTime READ expectedDepartureTime WRITE setExpectedDepartureTime) /** @c true if this has real-time data. */ Q_PROPERTY(bool hasExpectedDepartureTime READ hasExpectedDepartureTime STORED false) /** Difference to schedule in minutes. */ Q_PROPERTY(int departureDelay READ departureDelay STORED false) /** Planned arrival time. */ Q_PROPERTY(QDateTime scheduledArrivalTime READ scheduledArrivalTime WRITE setScheduledArrivalTime) /** Actual arrival time, if available. * Set to invalid to indicate real-time data is not available. */ Q_PROPERTY(QDateTime expectedArrivalTime READ expectedArrivalTime WRITE setExpectedArrivalTime) /** @c true if this has real-time data. */ Q_PROPERTY(bool hasExpectedArrivalTime READ hasExpectedArrivalTime STORED false) /** Difference to schedule in minutes. */ Q_PROPERTY(int arrivalDelay READ arrivalDelay STORED false) /** Duration of the section in seconds. */ Q_PROPERTY(int duration READ duration STORED false) /** Departure location of this segment. */ Q_PROPERTY(KPublicTransport::Location from READ from WRITE setFrom) /** Arrival location of this segment. */ Q_PROPERTY(KPublicTransport::Location to READ to WRITE setTo) /** Route to take on this segment. */ Q_PROPERTY(KPublicTransport::Route route READ route WRITE setRoute) - // TODO: platforms + /** Planned departure platform. */ + Q_PROPERTY(QString scheduledDeparturePlatform READ scheduledDeparturePlatform WRITE setScheduledDeparturePlatform) + /** Actual departure platform, in case real-time information are available. */ + Q_PROPERTY(QString expectedDeparturePlatform READ expectedDeparturePlatform WRITE setExpectedDeparturePlatform) + /** @c true if real-time platform information are available. */ + Q_PROPERTY(bool hasExpectedDeparturePlatform READ hasExpectedDeparturePlatform STORED false) + /** @c true if we have real-time platform information and the platform changed. */ + Q_PROPERTY(bool departurePlatformChanged READ departurePlatformChanged STORED false) + + /** Planned arrival platform. */ + Q_PROPERTY(QString scheduledArrivalPlatform READ scheduledArrivalPlatform WRITE setScheduledArrivalPlatform) + /** Actual arrival platform, in case real-time information are available. */ + Q_PROPERTY(QString expectedArrivalPlatform READ expectedArrivalPlatform WRITE setExpectedArrivalPlatform) + /** @c true if real-time platform information are available. */ + Q_PROPERTY(bool hasExpectedArrivalPlatform READ hasExpectedArrivalPlatform STORED false) + /** @c true if we have real-time platform information and the platform changed. */ + Q_PROPERTY(bool arrivalPlatformChanged READ arrivalPlatformChanged STORED false) public: /** Mode of transport. */ enum Mode { Invalid, PublicTransport, Transfer, Walking, Waiting }; Q_ENUM(Mode) Mode mode() const; void setMode(Mode mode); QDateTime scheduledDepartureTime() const; void setScheduledDepartureTime(const QDateTime &dt); QDateTime expectedDepartureTime() const; void setExpectedDepartureTime(const QDateTime &dt); bool hasExpectedDepartureTime() const; int departureDelay() const; QDateTime scheduledArrivalTime() const; void setScheduledArrivalTime(const QDateTime &dt); QDateTime expectedArrivalTime() const; void setExpectedArrivalTime(const QDateTime &dt); bool hasExpectedArrivalTime() const; int arrivalDelay() const; int duration() const; Location from() const; void setFrom(const Location &from); Location to() const; void setTo(const Location &to); Route route() const; void setRoute(const Route &route); + + QString scheduledDeparturePlatform() const; + void setScheduledDeparturePlatform(const QString &platform); + QString expectedDeparturePlatform() const; + void setExpectedDeparturePlatform(const QString &platform); + bool hasExpectedDeparturePlatform() const; + bool departurePlatformChanged() const; + + QString scheduledArrivalPlatform() const; + void setScheduledArrivalPlatform(const QString &platform); + QString expectedArrivalPlatform() const; + void setExpectedArrivalPlatform(const QString &platform); + bool hasExpectedArrivalPlatform() const; + bool arrivalPlatformChanged() const; }; class JourneyPrivate; /** A journey plan. */ class Journey { KPUBLICTRANSPORT_GADGET(Journey) /** Journey sections for consumption by QML. */ Q_PROPERTY(QVariantList sections READ sectionsVariant) /** Departure time of the journey, according to schedule. */ Q_PROPERTY(QDateTime scheduledDepartureTime READ scheduledDepartureTime STORED false) /** Arrival time of the journey, according to schedule. */ Q_PROPERTY(QDateTime scheduledArrivalTime READ scheduledArrivalTime STORED false) /** Duration of the entire journey in seconds. */ Q_PROPERTY(int duration READ duration STORED false) public: /** The journey sections. */ const std::vector& sections() const; /** Moves the journey sections out of this object. */ std::vector&& takeSections(); /** Sets the journey sections. */ void setSections(std::vector &§ions); QDateTime scheduledDepartureTime() const; QDateTime scheduledArrivalTime() const; int duration() const; private: QVariantList sectionsVariant() const; }; } Q_DECLARE_METATYPE(KPublicTransport::JourneySection) Q_DECLARE_METATYPE(KPublicTransport::Journey) #endif // KPUBLICTRANSPORT_JOURNEY_H diff --git a/tests/journeyquery.qml b/tests/journeyquery.qml index 7ccae6d..04229af 100644 --- a/tests/journeyquery.qml +++ b/tests/journeyquery.qml @@ -1,263 +1,274 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import QtQuick 2.5 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.1 as QQC2 import org.kde.kirigami 2.0 as Kirigami import org.kde.kpublictransport 1.0 Kirigami.ApplicationWindow { title: "Journey Query" reachableModeEnabled: false width: 480 height: 720 pageStack.initialPage: journyQueryPage ListModel { id: exampleModel ListElement { name: "CDG -> Gare de Lyon" fromLon: 2.57110 fromLat: 49.00406 toLon: 2.37708 toLat: 48.84388 } ListElement { name: "ZRH -> Randa" fromLon: 8.56275 fromLat: 47.45050 toLon: 7.78315 toLat: 46.09901 } ListElement { name: "Gare de Midi -> Fosdem" fromLon: 4.33620 fromLat: 50.83588 toLon: 4.38116 toLat: 50.81360 } ListElement { name: "VIE -> Akademy 2018 Accomodation" fromLon: 16.56312 fromLat: 48.12083 toLon: 16.37859 toLat: 48.18282 } ListElement { name: "Akademy 2018 BBQ -> Accomodation" fromLon: 16.43191 fromLat: 48.21612 toLon: 16.37859 toLat: 48.18282 } ListElement { name: "LEI -> Akademy 2017 Accomodation" fromLon: -2.37251 fromLat: 36.84774 toLon: -2.44788 toLat: 36.83731 } ListElement { name: "Akademy 2017 Venue -> Accomodation" fromLon: -2.40377 fromLat: 36.82784 toLon: -2.44788 toLat: 36.83731 } ListElement { name: "TXL -> Akademy 2016" fromLon: 13.29281 fromLat: 52.55420 toLon: 13.41644 toLat: 52.52068 } ListElement { name: "SXF -> Akademy 2016" fromLon: 13.51870 fromLat: 52.38841 toLon: 13.41644 toLat: 52.52068 } ListElement { name: "Brno central station -> Akademy 2014 venue" fromLon: 16.61287 fromLat: 49.19069 toLon: 16.57564 toLat: 49.22462 } } function displayDuration(dur) { if (dur < 60) return "<1min"; if (dur < 3600) return Math.floor(dur/60) + "min"; return Math.floor(dur/3600) + ":" + Math.floor((dur % 3600)/60) } Component { id: journeyDelegate Item { implicitHeight: topLayout.implicitHeight implicitWidth: topLayout.implicitWidth RowLayout { id: topLayout Rectangle { id: colorBar width: Kirigami.Units.largeSpacing color: modelData.route.line.color Layout.fillHeight: true } QQC2.Label { text: { switch (modelData.mode) { case JourneySection.PublicTransport: { switch (modelData.route.line.mode) { case Line.Air: return "✈️"; case Line.Boat: return "🛥️"; case Line.Bus: return "🚍"; case Line.BusRapidTransit: return "🚌"; case Line.Coach: return "🚌"; case Line.Ferry: return "⛴️"; case Line.Funicular: return "🚞"; case Line.LocalTrain: return "🚆"; case Line.LongDistanceTrain: return "🚄"; case Line.Metro: return "🚇"; case Line.RailShuttle: return "🚅"; case Line.RapidTransit: return "🚊"; case Line.Shuttle: return "🚐"; case Line.Taxi: return "🚕"; case Line.Train: return "🚆"; case Line.Tramway: return "🚈"; default: return "?"; } break; } case JourneySection.Walking: return "🚶"; case JourneySection.Waiting: return "⌛"; case JourneySection.Transfer: return "⇄"; default: return "?"; } } font.pointSize: Kirigami.Theme.defaultFont.pointSize * 2 } ColumnLayout { Layout.fillWidth: true - QQC2.Label { - text: "From: " + modelData.from.name + RowLayout { + QQC2.Label { + text: "From: " + modelData.from.name + " Platform: " + modelData.scheduledDeparturePlatform + } + QQC2.Label { + text: modelData.expectedDeparturePlatform + color: modelData.departurePlatformChanged ? Kirigami.Theme.negativeTextColor : Kirigami.Theme.positiveTextColor + visible: modelData.hasExpectedDeparturePlatform + } } - // TODO platform RowLayout { QQC2.Label { text: "Departure: " + modelData.scheduledDepartureTime.toTimeString() } QQC2.Label { text: (modelData.departureDelay >= 0 ? "+" : "") + modelData.departureDelay color: modelData.departureDelay > 1 ? Kirigami.Theme.negativeTextColor : Kirigami.Theme.positiveTextColor visible: modelData.hasExpectedDepartureTime } } QQC2.Label { text: { switch (modelData.mode) { case JourneySection.PublicTransport: return modelData.route.line.modeString + " " + modelData.route.line.name + " " + displayDuration(modelData.duration); case JourneySection.Walking: return "Walk " + displayDuration(modelData.duration) case JourneySection.Transfer: return "Transfer " + displayDuration(modelData.duration) case JourneySection.Waiting: return "Wait " + displayDuration(modelData.duration) return "???"; }} } - - QQC2.Label { - text: "To: " + modelData.to.name + RowLayout { + QQC2.Label { + text: "To: " + modelData.to.name + " Platform: " + modelData.scheduledArrivalPlatform + } + QQC2.Label { + text: modelData.expectedArrivalPlatform + color: modelData.arrivalPlatformChanged ? Kirigami.Theme.negativeTextColor : Kirigami.Theme.positiveTextColor + visible: modelData.hasExpectedArrivalPlatform + } } - // TODO platform RowLayout { QQC2.Label { text: "Arrival: " + modelData.scheduledArrivalTime.toTimeString() } QQC2.Label { text: (modelData.arrivalDelay >= 0 ? "+" : "") + modelData.arrivalDelay color: modelData.arrivalDelay > 1 ? Kirigami.Theme.negativeTextColor : Kirigami.Theme.positiveTextColor visible: modelData.hasExpectedArrivalTime } } } } } } Component { id: journyQueryPage Kirigami.Page { ColumnLayout { anchors.fill: parent QQC2.ComboBox { id: exampleSelector Layout.fillWidth: true model: exampleModel textRole: "name" onCurrentIndexChanged: { var obj = exampleModel.get(currentIndex); _queryMgr.findJourney(obj.fromLat, obj.fromLon, obj.toLat, obj.toLon); } } QQC2.ComboBox { id: journeySelector Layout.fillWidth: true model: _journeys } ListView { Layout.fillHeight: true Layout.fillWidth: true model: _journeys[journeySelector.currentIndex].sections spacing: Kirigami.Units.smallSpacing clip: true delegate: journeyDelegate QQC2.BusyIndicator { anchors.centerIn: parent running: _queryMgr.loading } QQC2.Label { anchors.centerIn: parent width: parent.width text: _queryMgr.errorMessage color: Kirigami.Theme.negativeTextColor wrapMode: Text.Wrap } } } } } }