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 "GeoDataPlacemark.h"
11#include "MarbleDebug.h"
12#include "MarbleModel.h"
13#include "MarblePlacemarkModel.h"
14#include "Planet.h"
15#include "PluginManager.h"
16#include "RunnerTask.h"
17#include "SearchRunnerPlugin.h"
18#include "routing/RouteRequest.h"
19#include "routing/RoutingProfilesModel.h"
20
21#include <QMutex>
22#include <QString>
23#include <QThreadPool>
24#include <QTimer>
25
26namespace Marble
27{
28
29class MarbleModel;
30
31class Q_DECL_HIDDEN SearchRunnerManager::Private
32{
33public:
34 Private(SearchRunnerManager *parent, const MarbleModel *marbleModel);
35
36 template<typename T>
37 QList<T *> plugins(const QList<T *> &plugins) const;
38
39 void addSearchResult(const QList<GeoDataPlacemark *> &result);
40 void cleanupSearchTask(SearchTask *task);
41 void notifySearchResultChange();
42 void notifySearchFinished();
43
44 SearchRunnerManager *const q;
45 const MarbleModel *const m_marbleModel;
46 const PluginManager *m_pluginManager;
47 QString m_lastSearchTerm;
48 GeoDataLatLonBox m_lastPreferredBox;
49 QMutex m_modelMutex;
50 MarblePlacemarkModel m_model;
51 QList<SearchTask *> m_searchTasks;
52 QList<GeoDataPlacemark *> m_placemarkContainer;
53};
54
55SearchRunnerManager::Private::Private(SearchRunnerManager *parent, const MarbleModel *marbleModel)
56 : q(parent)
57 , m_marbleModel(marbleModel)
58 , m_pluginManager(marbleModel->pluginManager())
59 , m_model(new MarblePlacemarkModel(parent))
60{
61 m_model.setPlacemarkContainer(&m_placemarkContainer);
62 qRegisterMetaType<QList<GeoDataPlacemark *>>("QList<GeoDataPlacemark*>");
63}
64
65template<typename T>
66QList<T *> SearchRunnerManager::Private::plugins(const QList<T *> &plugins) const
67{
68 QList<T *> result;
69 for (T *plugin : plugins) {
70 if ((m_marbleModel && m_marbleModel->workOffline() && !plugin->canWorkOffline())) {
71 continue;
72 }
73
74 if (!plugin->canWork()) {
75 continue;
76 }
77
78 if (m_marbleModel && !plugin->supportsCelestialBody(m_marbleModel->planet()->id())) {
79 continue;
80 }
81
82 result << plugin;
83 }
84
85 return result;
86}
87
88void SearchRunnerManager::Private::addSearchResult(const QList<GeoDataPlacemark *> &result)
89{
90 mDebug() << "Runner reports" << result.size() << " search results";
91 if (result.isEmpty())
92 return;
93
94 m_modelMutex.lock();
95 int start = m_placemarkContainer.size();
96 int count = 0;
97 bool distanceCompare = m_marbleModel->planet() != nullptr;
98 for (int i = 0; i < result.size(); ++i) {
99 bool same = false;
100 for (int j = 0; j < m_placemarkContainer.size(); ++j) {
101 if (distanceCompare
102 && (result[i]->coordinate().sphericalDistanceTo(m_placemarkContainer[j]->coordinate()) * m_marbleModel->planet()->radius() < 1)) {
103 same = true;
104 }
105 }
106 if (!same) {
107 m_placemarkContainer.append(result[i]);
108 ++count;
109 }
110 }
111 m_model.addPlacemarks(start, count);
112 m_modelMutex.unlock();
113 notifySearchResultChange();
114}
115
116void SearchRunnerManager::Private::cleanupSearchTask(SearchTask *task)
117{
118 m_searchTasks.removeAll(task);
119 mDebug() << "removing search task" << m_searchTasks.size() << (quintptr)task;
120 if (m_searchTasks.isEmpty()) {
121 if (m_placemarkContainer.isEmpty()) {
122 notifySearchResultChange();
123 }
124 notifySearchFinished();
125 }
126}
127
128void SearchRunnerManager::Private::notifySearchResultChange()
129{
130 Q_EMIT q->searchResultChanged(&m_model);
131 Q_EMIT q->searchResultChanged(m_placemarkContainer);
132}
133
134void SearchRunnerManager::Private::notifySearchFinished()
135{
136 Q_EMIT q->searchFinished(m_lastSearchTerm);
137 Q_EMIT q->placemarkSearchFinished();
138}
139
140SearchRunnerManager::SearchRunnerManager(const MarbleModel *marbleModel, QObject *parent)
141 : QObject(parent)
142 , d(new Private(this, marbleModel))
143{
144 if (QThreadPool::globalInstance()->maxThreadCount() < 4) {
146 }
147}
148
149SearchRunnerManager::~SearchRunnerManager()
150{
151 delete d;
152}
153
154void SearchRunnerManager::findPlacemarks(const QString &searchTerm, const GeoDataLatLonBox &preferred)
155{
156 if (searchTerm == d->m_lastSearchTerm && preferred == d->m_lastPreferredBox) {
157 d->notifySearchResultChange();
158 d->notifySearchFinished();
159 return;
160 }
161
162 d->m_lastSearchTerm = searchTerm;
163 d->m_lastPreferredBox = preferred;
164
165 d->m_searchTasks.clear();
166
167 d->m_modelMutex.lock();
168 bool placemarkContainerChanged = false;
169 if (!d->m_placemarkContainer.isEmpty()) {
170 d->m_model.removePlacemarks(QStringLiteral("PlacemarkRunnerManager"), 0, d->m_placemarkContainer.size());
171 qDeleteAll(d->m_placemarkContainer);
172 d->m_placemarkContainer.clear();
173 placemarkContainerChanged = true;
174 }
175 d->m_modelMutex.unlock();
176 if (placemarkContainerChanged) {
177 d->notifySearchResultChange();
178 }
179
180 if (searchTerm.trimmed().isEmpty()) {
181 d->notifySearchFinished();
182 return;
183 }
184
185 QList<const SearchRunnerPlugin *> plugins = d->plugins(d->m_pluginManager->searchRunnerPlugins());
186 for (const SearchRunnerPlugin *plugin : std::as_const(plugins)) {
187 auto task = new SearchTask(plugin->newRunner(), this, d->m_marbleModel, searchTerm, preferred);
188 connect(task, SIGNAL(finished(SearchTask *)), this, SLOT(cleanupSearchTask(SearchTask *)));
189 d->m_searchTasks << task;
190 mDebug() << "search task " << plugin->nameId() << " " << (quintptr)task;
191 }
192
193 for (SearchTask *task : std::as_const(d->m_searchTasks)) {
195 }
196
197 if (plugins.isEmpty()) {
198 d->cleanupSearchTask(nullptr);
199 }
200}
201
202QList<GeoDataPlacemark *> SearchRunnerManager::searchPlacemarks(const QString &searchTerm, const GeoDataLatLonBox &preferred, int timeout)
203{
204 QEventLoop localEventLoop;
205 QTimer watchdog;
206 watchdog.setSingleShot(true);
207 connect(&watchdog, SIGNAL(timeout()), &localEventLoop, SLOT(quit()));
208 connect(this, SIGNAL(placemarkSearchFinished()), &localEventLoop, SLOT(quit()), Qt::QueuedConnection);
209
210 watchdog.start(timeout);
211 findPlacemarks(searchTerm, preferred);
212 localEventLoop.exec();
213 return d->m_placemarkContainer;
214}
215
216}
217
218#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 Sat Dec 21 2024 17:04:14 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.