diff --git a/src/publictransport/datatypes/departure.cpp b/src/publictransport/datatypes/departure.cpp index 1d9994e..f48822d 100644 --- a/src/publictransport/datatypes/departure.cpp +++ b/src/publictransport/datatypes/departure.cpp @@ -1,115 +1,141 @@ /* 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 "departure.h" #include "datatypes_p.h" #include using namespace KPublicTransport; namespace KPublicTransport { class DeparturePrivate : public QSharedData { public: QDateTime scheduledTime; QDateTime expectedTime; QString scheduledPlatform; QString expectedPlatform; Route route; Location stopPoint; }; } KPUBLICTRANSPORT_MAKE_GADGET(Departure) QDateTime Departure::scheduledTime() const { return d->scheduledTime; } void Departure::setScheduledTime(const QDateTime &scheduledTime) { d.detach(); d->scheduledTime = scheduledTime; } QDateTime Departure::expectedTime() const { return d->expectedTime; } void Departure::setExpectedTime(const QDateTime &expectedTime) { d.detach(); d->expectedTime = expectedTime; } bool Departure::hasExpectedTime() const { return d->expectedTime.isValid(); } QString Departure::scheduledPlatform() const { return d->scheduledPlatform; } void Departure::setScheduledPlatform(const QString &platform) { d.detach(); d->scheduledPlatform = platform; } QString Departure::expectedPlatform() const { return d->expectedPlatform; } void Departure::setExpectedPlatform(const QString &platform) { d.detach(); d->expectedPlatform = platform; } bool Departure::hasExpectedPlatform() const { return !d->expectedPlatform.isEmpty(); } Route Departure::route() const { return d->route; } void Departure::setRoute(const Route &route) { d.detach(); d->route = route; } Location Departure::stopPoint() const { return d->stopPoint; } void Departure::setStopPoint(const Location &stopPoint) { d.detach(); d->stopPoint = stopPoint; } +bool Departure::isSame(const Departure &lhs, const Departure &rhs) +{ + if (lhs.scheduledTime() != rhs.scheduledTime()) { + return false; + } + + return Route::isSame(lhs.route(), rhs.route()); +} + +Departure Departure::merge(const Departure &lhs, const Departure &rhs) +{ + auto dep = lhs; + if (!dep.hasExpectedTime() && rhs.hasExpectedTime()) { + dep.setExpectedTime(rhs.expectedTime()); + } + if (dep.scheduledPlatform().isEmpty() && !rhs.scheduledPlatform().isEmpty()) { + dep.setScheduledPlatform(rhs.scheduledPlatform()); + } + if (!dep.hasExpectedPlatform() && rhs.hasExpectedPlatform()) { + dep.setExpectedPlatform(rhs.expectedPlatform()); + } + + dep.setRoute(Route::merge(lhs.route(), rhs.route())); + return dep; +} + #include "moc_departure.cpp" diff --git a/src/publictransport/datatypes/departure.h b/src/publictransport/datatypes/departure.h index 19c1e7d..d5415cf 100644 --- a/src/publictransport/datatypes/departure.h +++ b/src/publictransport/datatypes/departure.h @@ -1,81 +1,89 @@ /* 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_DEPARTURE_H #define KPUBLICTRANSPORT_DEPARTURE_H #include "datatypes.h" #include "line.h" #include "location.h" class QDateTime; namespace KPublicTransport { class DeparturePrivate; /** Information about a departure of a vehicle at a stop area. */ class Departure { KPUBLICTRANSPORT_GADGET(Departure) /** Planned departure time. */ Q_PROPERTY(QDateTime scheduledTime READ scheduledTime WRITE setScheduledTime) /** Actual departure time, if available. * Set to invalid to indicate real-time data is not available. */ Q_PROPERTY(QDateTime expectedTime READ expectedTime WRITE setExpectedTime) /** @c true if this has real-time data. */ Q_PROPERTY(bool hasExpectedTime READ hasExpectedTime STORED false) /** Planned departure platform. */ Q_PROPERTY(QString scheduledPlatform READ scheduledPlatform WRITE setScheduledPlatform) /** Actual departure platform, in case real-time information are available. */ Q_PROPERTY(QString expectedPlatform READ expectedPlatform WRITE setExpectedPlatform) /** @c true if real-time platform information are available. */ Q_PROPERTY(bool hasExpectedPlatform READ hasExpectedPlatform STORED false) /** The departing route. */ Q_PROPERTY(KPublicTransport::Route route READ route WRITE setRoute) /** The stop point of this departure. */ Q_PROPERTY(KPublicTransport::Location stopPoint READ stopPoint WRITE setStopPoint) public: QDateTime scheduledTime() const; void setScheduledTime(const QDateTime &scheduledTime); QDateTime expectedTime() const; void setExpectedTime(const QDateTime &expectedTime); bool hasExpectedTime() const; QString scheduledPlatform() const; void setScheduledPlatform(const QString &platform); QString expectedPlatform() const; void setExpectedPlatform(const QString &platform); bool hasExpectedPlatform() const; Route route() const; void setRoute(const Route &route); Location stopPoint() const; void setStopPoint(const Location &stopPoint); + + /** Checks if to instances refer to the same departure (which does not necessarily mean they are exactly equal). */ + static bool isSame(const Departure &lhs, const Departure &rhs); + + /** Merge two departure instances. + * This assumes isSame(lhs, rhs) and tries to preserve the most detailed information. + */ + static Departure merge(const Departure &lhs, const Departure &rhs); }; } Q_DECLARE_METATYPE(KPublicTransport::Departure) #endif // KPUBLICTRANSPORT_DEPARTURE_H diff --git a/src/publictransport/datatypes/line.cpp b/src/publictransport/datatypes/line.cpp index f5161b8..1315a28 100644 --- a/src/publictransport/datatypes/line.cpp +++ b/src/publictransport/datatypes/line.cpp @@ -1,125 +1,177 @@ /* 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 "line.h" #include "datatypes_p.h" #include +#include using namespace KPublicTransport; namespace KPublicTransport { class LinePrivate : public QSharedData { public: Line::Mode mode; QString modeString; QString name; QColor color; QColor textColor; }; class RoutePrivate : public QSharedData { public: Line line; QString direction; }; } +static bool isSameLocationName(const QString &lhs, const QString &rhs) +{ + if (lhs.size() == rhs.size()) { + return lhs.compare(rhs, Qt::CaseInsensitive) == 0; + } + if (lhs.size() < rhs.size()) { + return rhs.startsWith(lhs, Qt::CaseInsensitive); + } + return lhs.startsWith(rhs, Qt::CaseInsensitive); +} + +static bool isSameLineName(const QString &lhs, const QString &rhs) +{ + if (lhs.size() == rhs.size()) { + return lhs.compare(rhs, Qt::CaseInsensitive) == 0; + } + if (lhs.size() < rhs.size()) { + return rhs.endsWith(QLatin1Char(' ') + lhs, Qt::CaseInsensitive); + } + return lhs.endsWith(QLatin1Char(' ') + rhs, Qt::CaseInsensitive); +} + KPUBLICTRANSPORT_MAKE_GADGET(Line) QString Line::name() const { return d->name; } void Line::setName(const QString &name) { d.detach(); d->name = name; } QColor Line::color() const { return d->color; } void Line::setColor(const QColor &color) { d.detach(); d->color = color; } QColor Line::textColor() const { return d->textColor; } void Line::setTextColor(const QColor &textColor) { d.detach(); d->textColor = textColor; } Line::Mode Line::mode() const { return d->mode; } void Line::setMode(Line::Mode mode) { d.detach(); d->mode = mode; } QString Line::modeString() const { return d->modeString; } void Line::setModeString(const QString &modeString) { d.detach(); d->modeString = modeString; } +bool Line::isSame(const Line &lhs, const Line &rhs) +{ + return isSameLineName(lhs.name(), rhs.name()) && lhs.mode() == rhs.mode(); +} + +Line Line::merge(const Line &lhs, const Line &rhs) +{ + Line l(lhs); + if (!l.color().isValid() && rhs.color().isValid()) { + l.setColor(rhs.color()); + } + if (!l.textColor().isValid() && rhs.textColor().isValid()) { + l.setTextColor(rhs.textColor()); + } + return l; +} KPUBLICTRANSPORT_MAKE_GADGET(Route) Line Route::line() const { return d->line; } void Route::setLine(const Line &line) { d.detach(); d->line = line; } QString Route::direction() const { return d->direction; } void Route::setDirection(const QString &direction) { d.detach(); d->direction = direction; } +bool Route::isSame(const Route &lhs, const Route &rhs) +{ + return isSameLocationName(lhs.direction(), rhs.direction()) && + Line::isSame(lhs.line(), rhs.line()); +} + +Route Route::merge(const Route &lhs, const Route &rhs) +{ + Route r(lhs); + r.setLine(Line::merge(lhs.line(), rhs.line())); + return r; +} + #include "moc_line.cpp" diff --git a/src/publictransport/datatypes/line.h b/src/publictransport/datatypes/line.h index 0cfb629..9792b02 100644 --- a/src/publictransport/datatypes/line.h +++ b/src/publictransport/datatypes/line.h @@ -1,102 +1,118 @@ /* 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_LINE_H #define KPUBLICTRANSPORT_LINE_H #include "datatypes.h" namespace KPublicTransport { class LinePrivate; /** A public transport line. */ class Line { KPUBLICTRANSPORT_GADGET(Line) /** Name of the line. */ Q_PROPERTY(QString name READ name WRITE setName) /** Color of the line. */ Q_PROPERTY(QColor color READ color WRITE setColor) /** Text color to use on top of the line color. */ Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor) /** Type of transport. */ Q_PROPERTY(Mode mode READ mode WRITE setMode) /** Human readable representation of the type of transport. * This is not necessarily a simple 1:1 mapping from mode, but can contain * e.g. a product name. */ Q_PROPERTY(QString modeString READ modeString WRITE setModeString) public: QString name() const; void setName(const QString &name); QColor color() const; void setColor(const QColor &color); QColor textColor() const; void setTextColor(const QColor &textColor); enum Mode { // ### direct copy from Navitia, we maybe can reduce that a bit Unknown, Air, Boat, Bus, BusRapidTransit, Coach, Ferry, Funicular, LocalTrain, LongDistanceTrain, Metro, RailShuttle, RapidTransit, Shuttle, Taxi, Train, Tramway, }; Q_ENUM(Mode) Mode mode() const; void setMode(Mode mode); QString modeString() const; void setModeString(const QString &modeString); + + /** Checks if to instances refer to the same line (which does not necessarily mean they are exactly equal). */ + static bool isSame(const Line &lhs, const Line &rhs); + + /** Merge two Line instances. + * This assumes isSame(lhs, rhs) and tries to preserve the most detailed information. + */ + static Line merge(const Line &lhs, const Line &rhs); }; class RoutePrivate; /** A route of a public transport line. */ class Route { KPUBLICTRANSPORT_GADGET(Route) /** Line this route belongs to. */ Q_PROPERTY(KPublicTransport::Line line READ line WRITE setLine) /** Direction of the route. */ Q_PROPERTY(QString direction READ direction WRITE setDirection) public: Line line() const; void setLine(const Line &line); QString direction() const; void setDirection(const QString &direction); + + /** Checks if to instances refer to the same route (which does not necessarily mean they are exactly equal). */ + static bool isSame(const Route &lhs, const Route &rhs); + + /** Merge two Route instances. + * This assumes isSame(lhs, rhs) and tries to preserve the most detailed information. + */ + static Route merge(const Route &lhs, const Route &rhs); }; } Q_DECLARE_METATYPE(KPublicTransport::Line) Q_DECLARE_METATYPE(KPublicTransport::Route) #endif // KPUBLICTRANSPORT_LINE_H diff --git a/src/publictransport/departurereply.cpp b/src/publictransport/departurereply.cpp index 98ac7d8..060db62 100644 --- a/src/publictransport/departurereply.cpp +++ b/src/publictransport/departurereply.cpp @@ -1,84 +1,99 @@ /* 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 "departurereply.h" #include "reply_p.h" #include "departurerequest.h" #include "logging.h" #include #include using namespace KPublicTransport; namespace KPublicTransport { class DepartureReplyPrivate : public ReplyPrivate { public: void finalizeResult() override; DepartureRequest request; std::vector departures; }; } void DepartureReplyPrivate::finalizeResult() { if (departures.empty()) { return; } error = Reply::NoError; errorMsg.clear(); std::sort(departures.begin(), departures.end(), [](const auto &lhs, const auto &rhs) { return lhs.scheduledTime() < rhs.scheduledTime(); }); + + for (auto it = departures.begin(); it != departures.end(); ++it) { + for (auto mergeIt = it + 1; mergeIt != departures.end();) { + if ((*it).scheduledTime() != (*mergeIt).scheduledTime()) { + break; + } + + if (Departure::isSame(*it, *mergeIt)) { + *it = Departure::merge(*it, *mergeIt); + mergeIt = departures.erase(mergeIt); + } else { + ++mergeIt; + } + } + } } DepartureReply::DepartureReply(const DepartureRequest &req) : Reply(new DepartureReplyPrivate) { Q_D(DepartureReply); d->request = req; } DepartureReply::~DepartureReply() = default; DepartureRequest DepartureReply::request() const { Q_D(const DepartureReply); return d->request; } std::vector DepartureReply::departures() const { Q_D(const DepartureReply); return d->departures; // TODO this copies } void DepartureReply::addResult(std::vector &&res) { Q_D(DepartureReply); if (d->departures.empty()) { d->departures = std::move(res); } else { d->departures.insert(d->departures.end(), res.begin(), res.end()); } d->pendingOps--; d->emitFinishedIfDone(this); }