File indexing completed on 2024-04-21 03:49:55

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2012 Dennis Nienhüser <nienhueser@kde.org>
0004 //
0005 
0006 #include "SearchWidget.h"
0007 
0008 #include "GeoDataPlacemark.h"
0009 #include "GeoDataLatLonAltBox.h"
0010 #include "GeoDataDocument.h"
0011 #include "GeoDataTreeModel.h"
0012 #include "SearchInputWidget.h"
0013 #include "MarbleWidget.h"
0014 #include "MarbleModel.h"
0015 #include "BranchFilterProxyModel.h"
0016 #include "MarblePlacemarkModel.h"
0017 #include "SearchRunnerManager.h"
0018 #include "ViewportParams.h"
0019 #include "MarbleDebug.h"
0020 
0021 #include <QListView>
0022 #include <QVBoxLayout>
0023 #include <QElapsedTimer>
0024 
0025 namespace Marble {
0026 
0027 class SearchWidgetPrivate
0028 {
0029 public:
0030     SearchRunnerManager* m_runnerManager;
0031     SearchInputWidget *m_searchField;
0032     QListView *m_searchResultView;
0033     MarbleWidget *m_widget;
0034     BranchFilterProxyModel  m_branchfilter;
0035     QSortFilterProxyModel   m_sortproxy;
0036     GeoDataDocument        *m_document;
0037     QString m_planetId;
0038 
0039     SearchWidgetPrivate();
0040     void setSearchResult( const QVector<GeoDataPlacemark*>& );
0041     void search( const QString &searchTerm, SearchMode searchMode );
0042     void clearSearch();
0043     void centerMapOn( const QModelIndex &index );
0044     void handlePlanetChange();
0045 };
0046 
0047 SearchWidgetPrivate::SearchWidgetPrivate() :
0048     m_runnerManager( nullptr ),
0049     m_searchField( nullptr ),
0050     m_searchResultView( nullptr ),
0051     m_widget( nullptr ),
0052     m_branchfilter(),
0053     m_sortproxy(),
0054     m_document( new GeoDataDocument )
0055 {
0056     m_document->setName( QObject::tr( "Search Results" ) );
0057 }
0058 
0059 void SearchWidgetPrivate::setSearchResult( const QVector<GeoDataPlacemark *>& locations )
0060 {
0061     if( locations.isEmpty() ) {
0062         return;
0063     }
0064 
0065     QElapsedTimer timer;
0066     timer.start();
0067 
0068     // fill the local document with results
0069     m_widget->model()->placemarkSelectionModel()->clear();
0070     GeoDataTreeModel *treeModel = m_widget->model()->treeModel();
0071     treeModel->removeDocument( m_document );
0072     m_document->clear();
0073     m_document->setName( QString( QObject::tr( "Search for '%1'" ) ).arg( m_searchField->text() ) );
0074     for (GeoDataPlacemark *placemark: locations ) {
0075         m_document->append( new GeoDataPlacemark( *placemark ) );
0076     }
0077     treeModel->addDocument( m_document );
0078     m_branchfilter.setBranchIndex( treeModel, treeModel->index( m_document ) );
0079     m_searchResultView->setRootIndex(
0080                 m_sortproxy.mapFromSource(
0081                     m_branchfilter.mapFromSource( treeModel->index( m_document ) ) ) );
0082     m_widget->centerOn( m_document->latLonAltBox() );
0083     mDebug() << " Time elapsed:"<< timer.elapsed() << " ms";
0084 }
0085 
0086 SearchWidget::SearchWidget( QWidget *parent, Qt::WindowFlags flags ) :
0087     QWidget( parent, flags ),
0088     d( new SearchWidgetPrivate )
0089 {
0090     d->m_sortproxy.setSortRole( MarblePlacemarkModel::PopularityIndexRole );
0091     d->m_sortproxy.sort( 0, Qt::AscendingOrder );
0092     d->m_sortproxy.setDynamicSortFilter( true );
0093     d->m_sortproxy.setSourceModel( &d->m_branchfilter );
0094 
0095     d->m_searchField = new SearchInputWidget( this );
0096     setFocusProxy( d->m_searchField );
0097     connect( d->m_searchField, SIGNAL(search(QString,SearchMode)),
0098              this, SLOT(search(QString,SearchMode)) );
0099 
0100     d->m_searchResultView = new QListView( this );
0101     d->m_searchResultView->setModel( &d->m_sortproxy );
0102     d->m_searchResultView->setMinimumSize( 0, 0 );
0103     connect( d->m_searchResultView, SIGNAL(activated(QModelIndex)),
0104              this, SLOT(centerMapOn(QModelIndex)) );
0105 
0106     QVBoxLayout* layout = new QVBoxLayout;
0107     layout->addWidget( d->m_searchField );
0108     layout->addWidget( d->m_searchResultView );
0109     layout->setMargin( 0 );
0110     setLayout( layout );
0111 }
0112 
0113 SearchWidget::~SearchWidget()
0114 {
0115     delete d;
0116 }
0117 
0118 void SearchWidget::setMarbleWidget( MarbleWidget* widget )
0119 {
0120     if ( d->m_widget ) {
0121         return;
0122     }
0123 
0124     d->m_widget = widget;
0125 
0126     d->m_planetId = widget->model()->planetId();
0127     connect( widget->model(), SIGNAL(themeChanged(QString)),
0128              this, SLOT(handlePlanetChange()) );
0129 
0130     d->m_searchField->setCompletionModel( widget->model()->placemarkModel() );
0131     connect( d->m_searchField, SIGNAL(centerOn(GeoDataCoordinates)),
0132              widget, SLOT(centerOn(GeoDataCoordinates)) );
0133 
0134     d->m_runnerManager = new SearchRunnerManager( widget->model(), this );
0135     connect( d->m_runnerManager, SIGNAL(searchResultChanged(QVector<GeoDataPlacemark*>)),
0136              this,               SLOT(setSearchResult(QVector<GeoDataPlacemark*>)) );
0137     connect( d->m_runnerManager, SIGNAL(searchFinished(QString)),
0138              d->m_searchField,   SLOT(disableSearchAnimation()));
0139 
0140     GeoDataTreeModel* treeModel = d->m_widget->model()->treeModel();
0141     treeModel->addDocument( d->m_document );
0142 
0143     d->m_branchfilter.setSourceModel( treeModel );
0144     d->m_branchfilter.setBranchIndex( treeModel, treeModel->index( d->m_document ) );
0145 
0146     d->m_searchResultView->setRootIndex(
0147                 d->m_sortproxy.mapFromSource(
0148                     d->m_branchfilter.mapFromSource( treeModel->index( d->m_document ) ) ) );
0149 }
0150 
0151 void SearchWidgetPrivate::search( const QString &searchTerm, SearchMode searchMode )
0152 {
0153     if( searchTerm.isEmpty() ) {
0154         clearSearch();
0155     } else {
0156         if ( searchMode == AreaSearch ) {
0157             m_runnerManager->findPlacemarks( searchTerm, m_widget->viewport()->viewLatLonAltBox() );
0158         } else {
0159             m_runnerManager->findPlacemarks( searchTerm );
0160         }
0161     }
0162 }
0163 
0164 void SearchWidgetPrivate::clearSearch()
0165 {
0166     m_widget->model()->placemarkSelectionModel()->clear();
0167 
0168     // clear the local document
0169     GeoDataTreeModel *treeModel = m_widget->model()->treeModel();
0170     treeModel->removeDocument( m_document );
0171     m_document->clear();
0172     treeModel->addDocument( m_document );
0173     m_branchfilter.setBranchIndex( treeModel, treeModel->index( m_document ) );
0174     m_searchResultView->setRootIndex(
0175             m_sortproxy.mapFromSource(
0176                 m_branchfilter.mapFromSource( treeModel->index( m_document ) ) ) );
0177 
0178     // clear cached search results
0179     m_runnerManager->findPlacemarks( QString() );
0180 }
0181 
0182 void SearchWidgetPrivate::centerMapOn( const QModelIndex &index )
0183 {
0184     if( !index.isValid() ) {
0185         return;
0186     }
0187     GeoDataObject *object
0188             = index.model()->data(index, MarblePlacemarkModel::ObjectPointerRole ).value<GeoDataObject*>();
0189     GeoDataPlacemark *placemark = dynamic_cast<GeoDataPlacemark*>( object );
0190     if ( placemark ) {
0191         m_widget->centerOn( *placemark, true );
0192         m_widget->model()->placemarkSelectionModel()->select( index, QItemSelectionModel::ClearAndSelect );
0193     }
0194 }
0195 
0196 void SearchWidgetPrivate::handlePlanetChange()
0197 {
0198     const QString newPlanetId = m_widget->model()->planetId();
0199 
0200     if (newPlanetId == m_planetId) {
0201         return;
0202     }
0203 
0204     m_planetId = newPlanetId;
0205     clearSearch();
0206 }
0207 
0208 }
0209 
0210 #include "moc_SearchWidget.cpp"