1 /***************************************************************************
2                          qgslocator.h
3                          ------------
4     begin                : May 2017
5     copyright            : (C) 2017 by Nyall Dawson
6     email                : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #ifndef QGSLOCATOR_H
19 #define QGSLOCATOR_H
20 
21 #include <QObject>
22 #include <QFuture>
23 #include <QFutureWatcher>
24 #include <QMap>
25 #include <memory>
26 
27 #include "qgis_core.h"
28 #include "qgis_sip.h"
29 #include "qgslocatorfilter.h"
30 #include "qgsfeedback.h"
31 #include "qgslocatorcontext.h"
32 
33 
34 /**
35  * \class QgsLocator
36  * \ingroup core
37  * \brief Handles the management of QgsLocatorFilter objects and async collection of search results from them.
38  *
39  * QgsLocator acts as both a registry for QgsLocatorFilter objects and a means of firing up
40  * asynchronous queries against these filter objects.
41  *
42  * Filters are first registered to the locator by calling registerFilter(). Registering filters
43  * transfers their ownership to the locator object. Plugins which register filters to the locator
44  * must take care to correctly call deregisterFilter() and deregister their filter upon plugin
45  * unload to avoid crashes.
46  *
47  * In order to trigger a search across registered filters, the fetchResults() method is called.
48  * This triggers threaded calls to QgsLocatorFilter::fetchResults() for all registered filters.
49  * As individual filters find matching results, the foundResult() signal will be triggered
50  * for each result. Callers should connect this signal to an appropriate slot designed
51  * to collect and handle these results. Since foundResult() is triggered whenever a filter
52  * encounters an individual result, it will usually be triggered many times for a single
53  * call to fetchResults().
54  *
55  * \since QGIS 3.0
56 */
57 class CORE_EXPORT QgsLocator : public QObject
58 {
59     Q_OBJECT
60 
61   public:
62 
63     //! List of core filters (i.e. not plugin filters)
64     static const QList<QString> CORE_FILTERS;
65 
66     /**
67      * Constructor for QgsLocator.
68      */
69     QgsLocator( QObject *parent SIP_TRANSFERTHIS = nullptr );
70 
71     /**
72      * Destructor for QgsLocator. Destruction will block while any currently running query is terminated.
73      */
74     ~QgsLocator() override;
75 
76     /**
77      * Registers a \a filter within the locator. Ownership of the filter is transferred to the
78      * locator.
79      * \warning Plugins which register filters to the locator must take care to correctly call
80      * deregisterFilter() and deregister their filters upon plugin unload to avoid crashes.
81      * \see deregisterFilter()
82      */
83     void registerFilter( QgsLocatorFilter *filter SIP_TRANSFER );
84 
85     /**
86      * Deregisters a \a filter from the locator and deletes it. Calling this will block whilst
87      * any currently running query is terminated.
88      *
89      * Plugins which register filters to the locator must take care to correctly call
90      * deregisterFilter() to deregister their filters upon plugin unload to avoid crashes.
91      *
92      * \see registerFilter()
93      */
94     void deregisterFilter( QgsLocatorFilter *filter );
95 
96     /**
97      * Returns the list of filters registered in the locator.
98      * \param prefix If prefix is not empty, the list returned corresponds to the filter with the given active prefix
99      * \see prefixedFilters()
100      */
101     QList< QgsLocatorFilter *> filters( const QString &prefix = QString() );
102 
103     /**
104      * Returns a map of prefix to filter, for all registered filters
105      * with valid prefixes.
106      * \see filters()
107      * \deprecated since QGIS 3.2 use filters() instead
108      */
109     Q_DECL_DEPRECATED QMap<QString, QgsLocatorFilter *> prefixedFilters() const;
110 
111     /**
112      * Triggers the background fetching of filter results for a specified search \a string.
113      * The \a context argument encapsulates the context relating to the search (such as a map
114      * extent to prioritize).
115      *
116      * If specified, the \a feedback object must exist for the lifetime of this query.
117      *
118      * The foundResult() signal will be emitted for each individual result encountered
119      * by the registered filters.
120      */
121     void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback = nullptr );
122 
123     /**
124      * Cancels any current running query, and blocks until query is completely canceled by
125      * all filters.
126      * \see cancelWithoutBlocking()
127      */
128     void cancel();
129 
130     /**
131      * Triggers cancellation of any current running query without blocking. The query may
132      * take some time to cancel after calling this.
133      * \see cancel()
134      */
135     void cancelWithoutBlocking();
136 
137     /**
138      * Returns TRUE if a query is currently being executed by the locator.
139      */
140     bool isRunning() const;
141 
142     /**
143      * Will call clearPreviousResults on all filters
144      * \since QGIS 3.2
145      */
146     void clearPreviousResults();
147 
148     /**
149      * Returns the list for auto completion
150      * This list is updated when preparing the search
151      * \since QGIS 3.16
152      */
completionList()153     QStringList completionList() const {return mAutocompletionList;}
154 
155   signals:
156 
157     /**
158      * Emitted whenever a filter encounters a matching \a result after the fetchResults() method
159      * is called.
160      */
161     void foundResult( const QgsLocatorResult &result );
162 
163     /**
164      * Emitted when locator has prepared the search (\see QgsLocatorFilter::prepare)
165      * before the search is actually performed
166      * \since QGIS 3.16
167      */
168     void searchPrepared();
169 
170     /**
171      * Emitted when locator has finished a query, either as a result
172      * of successful completion or early cancellation.
173      */
174     void finished();
175 
176   private slots:
177 
178     void filterSentResult( QgsLocatorResult result );
179 
180   private:
181 
182     QgsFeedback *mFeedback = nullptr;
183     std::unique_ptr< QgsFeedback > mOwnedFeedback;
184 
185     QList< QgsLocatorFilter * > mFilters;
186     QList< QThread * > mActiveThreads;
187 
188     QStringList mAutocompletionList;
189 
190     void cancelRunningQuery();
191 
192 };
193 
194 #endif // QGSLOCATOR_H
195 
196 
197