File indexing completed on 2025-01-05 03:59:34

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