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"