Commit 6be69100 authored by Volker Krause's avatar Volker Krause
Browse files

Load the coverage format as used by the Transport API repository

This is not actively used yet, but is supposed to replace the current
temporary workarounds for this in Manager. As a side-effect coverage
data will become mandatory for all backends going forward, there wont
be in an implicit global coverage anymore.
parent 15eb10db
Pipeline #57901 passed with stage
in 25 seconds
......@@ -4,7 +4,9 @@
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include <KPublicTransport/Backend>
#include <KPublicTransport/BackendModel>
#include <KPublicTransport/CoverageArea>
#include <KPublicTransport/Manager>
#include <QAbstractItemModelTester>
......@@ -25,6 +27,19 @@ private Q_SLOTS:
QStandardPaths::setTestModeEnabled(true);
}
void testCoverageData()
{
Manager mgr;
for (const auto &b : mgr.backends()) {
QVERIFY(!b.identifier().isEmpty());
QVERIFY(!b.name().isEmpty());
// TODO make this mandatory once all configurations have it
if (b.coverageArea(CoverageArea::Realtime).isEmpty() && b.coverageArea(CoverageArea::Regular).isEmpty() && b.coverageArea(CoverageArea::Any).isEmpty()) {
qWarning() << b.identifier() << "has no coverage areas defined!";
}
}
}
void testBackendModel()
{
BackendModel model;
......
......@@ -49,6 +49,7 @@ set(kpublictransport_srcs
datatypes/attribution.cpp
datatypes/attributionutil.cpp
datatypes/backend.cpp
datatypes/coveragearea.cpp
datatypes/disruption.cpp
datatypes/equipment.cpp
datatypes/equipmentutil.cpp
......@@ -147,6 +148,7 @@ ecm_generate_headers(KPublicTransport_Datatypes_FORWARDING_HEADERS
HEADER_NAMES
Attribution
Backend
CoverageArea
Datatypes
Departure
Disruption
......
......@@ -7,6 +7,7 @@
#include "backend.h"
#include "backend_p.h"
#include "backends/abstractbackend.h"
#include "coveragearea.h"
#include "datatypes_p.h"
#include "json_p.h"
......@@ -44,6 +45,11 @@ QString Backend::primaryCountryCode() const
return {};
}
CoverageArea Backend::coverageArea(CoverageArea::Type coverageType) const
{
return d->coverage[coverageType];
}
const AbstractBackend* BackendPrivate::impl(const Backend &b)
{
return b.d->m_backendImpl.get();
......@@ -54,12 +60,32 @@ void BackendPrivate::setImpl(Backend &b, std::unique_ptr<AbstractBackend> &&impl
b.d->m_backendImpl = std::move(impl);
}
struct {
const char *name;
CoverageArea::Type type;
} static constexpr const coverage_area_map[] = {
{ "realtimeCoverage", CoverageArea::Realtime },
{ "regularCoverage", CoverageArea::Regular },
{ "anyCoverage", CoverageArea::Any },
};
Backend BackendPrivate::fromJson(const QJsonObject &obj)
{
Backend b;
const auto jsonMetaData = obj.value(QLatin1String("KPlugin")).toObject();
b.d->name = Json::translatedValue(jsonMetaData, QStringLiteral("Name"));
b.d->description = Json::translatedValue(jsonMetaData, QStringLiteral("Description"));
const auto coverage = obj.value(QLatin1String("coverage")).toObject();
for (const auto &c : coverage_area_map) {
const auto covObj = coverage.value(QLatin1String(c.name)).toObject();
if (covObj.empty()) {
continue;
}
b.d->coverage[c.type] = CoverageArea::fromJson(covObj);
b.d->coverage[c.type].setType(c.type);
}
return b;
}
......
......@@ -8,6 +8,7 @@
#define KPUBLICTRANSPORT_BACKEND_H
#include "kpublictransport_export.h"
#include "coveragearea.h"
#include "datatypes.h"
namespace KPublicTransport {
......@@ -44,6 +45,8 @@ public:
QString description() const;
bool isSecure() const;
QString primaryCountryCode() const;
CoverageArea coverageArea(CoverageArea::Type coverageType) const;
};
}
......
......@@ -7,6 +7,8 @@
#ifndef KPUBLICTRANSPORT_BACKEND_P_H
#define KPUBLICTRANSPORT_BACKEND_P_H
#include "coveragearea.h"
#include <QSharedData>
#include <QString>
......@@ -28,6 +30,7 @@ public:
std::unique_ptr<AbstractBackend> m_backendImpl;
QString name;
QString description;
CoverageArea coverage[3];
};
}
......
/*
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "coveragearea.h"
#include "datatypes_p.h"
#include "json_p.h"
#include "location.h"
#include "geo/geojson_p.h"
#include <QJsonObject>
#include <QPolygonF>
#include <QStringList>
using namespace KPublicTransport;
namespace KPublicTransport {
class CoverageAreaPrivate : public QSharedData {
public:
CoverageArea::Type type = CoverageArea::Any;
QStringList regions;
QPolygonF area;
};
}
KPUBLICTRANSPORT_MAKE_GADGET(CoverageArea)
KPUBLICTRANSPORT_MAKE_PROPERTY(CoverageArea, CoverageArea::Type, type, setType)
KPUBLICTRANSPORT_MAKE_PROPERTY(CoverageArea, QStringList, regions, setRegions)
bool CoverageArea::isEmpty() const
{
return d->regions.isEmpty() && d->area.isEmpty();
}
static QStringView countryCode(QStringView isoCode)
{
return isoCode.size() < 2 ? QStringView() : isoCode.left(2);
}
bool CoverageArea::coveresLocation(const Location &loc) const
{
if (loc.hasCoordinate() && !d->area.isEmpty()) {
return d->area.containsPoint({loc.longitude(), loc.latitude()}, Qt::WindingFill);
}
// TODO we could do a more precise check for ISO 3166-2 subdivision codes when available
if (loc.country().size() == 2 && !d->regions.empty()) {
return std::binary_search(d->regions.begin(), d->regions.end(), loc.country(), [](const auto &lhs, const auto &rhs) {
return countryCode(lhs) < countryCode(rhs);
});
}
return false;
}
CoverageArea CoverageArea::fromJson(const QJsonObject &obj)
{
CoverageArea ca;
ca.setRegions(Json::toStringList(obj.value(QLatin1String("region"))));
std::sort(ca.d->regions.begin(), ca.d->regions.end());
ca.d->area = GeoJson::readOuterPolygon(obj.value(QLatin1String("area")).toObject());
return ca;
}
#include "moc_coveragearea.cpp"
/*
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef KPUBLICTRANSPORT_COVERAGEAREA_H
#define KPUBLICTRANSPORT_COVERAGEAREA_H
#include "coveragearea.h"
#include "datatypes.h"
class QJsonObject;
class QStringList;
namespace KPublicTransport {
class CoverageAreaPrivate;
class Location;
/** Describes the area a specific KPublicTransport::Backend can provide information for. */
class KPUBLICTRANSPORT_EXPORT CoverageArea
{
KPUBLICTRANSPORT_GADGET(CoverageArea)
public:
/** Coverage quality as defined by the Transport API Repository format. */
enum Type {
Realtime,
Regular,
Any
};
KPUBLICTRANSPORT_PROPERTY(Type, type, setType)
/** ISO 3166-1/2 codes of covered regions.
* Note that actual coverage might be small (e.g. just a city inside the given region).
*/
KPUBLICTRANSPORT_PROPERTY(QStringList, regions, setRegions)
public:
/** Checks whether this coverage area is empty.
* coversLocation() would always return @p false for empty areas.
*/
bool isEmpty() const;
/** Checks whether @p loc is covered by this area. */
bool coveresLocation(const Location &loc) const;
/** Read a single coverage area information from a JSON object
* in Transport API Repository format.
*/
static CoverageArea fromJson(const QJsonObject &obj);
};
}
#endif // KPUBLICTRANSPORT_COVERAGEAREA_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment