1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtLocation module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL3$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or later as published by the Free
28 ** Software Foundation and appearing in the file LICENSE.GPL included in
29 ** the packaging of this file. Please review the following information to
30 ** ensure the GNU General Public License version 2.0 requirements will be
31 ** met: http://www.gnu.org/licenses/gpl-2.0.html.
32 **
33 ** $QT_END_LICENSE$
34 **
35 ****************************************************************************/
36 
37 #include "qdeclarativesearchsuggestionmodel_p.h"
38 #include "qdeclarativegeoserviceprovider_p.h"
39 
40 #include <QtQml/QQmlInfo>
41 #include <QtLocation/QGeoServiceProvider>
42 
43 #include <qplacemanager.h>
44 #include <qplacesearchrequest.h>
45 
46 QT_BEGIN_NAMESPACE
47 
48 /*!
49     \qmltype PlaceSearchSuggestionModel
50     \instantiates QDeclarativeSearchSuggestionModel
51     \inqmlmodule QtLocation
52     \ingroup qml-QtLocation5-places
53     \ingroup qml-QtLocation5-places-models
54     \since QtLocation 5.5
55 
56     \brief Provides access to search term suggestions.
57 
58     The PlaceSearchSuggestionModel can be used to provide search term suggestions as the user enters their
59     search term.  The properties of this model should match that of the \l PlaceSearchModel, which
60     will be used to perform the actual search query, to ensure that the search suggestion results are
61     relevant.
62 
63     There are two ways of accessing the data provided by this model, either through the
64     \l suggestions property or through views and delegates.  The latter is the preferred
65     method.
66 
67     The \l offset and \l limit properties can be used to access paged suggestions.  When the
68     \l offset and \l limit properties are set the suggestions between \l offset and
69     (\l offset + \l limit - 1) will be returned.  Support for paging may vary
70     from plugin to plugin.
71 
72     The model returns data for the following roles:
73 
74     \table
75         \header
76             \li Role
77             \li Type
78             \li Description
79         \row
80             \li suggestion
81             \li string
82             \li Suggested search term.
83     \endtable
84 
85     The following example shows how to use the PlaceSearchSuggestionModel to get suggested search terms
86     from a partial search term.  The \l searchArea is set to match what would be used to perform the
87     actual place search with \l PlaceSearchModel.
88 
89     \snippet declarative/places.qml QtQuick import
90     \snippet declarative/maps.qml QtLocation import
91     \codeline
92     \snippet declarative/places.qml SearchSuggestionModel
93 
94     \sa PlaceSearchModel, {QPlaceManager}
95 */
96 
97 /*!
98     \qmlproperty Plugin PlaceSearchSuggestionModel::plugin
99 
100     This property holds the provider \l Plugin which will be used to perform the search.
101 */
102 
103 /*!
104     \qmlproperty geoshape PlaceSearchSuggestionModel::searchArea
105 
106     This property holds the search area.  Search suggestion results returned by the model will be
107     relevant to the given search area.
108 
109     If this property is set to a \l {geocircle} its
110     \l {geocircle}{radius} property may be left unset, in which case the \l Plugin
111     will choose an appropriate radius for the search.
112 */
113 
114 /*!
115     \qmlproperty int PlaceSearchSuggestionModel::offset
116 
117     This property holds the index of the first item in the model.
118 
119     \sa limit
120 */
121 
122 /*!
123     \qmlproperty int PlaceSearchSuggestionModel::limit
124 
125     This property holds the limit of the number of items that will be returned.
126 
127     \sa offset
128 */
129 
130 /*!
131     \qmlproperty enum PlaceSearchSuggestionModel::status
132 
133     This property holds the status of the model.  It can be one of:
134 
135     \table
136         \row
137             \li PlaceSearchSuggestionModel.Null
138             \li No search query has been executed.  The model is empty.
139         \row
140             \li PlaceSearchSuggestionModel.Ready
141             \li The search query has completed, and the results are available.
142         \row
143             \li PlaceSearchSuggestionModel.Loading
144             \li A search query is currently being executed.
145         \row
146             \li PlaceSearchSuggestionModel.Error
147             \li An error occurred when executing the previous search query.
148     \endtable
149 */
150 
151 /*!
152     \qmlmethod void PlaceSearchSuggestionModel::update()
153 
154     Updates the model based on the provided query parameters.  The model will be populated with a
155     list of search suggestions for the partial \l searchTerm and \l searchArea.  If the \l plugin
156     supports it, other parameters such as \l limit and \l offset may be specified.  \c update()
157     submits the set of parameters to the \l plugin to process.
158 
159 
160     While the model is updating the \l status of the model is set to
161     \c PlaceSearchSuggestionModel.Loading.  If the model is successfully updated, the \l status is
162     set to \c PlaceSearchSuggestionModel.Ready, while if it unsuccessfully completes, the \l status
163     is set to \c PlaceSearchSuggestionModel.Error and the model cleared.
164 
165     This example shows use of the model
166     \code
167     PlaceSeachSuggestionModel {
168         id: model
169         plugin: backendPlugin
170         searchArea: QtPositioning.circle(QtPositioning.coordinate(10, 10))
171         ...
172     }
173 
174     MouseArea {
175         ...
176         onClicked: {
177             model.searchTerm = "piz"
178             model.searchArea.center.latitude = -27.5;
179             model.searchArea.cetner.longitude = 153;
180             model.update();
181         }
182     }
183     \endcode
184 
185     A more detailed example can be found in the in
186     \l {Places (QML)#Presenting-Search-Suggestions}{Places (QML)} example.
187 
188     \sa cancel(), status
189 */
190 
191 /*!
192     \qmlmethod void PlaceSearchSuggestionModel::cancel()
193 
194     Cancels an ongoing search suggestion operation immediately and sets the model
195     status to PlaceSearchSuggestionModel.Ready.  The model retains any search
196     suggestions it had before the operation was started.
197 
198     If an operation is not ongoing, invoking cancel() has no effect.
199 
200     \sa update(), status
201 */
202 
203 /*!
204     \qmlmethod void PlaceSearchSuggestionModel::reset()
205 
206     Resets the model.  All search suggestions are cleared, any outstanding requests are aborted and
207     possible errors are cleared.  Model status will be set to PlaceSearchSuggestionModel.Null.
208 */
209 
210 
211 /*!
212     \qmlmethod string QtLocation::PlaceSearchSuggestionModel::errorString() const
213 
214     This read-only property holds the textual presentation of the latest search suggestion model error.
215     If no error has occurred, or if the model was cleared, an empty string is returned.
216 
217     An empty string may also be returned if an error occurred which has no associated
218     textual representation.
219 */
220 
QDeclarativeSearchSuggestionModel(QObject * parent)221 QDeclarativeSearchSuggestionModel::QDeclarativeSearchSuggestionModel(QObject *parent)
222 :   QDeclarativeSearchModelBase(parent)
223 {
224 }
225 
~QDeclarativeSearchSuggestionModel()226 QDeclarativeSearchSuggestionModel::~QDeclarativeSearchSuggestionModel()
227 {
228 }
229 
230 /*!
231     \qmlproperty string PlaceSearchSuggestionModel::searchTerm
232 
233     This property holds the partial search term used in query.
234 */
searchTerm() const235 QString QDeclarativeSearchSuggestionModel::searchTerm() const
236 {
237     return m_request.searchTerm();
238 }
239 
setSearchTerm(const QString & searchTerm)240 void QDeclarativeSearchSuggestionModel::setSearchTerm(const QString &searchTerm)
241 {
242     if (m_request.searchTerm() == searchTerm)
243         return;
244 
245     m_request.setSearchTerm(searchTerm);
246     emit searchTermChanged();
247 }
248 
249 /*!
250     \qmlproperty stringlist PlaceSearchSuggestionModel::suggestions
251 
252     This property holds the list of predicted search terms that the model currently has.
253 */
suggestions() const254 QStringList QDeclarativeSearchSuggestionModel::suggestions() const
255 {
256     return m_suggestions;
257 }
258 
259 /*!
260     \internal
261 */
clearData(bool suppressSignal)262 void QDeclarativeSearchSuggestionModel::clearData(bool suppressSignal)
263 {
264     QDeclarativeSearchModelBase::clearData(suppressSignal);
265 
266     if (!m_suggestions.isEmpty()) {
267         m_suggestions.clear();
268 
269         if (!suppressSignal)
270             emit suggestionsChanged();
271     }
272 }
273 
274 /*!
275     \internal
276 */
rowCount(const QModelIndex & parent) const277 int QDeclarativeSearchSuggestionModel::rowCount(const QModelIndex &parent) const
278 {
279     Q_UNUSED(parent);
280 
281     return m_suggestions.count();
282 }
283 
284 /*!
285     \internal
286 */
data(const QModelIndex & index,int role) const287 QVariant QDeclarativeSearchSuggestionModel::data(const QModelIndex &index, int role) const
288 {
289     if (!index.isValid())
290         return QVariant();
291 
292     if (index.row() >= rowCount(index.parent()) || index.row() < 0)
293         return QVariant();
294 
295     switch (role) {
296     case Qt::DisplayRole:
297     case SearchSuggestionRole:
298         return m_suggestions.at(index.row());
299     }
300 
301     return QVariant();
302 }
303 
roleNames() const304 QHash<int, QByteArray> QDeclarativeSearchSuggestionModel::roleNames() const
305 {
306     QHash<int, QByteArray> roleNames = QDeclarativeSearchModelBase::roleNames();
307     roleNames.insert(SearchSuggestionRole, "suggestion");
308     return roleNames;
309 }
310 
311 /*!
312     \internal
313 */
queryFinished()314 void QDeclarativeSearchSuggestionModel::queryFinished()
315 {
316     if (!m_reply)
317         return;
318 
319     QPlaceReply *reply = m_reply;
320     m_reply = 0;
321 
322     int initialCount = m_suggestions.count();
323     beginResetModel();
324 
325     clearData(true);
326 
327     QPlaceSearchSuggestionReply *suggestionReply = qobject_cast<QPlaceSearchSuggestionReply *>(reply);
328     m_suggestions = suggestionReply->suggestions();
329 
330     if (initialCount != m_suggestions.count())
331         emit suggestionsChanged();
332 
333     endResetModel();
334 
335     if (suggestionReply->error() != QPlaceReply::NoError)
336         setStatus(Error, suggestionReply->errorString());
337     else
338         setStatus(Ready);
339 
340 
341     reply->deleteLater();
342 }
343 
344 /*!
345     \internal
346 */
sendQuery(QPlaceManager * manager,const QPlaceSearchRequest & request)347 QPlaceReply *QDeclarativeSearchSuggestionModel::sendQuery(QPlaceManager *manager,
348                                                         const QPlaceSearchRequest &request)
349 {
350     return manager->searchSuggestions(request);
351 }
352 
353 QT_END_NAMESPACE
354