Marble

SearchRunnerManager.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2008 Henry de Valence <[email protected]>
4 // SPDX-FileCopyrightText: 2010 Dennis Nienhüser <[email protected]>
5 // SPDX-FileCopyrightText: 2010-2013 Bernhard Beschow <[email protected]>
6 // SPDX-FileCopyrightText: 2011 Thibaut Gridel <[email protected]>
7 
8 #include "SearchRunnerManager.h"
9 
10 #include "MarblePlacemarkModel.h"
11 #include "MarbleDebug.h"
12 #include "MarbleModel.h"
13 #include "Planet.h"
14 #include "GeoDataPlacemark.h"
15 #include "PluginManager.h"
16 #include "ParseRunnerPlugin.h"
17 #include "ReverseGeocodingRunnerPlugin.h"
18 #include "RoutingRunnerPlugin.h"
19 #include "SearchRunnerPlugin.h"
20 #include "RunnerTask.h"
21 #include "routing/RouteRequest.h"
22 #include "routing/RoutingProfilesModel.h"
23 
24 #include <QString>
25 #include <QThreadPool>
26 #include <QTimer>
27 #include <QMutex>
28 
29 namespace Marble
30 {
31 
32 class MarbleModel;
33 
34 class Q_DECL_HIDDEN SearchRunnerManager::Private
35 {
36 public:
37  Private( SearchRunnerManager *parent, const MarbleModel *marbleModel );
38 
39  template<typename T>
40  QList<T*> plugins( const QList<T*> &plugins ) const;
41 
42  void addSearchResult( const QVector<GeoDataPlacemark *> &result );
43  void cleanupSearchTask( SearchTask *task );
44  void notifySearchResultChange();
45  void notifySearchFinished();
46 
47  SearchRunnerManager *const q;
48  const MarbleModel *const m_marbleModel;
49  const PluginManager* m_pluginManager;
50  QString m_lastSearchTerm;
51  GeoDataLatLonBox m_lastPreferredBox;
52  QMutex m_modelMutex;
53  MarblePlacemarkModel m_model;
54  QList<SearchTask *> m_searchTasks;
55  QVector<GeoDataPlacemark *> m_placemarkContainer;
56 };
57 
58 SearchRunnerManager::Private::Private( SearchRunnerManager *parent, const MarbleModel *marbleModel ) :
59  q( parent ),
60  m_marbleModel( marbleModel ),
61  m_pluginManager( marbleModel->pluginManager() ),
62  m_model( new MarblePlacemarkModel( parent ) )
63 {
64  m_model.setPlacemarkContainer( &m_placemarkContainer );
65  qRegisterMetaType<QVector<GeoDataPlacemark *> >( "QVector<GeoDataPlacemark*>" );
66 }
67 
68 template<typename T>
69 QList<T*> SearchRunnerManager::Private::plugins( const QList<T*> &plugins ) const
70 {
71  QList<T*> result;
72  for( T* plugin: plugins ) {
73  if ( ( m_marbleModel && m_marbleModel->workOffline() && !plugin->canWorkOffline() ) ) {
74  continue;
75  }
76 
77  if ( !plugin->canWork() ) {
78  continue;
79  }
80 
81  if ( m_marbleModel && !plugin->supportsCelestialBody( m_marbleModel->planet()->id() ) )
82  {
83  continue;
84  }
85 
86  result << plugin;
87  }
88 
89  return result;
90 }
91 
92 void SearchRunnerManager::Private::addSearchResult( const QVector<GeoDataPlacemark *> &result )
93 {
94  mDebug() << "Runner reports" << result.size() << " search results";
95  if( result.isEmpty() )
96  return;
97 
98  m_modelMutex.lock();
99  int start = m_placemarkContainer.size();
100  int count = 0;
101  bool distanceCompare = m_marbleModel->planet() != nullptr;
102  for( int i=0; i<result.size(); ++i ) {
103  bool same = false;
104  for ( int j=0; j<m_placemarkContainer.size(); ++j ) {
105  if ( distanceCompare &&
106  (result[i]->coordinate().sphericalDistanceTo(m_placemarkContainer[j]->coordinate())
107  * m_marbleModel->planet()->radius() < 1 ) ) {
108  same = true;
109  }
110  }
111  if ( !same ) {
112  m_placemarkContainer.append( result[i] );
113  ++count;
114  }
115  }
116  m_model.addPlacemarks( start, count );
117  m_modelMutex.unlock();
118  notifySearchResultChange();
119 }
120 
121 void SearchRunnerManager::Private::cleanupSearchTask( SearchTask *task )
122 {
123  m_searchTasks.removeAll( task );
124  mDebug() << "removing search task" << m_searchTasks.size() << (quintptr)task;
125  if ( m_searchTasks.isEmpty() ) {
126  if( m_placemarkContainer.isEmpty() ) {
127  notifySearchResultChange();
128  }
129  notifySearchFinished();
130  }
131 }
132 
133 void SearchRunnerManager::Private::notifySearchResultChange()
134 {
135  emit q->searchResultChanged(&m_model);
136  emit q->searchResultChanged(m_placemarkContainer);
137 }
138 
139 void SearchRunnerManager::Private::notifySearchFinished()
140 {
141  emit q->searchFinished(m_lastSearchTerm);
142  emit q->placemarkSearchFinished();
143 }
144 
145 SearchRunnerManager::SearchRunnerManager( const MarbleModel *marbleModel, QObject *parent ) :
146  QObject( parent ),
147  d( new Private( this, marbleModel ) )
148 {
149  if ( QThreadPool::globalInstance()->maxThreadCount() < 4 ) {
151  }
152 }
153 
154 SearchRunnerManager::~SearchRunnerManager()
155 {
156  delete d;
157 }
158 
159 void SearchRunnerManager::findPlacemarks( const QString &searchTerm, const GeoDataLatLonBox &preferred )
160 {
161  if ( searchTerm == d->m_lastSearchTerm && preferred == d->m_lastPreferredBox ) {
162  d->notifySearchResultChange();
163  d->notifySearchFinished();
164  return;
165  }
166 
167  d->m_lastSearchTerm = searchTerm;
168  d->m_lastPreferredBox = preferred;
169 
170  d->m_searchTasks.clear();
171 
172  d->m_modelMutex.lock();
173  bool placemarkContainerChanged = false;
174  if (!d->m_placemarkContainer.isEmpty()) {
175  d->m_model.removePlacemarks( "PlacemarkRunnerManager", 0, d->m_placemarkContainer.size() );
176  qDeleteAll( d->m_placemarkContainer );
177  d->m_placemarkContainer.clear();
178  placemarkContainerChanged = true;
179  }
180  d->m_modelMutex.unlock();
181  if (placemarkContainerChanged) {
182  d->notifySearchResultChange();
183  }
184 
185  if ( searchTerm.trimmed().isEmpty() ) {
186  d->notifySearchFinished();
187  return;
188  }
189 
190  QList<const SearchRunnerPlugin *> plugins = d->plugins( d->m_pluginManager->searchRunnerPlugins() );
191  for( const SearchRunnerPlugin *plugin: plugins ) {
192  SearchTask *task = new SearchTask( plugin->newRunner(), this, d->m_marbleModel, searchTerm, preferred );
193  connect( task, SIGNAL(finished(SearchTask*)), this, SLOT(cleanupSearchTask(SearchTask*)) );
194  d->m_searchTasks << task;
195  mDebug() << "search task " << plugin->nameId() << " " << (quintptr)task;
196  }
197 
198  for( SearchTask *task: d->m_searchTasks ) {
200  }
201 
202  if ( plugins.isEmpty() ) {
203  d->cleanupSearchTask( nullptr );
204  }
205 }
206 
207 QVector<GeoDataPlacemark *> SearchRunnerManager::searchPlacemarks( const QString &searchTerm, const GeoDataLatLonBox &preferred, int timeout )
208 {
209  QEventLoop localEventLoop;
210  QTimer watchdog;
211  watchdog.setSingleShot(true);
212  connect( &watchdog, SIGNAL(timeout()),
213  &localEventLoop, SLOT(quit()));
214  connect(this, SIGNAL(placemarkSearchFinished()),
215  &localEventLoop, SLOT(quit()), Qt::QueuedConnection );
216 
217  watchdog.start( timeout );
218  findPlacemarks( searchTerm, preferred );
219  localEventLoop.exec();
220  return d->m_placemarkContainer;
221 }
222 
223 }
224 
225 #include "moc_SearchRunnerManager.cpp"
bool isEmpty() const const
void start(QRunnable *runnable, int priority)
void setSingleShot(bool singleShot)
QString trimmed() const const
void clear()
QThreadPool * globalInstance()
int exec(QEventLoop::ProcessEventsFlags flags)
void start(int msec)
Q_SCRIPTABLE Q_NOREPLY void start()
bool isEmpty() const const
QueuedConnection
Binds a QML item to a specific geodetic location in screen coordinates.
const QList< QKeySequence > & quit()
int size() const const
void setMaxThreadCount(int maxThreadCount)
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Sep 25 2023 03:50:20 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.