mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-09 00:08:52 -04:00
Merge pull request #5112 from nyalldawson/locator_core
Move locator non-gui classes to core
This commit is contained in:
commit
742f3e5b4d
@ -66,6 +66,7 @@ IF(WITH_APIDOC)
|
|||||||
${CMAKE_SOURCE_DIR}/src/core/gps
|
${CMAKE_SOURCE_DIR}/src/core/gps
|
||||||
${CMAKE_SOURCE_DIR}/src/core/layertree
|
${CMAKE_SOURCE_DIR}/src/core/layertree
|
||||||
${CMAKE_SOURCE_DIR}/src/core/layout
|
${CMAKE_SOURCE_DIR}/src/core/layout
|
||||||
|
${CMAKE_SOURCE_DIR}/src/core/locator
|
||||||
${CMAKE_SOURCE_DIR}/src/core/metadata
|
${CMAKE_SOURCE_DIR}/src/core/metadata
|
||||||
${CMAKE_SOURCE_DIR}/src/core/pal
|
${CMAKE_SOURCE_DIR}/src/core/pal
|
||||||
${CMAKE_SOURCE_DIR}/src/core/processing
|
${CMAKE_SOURCE_DIR}/src/core/processing
|
||||||
|
@ -117,6 +117,7 @@ INCLUDE_DIRECTORIES(
|
|||||||
${CMAKE_SOURCE_DIR}/src/core/gps
|
${CMAKE_SOURCE_DIR}/src/core/gps
|
||||||
${CMAKE_SOURCE_DIR}/src/core/layertree
|
${CMAKE_SOURCE_DIR}/src/core/layertree
|
||||||
${CMAKE_SOURCE_DIR}/src/core/layout
|
${CMAKE_SOURCE_DIR}/src/core/layout
|
||||||
|
${CMAKE_SOURCE_DIR}/src/core/locator
|
||||||
${CMAKE_SOURCE_DIR}/src/core/metadata
|
${CMAKE_SOURCE_DIR}/src/core/metadata
|
||||||
${CMAKE_SOURCE_DIR}/src/core/processing
|
${CMAKE_SOURCE_DIR}/src/core/processing
|
||||||
${CMAKE_SOURCE_DIR}/src/core/processing/models
|
${CMAKE_SOURCE_DIR}/src/core/processing/models
|
||||||
|
@ -251,6 +251,7 @@
|
|||||||
%Include symbology/qgsvectorfieldsymbollayer.sip
|
%Include symbology/qgsvectorfieldsymbollayer.sip
|
||||||
%Include symbology/qgsgeometrygeneratorsymbollayer.sip
|
%Include symbology/qgsgeometrygeneratorsymbollayer.sip
|
||||||
%Include layertree/qgslayertreeutils.sip
|
%Include layertree/qgslayertreeutils.sip
|
||||||
|
%Include locator/qgslocatorcontext.sip
|
||||||
%Include geometry/qgsabstractgeometry.sip
|
%Include geometry/qgsabstractgeometry.sip
|
||||||
%Include geometry/qgsbox3d.sip
|
%Include geometry/qgsbox3d.sip
|
||||||
%Include geometry/qgscircularstring.sip
|
%Include geometry/qgscircularstring.sip
|
||||||
@ -374,6 +375,9 @@
|
|||||||
%Include composer/qgscomposition.sip
|
%Include composer/qgscomposition.sip
|
||||||
%Include composer/qgsgroupungroupitemscommand.sip
|
%Include composer/qgsgroupungroupitemscommand.sip
|
||||||
%Include composer/qgslayoutmanager.sip
|
%Include composer/qgslayoutmanager.sip
|
||||||
|
%Include locator/qgslocator.sip
|
||||||
|
%Include locator/qgslocatorfilter.sip
|
||||||
|
%Include locator/qgslocatormodel.sip
|
||||||
%Include processing/qgsprocessingalgrunnertask.sip
|
%Include processing/qgsprocessingalgrunnertask.sip
|
||||||
%Include processing/qgsprocessingfeedback.sip
|
%Include processing/qgsprocessingfeedback.sip
|
||||||
%Include processing/qgsprocessingprovider.sip
|
%Include processing/qgsprocessingprovider.sip
|
||||||
|
142
python/core/locator/qgslocator.sip
Normal file
142
python/core/locator/qgslocator.sip
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* This file has been generated automatically from *
|
||||||
|
* *
|
||||||
|
* src/core/locator/qgslocator.h *
|
||||||
|
* *
|
||||||
|
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class QgsLocator : QObject
|
||||||
|
{
|
||||||
|
%Docstring
|
||||||
|
Handles the management of QgsLocatorFilter objects and async collection of search results from them.
|
||||||
|
|
||||||
|
QgsLocator acts as both a registry for QgsLocatorFilter objects and a means of firing up
|
||||||
|
asynchronous queries against these filter objects.
|
||||||
|
|
||||||
|
Filters are first registered to the locator by calling registerFilter(). Registering filters
|
||||||
|
transfers their ownership to the locator object. Plugins which register filters to the locator
|
||||||
|
must take care to correctly call deregisterFilter() and deregister their filter upon plugin
|
||||||
|
unload to avoid crashes.
|
||||||
|
|
||||||
|
In order to trigger a search across registered filters, the fetchResults() method is called.
|
||||||
|
This triggers threaded calls to QgsLocatorFilter.fetchResults() for all registered filters.
|
||||||
|
As individual filters find matching results, the foundResult() signal will be triggered
|
||||||
|
for each result. Callers should connect this signal to an appropriate slot designed
|
||||||
|
to collect and handle these results. Since foundResult() is triggered whenever a filter
|
||||||
|
encounters an individual result, it will usually be triggered many times for a single
|
||||||
|
call to fetchResults().
|
||||||
|
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
%End
|
||||||
|
|
||||||
|
%TypeHeaderCode
|
||||||
|
#include "qgslocator.h"
|
||||||
|
%End
|
||||||
|
public:
|
||||||
|
|
||||||
|
QgsLocator( QObject *parent /TransferThis/ = 0 );
|
||||||
|
%Docstring
|
||||||
|
Constructor for QgsLocator.
|
||||||
|
%End
|
||||||
|
|
||||||
|
~QgsLocator();
|
||||||
|
%Docstring
|
||||||
|
Destructor for QgsLocator. Destruction will block while any currently running query is terminated.
|
||||||
|
%End
|
||||||
|
|
||||||
|
void registerFilter( QgsLocatorFilter *filter /Transfer/ );
|
||||||
|
%Docstring
|
||||||
|
Registers a ``filter`` within the locator. Ownership of the filter is transferred to the
|
||||||
|
locator.
|
||||||
|
\warning Plugins which register filters to the locator must take care to correctly call
|
||||||
|
deregisterFilter() and deregister their filters upon plugin unload to avoid crashes.
|
||||||
|
.. seealso:: deregisterFilter()
|
||||||
|
%End
|
||||||
|
|
||||||
|
void deregisterFilter( QgsLocatorFilter *filter );
|
||||||
|
%Docstring
|
||||||
|
Deregisters a ``filter`` from the locator and deletes it. Calling this will block whilst
|
||||||
|
any currently running query is terminated.
|
||||||
|
|
||||||
|
Plugins which register filters to the locator must take care to correctly call
|
||||||
|
deregisterFilter() to deregister their filters upon plugin unload to avoid crashes.
|
||||||
|
|
||||||
|
.. seealso:: registerFilter()
|
||||||
|
%End
|
||||||
|
|
||||||
|
QList< QgsLocatorFilter *> filters();
|
||||||
|
%Docstring
|
||||||
|
Returns the list of filters registered in the locator.
|
||||||
|
.. seealso:: prefixedFilters()
|
||||||
|
:rtype: list of QgsLocatorFilter
|
||||||
|
%End
|
||||||
|
|
||||||
|
QMap< QString, QgsLocatorFilter *> prefixedFilters() const;
|
||||||
|
%Docstring
|
||||||
|
Returns a map of prefix to filter, for all registered filters
|
||||||
|
with valid prefixes.
|
||||||
|
.. seealso:: filters()
|
||||||
|
:rtype: QMap< str, QgsLocatorFilter *>
|
||||||
|
%End
|
||||||
|
|
||||||
|
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
|
||||||
|
by the registered filters.
|
||||||
|
%End
|
||||||
|
|
||||||
|
void cancel();
|
||||||
|
%Docstring
|
||||||
|
Cancels any current running query, and blocks until query is completely canceled by
|
||||||
|
all filters.
|
||||||
|
.. seealso:: cancelWithoutBlocking()
|
||||||
|
%End
|
||||||
|
|
||||||
|
void cancelWithoutBlocking();
|
||||||
|
%Docstring
|
||||||
|
Triggers cancelation of any current running query without blocking. The query may
|
||||||
|
take some time to cancel after calling this.
|
||||||
|
.. seealso:: cancel()
|
||||||
|
%End
|
||||||
|
|
||||||
|
bool isRunning() const;
|
||||||
|
%Docstring
|
||||||
|
Returns true if a query is currently being executed by the locator.
|
||||||
|
:rtype: bool
|
||||||
|
%End
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void foundResult( const QgsLocatorResult &result );
|
||||||
|
%Docstring
|
||||||
|
Emitted whenever a filter encounters a matching ``result`` after the fetchResults() method
|
||||||
|
is called.
|
||||||
|
%End
|
||||||
|
|
||||||
|
void finished();
|
||||||
|
%Docstring
|
||||||
|
Emitted when locator has finished a query, either as a result
|
||||||
|
of successful completion or early cancelation.
|
||||||
|
%End
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* This file has been generated automatically from *
|
||||||
|
* *
|
||||||
|
* src/core/locator/qgslocator.h *
|
||||||
|
* *
|
||||||
|
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||||
|
************************************************************************/
|
53
python/core/locator/qgslocatorcontext.sip
Normal file
53
python/core/locator/qgslocatorcontext.sip
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* This file has been generated automatically from *
|
||||||
|
* *
|
||||||
|
* src/core/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/core/locator/qgslocatorcontext.h *
|
||||||
|
* *
|
||||||
|
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||||
|
************************************************************************/
|
225
python/core/locator/qgslocatorfilter.sip
Normal file
225
python/core/locator/qgslocatorfilter.sip
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* This file has been generated automatically from *
|
||||||
|
* *
|
||||||
|
* src/core/locator/qgslocatorfilter.h *
|
||||||
|
* *
|
||||||
|
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class QgsLocatorResult
|
||||||
|
{
|
||||||
|
%Docstring
|
||||||
|
Encapsulates properties of an individual matching result found by a QgsLocatorFilter.
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
%End
|
||||||
|
|
||||||
|
%TypeHeaderCode
|
||||||
|
#include "qgslocatorfilter.h"
|
||||||
|
%End
|
||||||
|
public:
|
||||||
|
|
||||||
|
QgsLocatorResult();
|
||||||
|
%Docstring
|
||||||
|
Constructor for QgsLocatorResult.
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsLocatorResult( QgsLocatorFilter *filter, const QString &displayString, const QVariant &userData = QVariant() );
|
||||||
|
%Docstring
|
||||||
|
Constructor for QgsLocatorResult.
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsLocatorFilter *filter;
|
||||||
|
%Docstring
|
||||||
|
Filter from which the result was obtained.
|
||||||
|
%End
|
||||||
|
|
||||||
|
QString displayString;
|
||||||
|
%Docstring
|
||||||
|
String displayed for result.
|
||||||
|
%End
|
||||||
|
|
||||||
|
QString description;
|
||||||
|
%Docstring
|
||||||
|
Descriptive text for result.
|
||||||
|
%End
|
||||||
|
|
||||||
|
QVariant userData;
|
||||||
|
%Docstring
|
||||||
|
Custom reference or other data set by the filter.
|
||||||
|
%End
|
||||||
|
|
||||||
|
QIcon icon;
|
||||||
|
%Docstring
|
||||||
|
Icon for result.
|
||||||
|
%End
|
||||||
|
|
||||||
|
double score;
|
||||||
|
%Docstring
|
||||||
|
Match score, from 0 - 1, where 1 represents a perfect match.
|
||||||
|
%End
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class QgsLocatorFilter : QObject
|
||||||
|
{
|
||||||
|
%Docstring
|
||||||
|
Abstract base class for filters which collect locator results.
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
%End
|
||||||
|
|
||||||
|
%TypeHeaderCode
|
||||||
|
#include "qgslocatorfilter.h"
|
||||||
|
%End
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Priority
|
||||||
|
{
|
||||||
|
Highest,
|
||||||
|
High,
|
||||||
|
Medium,
|
||||||
|
Low,
|
||||||
|
Lowest
|
||||||
|
};
|
||||||
|
|
||||||
|
QgsLocatorFilter( QObject *parent = 0 );
|
||||||
|
%Docstring
|
||||||
|
Constructor for QgsLocatorFilter.
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual QString name() const = 0;
|
||||||
|
%Docstring
|
||||||
|
Returns the unique name for the filter. This should be an untranslated string identifying the filter.
|
||||||
|
.. seealso:: displayName()
|
||||||
|
:rtype: str
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual QString displayName() const = 0;
|
||||||
|
%Docstring
|
||||||
|
Returns a translated, user-friendly name for the filter.
|
||||||
|
.. seealso:: name()
|
||||||
|
:rtype: str
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual Priority priority() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the priority for the filter, which controls how results are
|
||||||
|
ordered in the locator.
|
||||||
|
:rtype: Priority
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual QString prefix() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the search prefix character(s) for this filter. Prefix a search
|
||||||
|
with these characters will restrict the locator search to only include
|
||||||
|
results from this filter.
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Plugins are not permitted to utilize prefixes with < 3 characters,
|
||||||
|
as these are reserved for core QGIS functions. If a plugin registers
|
||||||
|
a filter with a prefix shorter than 3 characters then the prefix will
|
||||||
|
be ignored.
|
||||||
|
:rtype: str
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) = 0;
|
||||||
|
%Docstring
|
||||||
|
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.
|
||||||
|
|
||||||
|
Subclasses should periodically check the ``feedback`` object to determine
|
||||||
|
whether the query has been canceled. If so, the subclass should return
|
||||||
|
from this method as soon as possible.
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual void triggerResult( const QgsLocatorResult &result ) = 0;
|
||||||
|
%Docstring
|
||||||
|
Triggers a filter ``result`` from this filter. This is called when
|
||||||
|
one of the results obtained by a call to fetchResults() is triggered
|
||||||
|
by a user. The filter subclass must implement logic here
|
||||||
|
to perform the desired operation for the search result.
|
||||||
|
E.g. a file search filter would open file associated with the triggered
|
||||||
|
result.
|
||||||
|
%End
|
||||||
|
|
||||||
|
bool useWithoutPrefix() const;
|
||||||
|
%Docstring
|
||||||
|
Returns true if the filter should be used when no prefix
|
||||||
|
is entered.
|
||||||
|
.. seealso:: setUseWithoutPrefix()
|
||||||
|
:rtype: bool
|
||||||
|
%End
|
||||||
|
|
||||||
|
void setUseWithoutPrefix( bool useWithoutPrefix );
|
||||||
|
%Docstring
|
||||||
|
Sets whether the filter should be used when no prefix
|
||||||
|
is entered.
|
||||||
|
.. seealso:: useWithoutPrefix()
|
||||||
|
%End
|
||||||
|
|
||||||
|
static bool stringMatches( const QString &candidate, const QString &search );
|
||||||
|
%Docstring
|
||||||
|
Tests a ``candidate`` string to see if it should be considered a match for
|
||||||
|
a specified ``search`` string.
|
||||||
|
Filter subclasses should use this method when comparing strings instead
|
||||||
|
of directly using QString.contains() or Python 'in' checks.
|
||||||
|
:rtype: bool
|
||||||
|
%End
|
||||||
|
|
||||||
|
bool enabled() const;
|
||||||
|
%Docstring
|
||||||
|
Returns true if the filter is enabled.
|
||||||
|
.. seealso:: setEnabled()
|
||||||
|
:rtype: bool
|
||||||
|
%End
|
||||||
|
|
||||||
|
void setEnabled( bool enabled );
|
||||||
|
%Docstring
|
||||||
|
Sets whether the filter is ``enabled``.
|
||||||
|
.. seealso:: enabled()
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual bool hasConfigWidget() const;
|
||||||
|
%Docstring
|
||||||
|
Should return true if the filter has a configuration widget.
|
||||||
|
.. seealso:: createConfigWidget()
|
||||||
|
:rtype: bool
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual void openConfigWidget( QWidget *parent = 0 );
|
||||||
|
%Docstring
|
||||||
|
Opens the configuration widget for the filter (if it has one), with the specified ``parent`` widget.
|
||||||
|
The base class implementation does nothing. Subclasses can override this to show their own
|
||||||
|
custom configuration widget.
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
hasConfigWidget() must return true to indicate that the filter supports configuration.
|
||||||
|
%End
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void resultFetched( const QgsLocatorResult &result );
|
||||||
|
%Docstring
|
||||||
|
Should be emitted by filters whenever they encounter a matching result
|
||||||
|
during within their fetchResults() implementation.
|
||||||
|
%End
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* This file has been generated automatically from *
|
||||||
|
* *
|
||||||
|
* src/core/locator/qgslocatorfilter.h *
|
||||||
|
* *
|
||||||
|
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||||
|
************************************************************************/
|
162
python/core/locator/qgslocatormodel.sip
Normal file
162
python/core/locator/qgslocatormodel.sip
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* This file has been generated automatically from *
|
||||||
|
* *
|
||||||
|
* src/core/locator/qgslocatormodel.h *
|
||||||
|
* *
|
||||||
|
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class QgsLocatorModel : QAbstractTableModel
|
||||||
|
{
|
||||||
|
%Docstring
|
||||||
|
An abstract list model for displaying the results of locator searches.
|
||||||
|
|
||||||
|
Note that this class should generally be used with a QgsLocatorProxyModel
|
||||||
|
in order to ensure correct sorting of results by priority and match level.
|
||||||
|
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
%End
|
||||||
|
|
||||||
|
%TypeHeaderCode
|
||||||
|
#include "qgslocatormodel.h"
|
||||||
|
%End
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Role
|
||||||
|
{
|
||||||
|
ResultDataRole,
|
||||||
|
ResultTypeRole,
|
||||||
|
ResultFilterPriorityRole,
|
||||||
|
ResultScoreRole,
|
||||||
|
ResultFilterNameRole,
|
||||||
|
};
|
||||||
|
|
||||||
|
QgsLocatorModel( QObject *parent /TransferThis/ = 0 );
|
||||||
|
%Docstring
|
||||||
|
Constructor for QgsLocatorModel.
|
||||||
|
%End
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
%Docstring
|
||||||
|
Resets the model and clears all existing results.
|
||||||
|
.. seealso:: deferredClear()
|
||||||
|
%End
|
||||||
|
|
||||||
|
void deferredClear();
|
||||||
|
%Docstring
|
||||||
|
Resets the model and clears all existing results after a short delay, or whenever the next result is added to the model
|
||||||
|
(whichever occurs first). Using deferredClear() instead of clear() can avoid the visually distracting frequent clears
|
||||||
|
which may occur if the model is being updated quickly multiple times as a result of users typing in a search query.
|
||||||
|
.. seealso:: deferredClear()
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual int rowCount( const QModelIndex &parent = QModelIndex() ) const;
|
||||||
|
|
||||||
|
virtual int columnCount( const QModelIndex &parent = QModelIndex() ) const;
|
||||||
|
|
||||||
|
virtual QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const;
|
||||||
|
|
||||||
|
virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
|
||||||
|
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void addResult( const QgsLocatorResult &result );
|
||||||
|
%Docstring
|
||||||
|
Adds a new ``result`` to the model.
|
||||||
|
%End
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class QgsLocatorAutomaticModel : QgsLocatorModel
|
||||||
|
{
|
||||||
|
%Docstring
|
||||||
|
A QgsLocatorModel which has is associated directly with a
|
||||||
|
QgsLocator, and is automatically populated with results
|
||||||
|
from locator searches.
|
||||||
|
|
||||||
|
Use this QgsLocatorModel subclass when you want the connections
|
||||||
|
between a QgsLocator and the model to be automatically created
|
||||||
|
for you. If more flexibility in model behavior is required,
|
||||||
|
use the base QgsLocatorModel class instead and setup the
|
||||||
|
connections manually.
|
||||||
|
|
||||||
|
Note that this class should generally be used with a QgsLocatorProxyModel
|
||||||
|
in order to ensure correct sorting of results by priority and match level.
|
||||||
|
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
%End
|
||||||
|
|
||||||
|
%TypeHeaderCode
|
||||||
|
#include "qgslocatormodel.h"
|
||||||
|
%End
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit QgsLocatorAutomaticModel( QgsLocator *locator /TransferThis/ );
|
||||||
|
%Docstring
|
||||||
|
Constructor for QgsLocatorAutomaticModel, linked with the specified ``locator``.
|
||||||
|
|
||||||
|
The ``locator`` is used as the model's parent.
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsLocator *locator();
|
||||||
|
%Docstring
|
||||||
|
Returns a pointer to the locator utilized by this model.
|
||||||
|
:rtype: QgsLocator
|
||||||
|
%End
|
||||||
|
|
||||||
|
void search( const QString &string );
|
||||||
|
%Docstring
|
||||||
|
Enqueues a search for a specified ``string`` within the model.
|
||||||
|
|
||||||
|
Note that the search may not begin immediately if an existing search request
|
||||||
|
is still running. In this case the existing search must be completely
|
||||||
|
terminated before the new search can begin. The model handles this
|
||||||
|
situation automatically, and will trigger a search for the new
|
||||||
|
search string as soon as possible.
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual QgsLocatorContext createContext();
|
||||||
|
%Docstring
|
||||||
|
Returns a new locator context for searches. The default implementation
|
||||||
|
returns a default constructed QgsLocatorContext. Subclasses can override
|
||||||
|
this method to implement custom context creation logic.
|
||||||
|
:rtype: QgsLocatorContext
|
||||||
|
%End
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class QgsLocatorProxyModel : QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
%Docstring
|
||||||
|
A sort proxy model for QgsLocatorModel, which automatically sorts
|
||||||
|
results by precedence.
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
%End
|
||||||
|
|
||||||
|
%TypeHeaderCode
|
||||||
|
#include "qgslocatormodel.h"
|
||||||
|
%End
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit QgsLocatorProxyModel( QObject *parent /TransferThis/ = 0 );
|
||||||
|
%Docstring
|
||||||
|
Constructor for QgsLocatorProxyModel, with the specified ``parent`` object.
|
||||||
|
%End
|
||||||
|
virtual bool lessThan( const QModelIndex &left, const QModelIndex &right ) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* This file has been generated automatically from *
|
||||||
|
* *
|
||||||
|
* src/core/locator/qgslocatormodel.h *
|
||||||
|
* *
|
||||||
|
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||||
|
************************************************************************/
|
@ -46,7 +46,6 @@
|
|||||||
%Include layertree/qgslayertreeembeddedwidgetregistry.sip
|
%Include layertree/qgslayertreeembeddedwidgetregistry.sip
|
||||||
%Include layout/qgslayoutviewmouseevent.sip
|
%Include layout/qgslayoutviewmouseevent.sip
|
||||||
%Include layout/qgslayoutviewrubberband.sip
|
%Include layout/qgslayoutviewrubberband.sip
|
||||||
%Include locator/qgslocatorcontext.sip
|
|
||||||
%Include raster/qgsrasterrendererwidget.sip
|
%Include raster/qgsrasterrendererwidget.sip
|
||||||
%Include symbology/qgssymbolwidgetcontext.sip
|
%Include symbology/qgssymbolwidgetcontext.sip
|
||||||
%Include qgisinterface.sip
|
%Include qgisinterface.sip
|
||||||
@ -295,7 +294,5 @@
|
|||||||
%Include layout/qgslayoutviewtooltemporarykeyzoom.sip
|
%Include layout/qgslayoutviewtooltemporarykeyzoom.sip
|
||||||
%Include layout/qgslayoutviewtooltemporarymousepan.sip
|
%Include layout/qgslayoutviewtooltemporarymousepan.sip
|
||||||
%Include layout/qgslayoutviewtoolzoom.sip
|
%Include layout/qgslayoutviewtoolzoom.sip
|
||||||
%Include locator/qgslocator.sip
|
|
||||||
%Include locator/qgslocatorfilter.sip
|
|
||||||
%Include locator/qgslocatorwidget.sip
|
%Include locator/qgslocatorwidget.sip
|
||||||
%Include qgsadvanceddigitizingcanvasitem.sip
|
%Include qgsadvanceddigitizingcanvasitem.sip
|
||||||
|
@ -27,9 +27,9 @@ __revision__ = '$Format:%H$'
|
|||||||
|
|
||||||
|
|
||||||
from qgis.core import (QgsApplication,
|
from qgis.core import (QgsApplication,
|
||||||
QgsProcessingAlgorithm)
|
QgsProcessingAlgorithm,
|
||||||
from qgis.gui import (QgsLocatorFilter,
|
QgsLocatorFilter,
|
||||||
QgsLocatorResult)
|
QgsLocatorResult)
|
||||||
from processing.gui.MessageDialog import MessageDialog
|
from processing.gui.MessageDialog import MessageDialog
|
||||||
from processing.gui.AlgorithmDialog import AlgorithmDialog
|
from processing.gui.AlgorithmDialog import AlgorithmDialog
|
||||||
from qgis.utils import iface
|
from qgis.utils import iface
|
||||||
|
@ -512,6 +512,7 @@ INCLUDE_DIRECTORIES(
|
|||||||
${CMAKE_SOURCE_DIR}/src/core/geocms/geonode
|
${CMAKE_SOURCE_DIR}/src/core/geocms/geonode
|
||||||
${CMAKE_SOURCE_DIR}/src/core/metadata
|
${CMAKE_SOURCE_DIR}/src/core/metadata
|
||||||
${CMAKE_SOURCE_DIR}/src/core/layertree
|
${CMAKE_SOURCE_DIR}/src/core/layertree
|
||||||
|
${CMAKE_SOURCE_DIR}/src/core/locator
|
||||||
${CMAKE_SOURCE_DIR}/src/core/providers/memory
|
${CMAKE_SOURCE_DIR}/src/core/providers/memory
|
||||||
${CMAKE_SOURCE_DIR}/src/core/raster
|
${CMAKE_SOURCE_DIR}/src/core/raster
|
||||||
${CMAKE_SOURCE_DIR}/src/core/scalebar
|
${CMAKE_SOURCE_DIR}/src/core/scalebar
|
||||||
|
@ -93,6 +93,10 @@ SET(QGIS_CORE_SRCS
|
|||||||
expression/qgsexpressionfunction.cpp
|
expression/qgsexpressionfunction.cpp
|
||||||
expression/qgsexpressionutils.cpp
|
expression/qgsexpressionutils.cpp
|
||||||
|
|
||||||
|
locator/qgslocator.cpp
|
||||||
|
locator/qgslocatorfilter.cpp
|
||||||
|
locator/qgslocatormodel.cpp
|
||||||
|
|
||||||
processing/qgsnativealgorithms.cpp
|
processing/qgsnativealgorithms.cpp
|
||||||
processing/qgsprocessingalgorithm.cpp
|
processing/qgsprocessingalgorithm.cpp
|
||||||
processing/qgsprocessingalgrunnertask.cpp
|
processing/qgsprocessingalgrunnertask.cpp
|
||||||
@ -667,6 +671,10 @@ SET(QGIS_CORE_MOC_HDRS
|
|||||||
composer/qgslayoutmanager.h
|
composer/qgslayoutmanager.h
|
||||||
composer/qgspaperitem.h
|
composer/qgspaperitem.h
|
||||||
|
|
||||||
|
locator/qgslocator.h
|
||||||
|
locator/qgslocatorfilter.h
|
||||||
|
locator/qgslocatormodel.h
|
||||||
|
|
||||||
processing/qgsnativealgorithms.h
|
processing/qgsnativealgorithms.h
|
||||||
processing/qgsprocessingalgrunnertask.h
|
processing/qgsprocessingalgrunnertask.h
|
||||||
processing/qgsprocessingfeedback.h
|
processing/qgsprocessingfeedback.h
|
||||||
@ -1050,6 +1058,8 @@ SET(QGIS_CORE_HDRS
|
|||||||
|
|
||||||
layertree/qgslayertreeutils.h
|
layertree/qgslayertreeutils.h
|
||||||
|
|
||||||
|
locator/qgslocatorcontext.h
|
||||||
|
|
||||||
geometry/qgsabstractgeometry.h
|
geometry/qgsabstractgeometry.h
|
||||||
geometry/qgsbox3d.h
|
geometry/qgsbox3d.h
|
||||||
geometry/qgscircularstring.h
|
geometry/qgscircularstring.h
|
||||||
@ -1118,6 +1128,7 @@ INCLUDE_DIRECTORIES(
|
|||||||
geocms/geonode
|
geocms/geonode
|
||||||
layertree
|
layertree
|
||||||
layout
|
layout
|
||||||
|
locator
|
||||||
metadata
|
metadata
|
||||||
pal
|
pal
|
||||||
processing
|
processing
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
#ifndef QGSLOCATOR_H
|
#ifndef QGSLOCATOR_H
|
||||||
#define QGSLOCATOR_H
|
#define QGSLOCATOR_H
|
||||||
|
|
||||||
#include "qgis_gui.h"
|
#include "qgis_core.h"
|
||||||
#include "qgis_sip.h"
|
#include "qgis_sip.h"
|
||||||
#include "qgslocatorfilter.h"
|
#include "qgslocatorfilter.h"
|
||||||
#include "qgsfeedback.h"
|
#include "qgsfeedback.h"
|
||||||
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* \class QgsLocator
|
* \class QgsLocator
|
||||||
* \ingroup gui
|
* \ingroup core
|
||||||
* Handles the management of QgsLocatorFilter objects and async collection of search results from them.
|
* Handles the management of QgsLocatorFilter objects and async collection of search results from them.
|
||||||
*
|
*
|
||||||
* QgsLocator acts as both a registry for QgsLocatorFilter objects and a means of firing up
|
* QgsLocator acts as both a registry for QgsLocatorFilter objects and a means of firing up
|
||||||
@ -51,7 +51,7 @@
|
|||||||
*
|
*
|
||||||
* \since QGIS 3.0
|
* \since QGIS 3.0
|
||||||
*/
|
*/
|
||||||
class GUI_EXPORT QgsLocator : public QObject
|
class CORE_EXPORT QgsLocator : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -18,17 +18,17 @@
|
|||||||
#ifndef QGSLOCATORCONTEXT_H
|
#ifndef QGSLOCATORCONTEXT_H
|
||||||
#define QGSLOCATORCONTEXT_H
|
#define QGSLOCATORCONTEXT_H
|
||||||
|
|
||||||
#include "qgis_gui.h"
|
#include "qgis_core.h"
|
||||||
#include "qgsrectangle.h"
|
#include "qgsrectangle.h"
|
||||||
#include "qgscoordinatereferencesystem.h"
|
#include "qgscoordinatereferencesystem.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \class QgsLocatorContext
|
* \class QgsLocatorContext
|
||||||
* \ingroup gui
|
* \ingroup core
|
||||||
* Encapsulates the properties relating to the context of a locator search.
|
* Encapsulates the properties relating to the context of a locator search.
|
||||||
* \since QGIS 3.0
|
* \since QGIS 3.0
|
||||||
*/
|
*/
|
||||||
class GUI_EXPORT QgsLocatorContext
|
class CORE_EXPORT QgsLocatorContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -18,7 +18,7 @@
|
|||||||
#ifndef QGSLOCATORFILTER_H
|
#ifndef QGSLOCATORFILTER_H
|
||||||
#define QGSLOCATORFILTER_H
|
#define QGSLOCATORFILTER_H
|
||||||
|
|
||||||
#include "qgis_gui.h"
|
#include "qgis_core.h"
|
||||||
#include "qgslocatorcontext.h"
|
#include "qgslocatorcontext.h"
|
||||||
#include "qgslogger.h"
|
#include "qgslogger.h"
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@ -30,11 +30,11 @@ class QgsLocatorFilter;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* \class QgsLocatorResult
|
* \class QgsLocatorResult
|
||||||
* \ingroup gui
|
* \ingroup core
|
||||||
* Encapsulates properties of an individual matching result found by a QgsLocatorFilter.
|
* Encapsulates properties of an individual matching result found by a QgsLocatorFilter.
|
||||||
* \since QGIS 3.0
|
* \since QGIS 3.0
|
||||||
*/
|
*/
|
||||||
class GUI_EXPORT QgsLocatorResult
|
class CORE_EXPORT QgsLocatorResult
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -90,11 +90,11 @@ class GUI_EXPORT QgsLocatorResult
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* \class QgsLocatorFilter
|
* \class QgsLocatorFilter
|
||||||
* \ingroup gui
|
* \ingroup core
|
||||||
* Abstract base class for filters which collect locator results.
|
* Abstract base class for filters which collect locator results.
|
||||||
* \since QGIS 3.0
|
* \since QGIS 3.0
|
||||||
*/
|
*/
|
||||||
class GUI_EXPORT QgsLocatorFilter : public QObject
|
class CORE_EXPORT QgsLocatorFilter : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
300
src/core/locator/qgslocatormodel.cpp
Normal file
300
src/core/locator/qgslocatormodel.cpp
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
qgslocatormodel.cpp
|
||||||
|
--------------------
|
||||||
|
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. *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "qgslocatormodel.h"
|
||||||
|
#include "qgslocator.h"
|
||||||
|
#include "qgsapplication.h"
|
||||||
|
#include "qgslogger.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// QgsLocatorModel
|
||||||
|
//
|
||||||
|
|
||||||
|
QgsLocatorModel::QgsLocatorModel( QObject *parent )
|
||||||
|
: QAbstractTableModel( parent )
|
||||||
|
{
|
||||||
|
mDeferredClearTimer.setInterval( 100 );
|
||||||
|
mDeferredClearTimer.setSingleShot( true );
|
||||||
|
connect( &mDeferredClearTimer, &QTimer::timeout, this, &QgsLocatorModel::clear );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLocatorModel::clear()
|
||||||
|
{
|
||||||
|
mDeferredClearTimer.stop();
|
||||||
|
mDeferredClear = false;
|
||||||
|
|
||||||
|
beginResetModel();
|
||||||
|
mResults.clear();
|
||||||
|
mFoundResultsFromFilterNames.clear();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLocatorModel::deferredClear()
|
||||||
|
{
|
||||||
|
mDeferredClear = true;
|
||||||
|
mDeferredClearTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
int QgsLocatorModel::rowCount( const QModelIndex & ) const
|
||||||
|
{
|
||||||
|
return mResults.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int QgsLocatorModel::columnCount( const QModelIndex & ) const
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant QgsLocatorModel::data( const QModelIndex &index, int role ) const
|
||||||
|
{
|
||||||
|
if ( !index.isValid() || index.row() < 0 || index.column() < 0 ||
|
||||||
|
index.row() >= rowCount( QModelIndex() ) || index.column() >= columnCount( QModelIndex() ) )
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
switch ( role )
|
||||||
|
{
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
case Qt::EditRole:
|
||||||
|
{
|
||||||
|
switch ( index.column() )
|
||||||
|
{
|
||||||
|
case Name:
|
||||||
|
if ( !mResults.at( index.row() ).filter )
|
||||||
|
return mResults.at( index.row() ).result.displayString;
|
||||||
|
else
|
||||||
|
return mResults.at( index.row() ).filterTitle;
|
||||||
|
case Description:
|
||||||
|
if ( !mResults.at( index.row() ).filter )
|
||||||
|
return mResults.at( index.row() ).result.description;
|
||||||
|
else
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Qt::DecorationRole:
|
||||||
|
switch ( index.column() )
|
||||||
|
{
|
||||||
|
case Name:
|
||||||
|
if ( !mResults.at( index.row() ).filter )
|
||||||
|
{
|
||||||
|
QIcon icon = mResults.at( index.row() ).result.icon;
|
||||||
|
if ( !icon.isNull() )
|
||||||
|
return icon;
|
||||||
|
return QgsApplication::getThemeIcon( "/search.svg" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return QVariant();
|
||||||
|
case Description:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ResultDataRole:
|
||||||
|
if ( !mResults.at( index.row() ).filter )
|
||||||
|
return QVariant::fromValue( mResults.at( index.row() ).result );
|
||||||
|
else
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
case ResultTypeRole:
|
||||||
|
if ( mResults.at( index.row() ).filter )
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case ResultScoreRole:
|
||||||
|
if ( mResults.at( index.row() ).filter )
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return ( mResults.at( index.row() ).result.score );
|
||||||
|
|
||||||
|
case ResultFilterPriorityRole:
|
||||||
|
if ( !mResults.at( index.row() ).filter )
|
||||||
|
return mResults.at( index.row() ).result.filter->priority();
|
||||||
|
else
|
||||||
|
return mResults.at( index.row() ).filter->priority();
|
||||||
|
|
||||||
|
case ResultFilterNameRole:
|
||||||
|
if ( !mResults.at( index.row() ).filter )
|
||||||
|
return mResults.at( index.row() ).result.filter->displayName();
|
||||||
|
else
|
||||||
|
return mResults.at( index.row() ).filterTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags QgsLocatorModel::flags( const QModelIndex &index ) const
|
||||||
|
{
|
||||||
|
if ( !index.isValid() || index.row() < 0 || index.column() < 0 ||
|
||||||
|
index.row() >= rowCount( QModelIndex() ) || index.column() >= columnCount( QModelIndex() ) )
|
||||||
|
return QAbstractTableModel::flags( index );
|
||||||
|
|
||||||
|
Qt::ItemFlags flags = QAbstractTableModel::flags( index );
|
||||||
|
if ( !mResults.at( index.row() ).filterTitle.isEmpty() )
|
||||||
|
{
|
||||||
|
flags = flags & ~( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLocatorModel::addResult( const QgsLocatorResult &result )
|
||||||
|
{
|
||||||
|
mDeferredClearTimer.stop();
|
||||||
|
if ( mDeferredClear )
|
||||||
|
{
|
||||||
|
mFoundResultsFromFilterNames.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos = mResults.size();
|
||||||
|
bool addingFilter = !result.filter->displayName().isEmpty() && !mFoundResultsFromFilterNames.contains( result.filter->name() );
|
||||||
|
if ( addingFilter )
|
||||||
|
mFoundResultsFromFilterNames << result.filter->name();
|
||||||
|
|
||||||
|
if ( mDeferredClear )
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
mResults.clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
beginInsertRows( QModelIndex(), pos, pos + ( addingFilter ? 1 : 0 ) );
|
||||||
|
|
||||||
|
if ( addingFilter )
|
||||||
|
{
|
||||||
|
Entry entry;
|
||||||
|
entry.filterTitle = result.filter->displayName();
|
||||||
|
entry.filter = result.filter;
|
||||||
|
mResults << entry;
|
||||||
|
}
|
||||||
|
Entry entry;
|
||||||
|
entry.result = result;
|
||||||
|
mResults << entry;
|
||||||
|
|
||||||
|
if ( mDeferredClear )
|
||||||
|
endResetModel();
|
||||||
|
else
|
||||||
|
endInsertRows();
|
||||||
|
|
||||||
|
mDeferredClear = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// QgsLocatorAutomaticModel
|
||||||
|
//
|
||||||
|
|
||||||
|
QgsLocatorAutomaticModel::QgsLocatorAutomaticModel( QgsLocator *locator )
|
||||||
|
: QgsLocatorModel( locator )
|
||||||
|
, mLocator( locator )
|
||||||
|
{
|
||||||
|
Q_ASSERT( mLocator );
|
||||||
|
connect( mLocator, &QgsLocator::foundResult, this, &QgsLocatorAutomaticModel::addResult );
|
||||||
|
connect( mLocator, &QgsLocator::finished, this, &QgsLocatorAutomaticModel::searchFinished );
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsLocator *QgsLocatorAutomaticModel::locator()
|
||||||
|
{
|
||||||
|
return mLocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLocatorAutomaticModel::search( const QString &string )
|
||||||
|
{
|
||||||
|
if ( mLocator->isRunning() )
|
||||||
|
{
|
||||||
|
// can't do anything while a query is running, and can't block
|
||||||
|
// here waiting for the current query to cancel
|
||||||
|
// so we queue up this string until cancel has happened
|
||||||
|
mLocator->cancelWithoutBlocking();
|
||||||
|
mNextRequestedString = string;
|
||||||
|
mHasQueuedRequest = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deferredClear();
|
||||||
|
mLocator->fetchResults( string, createContext() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsLocatorContext QgsLocatorAutomaticModel::createContext()
|
||||||
|
{
|
||||||
|
return QgsLocatorContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLocatorAutomaticModel::searchFinished()
|
||||||
|
{
|
||||||
|
if ( mHasQueuedRequest )
|
||||||
|
{
|
||||||
|
// a queued request was waiting for this - run the queued search now
|
||||||
|
QString nextSearch = mNextRequestedString;
|
||||||
|
mNextRequestedString.clear();
|
||||||
|
mHasQueuedRequest = false;
|
||||||
|
search( nextSearch );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// QgsLocatorProxyModel
|
||||||
|
//
|
||||||
|
|
||||||
|
QgsLocatorProxyModel::QgsLocatorProxyModel( QObject *parent )
|
||||||
|
: QSortFilterProxyModel( parent )
|
||||||
|
{
|
||||||
|
setDynamicSortFilter( true );
|
||||||
|
setSortLocaleAware( true );
|
||||||
|
setFilterCaseSensitivity( Qt::CaseInsensitive );
|
||||||
|
sort( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsLocatorProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
|
||||||
|
{
|
||||||
|
// first go by filter priority
|
||||||
|
int leftFilterPriority = sourceModel()->data( left, QgsLocatorModel::ResultFilterPriorityRole ).toInt();
|
||||||
|
int rightFilterPriority = sourceModel()->data( right, QgsLocatorModel::ResultFilterPriorityRole ).toInt();
|
||||||
|
if ( leftFilterPriority != rightFilterPriority )
|
||||||
|
return leftFilterPriority < rightFilterPriority;
|
||||||
|
|
||||||
|
// then filter name
|
||||||
|
QString leftFilter = sourceModel()->data( left, QgsLocatorModel::ResultFilterNameRole ).toString();
|
||||||
|
QString rightFilter = sourceModel()->data( right, QgsLocatorModel::ResultFilterNameRole ).toString();
|
||||||
|
if ( leftFilter != rightFilter )
|
||||||
|
return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;
|
||||||
|
|
||||||
|
// then make sure filter title appears before filter's results
|
||||||
|
int leftTypeRole = sourceModel()->data( left, QgsLocatorModel::ResultTypeRole ).toInt();
|
||||||
|
int rightTypeRole = sourceModel()->data( right, QgsLocatorModel::ResultTypeRole ).toInt();
|
||||||
|
if ( leftTypeRole != rightTypeRole )
|
||||||
|
return leftTypeRole < rightTypeRole;
|
||||||
|
|
||||||
|
// sort filter's results by score
|
||||||
|
double leftScore = sourceModel()->data( left, QgsLocatorModel::ResultScoreRole ).toDouble();
|
||||||
|
double rightScore = sourceModel()->data( right, QgsLocatorModel::ResultScoreRole ).toDouble();
|
||||||
|
if ( !qgsDoubleNear( leftScore, rightScore ) )
|
||||||
|
return leftScore > rightScore;
|
||||||
|
|
||||||
|
// lastly sort filter's results by string
|
||||||
|
leftFilter = sourceModel()->data( left, Qt::DisplayRole ).toString();
|
||||||
|
rightFilter = sourceModel()->data( right, Qt::DisplayRole ).toString();
|
||||||
|
return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
198
src/core/locator/qgslocatormodel.h
Normal file
198
src/core/locator/qgslocatormodel.h
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
qgslocatormodel.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 QGSLOCATORMODEL_H
|
||||||
|
#define QGSLOCATORMODEL_H
|
||||||
|
|
||||||
|
#include "qgis_core.h"
|
||||||
|
#include "qgslocatorfilter.h"
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
|
class QgsLocator;
|
||||||
|
class QgsLocatorModel;
|
||||||
|
class QgsLocatorProxyModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class QgsLocatorModel
|
||||||
|
* \ingroup core
|
||||||
|
* An abstract list model for displaying the results of locator searches.
|
||||||
|
*
|
||||||
|
* Note that this class should generally be used with a QgsLocatorProxyModel
|
||||||
|
* in order to ensure correct sorting of results by priority and match level.
|
||||||
|
*
|
||||||
|
* \since QGIS 3.0
|
||||||
|
*/
|
||||||
|
class CORE_EXPORT QgsLocatorModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! Custom model roles
|
||||||
|
enum Role
|
||||||
|
{
|
||||||
|
ResultDataRole = Qt::UserRole + 1, //!< QgsLocatorResult data
|
||||||
|
ResultTypeRole, //!< Result type
|
||||||
|
ResultFilterPriorityRole, //!< Result priority, used by QgsLocatorProxyModel for sorting roles.
|
||||||
|
ResultScoreRole, //!< Result match score, used by QgsLocatorProxyModel for sorting roles.
|
||||||
|
ResultFilterNameRole, //!< Associated filter name which created the result
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for QgsLocatorModel.
|
||||||
|
*/
|
||||||
|
QgsLocatorModel( QObject *parent SIP_TRANSFERTHIS = nullptr );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the model and clears all existing results.
|
||||||
|
* \see deferredClear()
|
||||||
|
*/
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the model and clears all existing results after a short delay, or whenever the next result is added to the model
|
||||||
|
* (whichever occurs first). Using deferredClear() instead of clear() can avoid the visually distracting frequent clears
|
||||||
|
* which may occur if the model is being updated quickly multiple times as a result of users typing in a search query.
|
||||||
|
* \see deferredClear()
|
||||||
|
*/
|
||||||
|
void deferredClear();
|
||||||
|
|
||||||
|
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
|
||||||
|
int columnCount( const QModelIndex &parent = QModelIndex() ) const override;
|
||||||
|
QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
|
||||||
|
Qt::ItemFlags flags( const QModelIndex &index ) const override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new \a result to the model.
|
||||||
|
*/
|
||||||
|
void addResult( const QgsLocatorResult &result );
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum ColumnCount
|
||||||
|
{
|
||||||
|
Name = 0,
|
||||||
|
Description
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Entry
|
||||||
|
{
|
||||||
|
QgsLocatorResult result;
|
||||||
|
QString filterTitle;
|
||||||
|
QgsLocatorFilter *filter = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
QList<Entry> mResults;
|
||||||
|
QSet<QString> mFoundResultsFromFilterNames;
|
||||||
|
bool mDeferredClear = false;
|
||||||
|
QTimer mDeferredClearTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class QgsLocatorAutomaticModel
|
||||||
|
* \ingroup core
|
||||||
|
* A QgsLocatorModel which has is associated directly with a
|
||||||
|
* QgsLocator, and is automatically populated with results
|
||||||
|
* from locator searches.
|
||||||
|
*
|
||||||
|
* Use this QgsLocatorModel subclass when you want the connections
|
||||||
|
* between a QgsLocator and the model to be automatically created
|
||||||
|
* for you. If more flexibility in model behavior is required,
|
||||||
|
* use the base QgsLocatorModel class instead and setup the
|
||||||
|
* connections manually.
|
||||||
|
*
|
||||||
|
* Note that this class should generally be used with a QgsLocatorProxyModel
|
||||||
|
* in order to ensure correct sorting of results by priority and match level.
|
||||||
|
*
|
||||||
|
* \since QGIS 3.0
|
||||||
|
*/
|
||||||
|
class CORE_EXPORT QgsLocatorAutomaticModel : public QgsLocatorModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for QgsLocatorAutomaticModel, linked with the specified \a locator.
|
||||||
|
*
|
||||||
|
* The \a locator is used as the model's parent.
|
||||||
|
*/
|
||||||
|
explicit QgsLocatorAutomaticModel( QgsLocator *locator SIP_TRANSFERTHIS );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pointer to the locator utilized by this model.
|
||||||
|
*/
|
||||||
|
QgsLocator *locator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueues a search for a specified \a string within the model.
|
||||||
|
*
|
||||||
|
* Note that the search may not begin immediately if an existing search request
|
||||||
|
* is still running. In this case the existing search must be completely
|
||||||
|
* terminated before the new search can begin. The model handles this
|
||||||
|
* situation automatically, and will trigger a search for the new
|
||||||
|
* search string as soon as possible.
|
||||||
|
*/
|
||||||
|
void search( const QString &string );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new locator context for searches. The default implementation
|
||||||
|
* returns a default constructed QgsLocatorContext. Subclasses can override
|
||||||
|
* this method to implement custom context creation logic.
|
||||||
|
*/
|
||||||
|
virtual QgsLocatorContext createContext();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void searchFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QgsLocator *mLocator = nullptr;
|
||||||
|
|
||||||
|
QString mNextRequestedString;
|
||||||
|
bool mHasQueuedRequest = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class QgsLocatorProxyModel
|
||||||
|
* \ingroup core
|
||||||
|
* A sort proxy model for QgsLocatorModel, which automatically sorts
|
||||||
|
* results by precedence.
|
||||||
|
* \since QGIS 3.0
|
||||||
|
*/
|
||||||
|
class CORE_EXPORT QgsLocatorProxyModel : public QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for QgsLocatorProxyModel, with the specified \a parent object.
|
||||||
|
*/
|
||||||
|
explicit QgsLocatorProxyModel( QObject *parent SIP_TRANSFERTHIS = nullptr );
|
||||||
|
bool lessThan( const QModelIndex &left, const QModelIndex &right ) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QGSLOCATORMODEL_H
|
||||||
|
|
||||||
|
|
@ -175,8 +175,6 @@ SET(QGIS_GUI_SRCS
|
|||||||
layout/qgslayoutviewtooltemporarymousepan.cpp
|
layout/qgslayoutviewtooltemporarymousepan.cpp
|
||||||
layout/qgslayoutviewtoolzoom.cpp
|
layout/qgslayoutviewtoolzoom.cpp
|
||||||
|
|
||||||
locator/qgslocator.cpp
|
|
||||||
locator/qgslocatorfilter.cpp
|
|
||||||
locator/qgslocatorwidget.cpp
|
locator/qgslocatorwidget.cpp
|
||||||
|
|
||||||
ogr/qgsogrhelperfunctions.cpp
|
ogr/qgsogrhelperfunctions.cpp
|
||||||
@ -667,8 +665,6 @@ SET(QGIS_GUI_MOC_HDRS
|
|||||||
layout/qgslayoutviewtooltemporarymousepan.h
|
layout/qgslayoutviewtooltemporarymousepan.h
|
||||||
layout/qgslayoutviewtoolzoom.h
|
layout/qgslayoutviewtoolzoom.h
|
||||||
|
|
||||||
locator/qgslocator.h
|
|
||||||
locator/qgslocatorfilter.h
|
|
||||||
locator/qgslocatorwidget.h
|
locator/qgslocatorwidget.h
|
||||||
)
|
)
|
||||||
SET_PROPERTY(GLOBAL PROPERTY QGIS_GUI_MOC_HDRS ${QGIS_GUI_MOC_HDRS})
|
SET_PROPERTY(GLOBAL PROPERTY QGIS_GUI_MOC_HDRS ${QGIS_GUI_MOC_HDRS})
|
||||||
@ -769,8 +765,6 @@ SET(QGIS_GUI_HDRS
|
|||||||
layout/qgslayoutviewmouseevent.h
|
layout/qgslayoutviewmouseevent.h
|
||||||
layout/qgslayoutviewrubberband.h
|
layout/qgslayoutviewrubberband.h
|
||||||
|
|
||||||
locator/qgslocatorcontext.h
|
|
||||||
|
|
||||||
raster/qgsrasterrendererwidget.h
|
raster/qgsrasterrendererwidget.h
|
||||||
|
|
||||||
symbology/qgssymbolwidgetcontext.h
|
symbology/qgssymbolwidgetcontext.h
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "qgslocatorwidget.h"
|
#include "qgslocatorwidget.h"
|
||||||
#include "qgslocator.h"
|
#include "qgslocator.h"
|
||||||
|
#include "qgslocatormodel.h"
|
||||||
#include "qgsfilterlineedit.h"
|
#include "qgsfilterlineedit.h"
|
||||||
#include "qgsmapcanvas.h"
|
#include "qgsmapcanvas.h"
|
||||||
#include "qgsapplication.h"
|
#include "qgsapplication.h"
|
||||||
@ -344,179 +345,6 @@ QgsLocatorContext QgsLocatorWidget::createContext()
|
|||||||
|
|
||||||
///@cond PRIVATE
|
///@cond PRIVATE
|
||||||
|
|
||||||
//
|
|
||||||
// QgsLocatorModel
|
|
||||||
//
|
|
||||||
|
|
||||||
QgsLocatorModel::QgsLocatorModel( QObject *parent )
|
|
||||||
: QAbstractTableModel( parent )
|
|
||||||
{
|
|
||||||
mDeferredClearTimer.setInterval( 100 );
|
|
||||||
mDeferredClearTimer.setSingleShot( true );
|
|
||||||
connect( &mDeferredClearTimer, &QTimer::timeout, this, &QgsLocatorModel::clear );
|
|
||||||
}
|
|
||||||
|
|
||||||
void QgsLocatorModel::clear()
|
|
||||||
{
|
|
||||||
mDeferredClearTimer.stop();
|
|
||||||
mDeferredClear = false;
|
|
||||||
|
|
||||||
beginResetModel();
|
|
||||||
mResults.clear();
|
|
||||||
mFoundResultsFromFilterNames.clear();
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QgsLocatorModel::deferredClear()
|
|
||||||
{
|
|
||||||
mDeferredClear = true;
|
|
||||||
mDeferredClearTimer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
int QgsLocatorModel::rowCount( const QModelIndex & ) const
|
|
||||||
{
|
|
||||||
return mResults.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
int QgsLocatorModel::columnCount( const QModelIndex & ) const
|
|
||||||
{
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant QgsLocatorModel::data( const QModelIndex &index, int role ) const
|
|
||||||
{
|
|
||||||
if ( !index.isValid() || index.row() < 0 || index.column() < 0 ||
|
|
||||||
index.row() >= rowCount( QModelIndex() ) || index.column() >= columnCount( QModelIndex() ) )
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
switch ( role )
|
|
||||||
{
|
|
||||||
case Qt::DisplayRole:
|
|
||||||
case Qt::EditRole:
|
|
||||||
{
|
|
||||||
switch ( index.column() )
|
|
||||||
{
|
|
||||||
case Name:
|
|
||||||
if ( !mResults.at( index.row() ).filter )
|
|
||||||
return mResults.at( index.row() ).result.displayString;
|
|
||||||
else
|
|
||||||
return mResults.at( index.row() ).filterTitle;
|
|
||||||
case Description:
|
|
||||||
if ( !mResults.at( index.row() ).filter )
|
|
||||||
return mResults.at( index.row() ).result.description;
|
|
||||||
else
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Qt::DecorationRole:
|
|
||||||
switch ( index.column() )
|
|
||||||
{
|
|
||||||
case Name:
|
|
||||||
if ( !mResults.at( index.row() ).filter )
|
|
||||||
{
|
|
||||||
QIcon icon = mResults.at( index.row() ).result.icon;
|
|
||||||
if ( !icon.isNull() )
|
|
||||||
return icon;
|
|
||||||
return QgsApplication::getThemeIcon( "/search.svg" );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return QVariant();
|
|
||||||
case Description:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ResultDataRole:
|
|
||||||
if ( !mResults.at( index.row() ).filter )
|
|
||||||
return QVariant::fromValue( mResults.at( index.row() ).result );
|
|
||||||
else
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
case ResultTypeRole:
|
|
||||||
if ( mResults.at( index.row() ).filter )
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case ResultScoreRole:
|
|
||||||
if ( mResults.at( index.row() ).filter )
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return ( mResults.at( index.row() ).result.score );
|
|
||||||
|
|
||||||
case ResultFilterPriorityRole:
|
|
||||||
if ( !mResults.at( index.row() ).filter )
|
|
||||||
return mResults.at( index.row() ).result.filter->priority();
|
|
||||||
else
|
|
||||||
return mResults.at( index.row() ).filter->priority();
|
|
||||||
|
|
||||||
case ResultFilterNameRole:
|
|
||||||
if ( !mResults.at( index.row() ).filter )
|
|
||||||
return mResults.at( index.row() ).result.filter->displayName();
|
|
||||||
else
|
|
||||||
return mResults.at( index.row() ).filterTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
Qt::ItemFlags QgsLocatorModel::flags( const QModelIndex &index ) const
|
|
||||||
{
|
|
||||||
if ( !index.isValid() || index.row() < 0 || index.column() < 0 ||
|
|
||||||
index.row() >= rowCount( QModelIndex() ) || index.column() >= columnCount( QModelIndex() ) )
|
|
||||||
return QAbstractTableModel::flags( index );
|
|
||||||
|
|
||||||
Qt::ItemFlags flags = QAbstractTableModel::flags( index );
|
|
||||||
if ( !mResults.at( index.row() ).filterTitle.isEmpty() )
|
|
||||||
{
|
|
||||||
flags = flags & ~( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
|
|
||||||
}
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QgsLocatorModel::addResult( const QgsLocatorResult &result )
|
|
||||||
{
|
|
||||||
mDeferredClearTimer.stop();
|
|
||||||
if ( mDeferredClear )
|
|
||||||
{
|
|
||||||
mFoundResultsFromFilterNames.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
int pos = mResults.size();
|
|
||||||
bool addingFilter = !result.filter->displayName().isEmpty() && !mFoundResultsFromFilterNames.contains( result.filter->name() );
|
|
||||||
if ( addingFilter )
|
|
||||||
mFoundResultsFromFilterNames << result.filter->name();
|
|
||||||
|
|
||||||
if ( mDeferredClear )
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
mResults.clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
beginInsertRows( QModelIndex(), pos, pos + ( addingFilter ? 1 : 0 ) );
|
|
||||||
|
|
||||||
if ( addingFilter )
|
|
||||||
{
|
|
||||||
Entry entry;
|
|
||||||
entry.filterTitle = result.filter->displayName();
|
|
||||||
entry.filter = result.filter;
|
|
||||||
mResults << entry;
|
|
||||||
}
|
|
||||||
Entry entry;
|
|
||||||
entry.result = result;
|
|
||||||
mResults << entry;
|
|
||||||
|
|
||||||
if ( mDeferredClear )
|
|
||||||
endResetModel();
|
|
||||||
else
|
|
||||||
endInsertRows();
|
|
||||||
|
|
||||||
mDeferredClear = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// QgsLocatorResultsView
|
// QgsLocatorResultsView
|
||||||
//
|
//
|
||||||
@ -561,53 +389,6 @@ void QgsLocatorResultsView::selectPreviousResult()
|
|||||||
setCurrentIndex( model()->index( previousRow, 0 ) );
|
setCurrentIndex( model()->index( previousRow, 0 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// QgsLocatorProxyModel
|
|
||||||
//
|
|
||||||
|
|
||||||
QgsLocatorProxyModel::QgsLocatorProxyModel( QObject *parent )
|
|
||||||
: QSortFilterProxyModel( parent )
|
|
||||||
{
|
|
||||||
setDynamicSortFilter( true );
|
|
||||||
setSortLocaleAware( true );
|
|
||||||
setFilterCaseSensitivity( Qt::CaseInsensitive );
|
|
||||||
sort( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QgsLocatorProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
|
|
||||||
{
|
|
||||||
// first go by filter priority
|
|
||||||
int leftFilterPriority = sourceModel()->data( left, QgsLocatorModel::ResultFilterPriorityRole ).toInt();
|
|
||||||
int rightFilterPriority = sourceModel()->data( right, QgsLocatorModel::ResultFilterPriorityRole ).toInt();
|
|
||||||
if ( leftFilterPriority != rightFilterPriority )
|
|
||||||
return leftFilterPriority < rightFilterPriority;
|
|
||||||
|
|
||||||
// then filter name
|
|
||||||
QString leftFilter = sourceModel()->data( left, QgsLocatorModel::ResultFilterNameRole ).toString();
|
|
||||||
QString rightFilter = sourceModel()->data( right, QgsLocatorModel::ResultFilterNameRole ).toString();
|
|
||||||
if ( leftFilter != rightFilter )
|
|
||||||
return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;
|
|
||||||
|
|
||||||
// then make sure filter title appears before filter's results
|
|
||||||
int leftTypeRole = sourceModel()->data( left, QgsLocatorModel::ResultTypeRole ).toInt();
|
|
||||||
int rightTypeRole = sourceModel()->data( right, QgsLocatorModel::ResultTypeRole ).toInt();
|
|
||||||
if ( leftTypeRole != rightTypeRole )
|
|
||||||
return leftTypeRole < rightTypeRole;
|
|
||||||
|
|
||||||
// sort filter's results by score
|
|
||||||
double leftScore = sourceModel()->data( left, QgsLocatorModel::ResultScoreRole ).toDouble();
|
|
||||||
double rightScore = sourceModel()->data( right, QgsLocatorModel::ResultScoreRole ).toDouble();
|
|
||||||
if ( !qgsDoubleNear( leftScore, rightScore ) )
|
|
||||||
return leftScore > rightScore;
|
|
||||||
|
|
||||||
// lastly sort filter's results by string
|
|
||||||
leftFilter = sourceModel()->data( left, Qt::DisplayRole ).toString();
|
|
||||||
rightFilter = sourceModel()->data( right, Qt::DisplayRole ).toString();
|
|
||||||
return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// QgsLocatorFilterFilter
|
// QgsLocatorFilterFilter
|
||||||
//
|
//
|
||||||
|
@ -22,12 +22,10 @@
|
|||||||
#include "qgslocatorfilter.h"
|
#include "qgslocatorfilter.h"
|
||||||
#include "qgsfloatingwidget.h"
|
#include "qgsfloatingwidget.h"
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QAbstractListModel>
|
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
#include <QFocusEvent>
|
#include <QFocusEvent>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QSortFilterProxyModel>
|
|
||||||
|
|
||||||
class QgsLocator;
|
class QgsLocator;
|
||||||
class QgsFilterLineEdit;
|
class QgsFilterLineEdit;
|
||||||
@ -147,90 +145,6 @@ class QgsLocatorFilterFilter : public QgsLocatorFilter
|
|||||||
QgsLocatorWidget *mLocator = nullptr;
|
QgsLocatorWidget *mLocator = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* \class QgsLocatorModel
|
|
||||||
* \ingroup gui
|
|
||||||
* An abstract list model for displaying the results in a QgsLocatorWidget.
|
|
||||||
* \since QGIS 3.0
|
|
||||||
*/
|
|
||||||
class QgsLocatorModel : public QAbstractTableModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
//! Custom model roles
|
|
||||||
enum Role
|
|
||||||
{
|
|
||||||
ResultDataRole = Qt::UserRole + 1, //!< QgsLocatorResult data
|
|
||||||
ResultTypeRole,
|
|
||||||
ResultFilterPriorityRole,
|
|
||||||
ResultScoreRole,
|
|
||||||
ResultFilterNameRole,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum columnCount
|
|
||||||
{
|
|
||||||
Name = 0,
|
|
||||||
Description
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for QgsLocatorModel.
|
|
||||||
*/
|
|
||||||
QgsLocatorModel( QObject *parent = nullptr );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the model and clears all existing results.
|
|
||||||
* \see deferredClear()
|
|
||||||
*/
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the model and clears all existing results after a short delay, or whenever the next result is added to the model
|
|
||||||
* (whichever occurs first). Using deferredClear() instead of clear() can avoid the visually distracting frequent clears
|
|
||||||
* which may occur if the model is being updated quickly multiple times as a result of users typing in a search query.
|
|
||||||
* \see deferredClear()
|
|
||||||
*/
|
|
||||||
void deferredClear();
|
|
||||||
|
|
||||||
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
|
|
||||||
int columnCount( const QModelIndex &parent = QModelIndex() ) const override;
|
|
||||||
QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
|
|
||||||
Qt::ItemFlags flags( const QModelIndex &index ) const override;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new \a result to the model.
|
|
||||||
*/
|
|
||||||
void addResult( const QgsLocatorResult &result );
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
struct Entry
|
|
||||||
{
|
|
||||||
QgsLocatorResult result;
|
|
||||||
QString filterTitle;
|
|
||||||
QgsLocatorFilter *filter = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
QList<Entry> mResults;
|
|
||||||
QSet<QString> mFoundResultsFromFilterNames;
|
|
||||||
bool mDeferredClear = false;
|
|
||||||
QTimer mDeferredClearTimer;
|
|
||||||
};
|
|
||||||
|
|
||||||
class QgsLocatorProxyModel : public QSortFilterProxyModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit QgsLocatorProxyModel( QObject *parent = nullptr );
|
|
||||||
bool lessThan( const QModelIndex &left, const QModelIndex &right ) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \class QgsLocatorResultsView
|
* \class QgsLocatorResultsView
|
||||||
* \ingroup gui
|
* \ingroup gui
|
||||||
|
@ -15,10 +15,12 @@ import qgis # NOQA
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from qgis.gui import (QgsLocator,
|
from qgis.core import (QgsLocator,
|
||||||
QgsLocatorFilter,
|
QgsLocatorFilter,
|
||||||
QgsLocatorContext,
|
QgsLocatorContext,
|
||||||
QgsLocatorResult)
|
QgsLocatorResult,
|
||||||
|
QgsLocatorModel,
|
||||||
|
QgsLocatorAutomaticModel)
|
||||||
from qgis.PyQt.QtCore import QVariant, pyqtSignal, QCoreApplication
|
from qgis.PyQt.QtCore import QVariant, pyqtSignal, QCoreApplication
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from qgis.testing import start_app, unittest
|
from qgis.testing import start_app, unittest
|
||||||
@ -32,6 +34,12 @@ class test_filter(QgsLocatorFilter):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.prefix = prefix
|
self.prefix = prefix
|
||||||
|
|
||||||
|
def name(self):
|
||||||
|
return 'test'
|
||||||
|
|
||||||
|
def displayName(self):
|
||||||
|
return 'test'
|
||||||
|
|
||||||
def fetchResults(self, string, context, feedback):
|
def fetchResults(self, string, context, feedback):
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
#if feedback.isCanceled():
|
#if feedback.isCanceled():
|
||||||
@ -152,6 +160,102 @@ class TestQgsLocator(unittest.TestCase):
|
|||||||
l.fetchResults('a', context)
|
l.fetchResults('a', context)
|
||||||
l.cancel()
|
l.cancel()
|
||||||
|
|
||||||
|
def testModel(self):
|
||||||
|
m = QgsLocatorModel()
|
||||||
|
l = QgsLocator()
|
||||||
|
|
||||||
|
filter_a = test_filter('a')
|
||||||
|
l.registerFilter(filter_a)
|
||||||
|
l.foundResult.connect(m.addResult)
|
||||||
|
context = QgsLocatorContext()
|
||||||
|
|
||||||
|
l.fetchResults('a', context)
|
||||||
|
|
||||||
|
for i in range(100):
|
||||||
|
sleep(0.002)
|
||||||
|
QCoreApplication.processEvents()
|
||||||
|
|
||||||
|
# 4 results - one is locator name
|
||||||
|
self.assertEqual(m.rowCount(), 4)
|
||||||
|
self.assertEqual(m.data(m.index(0, 0)), 'test')
|
||||||
|
self.assertEqual(m.data(m.index(0, 0), QgsLocatorModel.ResultTypeRole), 0)
|
||||||
|
self.assertEqual(m.data(m.index(0, 0), QgsLocatorModel.ResultFilterNameRole), 'test')
|
||||||
|
self.assertEqual(m.data(m.index(1, 0)), 'a0')
|
||||||
|
self.assertEqual(m.data(m.index(1, 0), QgsLocatorModel.ResultTypeRole), 1)
|
||||||
|
self.assertEqual(m.data(m.index(1, 0), QgsLocatorModel.ResultFilterNameRole), 'test')
|
||||||
|
self.assertEqual(m.data(m.index(2, 0)), 'a1')
|
||||||
|
self.assertEqual(m.data(m.index(2, 0), QgsLocatorModel.ResultTypeRole), 1)
|
||||||
|
self.assertEqual(m.data(m.index(2, 0), QgsLocatorModel.ResultFilterNameRole), 'test')
|
||||||
|
self.assertEqual(m.data(m.index(3, 0)), 'a2')
|
||||||
|
self.assertEqual(m.data(m.index(3, 0), QgsLocatorModel.ResultTypeRole), 1)
|
||||||
|
self.assertEqual(m.data(m.index(3, 0), QgsLocatorModel.ResultFilterNameRole), 'test')
|
||||||
|
|
||||||
|
m.clear()
|
||||||
|
self.assertEqual(m.rowCount(), 0)
|
||||||
|
l.fetchResults('b', context)
|
||||||
|
|
||||||
|
for i in range(100):
|
||||||
|
sleep(0.002)
|
||||||
|
QCoreApplication.processEvents()
|
||||||
|
|
||||||
|
self.assertEqual(m.rowCount(), 4)
|
||||||
|
self.assertEqual(m.data(m.index(1, 0)), 'a0')
|
||||||
|
self.assertEqual(m.data(m.index(2, 0)), 'a1')
|
||||||
|
self.assertEqual(m.data(m.index(3, 0)), 'a2')
|
||||||
|
|
||||||
|
m.deferredClear()
|
||||||
|
# should not be immediately cleared!
|
||||||
|
self.assertEqual(m.rowCount(), 4)
|
||||||
|
for i in range(100):
|
||||||
|
sleep(0.002)
|
||||||
|
QCoreApplication.processEvents()
|
||||||
|
self.assertEqual(m.rowCount(), 0)
|
||||||
|
|
||||||
|
def testAutoModel(self):
|
||||||
|
"""
|
||||||
|
Test automatic model, QgsLocatorAutomaticModel - should be no need
|
||||||
|
for any manual connections
|
||||||
|
"""
|
||||||
|
l = QgsLocator()
|
||||||
|
m = QgsLocatorAutomaticModel(l)
|
||||||
|
|
||||||
|
filter_a = test_filter('a')
|
||||||
|
l.registerFilter(filter_a)
|
||||||
|
|
||||||
|
m.search('a')
|
||||||
|
|
||||||
|
for i in range(100):
|
||||||
|
sleep(0.002)
|
||||||
|
QCoreApplication.processEvents()
|
||||||
|
|
||||||
|
# 4 results - one is locator name
|
||||||
|
self.assertEqual(m.rowCount(), 4)
|
||||||
|
self.assertEqual(m.data(m.index(0, 0)), 'test')
|
||||||
|
self.assertEqual(m.data(m.index(0, 0), QgsLocatorModel.ResultTypeRole), 0)
|
||||||
|
self.assertEqual(m.data(m.index(0, 0), QgsLocatorModel.ResultFilterNameRole), 'test')
|
||||||
|
self.assertEqual(m.data(m.index(1, 0)), 'a0')
|
||||||
|
self.assertEqual(m.data(m.index(1, 0), QgsLocatorModel.ResultTypeRole), 1)
|
||||||
|
self.assertEqual(m.data(m.index(1, 0), QgsLocatorModel.ResultFilterNameRole), 'test')
|
||||||
|
self.assertEqual(m.data(m.index(2, 0)), 'a1')
|
||||||
|
self.assertEqual(m.data(m.index(2, 0), QgsLocatorModel.ResultTypeRole), 1)
|
||||||
|
self.assertEqual(m.data(m.index(2, 0), QgsLocatorModel.ResultFilterNameRole), 'test')
|
||||||
|
self.assertEqual(m.data(m.index(3, 0)), 'a2')
|
||||||
|
self.assertEqual(m.data(m.index(3, 0), QgsLocatorModel.ResultTypeRole), 1)
|
||||||
|
self.assertEqual(m.data(m.index(3, 0), QgsLocatorModel.ResultFilterNameRole), 'test')
|
||||||
|
|
||||||
|
m.search('a')
|
||||||
|
|
||||||
|
for i in range(100):
|
||||||
|
sleep(0.002)
|
||||||
|
QCoreApplication.processEvents()
|
||||||
|
|
||||||
|
# 4 results - one is locator name
|
||||||
|
self.assertEqual(m.rowCount(), 4)
|
||||||
|
self.assertEqual(m.data(m.index(0, 0)), 'test')
|
||||||
|
self.assertEqual(m.data(m.index(1, 0)), 'a0')
|
||||||
|
self.assertEqual(m.data(m.index(2, 0)), 'a1')
|
||||||
|
self.assertEqual(m.data(m.index(3, 0)), 'a2')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user