Skip to content
Permalink
Browse files

[FEATURE][locator] Add bookmark search to locator bar

Allows search for spatial bookmarks. Double clicking a search result will zoom to the bookmark.
Short video: https://www.youtube.com/watch?v=ymW4TU8QWy4

The new filter presents itself with a prefix of "b" and with tr( "Spatial bookmarks" ) as displayname.

A bookmark locator filter is added to the built in locator filters (class QgsBookmarkLocatorFilter is added to qgsinbuiltlocatorfilters.cpp). The wiring between the the new filter and QgsBookmarks has been implemented in
* QgisApp::getBookmarkIndexMap() (For reading bookmarks), and
* QgisApp::zoomToBookmarkIndex(const QModelIndex &index) (For navigating to a bookmark)

QgsBookmarks has been slightly refactored
  • Loading branch information
klavspc committed Mar 4, 2018
1 parent 871132e commit 1f7875ec3d9c4782845919b0ab5540dc6c171e40
@@ -1,10 +1,10 @@
/***************************************************************************
qgsinbuiltlocatorfilters.cpp
----------------------------
begin : May 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
qgsinbuiltlocatorfilters.cpp
----------------------------
begin : May 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/

/***************************************************************************
* *
@@ -320,3 +320,50 @@ void QgsExpressionCalculatorLocatorFilter::triggerResult( const QgsLocatorResult
{
QApplication::clipboard()->setText( result.userData.toString() );
}
// QgBookmarkLocatorFilter
//

QgsBookmarkLocatorFilter::QgsBookmarkLocatorFilter( QObject *parent )
: QgsLocatorFilter( parent )
{}

QgsBookmarkLocatorFilter *QgsBookmarkLocatorFilter::clone() const
{
return new QgsBookmarkLocatorFilter();
}

void QgsBookmarkLocatorFilter::fetchResults( const QString &string, const QgsLocatorContext &, QgsFeedback *feedback )
{
QMap<QString, QModelIndex> bookmarkMap = QgisApp::instance()->getBookmarkIndexMap();

QMapIterator<QString, QModelIndex> i( bookmarkMap );

while ( i.hasNext() )
{
i.next();
if ( feedback->isCanceled() )
return;

QString name = i.key();

if ( stringMatches( name, string ) )
{
QModelIndex index = i.value();
QgsLocatorResult result;
result.filter = this;
result.displayString = name;
result.userData = index;
//TODO Create svg for "Bookmark"?
//result.icon = TBD
result.score = static_cast< double >( string.length() ) / name.length();
emit resultFetched( result );
}
}

}

void QgsBookmarkLocatorFilter::triggerResult( const QgsLocatorResult &result )
{
QModelIndex index = qvariant_cast<QModelIndex>( result.userData );
QgisApp::instance()->zoomToBookmarkIndex( index );
}
@@ -132,6 +132,25 @@ class APP_EXPORT QgsExpressionCalculatorLocatorFilter : public QgsLocatorFilter
};


class QgsBookmarkLocatorFilter : public QgsLocatorFilter
{
Q_OBJECT

public:

QgsBookmarkLocatorFilter( QObject *parent = nullptr );
QgsBookmarkLocatorFilter *clone() const override;
QString name() const override { return QStringLiteral( "bookmarks" ); }
QString displayName() const override { return tr( "Spatial bookmarks" ); }
Priority priority() const override { return Highest; }
QString prefix() const override { return QStringLiteral( "b" ); }
QgsLocatorFilter::Flags flags() const override { return QgsLocatorFilter::FlagFast; }

void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
void triggerResult( const QgsLocatorResult &result ) override;

};

#endif // QGSINBUILTLOCATORFILTERS_H


@@ -2946,6 +2946,7 @@ void QgisApp::createStatusBar()
mLocatorWidget->locator()->registerFilter( new QgsActionLocatorFilter( actionObjects ) );
mLocatorWidget->locator()->registerFilter( new QgsActiveLayerFeaturesLocatorFilter() );
mLocatorWidget->locator()->registerFilter( new QgsExpressionCalculatorLocatorFilter() );
mLocatorWidget->locator()->registerFilter( new QgsBookmarkLocatorFilter() );
}

void QgisApp::setIconSizes( int size )
@@ -12343,6 +12344,16 @@ void QgisApp::showBookmarks( bool show )
mBookMarksDockWidget->setUserVisible( show );
}

QMap<QString, QModelIndex> QgisApp::getBookmarkIndexMap()
{
return mBookMarksDockWidget->getIndexMap();
}

void QgisApp::zoomToBookmarkIndex( const QModelIndex &index )
{
mBookMarksDockWidget->zoomToBookmarkIndex( index );
}

// Slot that gets called when the project file was saved with an older
// version of QGIS

@@ -685,6 +685,11 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
*/
bool askUserForDatumTransform( const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs );

