File indexing completed on 2024-04-28 15:16:06

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2008 Henry de Valence <hdevalence@gmail.com>
0004 // SPDX-FileCopyrightText: 2010 Dennis Nienhüser <nienhueser@kde.org>
0005 // SPDX-FileCopyrightText: 2010-2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
0006 // SPDX-FileCopyrightText: 2011 Thibaut Gridel <tgridel@free.fr>
0007 
0008 #include "RoutingRunnerManager.h"
0009 
0010 #include "MarblePlacemarkModel.h"
0011 #include "MarbleDebug.h"
0012 #include "MarbleModel.h"
0013 #include "Planet.h"
0014 #include "GeoDataDocument.h"
0015 #include "PluginManager.h"
0016 #include "RoutingRunnerPlugin.h"
0017 #include "RunnerTask.h"
0018 #include "routing/RouteRequest.h"
0019 #include "routing/RoutingProfilesModel.h"
0020 
0021 #include <QThreadPool>
0022 #include <QTimer>
0023 
0024 namespace Marble
0025 {
0026 
0027 class MarbleModel;
0028 
0029 class Q_DECL_HIDDEN RoutingRunnerManager::Private
0030 {
0031 public:
0032     Private( RoutingRunnerManager *parent, const MarbleModel *marbleModel );
0033 
0034     ~Private();
0035 
0036     template<typename T>
0037     QList<T*> plugins( const QList<T*> &plugins ) const;
0038 
0039     void addRoutingResult( GeoDataDocument *route );
0040     void cleanupRoutingTask( RoutingTask *task );
0041 
0042     RoutingRunnerManager *const q;
0043     const MarbleModel *const m_marbleModel;
0044     const PluginManager *const m_pluginManager;
0045     QList<RoutingTask*> m_routingTasks;
0046     QVector<GeoDataDocument*> m_routingResult;
0047 };
0048 
0049 RoutingRunnerManager::Private::Private( RoutingRunnerManager *parent, const MarbleModel *marbleModel ) :
0050     q( parent ),
0051     m_marbleModel( marbleModel ),
0052     m_pluginManager( marbleModel->pluginManager() )
0053 {
0054     qRegisterMetaType<GeoDataDocument*>( "GeoDataDocument*" );
0055 }
0056 
0057 RoutingRunnerManager::Private::~Private()
0058 {
0059     // nothing to do
0060 }
0061 
0062 template<typename T>
0063 QList<T*> RoutingRunnerManager::Private::plugins( const QList<T*> &plugins ) const
0064 {
0065     QList<T*> result;
0066     for( T* plugin: plugins ) {
0067         if ( ( m_marbleModel && m_marbleModel->workOffline() && !plugin->canWorkOffline() ) ) {
0068             continue;
0069         }
0070 
0071         if ( !plugin->canWork() ) {
0072             continue;
0073         }
0074 
0075         if ( m_marbleModel && !plugin->supportsCelestialBody( m_marbleModel->planet()->id() ) )
0076         {
0077             continue;
0078         }
0079 
0080         result << plugin;
0081     }
0082 
0083     return result;
0084 }
0085 
0086 void RoutingRunnerManager::Private::addRoutingResult( GeoDataDocument *route )
0087 {
0088     if ( route ) {
0089         mDebug() << "route retrieved";
0090         m_routingResult.push_back( route );
0091         emit q->routeRetrieved( route );
0092     }
0093 }
0094 
0095 void RoutingRunnerManager::Private::cleanupRoutingTask( RoutingTask *task )
0096 {
0097     m_routingTasks.removeAll( task );
0098     mDebug() << "removing task" << m_routingTasks.size() << " " << (quintptr)task;
0099     if ( m_routingTasks.isEmpty() ) {
0100         if ( m_routingResult.isEmpty() ) {
0101             emit q->routeRetrieved( nullptr );
0102         }
0103 
0104         emit q->routingFinished();
0105     }
0106 }
0107 
0108 RoutingRunnerManager::RoutingRunnerManager( const MarbleModel *marbleModel, QObject *parent )
0109     : QObject( parent ),
0110       d( new Private( this, marbleModel ) )
0111 {
0112     if ( QThreadPool::globalInstance()->maxThreadCount() < 4 ) {
0113         QThreadPool::globalInstance()->setMaxThreadCount( 4 );
0114     }
0115 }
0116 
0117 RoutingRunnerManager::~RoutingRunnerManager()
0118 {
0119     delete d;
0120 }
0121 
0122 void RoutingRunnerManager::retrieveRoute( const RouteRequest *request )
0123 {
0124     RoutingProfile profile = request->routingProfile();
0125 
0126     d->m_routingTasks.clear();
0127     d->m_routingResult.clear();
0128 
0129     QList<RoutingRunnerPlugin*> plugins = d->plugins( d->m_pluginManager->routingRunnerPlugins() );
0130     for( RoutingRunnerPlugin* plugin: plugins ) {
0131         if ( !profile.name().isEmpty() && !profile.pluginSettings().contains( plugin->nameId() ) ) {
0132             continue;
0133         }
0134 
0135         RoutingTask* task = new RoutingTask( plugin->newRunner(), this, request );
0136         connect( task, SIGNAL(finished(RoutingTask*)), this, SLOT(cleanupRoutingTask(RoutingTask*)) );
0137         mDebug() << "route task" << plugin->nameId() << " " << (quintptr)task;
0138         d->m_routingTasks << task;
0139     }
0140 
0141     for( RoutingTask* task: d->m_routingTasks ) {
0142         QThreadPool::globalInstance()->start( task );
0143     }
0144 
0145     if ( d->m_routingTasks.isEmpty() ) {
0146         mDebug() << "No suitable routing plugins found, cannot retrieve a route";
0147         d->cleanupRoutingTask( nullptr );
0148     }
0149 }
0150 
0151 QVector<GeoDataDocument*> RoutingRunnerManager::searchRoute( const RouteRequest *request, int timeout ) {
0152     QEventLoop localEventLoop;
0153     QTimer watchdog;
0154     watchdog.setSingleShot(true);
0155     connect( &watchdog, SIGNAL(timeout()),
0156              &localEventLoop, SLOT(quit()));
0157     connect(this, SIGNAL(routingFinished()),
0158             &localEventLoop, SLOT(quit()), Qt::QueuedConnection );
0159 
0160     watchdog.start( timeout );
0161     retrieveRoute( request );
0162     localEventLoop.exec();
0163     return d->m_routingResult;
0164 }
0165 
0166 }
0167 
0168 #include "moc_RoutingRunnerManager.cpp"