mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -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/layertree
|
||||
${CMAKE_SOURCE_DIR}/src/core/layout
|
||||
${CMAKE_SOURCE_DIR}/src/core/locator
|
||||
${CMAKE_SOURCE_DIR}/src/core/metadata
|
||||
${CMAKE_SOURCE_DIR}/src/core/pal
|
||||
${CMAKE_SOURCE_DIR}/src/core/processing
|
||||
|
@ -117,6 +117,7 @@ INCLUDE_DIRECTORIES(
|
||||
${CMAKE_SOURCE_DIR}/src/core/gps
|
||||
${CMAKE_SOURCE_DIR}/src/core/layertree
|
||||
${CMAKE_SOURCE_DIR}/src/core/layout
|
||||
${CMAKE_SOURCE_DIR}/src/core/locator
|
||||
${CMAKE_SOURCE_DIR}/src/core/metadata
|
||||
${CMAKE_SOURCE_DIR}/src/core/processing
|
||||
${CMAKE_SOURCE_DIR}/src/core/processing/models
|
||||
|
@ -251,6 +251,7 @@
|
||||
%Include symbology/qgsvectorfieldsymbollayer.sip
|
||||
%Include symbology/qgsgeometrygeneratorsymbollayer.sip
|
||||
%Include layertree/qgslayertreeutils.sip
|
||||
%Include locator/qgslocatorcontext.sip
|
||||
%Include geometry/qgsabstractgeometry.sip
|
||||
%Include geometry/qgsbox3d.sip
|
||||
%Include geometry/qgscircularstring.sip
|
||||
@ -374,6 +375,9 @@
|
||||
%Include composer/qgscomposition.sip
|
||||
%Include composer/qgsgroupungroupitemscommand.sip
|
||||
%Include composer/qgslayoutmanager.sip
|
||||
%Include locator/qgslocator.sip
|
||||
%Include locator/qgslocatorfilter.sip
|
||||
%Include locator/qgslocatormodel.sip
|
||||
%Include processing/qgsprocessingalgrunnertask.sip
|
||||
%Include processing/qgsprocessingfeedback.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 layout/qgslayoutviewmouseevent.sip
|
||||
%Include layout/qgslayoutviewrubberband.sip
|
||||
%Include locator/qgslocatorcontext.sip
|
||||
%Include raster/qgsrasterrendererwidget.sip
|
||||
%Include symbology/qgssymbolwidgetcontext.sip
|
||||
%Include qgisinterface.sip
|
||||
@ -295,7 +294,5 @@
|
||||
%Include layout/qgslayoutviewtooltemporarykeyzoom.sip
|
||||
%Include layout/qgslayoutviewtooltemporarymousepan.sip
|
||||
%Include layout/qgslayoutviewtoolzoom.sip
|
||||
%Include locator/qgslocator.sip
|
||||
%Include locator/qgslocatorfilter.sip
|
||||
%Include locator/qgslocatorwidget.sip
|
||||
%Include qgsadvanceddigitizingcanvasitem.sip
|
||||
|
@ -27,9 +27,9 @@ __revision__ = '$Format:%H$'
|
||||
|
||||
|
||||
from qgis.core import (QgsApplication,
|
||||
QgsProcessingAlgorithm)
|
||||
from qgis.gui import (QgsLocatorFilter,
|
||||
QgsLocatorResult)
|
||||
QgsProcessingAlgorithm,
|
||||
QgsLocatorFilter,
|
||||
QgsLocatorResult)
|
||||
from processing.gui.MessageDialog import MessageDialog
|
||||
from processing.gui.AlgorithmDialog import AlgorithmDialog
|
||||
from qgis.utils import iface
|
||||
|
@ -512,6 +512,7 @@ INCLUDE_DIRECTORIES(
|
||||
${CMAKE_SOURCE_DIR}/src/core/geocms/geonode
|
||||
${CMAKE_SOURCE_DIR}/src/core/metadata
|
||||
${CMAKE_SOURCE_DIR}/src/core/layertree
|
||||
${CMAKE_SOURCE_DIR}/src/core/locator
|
||||
${CMAKE_SOURCE_DIR}/src/core/providers/memory
|
||||
${CMAKE_SOURCE_DIR}/src/core/raster
|
||||
${CMAKE_SOURCE_DIR}/src/core/scalebar
|
||||
|
@ -93,6 +93,10 @@ SET(QGIS_CORE_SRCS
|
||||
expression/qgsexpressionfunction.cpp
|
||||
expression/qgsexpressionutils.cpp
|
||||
|
||||
locator/qgslocator.cpp
|
||||
locator/qgslocatorfilter.cpp
|
||||
locator/qgslocatormodel.cpp
|
||||
|
||||
processing/qgsnativealgorithms.cpp
|
||||
processing/qgsprocessingalgorithm.cpp
|
||||
processing/qgsprocessingalgrunnertask.cpp
|
||||
@ -667,6 +671,10 @@ SET(QGIS_CORE_MOC_HDRS
|
||||
composer/qgslayoutmanager.h
|
||||
composer/qgspaperitem.h
|
||||
|
||||
locator/qgslocator.h
|
||||
locator/qgslocatorfilter.h
|
||||
locator/qgslocatormodel.h
|
||||
|
||||
processing/qgsnativealgorithms.h
|
||||
processing/qgsprocessingalgrunnertask.h
|
||||
processing/qgsprocessingfeedback.h
|
||||
@ -1050,6 +1058,8 @@ SET(QGIS_CORE_HDRS
|
||||
|
||||
layertree/qgslayertreeutils.h
|
||||
|
||||
locator/qgslocatorcontext.h
|
||||
|
||||
geometry/qgsabstractgeometry.h
|
||||
geometry/qgsbox3d.h
|
||||
geometry/qgscircularstring.h
|
||||
@ -1118,6 +1128,7 @@ INCLUDE_DIRECTORIES(
|
||||
geocms/geonode
|
||||
layertree
|
||||
layout
|
||||
locator
|
||||
metadata
|
||||
pal
|
||||
processing
|
||||
|
@ -18,7 +18,7 @@
|
||||
#ifndef QGSLOCATOR_H
|
||||
#define QGSLOCATOR_H
|
||||
|
||||
#include "qgis_gui.h"
|
||||
#include "qgis_core.h"
|
||||
#include "qgis_sip.h"
|
||||
#include "qgslocatorfilter.h"
|
||||
#include "qgsfeedback.h"
|
||||
@ -30,7 +30,7 @@
|
||||
|
||||
/**
|
||||
* \class QgsLocator
|
||||
* \ingroup gui
|
||||
* \ingroup core
|
||||
* 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
|
||||
@ -51,7 +51,7 @@
|
||||
*
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class GUI_EXPORT QgsLocator : public QObject
|
||||
class CORE_EXPORT QgsLocator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -18,17 +18,17 @@
|
||||
#ifndef QGSLOCATORCONTEXT_H
|
||||
#define QGSLOCATORCONTEXT_H
|
||||
|
||||
#include "qgis_gui.h"
|
||||
#include "qgis_core.h"
|
||||
#include "qgsrectangle.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
|
||||
/**
|
||||
* \class QgsLocatorContext
|
||||
* \ingroup gui
|
||||
* \ingroup core
|
||||
* Encapsulates the properties relating to the context of a locator search.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class GUI_EXPORT QgsLocatorContext
|
||||
class CORE_EXPORT QgsLocatorContext
|
||||
{
|
||||
public:
|
||||
|
@ -18,7 +18,7 @@
|
||||
#ifndef QGSLOCATORFILTER_H
|
||||
#define QGSLOCATORFILTER_H
|
||||
|
||||
#include "qgis_gui.h"
|
||||
#include "qgis_core.h"
|
||||
#include "qgslocatorcontext.h"
|
||||
#include "qgslogger.h"
|
||||
#include <QString>
|
||||
@ -30,11 +30,11 @@ class QgsLocatorFilter;
|
||||
|
||||
/**
|
||||
* \class QgsLocatorResult
|
||||
* \ingroup gui
|
||||
* \ingroup core
|
||||
* Encapsulates properties of an individual matching result found by a QgsLocatorFilter.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class GUI_EXPORT QgsLocatorResult
|
||||
class CORE_EXPORT QgsLocatorResult
|
||||
{
|
||||
public:
|
||||
|
||||
@ -90,11 +90,11 @@ class GUI_EXPORT QgsLocatorResult
|
||||
|
||||
/**
|
||||
* \class QgsLocatorFilter
|
||||
* \ingroup gui
|
||||
* \ingroup core
|
||||
* Abstract base class for filters which collect locator results.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class GUI_EXPORT QgsLocatorFilter : public QObject
|
||||
class CORE_EXPORT QgsLocatorFilter : public QObject
|
||||
{
|
||||
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/qgslayoutviewtoolzoom.cpp
|
||||
|
||||
locator/qgslocator.cpp
|
||||
locator/qgslocatorfilter.cpp
|
||||
locator/qgslocatorwidget.cpp
|
||||
|
||||
ogr/qgsogrhelperfunctions.cpp
|
||||
@ -667,8 +665,6 @@ SET(QGIS_GUI_MOC_HDRS
|
||||
layout/qgslayoutviewtooltemporarymousepan.h
|
||||
layout/qgslayoutviewtoolzoom.h
|
||||
|
||||
locator/qgslocator.h
|
||||
locator/qgslocatorfilter.h
|
||||
locator/qgslocatorwidget.h
|
||||
)
|
||||
SET_PROPERTY(GLOBAL PROPERTY QGIS_GUI_MOC_HDRS ${QGIS_GUI_MOC_HDRS})
|
||||
@ -769,8 +765,6 @@ SET(QGIS_GUI_HDRS
|
||||
layout/qgslayoutviewmouseevent.h
|
||||
layout/qgslayoutviewrubberband.h
|
||||
|
||||
locator/qgslocatorcontext.h
|
||||
|
||||
raster/qgsrasterrendererwidget.h
|
||||
|
||||
symbology/qgssymbolwidgetcontext.h
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "qgslocatorwidget.h"
|
||||
#include "qgslocator.h"
|
||||
#include "qgslocatormodel.h"
|
||||
#include "qgsfilterlineedit.h"
|
||||
#include "qgsmapcanvas.h"
|
||||
#include "qgsapplication.h"
|
||||
@ -344,179 +345,6 @@ QgsLocatorContext QgsLocatorWidget::createContext()
|
||||
|
||||
///@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
|
||||
//
|
||||
@ -561,53 +389,6 @@ void QgsLocatorResultsView::selectPreviousResult()
|
||||
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
|
||||
//
|
||||
|
@ -22,12 +22,10 @@
|
||||
#include "qgslocatorfilter.h"
|
||||
#include "qgsfloatingwidget.h"
|
||||
#include <QWidget>
|
||||
#include <QAbstractListModel>
|
||||
#include <QTreeView>
|
||||
#include <QFocusEvent>
|
||||
#include <QHeaderView>
|
||||
#include <QTimer>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class QgsLocator;
|
||||
class QgsFilterLineEdit;
|
||||
@ -147,90 +145,6 @@ class QgsLocatorFilterFilter : public QgsLocatorFilter
|
||||
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
|
||||
* \ingroup gui
|
||||
|
@ -15,10 +15,12 @@ import qgis # NOQA
|
||||
|
||||
import os
|
||||
|
||||
from qgis.gui import (QgsLocator,
|
||||
QgsLocatorFilter,
|
||||
QgsLocatorContext,
|
||||
QgsLocatorResult)
|
||||
from qgis.core import (QgsLocator,
|
||||
QgsLocatorFilter,
|
||||
QgsLocatorContext,
|
||||
QgsLocatorResult,
|
||||
QgsLocatorModel,
|
||||
QgsLocatorAutomaticModel)
|
||||
from qgis.PyQt.QtCore import QVariant, pyqtSignal, QCoreApplication
|
||||
from time import sleep
|
||||
from qgis.testing import start_app, unittest
|
||||
@ -32,6 +34,12 @@ class test_filter(QgsLocatorFilter):
|
||||
super().__init__(parent)
|
||||
self.prefix = prefix
|
||||
|
||||
def name(self):
|
||||
return 'test'
|
||||
|
||||
def displayName(self):
|
||||
return 'test'
|
||||
|
||||
def fetchResults(self, string, context, feedback):
|
||||
for i in range(3):
|
||||
#if feedback.isCanceled():
|
||||
@ -152,6 +160,102 @@ class TestQgsLocator(unittest.TestCase):
|
||||
l.fetchResults('a', context)
|
||||
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__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user