File indexing completed on 2024-04-28 15:16:07
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 "SearchRunnerManager.h" 0009 0010 #include "MarblePlacemarkModel.h" 0011 #include "MarbleDebug.h" 0012 #include "MarbleModel.h" 0013 #include "Planet.h" 0014 #include "GeoDataPlacemark.h" 0015 #include "PluginManager.h" 0016 #include "ParseRunnerPlugin.h" 0017 #include "ReverseGeocodingRunnerPlugin.h" 0018 #include "RoutingRunnerPlugin.h" 0019 #include "SearchRunnerPlugin.h" 0020 #include "RunnerTask.h" 0021 #include "routing/RouteRequest.h" 0022 #include "routing/RoutingProfilesModel.h" 0023 0024 #include <QString> 0025 #include <QThreadPool> 0026 #include <QTimer> 0027 #include <QMutex> 0028 0029 namespace Marble 0030 { 0031 0032 class MarbleModel; 0033 0034 class Q_DECL_HIDDEN SearchRunnerManager::Private 0035 { 0036 public: 0037 Private( SearchRunnerManager *parent, const MarbleModel *marbleModel ); 0038 0039 template<typename T> 0040 QList<T*> plugins( const QList<T*> &plugins ) const; 0041 0042 void addSearchResult( const QVector<GeoDataPlacemark *> &result ); 0043 void cleanupSearchTask( SearchTask *task ); 0044 void notifySearchResultChange(); 0045 void notifySearchFinished(); 0046 0047 SearchRunnerManager *const q; 0048 const MarbleModel *const m_marbleModel; 0049 const PluginManager* m_pluginManager; 0050 QString m_lastSearchTerm; 0051 GeoDataLatLonBox m_lastPreferredBox; 0052 QMutex m_modelMutex; 0053 MarblePlacemarkModel m_model; 0054 QList<SearchTask *> m_searchTasks; 0055 QVector<GeoDataPlacemark *> m_placemarkContainer; 0056 }; 0057 0058 SearchRunnerManager::Private::Private( SearchRunnerManager *parent, const MarbleModel *marbleModel ) : 0059 q( parent ), 0060 m_marbleModel( marbleModel ), 0061 m_pluginManager( marbleModel->pluginManager() ), 0062 m_model( new MarblePlacemarkModel( parent ) ) 0063 { 0064 m_model.setPlacemarkContainer( &m_placemarkContainer ); 0065 qRegisterMetaType<QVector<GeoDataPlacemark *> >( "QVector<GeoDataPlacemark*>" ); 0066 } 0067 0068 template<typename T> 0069 QList<T*> SearchRunnerManager::Private::plugins( const QList<T*> &plugins ) const 0070 { 0071 QList<T*> result; 0072 for( T* plugin: plugins ) { 0073 if ( ( m_marbleModel && m_marbleModel->workOffline() && !plugin->canWorkOffline() ) ) { 0074 continue; 0075 } 0076 0077 if ( !plugin->canWork() ) { 0078 continue; 0079 } 0080 0081 if ( m_marbleModel && !plugin->supportsCelestialBody( m_marbleModel->planet()->id() ) ) 0082 { 0083 continue; 0084 } 0085 0086 result << plugin; 0087 } 0088 0089 return result; 0090 } 0091 0092 void SearchRunnerManager::Private::addSearchResult( const QVector<GeoDataPlacemark *> &result ) 0093 { 0094 mDebug() << "Runner reports" << result.size() << " search results"; 0095 if( result.isEmpty() ) 0096 return; 0097 0098 m_modelMutex.lock(); 0099 int start = m_placemarkContainer.size(); 0100 int count = 0; 0101 bool distanceCompare = m_marbleModel->planet() != nullptr; 0102 for( int i=0; i<result.size(); ++i ) { 0103 bool same = false; 0104 for ( int j=0; j<m_placemarkContainer.size(); ++j ) { 0105 if ( distanceCompare && 0106 (result[i]->coordinate().sphericalDistanceTo(m_placemarkContainer[j]->coordinate()) 0107 * m_marbleModel->planet()->radius() < 1 ) ) { 0108 same = true; 0109 } 0110 } 0111 if ( !same ) { 0112 m_placemarkContainer.append( result[i] ); 0113 ++count; 0114 } 0115 } 0116 m_model.addPlacemarks( start, count ); 0117 m_modelMutex.unlock(); 0118 notifySearchResultChange(); 0119 } 0120 0121 void SearchRunnerManager::Private::cleanupSearchTask( SearchTask *task ) 0122 { 0123 m_searchTasks.removeAll( task ); 0124 mDebug() << "removing search task" << m_searchTasks.size() << (quintptr)task; 0125 if ( m_searchTasks.isEmpty() ) { 0126 if( m_placemarkContainer.isEmpty() ) { 0127 notifySearchResultChange(); 0128 } 0129 notifySearchFinished(); 0130 } 0131 } 0132 0133 void SearchRunnerManager::Private::notifySearchResultChange() 0134 { 0135 emit q->searchResultChanged(&m_model); 0136 emit q->searchResultChanged(m_placemarkContainer); 0137 } 0138 0139 void SearchRunnerManager::Private::notifySearchFinished() 0140 { 0141 emit q->searchFinished(m_lastSearchTerm); 0142 emit q->placemarkSearchFinished(); 0143 } 0144 0145 SearchRunnerManager::SearchRunnerManager( const MarbleModel *marbleModel, QObject *parent ) : 0146 QObject( parent ), 0147 d( new Private( this, marbleModel ) ) 0148 { 0149 if ( QThreadPool::globalInstance()->maxThreadCount() < 4 ) { 0150 QThreadPool::globalInstance()->setMaxThreadCount( 4 ); 0151 } 0152 } 0153 0154 SearchRunnerManager::~SearchRunnerManager() 0155 { 0156 delete d; 0157 } 0158 0159 void SearchRunnerManager::findPlacemarks( const QString &searchTerm, const GeoDataLatLonBox &preferred ) 0160 { 0161 if ( searchTerm == d->m_lastSearchTerm && preferred == d->m_lastPreferredBox ) { 0162 d->notifySearchResultChange(); 0163 d->notifySearchFinished(); 0164 return; 0165 } 0166 0167 d->m_lastSearchTerm = searchTerm; 0168 d->m_lastPreferredBox = preferred; 0169 0170 d->m_searchTasks.clear(); 0171 0172 d->m_modelMutex.lock(); 0173 bool placemarkContainerChanged = false; 0174 if (!d->m_placemarkContainer.isEmpty()) { 0175 d->m_model.removePlacemarks( "PlacemarkRunnerManager", 0, d->m_placemarkContainer.size() ); 0176 qDeleteAll( d->m_placemarkContainer ); 0177 d->m_placemarkContainer.clear(); 0178 placemarkContainerChanged = true; 0179 } 0180 d->m_modelMutex.unlock(); 0181 if (placemarkContainerChanged) { 0182 d->notifySearchResultChange(); 0183 } 0184 0185 if ( searchTerm.trimmed().isEmpty() ) { 0186 d->notifySearchFinished(); 0187 return; 0188 } 0189 0190 QList<const SearchRunnerPlugin *> plugins = d->plugins( d->m_pluginManager->searchRunnerPlugins() ); 0191 for( const SearchRunnerPlugin *plugin: plugins ) { 0192 SearchTask *task = new SearchTask( plugin->newRunner(), this, d->m_marbleModel, searchTerm, preferred ); 0193 connect( task, SIGNAL(finished(SearchTask*)), this, SLOT(cleanupSearchTask(SearchTask*)) ); 0194 d->m_searchTasks << task; 0195 mDebug() << "search task " << plugin->nameId() << " " << (quintptr)task; 0196 } 0197 0198 for( SearchTask *task: d->m_searchTasks ) { 0199 QThreadPool::globalInstance()->start( task ); 0200 } 0201 0202 if ( plugins.isEmpty() ) { 0203 d->cleanupSearchTask( nullptr ); 0204 } 0205 } 0206 0207 QVector<GeoDataPlacemark *> SearchRunnerManager::searchPlacemarks( const QString &searchTerm, const GeoDataLatLonBox &preferred, int timeout ) 0208 { 0209 QEventLoop localEventLoop; 0210 QTimer watchdog; 0211 watchdog.setSingleShot(true); 0212 connect( &watchdog, SIGNAL(timeout()), 0213 &localEventLoop, SLOT(quit())); 0214 connect(this, SIGNAL(placemarkSearchFinished()), 0215 &localEventLoop, SLOT(quit()), Qt::QueuedConnection ); 0216 0217 watchdog.start( timeout ); 0218 findPlacemarks( searchTerm, preferred ); 0219 localEventLoop.exec(); 0220 return d->m_placemarkContainer; 0221 } 0222 0223 } 0224 0225 #include "moc_SearchRunnerManager.cpp"