Marble

SearchRunnerManager.cpp
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 "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
29namespace Marble
30{
31
32class MarbleModel;
33
34class Q_DECL_HIDDEN SearchRunnerManager::Private
35{
36public:
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
58SearchRunnerManager::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
68template<typename T>
69QList<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
92void 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
121void 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
133void SearchRunnerManager::Private::notifySearchResultChange()
134{
135 emit q->searchResultChanged(&m_model);
136 emit q->searchResultChanged(m_placemarkContainer);
137}
138
139void SearchRunnerManager::Private::notifySearchFinished()
140{
141 emit q->searchFinished(m_lastSearchTerm);
142 emit q->placemarkSearchFinished();
143}
144
145SearchRunnerManager::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
154SearchRunnerManager::~SearchRunnerManager()
155{
156 delete d;
157}
158
159void 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
207QVector<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"
This file contains the headers for MarbleModel.
Q_SCRIPTABLE Q_NOREPLY void start()
const QList< QKeySequence > & quit()
Binds a QML item to a specific geodetic location in screen coordinates.
int exec(ProcessEventsFlags flags)
bool isEmpty() const const
qsizetype size() const const
void clear()
bool isEmpty() const const
QString trimmed() const const
QueuedConnection
QTaskBuilder< Task > task(Task &&task)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QThreadPool * globalInstance()
void setMaxThreadCount(int maxThreadCount)
void start(Callable &&callableToRun, int priority)
void setSingleShot(bool singleShot)
void start()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.