diff options
Diffstat (limited to 'src/imports/location/qdeclarativegeocodemodel.cpp')
-rw-r--r-- | src/imports/location/qdeclarativegeocodemodel.cpp | 364 |
1 files changed, 312 insertions, 52 deletions
diff --git a/src/imports/location/qdeclarativegeocodemodel.cpp b/src/imports/location/qdeclarativegeocodemodel.cpp index 2f91f48b..5cb579e8 100644 --- a/src/imports/location/qdeclarativegeocodemodel.cpp +++ b/src/imports/location/qdeclarativegeocodemodel.cpp @@ -7,29 +7,29 @@ ** This file is part of the Qt Mobility Components. ** ** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** ** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception +** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** ** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. ** ** ** @@ -41,82 +41,342 @@ #include "qdeclarativegeocodemodel_p.h" +#include "qdeclarativegeoplace_p.h" +#include <QtDeclarative/qdeclarativeinfo.h> + +#include <qgeoserviceprovider.h> #include <qgeosearchmanager.h> QTM_BEGIN_NAMESPACE -QDeclarativeGeocodeModel::QDeclarativeGeocodeModel(QObject *parent) - : QDeclarativeGeoSearchModel(parent), - complete_(false) {} +QDeclarativeGeocodeModel::QDeclarativeGeocodeModel(QObject* parent) + : QAbstractListModel(parent), + autoUpdate_(false), + complete_(false), + reply_(0), + plugin_(0), + serviceProvider_(0), + searchManager_(0), + boundingArea_(0), + status_(QDeclarativeGeocodeModel::Null), + coordinate_(0), + address_(0) +{ + QHash<int, QByteArray> roleNames; + roleNames = QAbstractItemModel::roleNames(); + roleNames.insert(PlaceRole, "place"); + setRoleNames(roleNames); +} + +QDeclarativeGeocodeModel::~QDeclarativeGeocodeModel() +{ + if (serviceProvider_) + delete serviceProvider_; + qDeleteAll(declarativePlaces_); + declarativePlaces_.clear(); + if (reply_) + delete reply_; +} + +// From QDeclarativeParserStatus +void QDeclarativeGeocodeModel::componentComplete() +{ + complete_ = true; + if (autoUpdate_) + update(); +} -QDeclarativeGeocodeModel::~QDeclarativeGeocodeModel() {} +QGeoBoundingArea* QDeclarativeGeocodeModel::boundingArea() +{ + if (qobject_cast<QDeclarativeGeoBoundingBox*>(boundingArea_) && boundingBox_.isValid()) { + return &boundingBox_; + } else if (qobject_cast<QDeclarativeGeoBoundingCircle*>(boundingArea_) && boundingCircle_.isValid()) { + return &boundingCircle_; + } + return 0; +} -void QDeclarativeGeocodeModel::setAddress(QDeclarativeGeoAddress *address) +void QDeclarativeGeocodeModel::update() { - if (address_.address() == address->address()) + if (!complete_) + return; + if (!searchManager_) { + qmlInfo(this) << tr("Cannot geocode, search manager (/plugin) not set."); + return; + } + if ((!coordinate_ || !coordinate_->coordinate().isValid()) && + (!address_ || address_->address().isEmpty())) { + qmlInfo(this) << tr("Cannot geocode, valid query not set."); return; + } + abortRequest(); // abort possible previous requests + setError(""); // clear previous error string - address_.setAddress(address->address()); + if (coordinate_) { + setStatus(QDeclarativeGeocodeModel::Loading); + reply_ = searchManager_->reverseGeocode( + coordinate_->coordinate(), + boundingArea()); + if (reply_->isFinished()) { + if (reply_->error() == QGeoSearchReply::NoError) { + searchFinished(reply_); + } else { + searchError(reply_, reply_->error(), reply_->errorString()); + } + } + } else if (address_) { + setStatus(QDeclarativeGeocodeModel::Loading); + reply_ = searchManager_->geocode( + address_->address(), + boundingArea()); + if (reply_->isFinished()) { + if (reply_->error() == QGeoSearchReply::NoError) { + searchFinished(reply_); + } else { + searchError(reply_, reply_->error(), reply_->errorString()); + } + } + } +} - emit addressChanged(&address_); +void QDeclarativeGeocodeModel::abortRequest() +{ + if (reply_) { + reply_->abort(); + reply_->deleteLater(); + reply_ = 0; + } +} - if (complete_) +void QDeclarativeGeocodeModel::queryContentChanged() +{ + if (autoUpdate_) update(); } -QDeclarativeGeoAddress* QDeclarativeGeocodeModel::address() +// From QAbstractListModel +int QDeclarativeGeocodeModel::rowCount(const QModelIndex &parent) const { - return &address_; + Q_UNUSED(parent) + return declarativePlaces_.count(); } -void QDeclarativeGeocodeModel::componentComplete() +QVariant QDeclarativeGeocodeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + if (index.row() >= declarativePlaces_.count()) + return QVariant(); + if (role == QDeclarativeGeocodeModel::PlaceRole) { + QObject* placeObject = declarativePlaces_.at(index.row()); + Q_ASSERT(placeObject); + return QVariant::fromValue(placeObject); + } + return QVariant(); +} + +void QDeclarativeGeocodeModel::setPlugin(QDeclarativeGeoServiceProvider *plugin) { - if (!searchManager()) + if (plugin_ == plugin) return; + reset(); // reset the model + plugin_ = plugin; + if (complete_) + emit pluginChanged(); + serviceProvider_ = new QGeoServiceProvider(plugin_->name(), + plugin_->parameterMap()); + searchManager_ = serviceProvider_->searchManager(); + if (!searchManager_ || serviceProvider_->error() != QGeoServiceProvider::NoError) { + qmlInfo(this) << tr("Warning: Plugin does not support (reverse) geocoding."); + searchManager_ = 0; + return; + } + connect(searchManager_, + SIGNAL(finished(QGeoSearchReply*)), + this, + SLOT(searchFinished(QGeoSearchReply*))); + connect(searchManager_, + SIGNAL(error(QGeoSearchReply*, QGeoSearchReply::Error, QString)), + this, + SLOT(searchError(QGeoSearchReply*, QGeoSearchReply::Error, QString))); +} - complete_ = true; - update(); +QDeclarativeGeoServiceProvider* QDeclarativeGeocodeModel::plugin() const +{ + return plugin_; } -void QDeclarativeGeocodeModel::update() +void QDeclarativeGeocodeModel::setBounds(QObject* bounds) { - if (searchManager() && !address_.address().isEmpty()) { + if (boundingArea_ == bounds) + return; + if (qobject_cast<QDeclarativeGeoBoundingBox*>(bounds)) { + boundingBox_ = qobject_cast<QDeclarativeGeoBoundingBox*>(bounds)->box(); + } else if (qobject_cast<QDeclarativeGeoBoundingCircle*>(bounds)) { + boundingCircle_ = qobject_cast<QDeclarativeGeoBoundingCircle*>(bounds)->circle(); + } else { + qmlInfo(this) << tr("Unsupported bound type (Box and Circle supported)"); + return; + } + boundingArea_ = bounds; + emit boundsChanged(); +} + +QObject* QDeclarativeGeocodeModel::bounds() const +{ + return boundingArea_; +} + +void QDeclarativeGeocodeModel::searchFinished(QGeoSearchReply *reply) +{ + if (reply->error() != QGeoSearchReply::NoError) { + return; + } + int oldCount = declarativePlaces_.count(); + setPlaces(reply->places()); + setError(""); + setStatus(QDeclarativeGeocodeModel::Ready); + reply->deleteLater(); + reply_ = 0; + emit placesChanged(); + if (oldCount != declarativePlaces_.count()) + emit countChanged(); +} + +void QDeclarativeGeocodeModel::searchError(QGeoSearchReply *reply, + QGeoSearchReply::Error error, + const QString &errorString) +{ + Q_UNUSED(error); + setError(errorString); + setStatus(QDeclarativeGeocodeModel::Error); + reply->deleteLater(); + reply_ = 0; +} - setStatus(QDeclarativeGeoSearchModel::Loading); +QDeclarativeGeocodeModel::Status QDeclarativeGeocodeModel::status() const +{ + return status_; +} + +void QDeclarativeGeocodeModel::setStatus(QDeclarativeGeocodeModel::Status status) +{ + if (status_ == status) + return; + status_ = status; + emit statusChanged(); +} - searchManager()->geocode(address_.address()); +QString QDeclarativeGeocodeModel::error() const +{ + return error_; +} + +void QDeclarativeGeocodeModel::setError(const QString &error) +{ + if (error_ == error) + return; + error_ = error; + emit errorChanged(); +} - // TODO check for finished +void QDeclarativeGeocodeModel::setPlaces(const QList<QGeoPlace> &places) +{ + beginResetModel(); + qDeleteAll(declarativePlaces_); + declarativePlaces_.clear(); + for (int i = 0; i < places.count(); ++i) { + QDeclarativeGeoPlace* place = new QDeclarativeGeoPlace(places.at(i), this); + declarativePlaces_.append(place); } + endResetModel(); } -QVariant QDeclarativeGeocodeModel::data(const QModelIndex &index, int role) const +int QDeclarativeGeocodeModel::count() const { - if (!index.isValid()) - return QVariant(); + return declarativePlaces_.count(); +} - if (index.row() > places().count()) - return QVariant(); +Q_INVOKABLE QDeclarativeGeoPlace* QDeclarativeGeocodeModel::get(int index) +{ + if (index < 0 || index >= declarativePlaces_.count()) { + qmlInfo(this) << tr("Error, too big or small index in get(): ") << index; + return 0; + } + return declarativePlaces_.at(index); +} - QGeoPlace place = places().at(index.row()); +Q_INVOKABLE void QDeclarativeGeocodeModel::clear() +{ + setPlaces(QList<QGeoPlace>()); +} - if (role == Qt::DisplayRole) - return place.coordinate().toString(); +Q_INVOKABLE void QDeclarativeGeocodeModel::reset() +{ + clear(); + abortRequest(); + setError(""); + setStatus(QDeclarativeGeocodeModel::Null); +} - return QDeclarativeGeoSearchModel::data(index, role); +QVariant QDeclarativeGeocodeModel::query() const +{ + return queryVariant_; } -QVariant QDeclarativeGeocodeModel::headerData(int section, Qt::Orientation orientation, int role) const +void QDeclarativeGeocodeModel::setQuery(const QVariant& query) { - if (section != 0) - return QVariant(); + if (query == queryVariant_) + return; + QObject* object = qvariant_cast<QObject*>(query); + if (qobject_cast<QDeclarativeCoordinate*>(object)) { + if (coordinate_) + coordinate_->disconnect(this); + if (address_) + address_->disconnect(this); + coordinate_ = qobject_cast<QDeclarativeCoordinate*>(object); + address_ = 0; + connect(coordinate_, SIGNAL(latitudeChanged(double)), this, SLOT(queryContentChanged())); + connect(coordinate_, SIGNAL(longitudeChanged(double)), this, SLOT(queryContentChanged())); + connect(coordinate_, SIGNAL(altitudeChanged(double)), this, SLOT(queryContentChanged())); + } else if (qobject_cast<QDeclarativeGeoAddress*>(object)) { + if (address_) + address_->disconnect(this); + if (coordinate_) + coordinate_->disconnect(this); + address_ = qobject_cast<QDeclarativeGeoAddress*>(object); + connect(address_, SIGNAL(countryChanged()), this, SLOT(queryContentChanged())); + connect(address_, SIGNAL(countryCodeChanged()), this, SLOT(queryContentChanged())); + connect(address_, SIGNAL(stateChanged()), this, SLOT(queryContentChanged())); + connect(address_, SIGNAL(countyChanged()), this, SLOT(queryContentChanged())); + connect(address_, SIGNAL(cityChanged()), this, SLOT(queryContentChanged())); + connect(address_, SIGNAL(districtChanged()), this, SLOT(queryContentChanged())); + connect(address_, SIGNAL(streetChanged()), this, SLOT(queryContentChanged())); + connect(address_, SIGNAL(postcodeChanged()), this, SLOT(queryContentChanged())); + coordinate_ = 0; + } else { + qmlInfo(this) << tr("Unsupported query type for geocode model (Coordinate and Address supported)."); + return; + } + queryVariant_ = query; + emit queryChanged(); + if (autoUpdate_) + update(); +} - if (role == Qt::DisplayRole) - return QString("Coordinate"); - return QDeclarativeGeoSearchModel::headerData(section, orientation, role); +bool QDeclarativeGeocodeModel::autoUpdate() const +{ + return autoUpdate_; } +void QDeclarativeGeocodeModel::setAutoUpdate(bool update) +{ + if (autoUpdate_ == update) + return; + autoUpdate_ = update; + emit autoUpdateChanged(); +} #include "moc_qdeclarativegeocodemodel_p.cpp" |