Commit 4e1f6e59 authored by Volker Krause's avatar Volker Krause
Browse files

Use KI18nLocaleData when available

This duplicates a bit of code we can remove again once we depend
unconditionally on KF 5.88. Doing this now already however allows
for an easy side-by-side comparison of the results.

There are minor changes in places with ambiguous timezones, and
since country lookup is no longer tied to timezones, we now also
get proper results for Thailand and northern Vietnam.
parent 676d2bb1
Pipeline #89876 passed with stage
in 14 minutes and 12 seconds
......@@ -4,6 +4,7 @@
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include <config-kitinerary.h>
#include <knowledgedb/airportdb.h>
#include <KItinerary/LocationUtil>
......@@ -35,6 +36,12 @@ char *toString(const CountryId &code)
}
}}
char *toString(const QTimeZone &tz)
{
using QTest::toString;
return toString(tz.id());
}
class AirportDbTest : public QObject
{
Q_OBJECT
......
......@@ -6,6 +6,7 @@
#include <KItinerary/CountryDb>
#include <config-kitinerary.h>
#include <knowledgedb/alphaid.h>
#include <knowledgedb/trainstationdb.h>
......@@ -25,6 +26,12 @@ char *toString(CountryId c)
}
}}
char *toString(const QTimeZone &tz)
{
using QTest::toString;
return toString(tz.id());
}
class KnowledgeDbTest : public QObject
{
Q_OBJECT
......@@ -284,7 +291,11 @@ private Q_SLOTS:
QCOMPARE(timezoneForLocation(32.55783, -117.04773, u"US"), QTimeZone("America/Los_Angeles"));
// Cordoba (AR), AR has several sub-zones that are all equivalent
#if HAVE_KI18N_LOCALE_DATA
QCOMPARE(timezoneForLocation(-31.4, -64.2, u"AR"), QTimeZone("America/Argentina/Buenos_Aires"));
#else
QCOMPARE(timezoneForLocation(-31.4, -64.2, u"AR"), QTimeZone("America/Argentina/Cordoba"));
#endif
// polar regions
QCOMPARE(timezoneForLocation(-90.0, 0.0, {}), QTimeZone());
......@@ -310,6 +321,12 @@ private Q_SLOTS:
// ambiguous locations
QCOMPARE(countryForCoordinate(51.44344, 4.93373), QString());
#if HAVE_KI18N_LOCALE_DATA
// special case: northern Vietnam has a non-VN timezone (not the case anywhere else in the world up to 2020a)
QCOMPARE(countryForCoordinate(21.0, 106.0), QLatin1String("VN"));
QCOMPARE(countryForCoordinate(10.5, 107.0), QLatin1String{"VN"});
QCOMPARE(countryForCoordinate(13.7, 100.4), QLatin1String("TH"));
#else
// special case: northern Vietnam has a non-VN timezone (not the case anywhere else in the world up to 2020a)
QCOMPARE(countryForCoordinate(21.0, 106.0), QString());
QCOMPARE(countryForCoordinate(10.5, 107.0), QLatin1String{"VN"});
......@@ -317,6 +334,7 @@ private Q_SLOTS:
// disputed areas
QCOMPARE(countryForCoordinate(45.0, 34.0), QString());
#endif
// overseas territories with separate ISO 3166-1 codes
QCOMPARE(countryForCoordinate(4.8, -52.3), QLatin1String{"GF"}); // could also be "FR"
......@@ -330,6 +348,7 @@ private Q_SLOTS:
QCOMPARE(KnowledgeDb::countryIdForUicCode(0), CountryId{});
}
#if !HAVE_KI18N_LOCALE_DATA
void testIso3Lookup()
{
using namespace KnowledgeDb;
......@@ -337,6 +356,7 @@ private Q_SLOTS:
QCOMPARE(KnowledgeDb::countryIdFromIso3166_1alpha3(CountryId3{"ITA"}), CountryId{"IT"});
QCOMPARE(KnowledgeDb::countryIdFromIso3166_1alpha3(CountryId3{"FOO"}), CountryId{});
}
#endif
void testIndianRailwaysStationCodeLookup()
{
......
......@@ -180,6 +180,9 @@ target_link_libraries(KPimItinerary
if (HAVE_POPPLER)
target_link_libraries(KPimItinerary PRIVATE Poppler::Core)
endif()
if (TARGET KF5::I18nLocaleData)
target_link_libraries(KPimItinerary PRIVATE KF5::I18nLocaleData)
endif()
if (TARGET ZXing::ZXing)
target_link_libraries(KPimItinerary PRIVATE ZXing::ZXing)
......
......@@ -4,6 +4,8 @@
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include <ki18n_version.h> // ### temporary until we depend on >= KF 5.88
#ifndef CONFIG_KITINERARY_H
#define CONFIG_KITINERARY_H
......@@ -36,6 +38,12 @@
#cmakedefine HAVE_LIBXML2
#cmakedefine HAVE_PHONENUMBER
#if KI18N_VERSION >= K_VERSION_CHECK(5, 88, 0)
#define HAVE_KI18N_LOCALE_DATA 1
#else
#define HAVE_KI18N_LOCALE_DATA 0
#endif
#define CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}"
#endif
......@@ -34,7 +34,11 @@
#include <KItinerary/TrainTrip>
#include <KItinerary/Visit>
#if HAVE_KI18N_LOCALE_DATA
#include <KCountry>
#else
#include <KContacts/Address>
#endif
#include <QDebug>
#include <QJsonArray>
......@@ -448,6 +452,20 @@ PostalAddress ExtractorPostprocessorPrivate::processAddress(PostalAddress addr,
{
// convert to ISO 3166-1 alpha-2 country codes
if (addr.addressCountry().size() > 2) {
#if HAVE_KI18N_LOCALE_DATA
QString alpha2Code;
// try ISO 3166-1 alpha-3, we get that e.g. from Flixbus
if (addr.addressCountry().size() == 3) {
alpha2Code = KCountry::fromAlpha3(addr.addressCountry()).alpha2();
}
if (alpha2Code.isEmpty()) {
alpha2Code = KCountry::fromName(addr.addressCountry()).alpha2();
}
if (!alpha2Code.isEmpty()) {
addr.setAddressCountry(alpha2Code);
}
#else
const auto isoCode = KContacts::Address::countryToISO(addr.addressCountry()).toUpper();
if (!isoCode.isEmpty()) {
addr.setAddressCountry(isoCode);
......@@ -459,6 +477,7 @@ PostalAddress ExtractorPostprocessorPrivate::processAddress(PostalAddress addr,
addr.setAddressCountry(c.toString());
}
}
#endif
}
// upper case country codes
......
......@@ -4,6 +4,7 @@
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "config-kitinerary.h"
#include "countrydb.h"
#include "countrydb_data.cpp"
......@@ -88,6 +89,7 @@ PowerPlugTypes KnowledgeDb::incompatiblePowerSockets(PowerPlugTypes plugs, Power
return failSockets & ~plugs;
}
#if !HAVE_KI18N_LOCALE_DATA
KnowledgeDb::CountryId KnowledgeDb::countryIdFromIso3166_1alpha3(CountryId3 iso3Code)
{
const auto it = std::lower_bound(std::begin(iso_country_code_table), std::end(iso_country_code_table), iso3Code, [](const auto &lhs, CountryId3 rhs) {
......@@ -99,6 +101,7 @@ KnowledgeDb::CountryId KnowledgeDb::countryIdFromIso3166_1alpha3(CountryId3 iso3
return (*it).iso2Code;
}
#endif
KnowledgeDb::CountryId KnowledgeDb::countryIdForUicCode(uint16_t uicCountryCode)
{
......
......@@ -4,19 +4,53 @@
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "config-kitinerary.h"
#include "timezonedb.h"
#if !HAVE_KI18N_LOCALE_DATA
#include "countrydb.h"
#include "timezonedb_data.h"
#include "timezonedb_p.h"
#include "timezonedb_data.cpp"
#include "timezone_zindex.cpp"
#endif
#if HAVE_KI18N_LOCALE_DATA
#include <KCountry>
#include <KTimeZone>
#endif
#include <QDebug>
#include <QTimeZone>
#include <cmath>
#include <cstring>
using namespace KItinerary;
#if HAVE_KI18N_LOCALE_DATA
static QTimeZone toQTimeZone(const char *tzId)
{
if (!tzId || std::strcmp(tzId, "") == 0) {
return {};
}
return QTimeZone(tzId);
}
static QList<const char*> timezonesForCountry(const KCountry &country)
{
auto tzs = country.timeZoneIds();
if (tzs.size() <= 1) {
return tzs;
}
// filter overseas territories that map back to a different country code
tzs.erase(std::remove_if(tzs.begin(), tzs.end(), [country](const char *tz) {
return !(KTimeZone::country(tz) == country);
}), tzs.end());
return tzs;
}
#else
static const char* tzId(KnowledgeDb::Tz tz)
{
using namespace KnowledgeDb;
......@@ -78,6 +112,7 @@ static KnowledgeDb::Tz timezoneForCoordinate(float lat, float lon, bool *ambiguo
}
return static_cast<Tz>((*std::prev(it)).tz);
}
#endif
static bool compareOffsetData(const QTimeZone::OffsetData &lhs, const QTimeZone::OffsetData &rhs)
{
......@@ -109,6 +144,60 @@ static bool isEquivalentTimezone(const QTimeZone &lhs, const QTimeZone &rhs)
QTimeZone KnowledgeDb::timezoneForLocation(float lat, float lon, QStringView alpha2CountryCode)
{
#if HAVE_KI18N_LOCALE_DATA
const auto coordTz = KTimeZone::fromLocation(lat, lon);
const auto coordZone = toQTimeZone(coordTz);
const auto country = KCountry::fromAlpha2(alpha2CountryCode);
const auto countryTzs = timezonesForCountry(country);
const auto countryFromTz = KTimeZone::country(coordTz);
// if we determine a different country than was provided, search for an equivalent timezone
// in the requested country
// example: Tijuana airport ending up in America/Los Angeles, and America/Tijuna being the only MX timezone equivalent to that
if (coordTz && countryFromTz.isValid() && country.isValid() && !(countryFromTz == country)) { // ### clean up once KCountry has op!=
bool nonUnique = false;
QTimeZone foundTz;
for (const char *countryTz : countryTzs) {
const auto t = toQTimeZone(countryTz);
if (!isEquivalentTimezone(t, coordZone)) {
continue;
}
if (foundTz.isValid()) {
nonUnique = true;
break;
}
foundTz = t;
}
if (!nonUnique && foundTz.isValid()) {
return foundTz;
}
}
// only one method found a result, let's use that one
if ((coordZone.isValid() && countryTzs.contains(coordTz)) || countryTzs.isEmpty()) {
return coordZone;
}
if (!coordZone.isValid() && countryTzs.size() == 1) {
return toQTimeZone(countryTzs.at(0));
}
// if the coordinate-based timezone is also in @p country, that takes precedence
// example: the various AR sub-zones, or the MY sub-zone
if (country == countryFromTz) {
return coordZone;
}
// if both timezones are equivalent, the country-based one wins, otherwise we use the coordinate one
if (countryTzs.size() == 1) {
const auto countryQtz = toQTimeZone(countryTzs.at(0));
return isEquivalentTimezone(coordZone, countryQtz) ? countryQtz : coordZone;
}
return coordZone;
#else
const auto country = CountryId{alpha2CountryCode};
bool ambiguous = false;
const auto coordTz = timezoneForCoordinate(lat, lon, &ambiguous);
......@@ -162,14 +251,19 @@ QTimeZone KnowledgeDb::timezoneForLocation(float lat, float lon, QStringView alp
const auto coordQtz = toQTimeZone(coordTz);
const auto countryQtz = toQTimeZone(countryTz);
return isEquivalentTimezone(coordQtz, countryQtz) ? countryQtz : coordQtz;
#endif
}
QString KnowledgeDb::countryForCoordinate(float lat, float lon)
{
#if HAVE_KI18N_LOCALE_DATA
return KCountry::fromLocation(lat, lon).alpha2();
#else
bool ambiguous = false;
const auto tz = timezoneForCoordinate(lat, lon, &ambiguous);
if (!ambiguous) {
return countryForTimezone(tz).toString();
}
return {};
#endif
}
Supports Markdown
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