File indexing completed on 2024-04-28 11:31:18

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 "ReverseGeocodingRunnerManager.h"
0009 
0010 #include "MarbleDebug.h"
0011 #include "MarbleModel.h"
0012 #include "GeoDataCoordinates.h"
0013 #include "GeoDataPlacemark.h"
0014 #include "Planet.h"
0015 #include "PluginManager.h"
0016 #include "ReverseGeocodingRunnerPlugin.h"
0017 #include "RunnerTask.h"
0018 
0019 #include <QList>
0020 #include <QThreadPool>
0021 #include <QTimer>
0022 
0023 namespace Marble
0024 {
0025 
0026 class MarbleModel;
0027 
0028 class Q_DECL_HIDDEN ReverseGeocodingRunnerManager::Private
0029 {
0030 public:
0031     Private( ReverseGeocodingRunnerManager *parent, const MarbleModel *marbleModel );
0032 
0033     QList<const ReverseGeocodingRunnerPlugin *> plugins( const QList<const ReverseGeocodingRunnerPlugin *> &plugins ) const;
0034 
0035     void addReverseGeocodingResult( const GeoDataCoordinates &coordinates, const GeoDataPlacemark &placemark );
0036     void cleanupReverseGeocodingTask( ReverseGeocodingTask *task );
0037 
0038     ReverseGeocodingRunnerManager *const q;
0039     const MarbleModel *const m_marbleModel;
0040     const PluginManager* m_pluginManager;
0041     QList<ReverseGeocodingTask*> m_reverseTasks;
0042     QVector<GeoDataCoordinates> m_reverseGeocodingResults;
0043     QString m_reverseGeocodingResult;
0044 };
0045 
0046 ReverseGeocodingRunnerManager::Private::Private( ReverseGeocodingRunnerManager *parent, const MarbleModel *marbleModel ) :
0047     q( parent ),
0048     m_marbleModel( marbleModel ),
0049     m_pluginManager( marbleModel->pluginManager() )
0050 {
0051     qRegisterMetaType<GeoDataPlacemark>( "GeoDataPlacemark" );
0052     qRegisterMetaType<GeoDataCoordinates>( "GeoDataCoordinates" );
0053 }
0054 
0055 QList<const ReverseGeocodingRunnerPlugin *> ReverseGeocodingRunnerManager::Private::plugins( const QList<const ReverseGeocodingRunnerPlugin *> &plugins ) const
0056 {
0057     QList<const ReverseGeocodingRunnerPlugin *> result;
0058 
0059     for( const ReverseGeocodingRunnerPlugin *plugin: plugins ) {
0060         if ( ( m_marbleModel && m_marbleModel->workOffline() && !plugin->canWorkOffline() ) ) {
0061             continue;
0062         }
0063 
0064         if ( !plugin->canWork() ) {
0065             continue;
0066         }
0067 
0068         if ( m_marbleModel && !plugin->supportsCelestialBody( m_marbleModel->planet()->id() ) )
0069         {
0070             continue;
0071         }
0072 
0073         result << plugin;
0074     }
0075 
0076     return result;
0077 }
0078 
0079 void ReverseGeocodingRunnerManager::Private::addReverseGeocodingResult( const GeoDataCoordinates &coordinates, const GeoDataPlacemark &placemark )
0080 {
0081     if ( !m_reverseGeocodingResults.contains( coordinates ) && !placemark.address().isEmpty() ) {
0082         m_reverseGeocodingResults.push_back( coordinates );
0083         m_reverseGeocodingResult = placemark.address();
0084         emit q->reverseGeocodingFinished( coordinates, placemark );
0085     }
0086 
0087     if ( m_reverseTasks.isEmpty() ) {
0088         emit q->reverseGeocodingFinished();
0089     }
0090 }
0091 
0092 void ReverseGeocodingRunnerManager::Private::cleanupReverseGeocodingTask( ReverseGeocodingTask *task )
0093 {
0094     m_reverseTasks.removeAll( task );
0095     mDebug() << "removing task " << m_reverseTasks.size() << " " << (quintptr)task;
0096     if ( m_reverseTasks.isEmpty() ) {
0097         emit q->reverseGeocodingFinished();
0098     }
0099 }
0100 
0101 ReverseGeocodingRunnerManager::ReverseGeocodingRunnerManager( const MarbleModel *marbleModel, QObject *parent ) :
0102     QObject( parent ),
0103     d( new Private( this, marbleModel ) )
0104 {
0105     if ( QThreadPool::globalInstance()->maxThreadCount() < 4 ) {
0106         QThreadPool::globalInstance()->setMaxThreadCount( 4 );
0107     }
0108 }
0109 
0110 ReverseGeocodingRunnerManager::~ReverseGeocodingRunnerManager()
0111 {
0112     delete d;
0113 }
0114 
0115 void ReverseGeocodingRunnerManager::reverseGeocoding( const GeoDataCoordinates &coordinates )
0116 {
0117     d->m_reverseTasks.clear();
0118     d->m_reverseGeocodingResult.clear();
0119     d->m_reverseGeocodingResults.removeAll( coordinates );
0120 
0121     QList<const ReverseGeocodingRunnerPlugin*> plugins = d->plugins( d->m_pluginManager->reverseGeocodingRunnerPlugins() );
0122     for( const ReverseGeocodingRunnerPlugin* plugin: plugins ) {
0123         ReverseGeocodingTask* task = new ReverseGeocodingTask( plugin->newRunner(), this, d->m_marbleModel, coordinates );
0124         connect( task, SIGNAL(finished(ReverseGeocodingTask*)), this, SLOT(cleanupReverseGeocodingTask(ReverseGeocodingTask*)) );
0125         mDebug() << "reverse task " << plugin->nameId() << " " << (quintptr)task;
0126         d->m_reverseTasks << task;
0127     }
0128 
0129     for( ReverseGeocodingTask* task: d->m_reverseTasks ) {
0130         QThreadPool::globalInstance()->start( task );
0131     }
0132 
0133     if ( plugins.isEmpty() ) {
0134         GeoDataPlacemark anonymous;
0135         anonymous.setCoordinate( coordinates );
0136         emit reverseGeocodingFinished( coordinates, anonymous );
0137         d->cleanupReverseGeocodingTask( nullptr );
0138     }
0139 }
0140 
0141 QString ReverseGeocodingRunnerManager::searchReverseGeocoding( const GeoDataCoordinates &coordinates, int timeout ) {
0142     QEventLoop localEventLoop;
0143     QTimer watchdog;
0144     watchdog.setSingleShot(true);
0145     connect( &watchdog, SIGNAL(timeout()),
0146              &localEventLoop, SLOT(quit()));
0147     connect(this, SIGNAL(reverseGeocodingFinished()),
0148             &localEventLoop, SLOT(quit()), Qt::QueuedConnection );
0149 
0150     watchdog.start( timeout );
0151     reverseGeocoding( coordinates );
0152     localEventLoop.exec();
0153     return d->m_reverseGeocodingResult;
0154 }
0155 
0156 }
0157 
0158 #include "moc_ReverseGeocodingRunnerManager.cpp"