| 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 |  |