1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2008 Henry de Valence <hdevalence@gmail.com>
4 // SPDX-FileCopyrightText: 2010 Dennis Nienhüser <nienhueser@kde.org>
5 // SPDX-FileCopyrightText: 2010-2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
6 // SPDX-FileCopyrightText: 2011 Thibaut Gridel <tgridel@free.fr>
7
8 #include "ReverseGeocodingRunnerManager.h"
9
10 #include "MarbleDebug.h"
11 #include "MarbleModel.h"
12 #include "GeoDataCoordinates.h"
13 #include "GeoDataPlacemark.h"
14 #include "Planet.h"
15 #include "PluginManager.h"
16 #include "ReverseGeocodingRunnerPlugin.h"
17 #include "RunnerTask.h"
18
19 #include <QList>
20 #include <QThreadPool>
21 #include <QTimer>
22
23 namespace Marble
24 {
25
26 class MarbleModel;
27
28 class Q_DECL_HIDDEN ReverseGeocodingRunnerManager::Private
29 {
30 public:
31 Private( ReverseGeocodingRunnerManager *parent, const MarbleModel *marbleModel );
32
33 QList<const ReverseGeocodingRunnerPlugin *> plugins( const QList<const ReverseGeocodingRunnerPlugin *> &plugins ) const;
34
35 void addReverseGeocodingResult( const GeoDataCoordinates &coordinates, const GeoDataPlacemark &placemark );
36 void cleanupReverseGeocodingTask( ReverseGeocodingTask *task );
37
38 ReverseGeocodingRunnerManager *const q;
39 const MarbleModel *const m_marbleModel;
40 const PluginManager* m_pluginManager;
41 QList<ReverseGeocodingTask*> m_reverseTasks;
42 QVector<GeoDataCoordinates> m_reverseGeocodingResults;
43 QString m_reverseGeocodingResult;
44 };
45
Private(ReverseGeocodingRunnerManager * parent,const MarbleModel * marbleModel)46 ReverseGeocodingRunnerManager::Private::Private( ReverseGeocodingRunnerManager *parent, const MarbleModel *marbleModel ) :
47 q( parent ),
48 m_marbleModel( marbleModel ),
49 m_pluginManager( marbleModel->pluginManager() )
50 {
51 qRegisterMetaType<GeoDataPlacemark>( "GeoDataPlacemark" );
52 qRegisterMetaType<GeoDataCoordinates>( "GeoDataCoordinates" );
53 }
54
plugins(const QList<const ReverseGeocodingRunnerPlugin * > & plugins) const55 QList<const ReverseGeocodingRunnerPlugin *> ReverseGeocodingRunnerManager::Private::plugins( const QList<const ReverseGeocodingRunnerPlugin *> &plugins ) const
56 {
57 QList<const ReverseGeocodingRunnerPlugin *> result;
58
59 for( const ReverseGeocodingRunnerPlugin *plugin: plugins ) {
60 if ( ( m_marbleModel && m_marbleModel->workOffline() && !plugin->canWorkOffline() ) ) {
61 continue;
62 }
63
64 if ( !plugin->canWork() ) {
65 continue;
66 }
67
68 if ( m_marbleModel && !plugin->supportsCelestialBody( m_marbleModel->planet()->id() ) )
69 {
70 continue;
71 }
72
73 result << plugin;
74 }
75
76 return result;
77 }
78
addReverseGeocodingResult(const GeoDataCoordinates & coordinates,const GeoDataPlacemark & placemark)79 void ReverseGeocodingRunnerManager::Private::addReverseGeocodingResult( const GeoDataCoordinates &coordinates, const GeoDataPlacemark &placemark )
80 {
81 if ( !m_reverseGeocodingResults.contains( coordinates ) && !placemark.address().isEmpty() ) {
82 m_reverseGeocodingResults.push_back( coordinates );
83 m_reverseGeocodingResult = placemark.address();
84 emit q->reverseGeocodingFinished( coordinates, placemark );
85 }
86
87 if ( m_reverseTasks.isEmpty() ) {
88 emit q->reverseGeocodingFinished();
89 }
90 }
91
cleanupReverseGeocodingTask(ReverseGeocodingTask * task)92 void ReverseGeocodingRunnerManager::Private::cleanupReverseGeocodingTask( ReverseGeocodingTask *task )
93 {
94 m_reverseTasks.removeAll( task );
95 mDebug() << "removing task " << m_reverseTasks.size() << " " << (quintptr)task;
96 if ( m_reverseTasks.isEmpty() ) {
97 emit q->reverseGeocodingFinished();
98 }
99 }
100
ReverseGeocodingRunnerManager(const MarbleModel * marbleModel,QObject * parent)101 ReverseGeocodingRunnerManager::ReverseGeocodingRunnerManager( const MarbleModel *marbleModel, QObject *parent ) :
102 QObject( parent ),
103 d( new Private( this, marbleModel ) )
104 {
105 if ( QThreadPool::globalInstance()->maxThreadCount() < 4 ) {
106 QThreadPool::globalInstance()->setMaxThreadCount( 4 );
107 }
108 }
109
~ReverseGeocodingRunnerManager()110 ReverseGeocodingRunnerManager::~ReverseGeocodingRunnerManager()
111 {
112 delete d;
113 }
114
reverseGeocoding(const GeoDataCoordinates & coordinates)115 void ReverseGeocodingRunnerManager::reverseGeocoding( const GeoDataCoordinates &coordinates )
116 {
117 d->m_reverseTasks.clear();
118 d->m_reverseGeocodingResult.clear();
119 d->m_reverseGeocodingResults.removeAll( coordinates );
120
121 QList<const ReverseGeocodingRunnerPlugin*> plugins = d->plugins( d->m_pluginManager->reverseGeocodingRunnerPlugins() );
122 for( const ReverseGeocodingRunnerPlugin* plugin: plugins ) {
123 ReverseGeocodingTask* task = new ReverseGeocodingTask( plugin->newRunner(), this, d->m_marbleModel, coordinates );
124 connect( task, SIGNAL(finished(ReverseGeocodingTask*)), this, SLOT(cleanupReverseGeocodingTask(ReverseGeocodingTask*)) );
125 mDebug() << "reverse task " << plugin->nameId() << " " << (quintptr)task;
126 d->m_reverseTasks << task;
127 }
128
129 for( ReverseGeocodingTask* task: d->m_reverseTasks ) {
130 QThreadPool::globalInstance()->start( task );
131 }
132
133 if ( plugins.isEmpty() ) {
134 GeoDataPlacemark anonymous;
135 anonymous.setCoordinate( coordinates );
136 emit reverseGeocodingFinished( coordinates, anonymous );
137 d->cleanupReverseGeocodingTask( nullptr );
138 }
139 }
140
searchReverseGeocoding(const GeoDataCoordinates & coordinates,int timeout)141 QString ReverseGeocodingRunnerManager::searchReverseGeocoding( const GeoDataCoordinates &coordinates, int timeout ) {
142 QEventLoop localEventLoop;
143 QTimer watchdog;
144 watchdog.setSingleShot(true);
145 connect( &watchdog, SIGNAL(timeout()),
146 &localEventLoop, SLOT(quit()));
147 connect(this, SIGNAL(reverseGeocodingFinished()),
148 &localEventLoop, SLOT(quit()), Qt::QueuedConnection );
149
150 watchdog.start( timeout );
151 reverseGeocoding( coordinates );
152 localEventLoop.exec();
153 return d->m_reverseGeocodingResult;
154 }
155
156 }
157
158 #include "moc_ReverseGeocodingRunnerManager.cpp"
159