Add a context variable for locator searches

This allows encapsulation of properties relating to the context
of a search, such as a target map extent. Locator filters could
use this to prioritise results close to the current canvas extent.
This commit is contained in:
Nyall Dawson 2017-05-08 19:47:35 +10:00
parent 376d6b3d08
commit a7d590e041
12 changed files with 150 additions and 17 deletions

View File

@ -212,6 +212,7 @@
%Include layertree/qgslayertreeviewdefaultactions.sip
%Include locator/qgslocator.sip
%Include locator/qgslocatorcontext.sip
%Include locator/qgslocatorfilter.sip
%Include locator/qgslocatorwidget.sip

View File

@ -74,9 +74,12 @@ class QgsLocator : QObject
:rtype: list of QgsLocatorFilter
%End
void fetchResults( const QString &string, QgsFeedback *feedback = 0 );
void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback = 0 );
%Docstring
Triggers the background fetching of filter results for a specified search ``string``.
The ``context`` argument encapsulates the context relating to the search (such as a map
extent to prioritize).
If specified, the ``feedback`` object must exist for the lifetime of this query.
The foundResult() signal will be emitted for each individual result encountered

View File

@ -0,0 +1,53 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/locator/qgslocatorcontext.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsLocatorContext
{
%Docstring
Encapsulates the properties relating to the context of a locator search.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslocatorcontext.h"
%End
public:
QgsLocatorContext();
%Docstring
Constructor for QgsLocatorContext.
%End
QgsRectangle targetExtent;
%Docstring
Map extent to target in results. This can be used to prioritize searching
for results close to the current map extent. The CRS for the extent
is specified by targetExtentCrs.
.. seealso:: targetExtentCrs
%End
QgsCoordinateReferenceSystem targetExtentCrs;
%Docstring
Coordinate reference system for the map extent variable.
.. seealso:: targetExtent
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/locator/qgslocatorcontext.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -71,9 +71,11 @@ class QgsLocatorFilter : QObject
Constructor for QgsLocatorFilter.
%End
virtual void fetchResults( const QString &string, QgsFeedback *feedback ) = 0;
virtual void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) = 0;
%Docstring
Retrieves the filter results for a specified search ``string``.
Retrieves the filter results for a specified search ``string``. The ``context``
argument encapsulates the context relating to the search (such as a map
extent to prioritize).
Implementations of fetchResults() should emit the resultFetched()
signal whenever they encounter a matching result.

View File

@ -30,7 +30,7 @@ QgsLayerTreeLocatorFilter::QgsLayerTreeLocatorFilter( QObject *parent )
: QgsLocatorFilter( parent )
{}
void QgsLayerTreeLocatorFilter::fetchResults( const QString &string, QgsFeedback *feedback )
void QgsLayerTreeLocatorFilter::fetchResults( const QString &string, const QgsLocatorContext &, QgsFeedback *feedback )
{
QgsLayerTree *tree = QgsProject::instance()->layerTreeRoot();
QList<QgsLayerTreeLayer *> layers = tree->findLayers();
@ -66,7 +66,7 @@ QgsLayoutLocatorFilter::QgsLayoutLocatorFilter( QObject *parent )
: QgsLocatorFilter( parent )
{}
void QgsLayoutLocatorFilter::fetchResults( const QString &string, QgsFeedback *feedback )
void QgsLayoutLocatorFilter::fetchResults( const QString &string, const QgsLocatorContext &, QgsFeedback *feedback )
{
Q_FOREACH ( QgsComposition *composition, QgsProject::instance()->layoutManager()->compositions() )
{

View File

@ -27,7 +27,7 @@ class QgsLayerTreeLocatorFilter : public QgsLocatorFilter
public:
QgsLayerTreeLocatorFilter( QObject *parent = nullptr );
void fetchResults( const QString &string, QgsFeedback *feedback ) override;
void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
void triggerResult( const QgsLocatorResult &result ) override;
};
@ -39,7 +39,7 @@ class QgsLayoutLocatorFilter : public QgsLocatorFilter
public:
QgsLayoutLocatorFilter( QObject *parent = nullptr );
void fetchResults( const QString &string, QgsFeedback *feedback ) override;
void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
void triggerResult( const QgsLocatorResult &result ) override;
};

View File

@ -693,6 +693,8 @@ SET(QGIS_GUI_HDRS
layertree/qgslayertreeembeddedconfigwidget.h
layertree/qgslayertreeembeddedwidgetregistry.h
locator/qgslocatorcontext.h
raster/qgsrasterrendererwidget.h
symbology-ng/qgssymbolwidgetcontext.h

View File

@ -52,7 +52,7 @@ void QgsLocator::registerFilter( QgsLocatorFilter *filter )
connect( filter, &QgsLocatorFilter::resultFetched, this, &QgsLocator::filterSentResult, Qt::QueuedConnection );
}
void QgsLocator::fetchResults( const QString &string, QgsFeedback *feedback )
void QgsLocator::fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback )
{
// ideally this should not be required, as well behaved callers
// will NOT fire up a new fetchResults call while an existing one is
@ -75,7 +75,7 @@ void QgsLocator::fetchResults( const QString &string, QgsFeedback *feedback )
auto gatherFilterResults = [string, feedback]( QgsLocatorFilter * filter )
{
if ( !feedback->isCanceled() )
filter->fetchResults( string, feedback );
filter->fetchResults( string, context, feedback );
};
mFuture = QtConcurrent::map( mFilters, gatherFilterResults );

View File

@ -22,6 +22,7 @@
#include "qgis_sip.h"
#include "qgslocatorfilter.h"
#include "qgsfeedback.h"
#include "qgslocatorcontext.h"
#include <QObject>
#include <QFuture>
#include <QFutureWatcher>
@ -93,12 +94,15 @@ class GUI_EXPORT QgsLocator : public QObject
/**
* Triggers the background fetching of filter results for a specified search \a string.
* The \a context argument encapsulates the context relating to the search (such as a map
* extent to prioritize).
*
* If specified, the \a feedback object must exist for the lifetime of this query.
*
* The foundResult() signal will be emitted for each individual result encountered
* by the registered filters.
*/
void fetchResults( const QString &string, QgsFeedback *feedback = nullptr );
void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback = nullptr );
/**
* Cancels any current running query, and blocks until query is completely canceled by

View File

@ -0,0 +1,58 @@
/***************************************************************************
qgslocatorcontext.h
------------------
begin : May 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSLOCATORCONTEXT_H
#define QGSLOCATORCONTEXT_H
#include "qgis_gui.h"
#include "qgsrectangle.h"
#include "qgscoordinatereferencesystem.h"
/**
* \class QgsLocatorContext
* \ingroup gui
* Encapsulates the properties relating to the context of a locator search.
* \since QGIS 3.0
*/
class GUI_EXPORT QgsLocatorContext
{
public:
/**
* Constructor for QgsLocatorContext.
*/
QgsLocatorContext() = default;
/**
* Map extent to target in results. This can be used to prioritize searching
* for results close to the current map extent. The CRS for the extent
* is specified by targetExtentCrs.
* \see targetExtentCrs
*/
QgsRectangle targetExtent;
/**
* Coordinate reference system for the map extent variable.
* \see targetExtent
*/
QgsCoordinateReferenceSystem targetExtentCrs;
};
#endif // QGSLOCATORCONTEXT_H