//! Get map of bookmarks
QMap<QString, QModelIndex> getBookmarkIndexMap();
//! Zoom to a bookmark
void zoomToBookmarkIndex( const QModelIndex & );

public slots:
//! save current vector layer
void saveAsFile( QgsMapLayer *layer = nullptr );
@@ -236,7 +236,11 @@ void QgsBookmarks::zoomToBookmark()
QModelIndex index = lstBookmarks->currentIndex();
if ( !index.isValid() )
return;
zoomToBookmarkIndex( index );
}

void QgsBookmarks::zoomToBookmarkIndex( const QModelIndex &index )
{
double xmin = index.sibling( index.row(), 3 ).data().toDouble();
double ymin = index.sibling( index.row(), 4 ).data().toDouble();
double xmax = index.sibling( index.row(), 5 ).data().toDouble();
@@ -254,7 +258,7 @@ void QgsBookmarks::zoomToBookmark()
rect = ct.transform( rect );
if ( rect.isEmpty() )
{
QMessageBox::warning( this, tr( "Zoom to Bookmark" ), tr( "Reprojected extent is empty." ) );
QMessageBox::warning( this, tr( "Empty Extent" ), tr( "Reprojected extent is empty." ) );
return;
}
}
@@ -340,6 +344,30 @@ void QgsBookmarks::importFromXml()
mProxyModel->_resetModel();
}

QMap<QString, QModelIndex> QgsBookmarks::getIndexMap()
{
QMap<QString, QModelIndex> map;
int rowCount = mMergedModel->rowCount();

for ( int i = 0; i < rowCount; ++i )
{
QModelIndex idx = mMergedModel->index( i, 1 ); //Name col
if ( idx.isValid() )
{
QString name = idx.data( Qt::DisplayRole ).toString();
QString project = idx.sibling( idx.row(), 2 ).data().toString();
if ( !project.isEmpty() )
{
name = name + " (" + project + ")";
}
map.insert( name, idx ); //Duplicate name/project pairs are overwritten by subsequent bookmarks
}
}

return map;

}

void QgsBookmarks::exportToXml()
{
QgsSettings settings;
@@ -145,6 +145,8 @@ class APP_EXPORT QgsBookmarks : public QgsDockWidget, private Ui::QgsBookmarksBa
public:
QgsBookmarks( QWidget *parent = nullptr );
~QgsBookmarks() override;
QMap<QString, QModelIndex> getIndexMap();
void zoomToBookmarkIndex( const QModelIndex & );

public slots:
void addClicked();
@@ -61,7 +61,8 @@ void QgsLocator::registerFilter( QgsLocatorFilter *filter )
{
if ( filter->name() == QStringLiteral( "actions" ) || filter->name() == QStringLiteral( "processing_alg" )
|| filter->name() == QStringLiteral( "layertree" ) || filter->name() == QStringLiteral( "layouts" )
|| filter->name() == QStringLiteral( "features" ) || filter->name() == QStringLiteral( "calculator" ) )
|| filter->name() == QStringLiteral( "features" ) || filter->name() == QStringLiteral( "calculator" )
|| filter->name() == QStringLiteral( "bookmarks" ) )
{
//inbuilt filter, no prefix check
mPrefixedFilters.insert( filter->prefix(), filter );

0 comments on commit 1f7875e

Please sign in to comment.
You can’t perform that action at this time.