6#include "RoutingManager.h" 
    8#include "AlternativeRoutesModel.h" 
    9#include "GeoDataData.h" 
   10#include "GeoDataDocument.h" 
   11#include "GeoDataExtendedData.h" 
   12#include "GeoDataFolder.h" 
   13#include "GeoDataParser.h" 
   14#include "GeoDataPlacemark.h" 
   15#include "GeoDataTreeModel.h" 
   17#include "MarbleColors.h" 
   18#include "MarbleDebug.h" 
   19#include "MarbleDirs.h" 
   21#include "PluginManager.h" 
   22#include "PositionProviderPlugin.h" 
   23#include "PositionTracking.h" 
   25#include "RouteRequest.h" 
   26#include "RoutingModel.h" 
   27#include "RoutingProfilesModel.h" 
   28#include "RoutingRunnerManager.h" 
   29#include "RoutingRunnerPlugin.h" 
   30#include <KmlElementDictionary.h> 
   35#include <QMutexLocker> 
   40class RoutingManagerPrivate
 
   43    RoutingManager *
const q;
 
   45    RouteRequest m_routeRequest;
 
   47    RoutingModel m_routingModel;
 
   49    RoutingProfilesModel m_profilesModel;
 
   51    RoutingManager::State m_state;
 
   53    const PluginManager *
const m_pluginManager;
 
   55    GeoDataTreeModel *
const m_treeModel;
 
   57    PositionTracking *
const m_positionTracking;
 
   59    AlternativeRoutesModel m_alternativeRoutesModel;
 
   61    RoutingRunnerManager m_runnerManager;
 
   65    bool m_guidanceModeEnabled;
 
   69    bool m_shutdownPositionTracking;
 
   71    bool m_guidanceModeWarning;
 
   73    QString m_lastOpenPath;
 
   75    QString m_lastSavePath;
 
   77    QColor m_routeColorStandard;
 
   79    QColor m_routeColorHighlighted;
 
   81    QColor m_routeColorAlternative;
 
   83    RoutingManagerPrivate(MarbleModel *marbleModel, RoutingManager *manager);
 
   85    static GeoDataFolder *createFolderFromRequest(
const RouteRequest &request);
 
   87    static QString stateFile(
const QString &name = QStringLiteral(
"route.kml"));
 
   89    void saveRoute(
const QString &filename);
 
   91    void loadRoute(
const QString &filename);
 
   93    void addRoute(GeoDataDocument *route);
 
   95    void routingFinished();
 
   97    void setCurrentRoute(
const GeoDataDocument *route);
 
   99    void recalculateRoute(
bool deviated);
 
  101    static void importPlacemark(RouteSegment &outline, QList<RouteSegment> &segments, 
const GeoDataPlacemark *placemark);
 
  106    , m_routeRequest(manager)
 
  107    , m_routingModel(&m_routeRequest, model->positionTracking(), manager)
 
  108    , m_profilesModel(model->pluginManager())
 
  110    , m_pluginManager(model->pluginManager())
 
  111    , m_treeModel(model->treeModel())
 
  112    , m_positionTracking(model->positionTracking())
 
  113    , m_alternativeRoutesModel(manager)
 
  114    , m_runnerManager(model, manager)
 
  116    , m_guidanceModeEnabled(false)
 
  117    , m_shutdownPositionTracking(false)
 
  118    , m_guidanceModeWarning(true)
 
  119    , m_routeColorStandard(Oxygen::skyBlue4)
 
  120    , m_routeColorHighlighted(Oxygen::skyBlue1)
 
  121    , m_routeColorAlternative(Oxygen::aluminumGray4)
 
  124    m_routeColorHighlighted.
setAlpha(200);
 
  125    m_routeColorAlternative.
setAlpha(200);
 
  128GeoDataFolder *RoutingManagerPrivate::createFolderFromRequest(
const RouteRequest &request)
 
  130    auto result = 
