Marble

SearchWidget.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2012 Dennis Nienhüser <nienhueser@kde.org>
4//
5
6#include "SearchWidget.h"
7
8#include "BranchFilterProxyModel.h"
9#include "GeoDataDocument.h"
10#include "GeoDataLatLonAltBox.h"
11#include "GeoDataPlacemark.h"
12#include "GeoDataTreeModel.h"
13#include "MarbleDebug.h"
14#include "MarbleModel.h"
15#include "MarblePlacemarkModel.h"
16#include "MarbleWidget.h"
17#include "SearchInputWidget.h"
18#include "SearchRunnerManager.h"
19#include "ViewportParams.h"
20
21#include <QElapsedTimer>
22#include <QListView>
23#include <QVBoxLayout>
24
25namespace Marble
26{
27
28class SearchWidgetPrivate
29{
30public:
31 SearchRunnerManager *m_runnerManager;
32 SearchInputWidget *m_searchField;
33 QListView *m_searchResultView;
34 MarbleWidget *m_widget;
35 BranchFilterProxyModel m_branchfilter;
36 QSortFilterProxyModel m_sortproxy;
37 GeoDataDocument *m_document;
38 QString m_planetId;
39
40 SearchWidgetPrivate();
41 void setSearchResult(const QList<GeoDataPlacemark *> &);
42 void search(const QString &searchTerm, SearchMode searchMode);
43 void clearSearch();
44 void centerMapOn(const QModelIndex &index);
45 void handlePlanetChange();
46};
47
48SearchWidgetPrivate::SearchWidgetPrivate()
49 : m_runnerManager(nullptr)
50 , m_searchField(nullptr)
51 , m_searchResultView(nullptr)
52 , m_widget(nullptr)
53 , m_branchfilter()
54 , m_sortproxy()
55 , m_document(new GeoDataDocument)
56{
57 m_document->setName(QObject::tr("Search Results"));
58}
59
60void SearchWidgetPrivate::setSearchResult(const QList<GeoDataPlacemark *> &locations)
61{
62 if (locations.isEmpty()) {
63 return;
64 }
65
66 QElapsedTimer timer;
67 timer.start();
68
69 // fill the local document with results
70 m_widget->model()->placemarkSelectionModel()->clear();
71 GeoDataTreeModel *treeModel = m_widget->model()->treeModel();
72 treeModel->removeDocument(m_document);
73 m_document->clear();
74 m_document->setName(QObject::tr("Search for '%1'").arg(m_searchField->text()));
75 for (GeoDataPlacemark *placemark : locations) {
76 m_document->append(new GeoDataPlacemark(*placemark));
77 }
78 treeModel->addDocument(m_document);
79 m_branchfilter.setBranchIndex(treeModel, treeModel->index(m_document));
80 m_searchResultView->setRootIndex(m_sortproxy.mapFromSource(m_branchfilter.mapFromSource(treeModel->index(m_document))));
81 m_widget->centerOn(m_document->latLonAltBox());
82 mDebug() << " Time elapsed:" << timer.elapsed() << " ms";
83}
84
85SearchWidget::SearchWidget(QWidget *parent, Qt::WindowFlags flags)
86 : QWidget(parent, flags)
87 , d(new SearchWidgetPrivate)
88{
89 d->m_sortproxy.setSortRole(MarblePlacemarkModel::PopularityIndexRole);
90 d->m_sortproxy.sort(0, Qt::AscendingOrder);
91 d->m_sortproxy.setDynamicSortFilter(true);
92 d->m_sortproxy.setSourceModel(&d->m_branchfilter);
93
94 d->m_searchField = new SearchInputWidget(this);
95 setFocusProxy(d->m_searchField);
96 connect(d->m_searchField, SIGNAL(search(QString, SearchMode)), this, SLOT(search(QString, SearchMode)));
97
98 d->m_searchResultView = new QListView(this);
99 d->m_searchResultView->setModel(&d->m_sortproxy);
100 d->m_searchResultView->setMinimumSize(0, 0);
101 connect(d->m_searchResultView, SIGNAL(activated(QModelIndex)), this, SLOT(centerMapOn(QModelIndex)));
102
103 auto layout = new QVBoxLayout(this);
104 layout->addWidget(d->m_searchField);
105 layout->addWidget(d->m_searchResultView);
106 layout->setContentsMargins({});
107}
108
109SearchWidget::~SearchWidget()
110{
111 delete d;
112}
113
114void SearchWidget::setMarbleWidget(MarbleWidget *widget)
115{
116 if (d->m_widget) {
117 return;
118 }
119
120 d->m_widget = widget;
121
122 d->m_planetId = widget->model()->planetId();
123 connect(widget->model(), SIGNAL(themeChanged(QString)), this, SLOT(handlePlanetChange()));
124
125 d->m_searchField->setCompletionModel(widget->model()->placemarkModel());
126 connect(d->m_searchField, SIGNAL(centerOn(GeoDataCoordinates)), widget, SLOT(centerOn(GeoDataCoordinates)));
127
128 d->m_runnerManager = new SearchRunnerManager(widget->model(), this);
129 connect(d->m_runnerManager, SIGNAL(searchResultChanged(QList<GeoDataPlacemark *>)), this, SLOT(setSearchResult(QList<GeoDataPlacemark *>)));
130 connect(d->m_runnerManager, SIGNAL(searchFinished(QString)), d->m_searchField, SLOT(disableSearchAnimation()));
131
132 GeoDataTreeModel *treeModel = d->m_widget->model()->treeModel();
133 treeModel->addDocument(d->m_document);
134
135 d->m_branchfilter.setSourceModel(treeModel);
136 d->m_branchfilter.setBranchIndex(treeModel, treeModel->index(d->m_document));
137
138 d->m_searchResultView->setRootIndex(d->m_sortproxy.mapFromSource(d->m_branchfilter.mapFromSource(treeModel->index(d->m_document))));
139}
140
141void SearchWidgetPrivate::search(const QString &searchTerm, SearchMode searchMode)
142{
143 if (searchTerm.isEmpty()) {
144 clearSearch();
145 } else {
146 if (searchMode == AreaSearch) {
147 m_runnerManager->findPlacemarks(searchTerm, m_widget->viewport()->viewLatLonAltBox());
148 } else {
149 m_runnerManager->findPlacemarks(searchTerm);
150 }
151 }
152}
153
154void SearchWidgetPrivate::clearSearch()
155{
156 m_widget->model()->placemarkSelectionModel()->clear();
157
158 // clear the local document
159 GeoDataTreeModel *treeModel = m_widget->model()->treeModel();
160 treeModel->removeDocument(m_document);
161 m_document->clear();
162 treeModel->addDocument(m_document);
163 m_branchfilter.setBranchIndex(treeModel, treeModel->index(m_document));
164 m_searchResultView->setRootIndex(m_sortproxy.mapFromSource(m_branchfilter.mapFromSource(treeModel->index(m_document))));
165
166 // clear cached search results
167 m_runnerManager->findPlacemarks(QString());
168}
169
170void SearchWidgetPrivate::centerMapOn(const QModelIndex &index)
171{
172 if (!index.isValid()) {
173 return;
174 }
175 auto object = index.model()->data(index, MarblePlacemarkModel::ObjectPointerRole).value<GeoDataObject *>();
176 auto placemark = dynamic_cast<GeoDataPlacemark *>(object);
177 if (placemark) {
178 m_widget->centerOn(*placemark, true);
179 m_widget->model()->placemarkSelectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
180 }
181}
182
183void SearchWidgetPrivate::handlePlanetChange()
184{
185 const QString newPlanetId = m_widget->model()->planetId();
186
187 if (newPlanetId == m_planetId) {
188 return;
189 }
190
191 m_planetId = newPlanetId;
192 clearSearch();
193}
194
195}
196
197#include "moc_SearchWidget.cpp"
This file contains the headers for MarbleModel.
This file contains the headers for MarbleWidget.
This file contains the headers for ViewportParams.
Binds a QML item to a specific geodetic location in screen coordinates.
SearchMode
Search mode: Global (worldwide) versus area (local, regional) search.
virtual QVariant data(const QModelIndex &index, int role) const const=0
qint64 elapsed() const const
bool isEmpty() const const
bool isValid() const const
const QAbstractItemModel * model() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
bool isEmpty() const const
AscendingOrder
typedef WindowFlags
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
T value() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 8 2024 12:02:44 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.