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 "qdeclarativegeocodemodel_p.h" |
38 | #include "error_messages_p.h" |
39 | |
40 | #include <QtCore/QCoreApplication> |
41 | #include <QtQml/QQmlInfo> |
42 | #include <QtPositioning/QGeoCircle> |
43 | #include <QtLocation/QGeoServiceProvider> |
44 | #include <QtLocation/QGeoCodingManager> |
45 | #include <QtLocation/private/qgeocodereply_p.h> |
46 | #include <QtPositioning/QGeoPolygon> |
47 | |
48 | QT_BEGIN_NAMESPACE |
49 | |
50 | /*! |
51 | \qmltype GeocodeModel |
52 | \instantiates QDeclarativeGeocodeModel |
53 | \inqmlmodule QtLocation |
54 | \ingroup qml-QtLocation5-geocoding |
55 | \since QtLocation 5.5 |
56 | |
57 | \brief The GeocodeModel type provides support for searching operations |
58 | related to geographic information. |
59 | |
60 | The GeocodeModel type is used as part of a model/view grouping to |
61 | match addresses or search strings with geographic locations. How the |
62 | geographic locations generated are used or displayed is decided by any |
63 | Views attached to the GeocodeModel (for example a \l MapItemView or \l{ListView}). |
64 | |
65 | Like \l Map and \l RouteModel, all the data for a GeocodeModel to work |
66 | comes from a services plugin. This is contained in the \l{plugin} property, |
67 | and this must be set before the GeocodeModel can do any useful work. |
68 | |
69 | Once the plugin is set, the \l{query} property can be used to specify the |
70 | address or search string to match. If \l{autoUpdate} is enabled, the Model |
71 | will update its output automatically. Otherwise, the \l{update} method may |
72 | be used. By default, autoUpdate is disabled. |
73 | |
74 | The data stored and returned in the GeocodeModel consists of \l [QML] {Location} |
75 | objects, as a list with the role name "locationData". See the documentation |
76 | for \l [QML] {Location} for further details on its structure and contents. |
77 | |
78 | \section2 Example Usage |
79 | |
80 | The following snippet is two-part, showing firstly the declaration of |
81 | objects, and secondly a short piece of procedural code using it. We set |
82 | the geocodeModel's \l{autoUpdate} property to false, and call \l{update} once |
83 | the query is set up. In this case, as we use a string value in \l{query}, |
84 | only one update would occur, even with autoUpdate enabled. However, if we |
85 | provided an \l{Address} object we may inadvertently trigger multiple |
86 | requests whilst setting its properties. |
87 | |
88 | \code |
89 | Plugin { |
90 | id: aPlugin |
91 | } |
92 | |
93 | GeocodeModel { |
94 | id: geocodeModel |
95 | plugin: aPlugin |
96 | autoUpdate: false |
97 | } |
98 | \endcode |
99 | |
100 | \code |
101 | { |
102 | geocodeModel.query = "53 Brandl St, Eight Mile Plains, Australia" |
103 | geocodeModel.update() |
104 | } |
105 | \endcode |
106 | */ |
107 | |
108 | /*! |
109 | \qmlsignal QtLocation::GeocodeModel::locationsChanged() |
110 | |
111 | This signal is emitted when locations in the model have changed. |
112 | |
113 | \sa count |
114 | */ |
115 | |
116 | |
117 | QDeclarativeGeocodeModel::QDeclarativeGeocodeModel(QObject *parent) |
118 | : QAbstractListModel(parent), autoUpdate_(false), complete_(false), reply_(0), plugin_(0), |
119 | status_(QDeclarativeGeocodeModel::Null), error_(QDeclarativeGeocodeModel::NoError), |
120 | address_(0), limit_(-1), offset_(0) |
121 | { |
122 | } |
123 | |
124 | QDeclarativeGeocodeModel::~QDeclarativeGeocodeModel() |
125 | { |
126 | qDeleteAll(c: declarativeLocations_); |
127 | declarativeLocations_.clear(); |
128 | delete reply_; |
129 | } |
130 | |
131 | /*! |
132 | \internal |
133 | From QQmlParserStatus |
134 | */ |
135 | void QDeclarativeGeocodeModel::componentComplete() |
136 | { |
137 | complete_ = true; |
138 | if (autoUpdate_) |
139 | update(); |
140 | } |
141 | |
142 | /*! |
143 | \qmlmethod void QtLocation::GeocodeModel::update() |
144 | |
145 | Instructs the GeocodeModel to update its data. This is most useful |
146 | when \l autoUpdate is disabled, to force a refresh when the query |
147 | has been changed. |
148 | */ |
149 | void QDeclarativeGeocodeModel::update() |
150 | { |
151 | if (!complete_) |
152 | return; |
153 | |
154 | if (!plugin_) { |
155 | setError(error: EngineNotSetError, errorString: tr(s: "Cannot geocode, plugin not set." )); |
156 | return; |
157 | } |
158 | |
159 | QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider(); |
160 | if (!serviceProvider) |
161 | return; |
162 | |
163 | QGeoCodingManager *geocodingManager = serviceProvider->geocodingManager(); |
164 | if (!geocodingManager) { |
165 | setError(error: EngineNotSetError, errorString: tr(s: "Cannot geocode, geocode manager not set." )); |
166 | return; |
167 | } |
168 | if (!coordinate_.isValid() && (!address_ || address_->address().isEmpty()) && |
169 | (searchString_.isEmpty())) { |
170 | setError(error: ParseError, errorString: tr(s: "Cannot geocode, valid query not set." )); |
171 | return; |
172 | } |
173 | abortRequest(); // abort possible previous requests |
174 | setError(error: NoError, errorString: QString()); |
175 | |
176 | if (coordinate_.isValid()) { |
177 | setStatus(QDeclarativeGeocodeModel::Loading); |
178 | reply_ = geocodingManager->reverseGeocode(coordinate: coordinate_, bounds: boundingArea_); |
179 | if (reply_->isFinished()) { |
180 | if (reply_->error() == QGeoCodeReply::NoError) { |
181 | geocodeFinished(reply: reply_); |
182 | } else { |
183 | geocodeError(reply: reply_, error: reply_->error(), errorString: reply_->errorString()); |
184 | } |
185 | } |
186 | } else if (address_) { |
187 | setStatus(QDeclarativeGeocodeModel::Loading); |
188 | reply_ = geocodingManager->geocode(address: address_->address(), bounds: boundingArea_); |
189 | if (reply_->isFinished()) { |
190 | if (reply_->error() == QGeoCodeReply::NoError) { |
191 | geocodeFinished(reply: reply_); |
192 | } else { |
193 | geocodeError(reply: reply_, error: reply_->error(), errorString: reply_->errorString()); |
194 | } |
195 | } |
196 | } else if (!searchString_.isEmpty()) { |
197 | setStatus(QDeclarativeGeocodeModel::Loading); |
198 | reply_ = geocodingManager->geocode(searchString: searchString_, limit: limit_, offset: offset_, bounds: boundingArea_); |
199 | if (reply_->isFinished()) { |
200 | if (reply_->error() == QGeoCodeReply::NoError) { |
201 | geocodeFinished(reply: reply_); |
202 | } else { |
203 | geocodeError(reply: reply_, error: reply_->error(), errorString: reply_->errorString()); |
204 | } |
205 | } |
206 | } |
207 | } |
208 | |
209 | /*! |
210 | \internal |
211 | */ |
212 | void QDeclarativeGeocodeModel::abortRequest() |
213 | { |
214 | if (reply_) { |
215 | reply_->abort(); |
216 | reply_->deleteLater(); |
217 | reply_ = 0; |
218 | } |
219 | } |
220 | |
221 | /*! |
222 | \internal |
223 | */ |
224 | void QDeclarativeGeocodeModel::queryContentChanged() |
225 | { |
226 | if (autoUpdate_) |
227 | update(); |
228 | } |
229 | |
230 | /*! |
231 | \internal |
232 | From QAbstractListModel |
233 | */ |
234 | int QDeclarativeGeocodeModel::rowCount(const QModelIndex &parent) const |
235 | { |
236 | Q_UNUSED(parent); |
237 | return declarativeLocations_.count(); |
238 | } |
239 | |
240 | /*! |
241 | \internal |
242 | */ |
243 | QVariant QDeclarativeGeocodeModel::data(const QModelIndex &index, int role) const |
244 | { |
245 | if (!index.isValid()) |
246 | return QVariant(); |
247 | if (index.row() >= declarativeLocations_.count()) |
248 | return QVariant(); |
249 | if (role == QDeclarativeGeocodeModel::LocationRole) { |
250 | QObject *locationObject = declarativeLocations_.at(i: index.row()); |
251 | Q_ASSERT(locationObject); |
252 | return QVariant::fromValue(value: locationObject); |
253 | } |
254 | return QVariant(); |
255 | } |
256 | |
257 | QHash<int, QByteArray> QDeclarativeGeocodeModel::roleNames() const |
258 | { |
259 | QHash<int, QByteArray> roleNames = QAbstractItemModel::roleNames(); |
260 | roleNames.insert(akey: LocationRole, avalue: "locationData" ); |
261 | return roleNames; |
262 | } |
263 | |
264 | /*! |
265 | \internal |
266 | */ |
267 | void QDeclarativeGeocodeModel::setPlugin(QDeclarativeGeoServiceProvider *plugin) |
268 | { |
269 | if (plugin_ == plugin) |
270 | return; |
271 | |
272 | reset(); // reset the model |
273 | plugin_ = plugin; |
274 | if (complete_) |
275 | emit pluginChanged(); |
276 | |
277 | if (!plugin) |
278 | return; |
279 | |
280 | if (plugin_->isAttached()) { |
281 | pluginReady(); |
282 | } else { |
283 | connect(sender: plugin_, SIGNAL(attached()), |
284 | receiver: this, SLOT(pluginReady())); |
285 | } |
286 | } |
287 | |
288 | /*! |
289 | \internal |
290 | */ |
291 | void QDeclarativeGeocodeModel::pluginReady() |
292 | { |
293 | QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider(); |
294 | QGeoCodingManager *geocodingManager = serviceProvider->geocodingManager(); |
295 | |
296 | if (serviceProvider->geocodingError() != QGeoServiceProvider::NoError) { |
297 | QDeclarativeGeocodeModel::GeocodeError newError = UnknownError; |
298 | switch (serviceProvider->geocodingError()) { |
299 | case QGeoServiceProvider::NotSupportedError: |
300 | newError = EngineNotSetError; break; |
301 | case QGeoServiceProvider::UnknownParameterError: |
302 | newError = UnknownParameterError; break; |
303 | case QGeoServiceProvider::MissingRequiredParameterError: |
304 | newError = MissingRequiredParameterError; break; |
305 | case QGeoServiceProvider::ConnectionError: |
306 | newError = CommunicationError; break; |
307 | default: |
308 | break; |
309 | } |
310 | |
311 | setError(error: newError, errorString: serviceProvider->geocodingErrorString()); |
312 | return; |
313 | } |
314 | |
315 | if (!geocodingManager) { |
316 | setError(error: EngineNotSetError,errorString: tr(s: "Plugin does not support (reverse) geocoding." )); |
317 | return; |
318 | } |
319 | |
320 | connect(sender: geocodingManager, SIGNAL(finished(QGeoCodeReply*)), |
321 | receiver: this, SLOT(geocodeFinished(QGeoCodeReply*))); |
322 | connect(sender: geocodingManager, SIGNAL(error(QGeoCodeReply*,QGeoCodeReply::Error,QString)), |
323 | receiver: this, SLOT(geocodeError(QGeoCodeReply*,QGeoCodeReply::Error,QString))); |
324 | |
325 | if (complete_ && autoUpdate_) |
326 | update(); |
327 | } |
328 | |
329 | /*! |
330 | \qmlproperty Plugin QtLocation::GeocodeModel::plugin |
331 | |
332 | This property holds the plugin that provides the actual geocoding service. |
333 | Note that all plugins do not necessarily provide geocoding (could for example provide |
334 | only routing or maps). |
335 | |
336 | \sa Plugin |
337 | */ |
338 | |
339 | QDeclarativeGeoServiceProvider *QDeclarativeGeocodeModel::plugin() const |
340 | { |
341 | return plugin_; |
342 | } |
343 | |
344 | void QDeclarativeGeocodeModel::setBounds(const QVariant &boundingArea) |
345 | { |
346 | QGeoShape s; |
347 | |
348 | if (boundingArea.userType() == qMetaTypeId<QGeoRectangle>()) |
349 | s = boundingArea.value<QGeoRectangle>(); |
350 | else if (boundingArea.userType() == qMetaTypeId<QGeoCircle>()) |
351 | s = boundingArea.value<QGeoCircle>(); |
352 | else if (boundingArea.userType() == qMetaTypeId<QGeoShape>()) |
353 | s = boundingArea.value<QGeoShape>(); |
354 | |
355 | |
356 | if (boundingArea_ == s) |
357 | return; |
358 | |
359 | boundingArea_ = s; |
360 | emit boundsChanged(); |
361 | } |
362 | |
363 | /*! |
364 | \qmlproperty geoshape QtLocation::GeocodeModel::bounds |
365 | |
366 | This property holds the bounding area used to limit the results to those |
367 | within the area. This is particularly useful if query is only partially filled out, |
368 | as the service will attempt to (reverse) geocode all matches for the specified data. |
369 | |
370 | Accepted types are \l {georectangle} and |
371 | \l {geocircle}. |
372 | */ |
373 | QVariant QDeclarativeGeocodeModel::bounds() const |
374 | { |
375 | if (boundingArea_.type() == QGeoShape::RectangleType) |
376 | return QVariant::fromValue(value: QGeoRectangle(boundingArea_)); |
377 | else if (boundingArea_.type() == QGeoShape::CircleType) |
378 | return QVariant::fromValue(value: QGeoCircle(boundingArea_)); |
379 | else if (boundingArea_.type() == QGeoShape::PolygonType) |
380 | return QVariant::fromValue(value: QGeoPolygon(boundingArea_)); |
381 | else |
382 | return QVariant::fromValue(value: boundingArea_); |
383 | } |
384 | |
385 | void QDeclarativeGeocodeModel::geocodeFinished(QGeoCodeReply *reply) |
386 | { |
387 | if (reply != reply_ || reply->error() != QGeoCodeReply::NoError) |
388 | return; |
389 | |
390 | reply->deleteLater(); |
391 | reply_ = 0; |
392 | int oldCount = declarativeLocations_.count(); |
393 | // const QVariantMap &extraData = QGeoCodeReplyPrivate::get(*reply)->extraData(); |
394 | setLocations(reply->locations()); |
395 | setError(error: NoError, errorString: QString()); |
396 | setStatus(QDeclarativeGeocodeModel::Ready); |
397 | emit locationsChanged(); |
398 | if (oldCount != declarativeLocations_.count()) |
399 | emit countChanged(); |
400 | } |
401 | |
402 | /*! |
403 | \internal |
404 | */ |
405 | void QDeclarativeGeocodeModel::geocodeError(QGeoCodeReply *reply, |
406 | QGeoCodeReply::Error error, |
407 | const QString &errorString) |
408 | { |
409 | if (reply != reply_) |
410 | return; |
411 | |
412 | reply->deleteLater(); |
413 | reply_ = 0; |
414 | int oldCount = declarativeLocations_.count(); |
415 | if (oldCount > 0) { |
416 | // Reset the model |
417 | setLocations(reply->locations()); |
418 | emit locationsChanged(); |
419 | emit countChanged(); |
420 | } |
421 | setError(error: static_cast<QDeclarativeGeocodeModel::GeocodeError>(error), errorString); |
422 | setStatus(QDeclarativeGeocodeModel::Error); |
423 | } |
424 | |
425 | /*! |
426 | \qmlproperty enumeration QtLocation::GeocodeModel::status |
427 | |
428 | This read-only property holds the current status of the model. |
429 | |
430 | \list |
431 | \li GeocodeModel.Null - No geocode requests have been issued or \l reset has been called. |
432 | \li GeocodeModel.Ready - Geocode request(s) have finished successfully. |
433 | \li GeocodeModel.Loading - Geocode request has been issued but not yet finished |
434 | \li GeocodeModel.Error - Geocoding error has occurred, details are in \l error and \l errorString |
435 | \endlist |
436 | */ |
437 | |
438 | QDeclarativeGeocodeModel::Status QDeclarativeGeocodeModel::status() const |
439 | { |
440 | return status_; |
441 | } |
442 | |
443 | void QDeclarativeGeocodeModel::setStatus(QDeclarativeGeocodeModel::Status status) |
444 | { |
445 | if (status_ == status) |
446 | return; |
447 | status_ = status; |
448 | emit statusChanged(); |
449 | } |
450 | |
451 | /*! |
452 | \qmlproperty enumeration QtLocation::GeocodeModel::error |
453 | |
454 | This read-only property holds the latest error value of the geocoding request. |
455 | |
456 | \list |
457 | \li GeocodeModel.NoError - No error has occurred. |
458 | \li GeocodeModel.CombinationError - An error occurred while results where being combined from multiple sources. |
459 | \li GeocodeModel.CommunicationError - An error occurred while communicating with the service provider. |
460 | \li GeocodeModel.EngineNotSetError - The model's plugin property was not set or there is no geocoding manager associated with the plugin. |
461 | \li GeocodeModel.MissingRequiredParameterError - A required parameter was not specified. |
462 | \li GeocodeModel.ParseError - The response from the service provider was in an unrecognizable format. |
463 | \li GeocodeModel.UnknownError - An error occurred which does not fit into any of the other categories. |
464 | \li GeocodeModel.UnknownParameterError - The plugin did not recognize one of the parameters it was given. |
465 | \li GeocodeModel.UnsupportedOptionError - The requested operation is not supported by the geocoding provider. |
466 | This may happen when the loaded engine does not support a particular geocoding request |
467 | such as reverse geocoding. |
468 | \endlist |
469 | */ |
470 | |
471 | QDeclarativeGeocodeModel::GeocodeError QDeclarativeGeocodeModel::error() const |
472 | { |
473 | return error_; |
474 | } |
475 | |
476 | void QDeclarativeGeocodeModel::setError(GeocodeError error, const QString &errorString) |
477 | { |
478 | if (error_ == error && errorString_ == errorString) |
479 | return; |
480 | error_ = error; |
481 | errorString_ = errorString; |
482 | emit errorChanged(); |
483 | } |
484 | |
485 | /*! |
486 | \qmlproperty string QtLocation::GeocodeModel::errorString |
487 | |
488 | This read-only property holds the textual presentation of the latest geocoding error. |
489 | If no error has occurred or the model has been reset, an empty string is returned. |
490 | |
491 | An empty string may also be returned if an error occurred which has no associated |
492 | textual representation. |
493 | */ |
494 | |
495 | QString QDeclarativeGeocodeModel::errorString() const |
496 | { |
497 | return errorString_; |
498 | } |
499 | |
500 | /*! |
501 | \internal |
502 | */ |
503 | void QDeclarativeGeocodeModel::setLocations(const QList<QGeoLocation> &locations) |
504 | { |
505 | beginResetModel(); |
506 | qDeleteAll(c: declarativeLocations_); |
507 | declarativeLocations_.clear(); |
508 | for (int i = 0; i < locations.count(); ++i) { |
509 | QDeclarativeGeoLocation *location = new QDeclarativeGeoLocation(locations.at(i), this); |
510 | declarativeLocations_.append(t: location); |
511 | } |
512 | endResetModel(); |
513 | } |
514 | |
515 | /*! |
516 | \qmlproperty int QtLocation::GeocodeModel::count |
517 | |
518 | This property holds how many locations the model currently has. |
519 | Amongst other uses, you can use this value when accessing locations |
520 | via the GeocodeModel::get -method. |
521 | */ |
522 | |
523 | int QDeclarativeGeocodeModel::count() const |
524 | { |
525 | return declarativeLocations_.count(); |
526 | } |
527 | |
528 | /*! |
529 | \qmlmethod Location QtLocation::GeocodeModel::get(int index) |
530 | |
531 | Returns the \l [QML] {Location} at given \a index. Use \l count property to check the |
532 | amount of locations available. The locations are indexed from zero, so the accessible range |
533 | is 0...(count - 1). |
534 | |
535 | If you access out of bounds, a zero (null object) is returned and a warning is issued. |
536 | */ |
537 | |
538 | QDeclarativeGeoLocation *QDeclarativeGeocodeModel::get(int index) |
539 | { |
540 | if (index < 0 || index >= declarativeLocations_.count()) { |
541 | qmlWarning(me: this) << QStringLiteral("Index '%1' out of range" ).arg(a: index); |
542 | return 0; |
543 | } |
544 | return declarativeLocations_.at(i: index); |
545 | } |
546 | |
547 | /*! |
548 | \qmlproperty int QtLocation::GeocodeModel::limit |
549 | |
550 | This property holds the maximum number of results. The limit and \l offset values are only |
551 | applicable with free string geocoding (that is they are not considered when using addresses |
552 | or coordinates in the search query). |
553 | |
554 | If limit is -1 the entire result set will be returned, otherwise at most limit results will be |
555 | returned. The limit and \l offset results can be used together to implement paging. |
556 | */ |
557 | |
558 | int QDeclarativeGeocodeModel::limit() const |
559 | { |
560 | return limit_; |
561 | } |
562 | |
563 | void QDeclarativeGeocodeModel::setLimit(int limit) |
564 | { |
565 | if (limit == limit_) |
566 | return; |
567 | limit_ = limit; |
568 | if (autoUpdate_) { |
569 | update(); |
570 | } |
571 | emit limitChanged(); |
572 | } |
573 | |
574 | /*! |
575 | \qmlproperty int QtLocation::GeocodeModel::offset |
576 | |
577 | This property tells not to return the first 'offset' number of the results. The \l limit and |
578 | offset values are only applicable with free string geocoding (that is they are not considered |
579 | when using addresses or coordinates in the search query). |
580 | |
581 | The \l limit and offset results can be used together to implement paging. |
582 | */ |
583 | |
584 | int QDeclarativeGeocodeModel::offset() const |
585 | { |
586 | return offset_; |
587 | } |
588 | |
589 | void QDeclarativeGeocodeModel::setOffset(int offset) |
590 | { |
591 | if (offset == offset_) |
592 | return; |
593 | offset_ = offset; |
594 | if (autoUpdate_) { |
595 | update(); |
596 | } |
597 | emit offsetChanged(); |
598 | } |
599 | |
600 | /*! |
601 | \qmlmethod void QtLocation::GeocodeModel::reset() |
602 | |
603 | Resets the model. All location data is cleared, any outstanding requests |
604 | are aborted and possible errors are cleared. Model status will be set |
605 | to GeocodeModel.Null |
606 | */ |
607 | |
608 | void QDeclarativeGeocodeModel::reset() |
609 | { |
610 | beginResetModel(); |
611 | if (!declarativeLocations_.isEmpty()) { |
612 | setLocations(QList<QGeoLocation>()); |
613 | emit countChanged(); |
614 | } |
615 | endResetModel(); |
616 | |
617 | abortRequest(); |
618 | setError(error: NoError, errorString: QString()); |
619 | setStatus(QDeclarativeGeocodeModel::Null); |
620 | } |
621 | |
622 | /*! |
623 | \qmlmethod void QtLocation::GeocodeModel::cancel() |
624 | |
625 | Cancels any outstanding requests and clears errors. Model status will be set to either |
626 | GeocodeModel.Null or GeocodeModel.Ready. |
627 | */ |
628 | void QDeclarativeGeocodeModel::cancel() |
629 | { |
630 | abortRequest(); |
631 | setError(error: NoError, errorString: QString()); |
632 | setStatus(declarativeLocations_.isEmpty() ? Null : Ready); |
633 | } |
634 | |
635 | /*! |
636 | \qmlproperty QVariant QtLocation::GeocodeModel::query |
637 | |
638 | This property holds the data of the geocoding request. |
639 | The property accepts three types of queries which determine both the data and |
640 | the type of action to be performed: |
641 | |
642 | \list |
643 | \li Address - Geocoding (address to coordinate) |
644 | \li \l {coordinate} - Reverse geocoding (coordinate to address) |
645 | \li string - Geocoding (address to coordinate) |
646 | \endlist |
647 | */ |
648 | |
649 | QVariant QDeclarativeGeocodeModel::query() const |
650 | { |
651 | return queryVariant_; |
652 | } |
653 | |
654 | void QDeclarativeGeocodeModel::setQuery(const QVariant &query) |
655 | { |
656 | if (query == queryVariant_) |
657 | return; |
658 | |
659 | if (query.userType() == qMetaTypeId<QGeoCoordinate>()) { |
660 | if (address_) { |
661 | address_->disconnect(receiver: this); |
662 | address_ = 0; |
663 | } |
664 | searchString_.clear(); |
665 | |
666 | coordinate_ = query.value<QGeoCoordinate>(); |
667 | } else if (query.type() == QVariant::String) { |
668 | searchString_ = query.toString(); |
669 | if (address_) { |
670 | address_->disconnect(receiver: this); |
671 | address_ = 0; |
672 | } |
673 | coordinate_ = QGeoCoordinate(); |
674 | } else if (QObject *object = query.value<QObject *>()) { |
675 | if (QDeclarativeGeoAddress *address = qobject_cast<QDeclarativeGeoAddress *>(object)) { |
676 | if (address_) |
677 | address_->disconnect(receiver: this); |
678 | coordinate_ = QGeoCoordinate(); |
679 | searchString_.clear(); |
680 | |
681 | address_ = address; |
682 | connect(sender: address_, SIGNAL(countryChanged()), receiver: this, SLOT(queryContentChanged())); |
683 | connect(sender: address_, SIGNAL(countryCodeChanged()), receiver: this, SLOT(queryContentChanged())); |
684 | connect(sender: address_, SIGNAL(stateChanged()), receiver: this, SLOT(queryContentChanged())); |
685 | connect(sender: address_, SIGNAL(countyChanged()), receiver: this, SLOT(queryContentChanged())); |
686 | connect(sender: address_, SIGNAL(cityChanged()), receiver: this, SLOT(queryContentChanged())); |
687 | connect(sender: address_, SIGNAL(districtChanged()), receiver: this, SLOT(queryContentChanged())); |
688 | connect(sender: address_, SIGNAL(streetChanged()), receiver: this, SLOT(queryContentChanged())); |
689 | connect(sender: address_, SIGNAL(postalCodeChanged()), receiver: this, SLOT(queryContentChanged())); |
690 | } else { |
691 | qmlWarning(me: this) << QStringLiteral("Unsupported query type for geocode model " ) |
692 | << QStringLiteral("(coordinate, string and Address supported)." ); |
693 | return; |
694 | } |
695 | } else { |
696 | qmlWarning(me: this) << QStringLiteral("Unsupported query type for geocode model " ) |
697 | << QStringLiteral("(coordinate, string and Address supported)." ); |
698 | return; |
699 | } |
700 | |
701 | queryVariant_ = query; |
702 | emit queryChanged(); |
703 | if (autoUpdate_) |
704 | update(); |
705 | } |
706 | |
707 | /*! |
708 | \qmlproperty bool QtLocation::GeocodeModel::autoUpdate |
709 | |
710 | This property controls whether the Model automatically updates in response |
711 | to changes in its attached query. The default value of this property |
712 | is false. |
713 | |
714 | If setting this value to 'true' and using an Address or |
715 | \l {coordinate} as the query, note that any change at all in the |
716 | object's properties will trigger a new request to be sent. If you are adjusting many |
717 | properties of the object whilst autoUpdate is enabled, this can generate large numbers of |
718 | useless (and later discarded) requests. |
719 | */ |
720 | |
721 | bool QDeclarativeGeocodeModel::autoUpdate() const |
722 | { |
723 | return autoUpdate_; |
724 | } |
725 | |
726 | void QDeclarativeGeocodeModel::setAutoUpdate(bool update) |
727 | { |
728 | if (autoUpdate_ == update) |
729 | return; |
730 | autoUpdate_ = update; |
731 | emit autoUpdateChanged(); |
732 | } |
733 | |
734 | QT_END_NAMESPACE |
735 | |