new GeoDataFolder;
 
  132    result->setName(QStringLiteral(
"Route Request"));
 
  134    for (
int i = 0; i < request.size(); ++i) {
 
  135        auto placemark = 
new GeoDataPlacemark(request[i]);
 
  136        result->append(placemark);
 
  144    QString const subdir = QStringLiteral(
"routing");
 
  145    QDir dir(MarbleDirs::localPath());
 
  146    if (!
dir.exists(subdir)) {
 
  147        if (!
dir.mkdir(subdir)) {
 
  148            mDebug() << 
"Unable to create dir " << 
dir.absoluteFilePath(subdir);
 
  149            return dir.absolutePath();
 
  153    if (!
dir.cd(subdir)) {
 
  154        mDebug() << 
"Cannot change into " << 
dir.absoluteFilePath(subdir);
 
  157    return dir.absoluteFilePath(name);
 
  160void RoutingManagerPrivate::saveRoute(
const QString &filename)
 
  166    QFile file(filename);
 
  168        mDebug() << 
"Cannot write to " << file.fileName();
 
  172    GeoDataDocument container;
 
  173    container.setName(QStringLiteral(
"Route"));
 
  174    GeoDataFolder *request = createFolderFromRequest(m_routeRequest);
 
  176        container.append(request);
 
  179    const GeoDataDocument *route = m_alternativeRoutesModel.currentRoute();
 
  181        container.append(
new GeoDataDocument(*route));
 
  184    if (!writer.write(&file, &container)) {
 
  185        mDebug() << 
"Can not write route state to " << file.fileName();
 
  190void RoutingManagerPrivate::loadRoute(
const QString &filename)
 
  192    QFile file(filename);
 
  194        mDebug() << 
"Can not read route from " << file.fileName();
 
  198    GeoDataParser parser(GeoData_KML);
 
  199    if (!parser.read(&file)) {
 
  200        mDebug() << 
"Could not parse file: " << parser.errorString();
 
  204    GeoDocument *doc = parser.releaseDocument();
 
  208    auto container = 
dynamic_cast<GeoDataDocument *
>(doc);
 
  209    if (container && !container->isEmpty()) {
 
  210        auto viaPoints = 
dynamic_cast<GeoDataFolder *
>(&container->first());
 
  214            for (
int i = 0; i < placemarks.
size(); ++i) {
 
  215                if (i < m_routeRequest.size()) {
 
  216                    m_routeRequest[i] = *placemarks[i];
 
  218                    m_routeRequest.append(*placemarks[i]);
 
  223            const int viaPoints_needed = placemarks.
size();
 
  224            for (
int i = m_routeRequest.size(); i > viaPoints_needed; --i) {
 
  225                m_routeRequest.remove(viaPoints_needed);
 
  228            mDebug() << 
"Expected a GeoDataDocument with at least one child, didn't get one though";
 
  232    if (container && container->size() == 2) {
 
  233        auto route = 
dynamic_cast<GeoDataDocument *
>(&container->last());
 
  236            m_alternativeRoutesModel.clear();
 
  237            m_alternativeRoutesModel.addRoute(
new GeoDataDocument(*route), AlternativeRoutesModel::Instant);
 
  238            m_alternativeRoutesModel.setCurrentRoute(0);
 
  239            m_state = RoutingManager::Retrieved;
 
  240            Q_EMIT q->stateChanged(m_state);
 
  241            Q_EMIT q->routeRetrieved(route);
 
  243            mDebug() << 
"Expected a GeoDataDocument child, didn't get one though";
 
  250        mDebug() << 
"File " << filename << 
" is not a valid Marble route .kml file";
 
  252            m_treeModel->addDocument(container);
 
  259    , d(new RoutingManagerPrivate(marbleModel, this))
 
  262    connect(&d->m_runnerManager, SIGNAL(routingFinished()), 
this, SLOT(routingFinished()));
 
  264    connect(&d->m_routingModel, SIGNAL(deviatedFromRoute(
bool)), 
this, SLOT(recalculateRoute(
bool)));
 
 
  274    return &d->m_profilesModel;
 
 
  279    return &d->m_routingModel;
 
 
  284    return &d->m_routingModel;
 
  289    return &d->m_routeRequest;
 
 
  292RoutingManager::State RoutingManager::state()
 const 
 
  299    d->m_haveRoute = 
false;
 
  302    for (
int i = 0; i < d->m_routeRequest.size(); ++i) {
 
  304        if (d->m_routeRequest.at(i).isValid()) {
 
  309    d->m_alternativeRoutesModel.newRequest(&d->m_routeRequest);
 
  311        d->m_state = RoutingManager::Downloading;
 
  312        d->m_runnerManager.retrieveRoute(&d->m_routeRequest);
 
  314        d->m_routingModel.clear();
 
  315        d->m_state = RoutingManager::Retrieved;
 
 
  323        m_alternativeRoutesModel.addRoute(route);
 
  327        m_haveRoute = route != 
nullptr;
 
  330    Q_EMIT q->routeRetrieved(route);
 
  333void RoutingManagerPrivate::routingFinished()
 
  335    m_state = RoutingManager::Retrieved;
 
  336    Q_EMIT q->stateChanged(m_state);
 
  339void RoutingManagerPrivate::setCurrentRoute(
const GeoDataDocument *document)
 
  341    QList<RouteSegment> segments;
 
  342    RouteSegment outline;
 
  344    if (document != 
nullptr) {
 
  345        const auto folders = document->folderList();
 
  346        for (
const auto folder : folders) {
 
  347            for (
const auto placemark : folder->placemarkList()) {
 
  348                importPlacemark(outline, segments, placemark);
 
  352        for (
const auto placemark : document->placemarkList()) {
 
  353            importPlacemark(outline, segments, placemark);
 
  362    if (m_routeRequest.size() > 1 && segments.
size() > 1) {
 
  364        for (
int j = 0; j < m_routeRequest.size(); ++j) {
 
  365            QPair<int, qreal> minimum(-1, -1.0);
 
  367            for (
int i = index; i < segments.
size(); ++i) {
 
  368                const RouteSegment &segment = segments[i];
 
  369                GeoDataCoordinates closest;
 
  370                const qreal 
distance = segment.distanceTo(m_routeRequest.at(j), closest, closest);
 
  371                if (minimum.first < 0 || distance < minimum.second) {
 
  378            if (minimum.first >= 0) {
 
  379                index = minimum.first;
 
  380                Maneuver viaPoint = segments[minimum.first].maneuver();
 
  381                viaPoint.setWaypoint(m_routeRequest.at(viaIndex), viaIndex);
 
  382                segments[minimum.first].setManeuver(viaPoint);
 
  390        for (
const RouteSegment &segment : std::as_const(segments)) {
 
  391            route.addRouteSegment(segment);
 
  395    m_routingModel.setRoute(route);
 
  398void RoutingManagerPrivate::importPlacemark(RouteSegment &outline, QList<RouteSegment> &segments, 
const GeoDataPlacemark *placemark)
 
  400    const GeoDataGeometry *geometry = placemark->geometry();
 
  401    const auto lineString = 
dynamic_cast<const GeoDataLineString *
>(geometry);
 
  402    QStringList blacklist = QStringList() << QString() << QStringLiteral(
"Route") << QStringLiteral(
"Tessellated");
 
  403    RouteSegment segment;
 
  404    bool isOutline = 
true;
 
  405    if (!blacklist.
contains(placemark->name())) {
 
  408            maneuver.setInstructionText(placemark->name());
 
  409            maneuver.setPosition(lineString->at(0));
 
  411            if (placemark->extendedData().contains(QStringLiteral(
"turnType"))) {
 
  412                QVariant turnType = placemark->extendedData().value(QStringLiteral(
"turnType")).value();
 
  416                maneuver.setDirection(Maneuver::Direction(turnType.
toInt()));
 
  419            if (placemark->extendedData().contains(QStringLiteral(
"roadName"))) {
 
  420                QVariant roadName = placemark->extendedData().value(QStringLiteral(
"roadName")).value();
 
  421                maneuver.setRoadName(roadName.
toString());
 
  424            segment.setManeuver(maneuver);
 
  430        segment.setPath(*lineString);
 
  442    return &d->m_alternativeRoutesModel;
 
 
  447    d->saveRoute(d->stateFile());
 
 
  452    d->saveRoute(filename);
 
 
  457    d->loadRoute(filename);
 
 
  462    RoutingProfile profile;
 
  463    RoutingProfilesModel::ProfileTemplate tpl = RoutingProfilesModel::CarFastestTemplate;
 
  464    switch (transportType) {
 
  465    case RoutingProfile::Motorcar:
 
  466        tpl = RoutingProfilesModel::CarFastestTemplate;
 
  467        profile.setName(QStringLiteral(
"Motorcar"));
 
  468        profile.setTransportType(RoutingProfile::Motorcar);
 
  470    case RoutingProfile::Bicycle:
 
  471        tpl = RoutingProfilesModel::BicycleTemplate;
 
  472        profile.setName(QStringLiteral(
"Bicycle"));
 
  473        profile.setTransportType(RoutingProfile::Bicycle);
 
  475    case RoutingProfile::Pedestrian:
 
  476        tpl = RoutingProfilesModel::PedestrianTemplate;
 
  477        profile.setName(QStringLiteral(
"Pedestrian"));
 
  478        profile.setTransportType(RoutingProfile::Pedestrian);
 
  483        if (plugin->supportsTemplate(tpl)) {
 
  484            profile.pluginSettings()[plugin->nameId()] = plugin->templateSettings(tpl);
 
 
  493    d->loadRoute(d->stateFile());
 
 
  498    if (d->m_guidanceModeEnabled == enabled) {
 
  502    d->m_guidanceModeEnabled = enabled;
 
  505        d->saveRoute(d->stateFile(QStringLiteral(
"guidance.kml")));
 
  507        if (d->m_guidanceModeWarning) {
 
  509                + 
tr(
"Road construction, weather and other unforeseen variables can result in the suggested route not to be the most expedient or safest route " 
  510                     "to your destination.")
 
  512                + 
tr(
"The Marble development team wishes you a pleasant and safe journey.") + 
QLatin1StringView(
"</p>");
 
  515            showAgain->setChecked(
true);
 
  516            showAgain->blockSignals(
true); 
 
  518            const bool smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
 
  519            messageBox->resize(380, smallScreen ? 400 : 240);
 
  521            if (!messageBox.isNull()) {
 
  522                d->m_guidanceModeWarning = showAgain->isChecked();
 
  527        d->loadRoute(d->stateFile(QStringLiteral(
"guidance.kml")));
 
  531    if (!positionProvider && enabled) {
 
  534            positionProvider = plugins.
first()->newInstance();
 
  536        d->m_positionTracking->setPositionProviderPlugin(positionProvider);
 
  537        d->m_shutdownPositionTracking = 
true;
 
  538    } 
else if (positionProvider && !enabled && d->m_shutdownPositionTracking) {
 
  539        d->m_shutdownPositionTracking = 
false;
 
  540        d->m_positionTracking->setPositionProviderPlugin(
nullptr);
 
  543    Q_EMIT guidanceModeEnabledChanged(d->m_guidanceModeEnabled);
 
 
  546void RoutingManagerPrivate::recalculateRoute(
bool deviated)
 
  548    if (m_guidanceModeEnabled && deviated) {
 
  549        for (
int i = m_routeRequest.size() - 3; i >= 0; --i) {
 
  550            if (m_routeRequest.visited(i)) {
 
  551                m_routeRequest.remove(i);
 
  555        if (m_routeRequest.size() == 2 && m_routeRequest.visited(0) && !m_routeRequest.visited(1)) {
 
  556            m_routeRequest.setPosition(0, m_positionTracking->currentLocation(), 
QObject::tr(
"Current Location"));
 
  558        } 
else if (m_routeRequest.size() != 0 && !m_routeRequest.visited(m_routeRequest.size() - 1)) {
 
  559            m_routeRequest.insert(0, m_positionTracking->currentLocation(), 
QObject::tr(
"Current Location"));
 
  567    d->m_routeRequest.reverse();
 
 
  573    d->m_routeRequest.clear();
 
 
  579    d->m_guidanceModeWarning = show;
 
 
  584    return d->m_guidanceModeWarning;
 
 
  589    d->m_lastOpenPath = path;
 
 
  594    return d->m_lastOpenPath;
 
 
  599    d->m_lastSavePath = path;
 
 
  604    return d->m_lastSavePath;
 
 
  609    d->m_routeColorStandard = color;
 
 
  614    return d->m_routeColorStandard;
 
 
  619    d->m_routeColorHighlighted = color;
 
 
  624    return d->m_routeColorHighlighted;
 
 
  629    d->m_routeColorAlternative = color;
 
 
  634    return d->m_routeColorAlternative;
 
 
  637bool RoutingManager::guidanceModeEnabled()
 const 
  639    return d->m_guidanceModeEnabled;
 
  644#include "moc_RoutingManager.cpp" 
This file contains the headers for MarbleModel.
 
A container for Features, Styles and in the future Schemas.
 
a class representing a point of interest on the map
 
The data model (not based on QAbstractModel) for a MarbleWidget.
 
The abstract class that provides position information.
 
Points to be included in a route.
 
Delegates data retrieval and model updates to the appropriate routing provider.
 
QString lastOpenPath() const
Return last directory the user opened a route from.
 
void setGuidanceModeEnabled(bool enabled)
Toggle turn by turn navigation mode.
 
void clearRoute()
Clear all via points.
 
~RoutingManager() override
Destructor.
 
RoutingProfile defaultProfile(RoutingProfile::TransportType transportType) const
Generates a routing profile with default settings for the given transport type.
 
void loadRoute(const QString &filename)
Opens the given filename (kml format) and loads the route contained in it.
 
QColor routeColorStandard() const
Get color for standard route rendering.
 
void setRouteColorAlternative(const QColor &color)
Set color for alternative route rendering.
 
RoutingModel * routingModel()
Provides access to the routing model which contains a list of routing instructions describing steps t...
 
void setShowGuidanceModeStartupWarning(bool show)
Set whether a warning message should be shown to the user before starting guidance mode.
 
RouteRequest * routeRequest()
Returns the current route request.
 
RoutingProfilesModel * profilesModel()
Provides access to the model which contains all possible routing profiles.
 
AlternativeRoutesModel * alternativeRoutesModel()
Provides access to the model which contains a list of alternative routes.
 
RoutingManager(MarbleModel *marbleModel, QObject *parent=nullptr)
Constructor.
 
void setRouteColorStandard(const QColor &color)
Set color for standard route rendering.
 
void setRouteColorHighlighted(const QColor &color)
Set color for highlighted route rendering.
 
void stateChanged(RoutingManager::State newState)
Directions and waypoints for the given route are being downloaded or have been retrieved – newState t...
 
bool showGuidanceModeStartupWarning() const
Returns true (default) if a warning is shown to the user when starting guidance mode.
 
void setLastSavePath(const QString &path)
Set last directory the user saved a route to.
 
void retrieveRoute()
Retrieve a route suiting the routeRequest.
 
void setLastOpenPath(const QString &path)
Set last directory the user opened a route from.
 
void saveRoute(const QString &filename) const
Saves the current route to the file with the given filename.
 
QColor routeColorHighlighted() const
Get color for highlighted route rendering.
 
QColor routeColorAlternative() const
Get color for alternative route rendering.
 
void reverseRoute()
Reverse the previously requested route, i.e.
 
void writeSettings() const
Saves the current route request and the current route to disk.
 
QString lastSavePath() const
Return last directory the user saved a route to.
 
void readSettings()
Restores a previously saved route request and route from disk, if any.
 
A plugin for Marble to execute a routing task.
 
KIOCORE_EXPORT QString dir(const QString &fileClass)
 
Binds a QML item to a specific geodetic location in screen coordinates.
 
KOSM_EXPORT double distance(const std::vector< const OSM::Node * > &path, Coordinate coord)
 
bool isEmpty() const const
 
void push_back(parameter_type value)
 
qsizetype size() const const
 
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
 
QObject * parent() const const
 
QString tr(const char *sourceText, const char *disambiguation, int n)
 
QString fromLatin1(QByteArrayView str)
 
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
 
int toInt(bool *ok) const const
 
QString toString() const const