View File

@ -19,6 +19,7 @@
#define QGSLOCATORFILTER_H
#include "qgis_gui.h"
#include "qgslocatorcontext.h"
#include "qgslogger.h"
#include <QString>
#include <QVariant>
@ -91,7 +92,9 @@ class GUI_EXPORT QgsLocatorFilter : public QObject
QgsLocatorFilter( QObject *parent = nullptr );
/**
* Retrieves the filter results for a specified search \a string.
* Retrieves the filter results for a specified search \a string. The \a context
* argument encapsulates the context relating to the search (such as a map
* extent to prioritize).
*
* Implementations of fetchResults() should emit the resultFetched()
* signal whenever they encounter a matching result.
@ -100,7 +103,7 @@ class GUI_EXPORT QgsLocatorFilter : public QObject
* whether the query has been canceled. If so, the subclass should return
* from this method as soon as possible.
*/
virtual void fetchResults( const QString &string, QgsFeedback *feedback ) = 0;
virtual void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) = 0;
/**
* Triggers a filter \a result from this filter. This is called when

View File

@ -17,6 +17,7 @@ import os
from qgis.gui import (QgsLocator,
QgsLocatorFilter,
QgsLocatorContext,
QgsLocatorResult)
from qgis.PyQt.QtCore import QVariant, pyqtSignal, QCoreApplication
from time import sleep
@ -31,7 +32,7 @@ class test_filter(QgsLocatorFilter):
super().__init__(parent)
self.prefix = prefix
def fetchResults(self, string, feedback):
def fetchResults(self, string, context, feedback):
for i in range(3):
#if feedback.isCanceled():
# return
@ -83,13 +84,15 @@ class TestQgsLocator(unittest.TestCase):
got_hit._results_ = []
context = QgsLocatorContext()
# one filter
l = QgsLocator()
filter_a = test_filter('a')
l.registerFilter(filter_a)
l.foundResult.connect(got_hit)
l.fetchResults('a')
l.fetchResults('a', context)
for i in range(100):
sleep(0.002)
@ -101,7 +104,7 @@ class TestQgsLocator(unittest.TestCase):
filter_b = test_filter('b')
l.registerFilter(filter_b)
got_hit._results_ = []
l.fetchResults('a')
l.fetchResults('a', context)
for i in range(100):
sleep(0.002)
@ -119,12 +122,14 @@ class TestQgsLocator(unittest.TestCase):
got_hit._results_ = []
context = QgsLocatorContext()
l = QgsLocator()
filter_a = test_filter('a')
l.registerFilter(filter_a)
l.foundResult.connect(got_hit)
l.fetchResults('a')
l.fetchResults('a', context)
del l
def testCancelWhileFetchingResults(self):
@ -137,12 +142,14 @@ class TestQgsLocator(unittest.TestCase):
got_hit._results_ = []
context = QgsLocatorContext()
l = QgsLocator()
filter_a = test_filter('a')
l.registerFilter(filter_a)
l.foundResult.connect(got_hit)
l.fetchResults('a')
l.fetchResults('a', context)
l.cancel()