Commit a504d281 authored by Volker Krause's avatar Volker Krause
Browse files

Prefer nationwide providers for location searches with a known country

This makes name-based location searches practically useful in countries
with many known local providers, such as AT or DE.
parent 17da55e1
......@@ -79,6 +79,11 @@ bool CoverageArea::coversLocation(const Location &loc) const
return true;
}
bool CoverageArea::hasNationWideCoverage(const QString &country) const
{
return std::binary_search(d->regions.begin(), d->regions.end(), country);
}
CoverageArea CoverageArea::fromJson(const QJsonObject &obj)
{
CoverageArea ca;
......
......@@ -52,6 +52,9 @@ public:
/** Checks whether @p loc is covered by this area. */
bool coversLocation(const Location &loc) const;
/** Checks whether this includes the entire country @p country. */
bool hasNationWideCoverage(const QString &country) const;
/** Read a single coverage area information from a JSON object
* in Transport API Repository format.
*/
......
......@@ -86,6 +86,8 @@ public:
void readCachedAttributions();
int queryLocationOnBackend(const LocationRequest &req, LocationReply *reply, const Backend &backend);
Manager *q = nullptr;
QNetworkAccessManager *m_nam = nullptr;
std::vector<Backend> m_backends;
......@@ -663,7 +665,7 @@ StopoverReply* Manager::queryStopover(const StopoverRequest &req) const
}
}
if (req.downloadAssets()) {
if (req.downloadAssets()) {
reply->addAttributions(AssetRepository::instance()->attributions());
}
reply->setPendingOps(pendingOps);
......@@ -675,6 +677,30 @@ StopoverReply* Manager::queryDeparture(const StopoverRequest &req) const
return queryStopover(req);
}
int ManagerPrivate::queryLocationOnBackend(const LocationRequest &req, LocationReply *reply, const Backend &backend)
{
auto cache = Cache::lookupLocation(backend.identifier(), req.cacheKey());
switch (cache.type) {
case CacheHitType::Negative:
qCDebug(Log) << "Negative cache hit for backend" << backend.identifier();
break;
case CacheHitType::Positive:
qCDebug(Log) << "Positive cache hit for backend" << backend.identifier();
reply->addAttributions(std::move(cache.attributions));
reply->addResult(std::move(cache.data));
break;
case CacheHitType::Miss:
qCDebug(Log) << "Cache miss for backend" << backend.identifier();
reply->addAttribution(BackendPrivate::impl(backend)->attribution());
if (BackendPrivate::impl(backend)->queryLocation(req, reply, nam())) {
return 1;
}
break;
}
return 0;
}
LocationReply* Manager::queryLocation(const LocationRequest &req) const
{
auto reply = d->makeReply<LocationReply>(req);
......@@ -689,37 +715,43 @@ LocationReply* Manager::queryLocation(const LocationRequest &req) const
QSet<QString> triedBackends;
bool foundNonGlobalCoverage = false;
const auto loc = req.location();
const auto isCountryOnly = !loc.hasCoordinate() && !loc.country().isEmpty() && loc.region().isEmpty();
for (const auto coverageType : { CoverageArea::Realtime, CoverageArea::Regular, CoverageArea::Any }) {
// pass 1: coordinate-based coverage, or nationwide country coverage
for (const auto &backend : d->m_backends) {
if (triedBackends.contains(backend.identifier()) || d->shouldSkipBackend(backend, req)) {
continue;
}
const auto coverage = backend.coverageArea(coverageType);
if (coverage.isEmpty() || !coverage.coversLocation(req.location())) {
if (coverage.isEmpty() || !coverage.coversLocation(loc)) {
continue;
}
if (isCountryOnly && !coverage.hasNationWideCoverage(loc.country())) {
continue;
}
triedBackends.insert(backend.identifier());
foundNonGlobalCoverage |= !coverage.isGlobal();
pendingOps += d->queryLocationOnBackend(req, reply, backend);
}
if (pendingOps && foundNonGlobalCoverage) {
break;
}
reply->addAttribution(BackendPrivate::impl(backend)->attribution());
auto cache = Cache::lookupLocation(backend.identifier(), req.cacheKey());
switch (cache.type) {
case CacheHitType::Negative:
qCDebug(Log) << "Negative cache hit for backend" << backend.identifier();
break;
case CacheHitType::Positive:
qCDebug(Log) << "Positive cache hit for backend" << backend.identifier();
reply->addAttributions(std::move(cache.attributions));
reply->addResult(std::move(cache.data));
break;
case CacheHitType::Miss:
qCDebug(Log) << "Cache miss for backend" << backend.identifier();
if (BackendPrivate::impl(backend)->queryLocation(req, reply, d->nam())) {
++pendingOps;
}
break;
// pass 2: any country match
for (const auto &backend : d->m_backends) {
if (triedBackends.contains(backend.identifier()) || d->shouldSkipBackend(backend, req)) {
continue;
}
const auto coverage = backend.coverageArea(coverageType);
if (coverage.isEmpty() || !coverage.coversLocation(loc)) {
continue;
}
triedBackends.insert(backend.identifier());
foundNonGlobalCoverage |= !coverage.isGlobal();
pendingOps += d->queryLocationOnBackend(req, reply, backend);
}
if (pendingOps && foundNonGlobalCoverage) {
break;
......
......@@ -9,6 +9,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15 as QQC2
import org.kde.kirigami 2.17 as Kirigami
import org.kde.kitemmodels 1.0
import org.kde.i18n.localeData 1.0
import org.kde.kpublictransport 1.0
Kirigami.ApplicationWindow {
......@@ -34,13 +35,29 @@ Kirigami.ApplicationWindow {
}
]
header: ColumnLayout {
QQC2.ComboBox {
id: countryCombo
model: Country.allCountries
Layout.fillWidth: true
displayText: currentValue.emojiFlag + ' ' + currentValue.name
delegate: QQC2.ItemDelegate {
text: modelData.emojiFlag + ' ' + modelData.name
width: parent ? parent.width : undefined
}
Component.onCompleted: {
countryCombo.currentIndex = countryCombo.indexOfValue(Country.fromAlpha2(Qt.locale().name.match(/_([A-Z]{2})/)[1]))
}
}
Kirigami.SearchField {
id: queryTextField
Layout.fillWidth: true
onAccepted: {
if (text !== "") {
locationQueryModel.request.name = text;
locationQueryModel.request.backends = [ "de_db" ]; // TODO
var loc = locationQueryModel.request.location;
loc.name = text;
loc.country = countryCombo.currentValue.alpha2
locationQueryModel.request.location = loc;
locationQueryModel.request.type = Location.Stop
}
}
}
......
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