Marble

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

KDE's Doxygen guidelines are available online.