File indexing completed on 2025-02-02 05:02:32

0001 /*
0002     SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "navigationcontroller.h"
0008 #include "logging.h"
0009 
0010 #include <KItinerary/LocationUtil>
0011 #include <KItinerary/Place>
0012 
0013 #include <QCoreApplication>
0014 #include <QDebug>
0015 #include <QDesktopServices>
0016 #include <QUrl>
0017 #include <QUrlQuery>
0018 
0019 #ifdef Q_OS_ANDROID
0020 #include "kandroidextras/activity.h"
0021 #include "kandroidextras/intent.h"
0022 #else
0023 #include <QGeoPositionInfo>
0024 #include <QGeoPositionInfoSource>
0025 #endif
0026 
0027 using namespace KItinerary;
0028 
0029 #ifdef Q_OS_ANDROID
0030 static bool startActivity(const QUrl &url)
0031 {
0032     using namespace KAndroidExtras;
0033 
0034     Intent intent;
0035     intent.setAction(Intent::ACTION_VIEW);
0036     intent.setData(url);
0037     return Activity::startActivity(intent, 0);
0038 }
0039 #endif
0040 
0041 void NavigationController::showOnMap(const QVariant &place)
0042 {
0043     if (place.isNull()) {
0044         return;
0045     }
0046 
0047     const auto geo = LocationUtil::geo(place);
0048     if (geo.isValid()) {
0049         // zoom out further from airports, they are larger and you usually want to go further away from them
0050         showOnMap(geo.latitude(), geo.longitude(), place.userType() == qMetaTypeId<Airport>() ? 12 : 17);
0051         return;
0052     }
0053 
0054     const auto addr = LocationUtil::address(place);
0055     if (!addr.isEmpty()) {
0056         QDesktopServices::openUrl(LocationUtil::geoUri(place));
0057     }
0058 }
0059 
0060 void NavigationController::showOnMap(float latitude, float longitude, int zoom)
0061 {
0062     QUrl url;
0063     url.setScheme(QStringLiteral("geo"));
0064     url.setPath(QString::number(latitude) + QLatin1Char(',') + QString::number(longitude));
0065     QUrlQuery query;
0066     query.addQueryItem(QStringLiteral("z"), QString::number(zoom));
0067     url.setQuery(query);
0068     QDesktopServices::openUrl(url);
0069 }
0070 
0071 void NavigationController::showOnWheelmap(float latitude, float longitude)
0072 {
0073     QUrl url;
0074     url.setScheme(QStringLiteral("https"));
0075     url.setHost(QStringLiteral("wheelmap.org"));
0076     QUrlQuery query;
0077     query.addQueryItem(QStringLiteral("lat"), QString::number(latitude));
0078     query.addQueryItem(QStringLiteral("lon"), QString::number(longitude));
0079     url.setQuery(query);
0080     QDesktopServices::openUrl(url);
0081 }
0082 
0083 bool NavigationController::canNavigateTo(const QVariant& place)
0084 {
0085     if (place.isNull()) {
0086         return false;
0087     }
0088 
0089     if (LocationUtil::geo(place).isValid()) {
0090         return true;
0091     }
0092 
0093 #ifdef Q_OS_ANDROID
0094     return !LocationUtil::address(place).isEmpty();
0095 #else
0096     return false;
0097 #endif
0098 }
0099 
0100 void NavigationController::navigateTo(const QVariant& place)
0101 {
0102     if (place.isNull()) {
0103         return;
0104     }
0105 
0106 #ifdef Q_OS_ANDROID
0107     const auto geo = LocationUtil::geo(place);;
0108     const auto addr = LocationUtil::address(place);
0109 
0110     QUrl url;
0111     url.setScheme(QStringLiteral("google.navigation"));
0112     if (geo.isValid()) {
0113         url.setPath(QLatin1StringView("q=") + QString::number(geo.latitude())+ QLatin1Char(',') + QString::number(geo.longitude()));
0114     } else if (!addr.isEmpty()) {
0115         url.setPath(QLatin1StringView("q=") + addr.streetAddress() + QLatin1StringView(", ")
0116             + addr.postalCode() + QLatin1Char(' ')
0117             + addr.addressLocality() + QLatin1StringView(", ")
0118             + addr.addressCountry());
0119     } else {
0120         return;
0121     }
0122     startActivity(url);
0123 
0124 #else
0125     if (m_pendingNavigation) {
0126         return;
0127     }
0128 
0129     if (!m_positionSource) {
0130         m_positionSource = QGeoPositionInfoSource::createDefaultSource(QCoreApplication::instance());
0131         if (!m_positionSource) {
0132             qWarning() << "no geo position info source available";
0133             return;
0134         }
0135     }
0136 
0137     if (m_positionSource->lastKnownPosition().isValid()) {
0138         navigateTo(m_positionSource->lastKnownPosition(), place);
0139     } else {
0140         m_pendingNavigation = QObject::connect(m_positionSource, &QGeoPositionInfoSource::positionUpdated, [this, place](const QGeoPositionInfo &pos) {
0141             navigateTo(pos, place);
0142         });
0143         m_positionSource->requestUpdate();
0144     }
0145 #endif
0146 }
0147 
0148 #ifndef Q_OS_ANDROID
0149 void NavigationController::navigateTo(const QGeoPositionInfo &from, const QVariant &to)
0150 {
0151     qCDebug(Log) << from.coordinate() << from.isValid();
0152     QObject::disconnect(m_pendingNavigation);
0153     if (!from.isValid()) {
0154         return;
0155     }
0156 
0157     const auto geo = LocationUtil::geo(to);
0158     if (geo.isValid()) {
0159         QUrl url;
0160         url.setScheme(QStringLiteral("https"));
0161         url.setHost(QStringLiteral("www.openstreetmap.org"));
0162         url.setPath(QStringLiteral("/directions"));
0163         QUrlQuery query;
0164         query.addQueryItem(QLatin1StringView("route"),
0165             QString::number(from.coordinate().latitude()) + QLatin1Char(',') + QString::number(from.coordinate().longitude())
0166             + QLatin1Char(';') + QString::number(geo.latitude()) + QLatin1Char(',') + QString::number(geo.longitude()));
0167         url.setQuery(query);
0168         QDesktopServices::openUrl(url);
0169         return;
0170     }
0171 }
0172 #endif
0173 
0174 void NavigationController::navigateTo(const QVariant& from, const QVariant& to)
0175 {
0176     const auto fromGeo = LocationUtil::geo(from);
0177     const auto toGeo = LocationUtil::geo(to);
0178     if (!fromGeo.isValid() || !toGeo.isValid()) {
0179         navigateTo(to);
0180         return;
0181     }
0182 
0183 #ifdef Q_OS_ANDROID
0184     QUrlQuery query;
0185     query.addQueryItem(QStringLiteral("start_lat"), QString::number(fromGeo.latitude()));
0186     query.addQueryItem(QStringLiteral("start_lon"), QString::number(fromGeo.longitude()));
0187     query.addQueryItem(QStringLiteral("dest_lat"), QString::number(toGeo.latitude()));
0188     query.addQueryItem(QStringLiteral("dest_lon"), QString::number(toGeo.longitude()));
0189     query.addQueryItem(QStringLiteral("start_name"), LocationUtil::name(from));
0190     query.addQueryItem(QStringLiteral("dest_name"), LocationUtil::name(to));
0191     QUrl url;
0192     url.setScheme(QStringLiteral("osmand.api"));
0193     url.setHost(QStringLiteral("navigate"));
0194     url.setQuery(query);
0195     if (!startActivity(url)) {
0196         navigateTo(to);
0197     }
0198 
0199 #else
0200     QUrl url;
0201     url.setScheme(QStringLiteral("https"));
0202     url.setHost(QStringLiteral("www.openstreetmap.org"));
0203     url.setPath(QStringLiteral("/directions"));
0204     QUrlQuery query;
0205     query.addQueryItem(QLatin1StringView("route"),
0206         QString::number(fromGeo.latitude()) + QLatin1Char(',') + QString::number(fromGeo.longitude())
0207         + QLatin1Char(';') + QString::number(toGeo.latitude()) + QLatin1Char(',') + QString::number(toGeo.longitude()));
0208     url.setQuery(query);
0209     QDesktopServices::openUrl(url);
0210 #endif
0211 }
0212 
0213 #include "moc_navigationcontroller.cpp"