QML Geohelper Plugin
somnathbanik
(Talk | contribs) |
hamishwillee
(Talk | contribs) m (Text replace - "<code cpp>" to "<code cpp-qt>") |
||
| (8 intermediate revisions by 3 users not shown) | |||
| Line 1: | Line 1: | ||
[[Category:Qt]][[Category:Qt Mobility]][[Category:Qt Quick]][[Category:Symbian]] | [[Category:Qt]][[Category:Qt Mobility]][[Category:Qt Quick]][[Category:Symbian]] | ||
| − | + | {{ArticleMetaData <!-- v1.2 --> | |
| − | + | |sourcecode= <!-- Link to example source code (e.g. [[Media:The Code Example ZIP.zip]]) --> | |
| − | {{ | + | |installfile= <!-- Link to installation file (e.g. [[Media:The Installation File.sis]]) --> |
| − | | | + | |devices= N8, E7, C7 |
| − | | | + | |sdk= <!-- SDK(s) built and tested against (e.g. [http://linktosdkdownload/ Nokia Qt SDK 1.1]) --> |
| − | |devices=N8, E7, C7 | + | |platform= Symbian 3 |
| − | | | + | |devicecompatability= <!-- Compatible devices (e.g.: All* (must have GPS) ) --> |
| + | |dependencies= <!-- Any other/external dependencies e.g.: Google Maps Api v1.0 --> | ||
| + | |signing= <!-- Empty or one of Self-Signed, DevCert, Manufacturer --> | ||
| + | |capabilities= <!-- Capabilities required by the article/code example (e.g. Location, NetworkServices. --> | ||
| + | |keywords= QML, Geocoding, Location, Maps, Map objects, JSON stringify | ||
| + | |language= <!-- Language category code for non-English topics - e.g. Lang-Chinese --> | ||
| + | |translated-by= <!-- [[User:XXXX]] --> | ||
| + | |translated-from-title= <!-- Title only --> | ||
| + | |translated-from-id= <!-- Id of translated revision --> | ||
| + | |review-by= <!-- After re-review: [[User:username]] --> | ||
| + | |review-timestamp= <!-- After re-review: YYYYMMDD --> | ||
| + | |update-by= <!-- After significant update: [[User:username]]--> | ||
| + | |update-timestamp= <!-- After significant update: YYYYMMDD --> | ||
| + | |creationdate= 29.04.2011 | ||
| + | |author= [[User:Jahartik]] | ||
| + | <!-- The following are not in current metadata --> | ||
|subcategory= Location | |subcategory= Location | ||
| − | |||
| − | |||
}} | }} | ||
| Line 26: | Line 39: | ||
==Preconditions== | ==Preconditions== | ||
| − | Qt 4.7.1 or newer and Qt mobility 1.1.0 or newer installed | + | [http://qt.nokia.com/downloads Qt SDK ]4.7.1 or newer and [http://qt.nokia.com/products/qt-addons/mobility Qt mobility ]1.1.0 or newer installed |
| + | |||
==Pro file == | ==Pro file == | ||
| Line 32: | Line 46: | ||
The following capabilities and libraries are required: | The following capabilities and libraries are required: | ||
| + | <code cpp-qt> | ||
CAPABILITY: | CAPABILITY: | ||
| − | |||
symbian:TARGET.CAPABILITY = NetworkServices Location ReadUserData WriteUserData | symbian:TARGET.CAPABILITY = NetworkServices Location ReadUserData WriteUserData | ||
| − | |||
CONFIG += mobility | CONFIG += mobility | ||
| − | |||
MOBILITY = location | MOBILITY = location | ||
| + | </code> | ||
==Header file== | ==Header file== | ||
| − | geohelper.h applying this macro to definitions of member functions to allow them to be invoked via the meta-object system | + | '''geohelper.h''' applying this macro to definitions of member functions to allow them to be invoked via the''' meta-object system''' |
| − | <code> | + | <code cpp-qt> |
#ifndef GEOHELPER_H | #ifndef GEOHELPER_H | ||
| Line 139: | Line 152: | ||
geohelper source code | geohelper source code | ||
| − | <code> | + | <code cpp-qt> |
#include "geohelper.h" | #include "geohelper.h" | ||
| Line 560: | Line 573: | ||
To register the C++ type in the QML system with the name GeoHelper include following code in your main.cpp file | To register the C++ type in the QML system with the name GeoHelper include following code in your main.cpp file | ||
| − | <code> | + | <code cpp-qt> |
qmlRegisterType<GeoHelper>("GeoHelper",1,0,"GeoHelper"); | qmlRegisterType<GeoHelper>("GeoHelper",1,0,"GeoHelper"); | ||
</code> | </code> | ||
Import geohelper plugin in QML | Import geohelper plugin in QML | ||
| − | <code> | + | <code cpp-qt> |
import GeoHelper 1.0 | import GeoHelper 1.0 | ||
</code> | </code> | ||
Example use QML | Example use QML | ||
| − | <code> | + | <code cpp-qt> |
GeoHelper { | GeoHelper { | ||
id: geohelper… | id: geohelper… | ||
---- | ---- | ||
| − | + | Geohelper developer APIs | |
| − | + | ||
| + | Constructor and destructor | ||
| + | GeoHelper(QObject *parent = 0); | ||
| + | ~GeoHelper(); | ||
| + | |||
| + | Public slots: | ||
| + | void findRoute(double fromLatitude, double fromLongitude, double toLatitude, double toLongitude); | ||
| + | void findAddress(double latitude, double longitude); | ||
| + | void findCoordinates(QString street, QString city, QString country = QString("FINLAND")); | ||
| + | void clearMap(); | ||
| + | void removeFromMap(QString id); | ||
| + | void drawPolyline(QString id, QString coordinateArr); | ||
| + | void drawImage(QString id, double latitude, double longitude, QString imagepath, int xOffset, int yOffset); | ||
| + | void drawText(QString id, double latitude, double longitude, QString text); | ||
| + | void findObjectsInCoordinates(double latitude, double longitude); | ||
| + | |||
| + | Public signals | ||
| + | void searchError(const QString &error); | ||
| + | void routingError(const QString &error); | ||
| + | void searchReply(const QString &reply); | ||
| + | void routingReply(const QString &reply); | ||
| + | void geomapobjectSelected(QString id, bool selected); | ||
| + | void debugMsg(const QString &reply); | ||
| + | |||
</code> | </code> | ||
Latest revision as of 04:18, 11 October 2012
Article Metadata
Tested with
Compatibility
Article
Contents |
Overview
Geohelper plug-in to expose Qt mobility location geoservice APIs to QML environment
Geohelper source code includes also workaround to manage several map objects: Map object “copy” to construct the map's objects list again. This is because the objects list does not have a method to remove a single object, see method void GeoHelper::removeFromMap(QString id)
This snippet can be self-signed.
Preconditions
Qt SDK 4.7.1 or newer and Qt mobility 1.1.0 or newer installed
Pro file
The following capabilities and libraries are required:
CAPABILITY:
symbian:TARGET.CAPABILITY = NetworkServices Location ReadUserData WriteUserData
CONFIG += mobility
MOBILITY = location
Header file
geohelper.h applying this macro to definitions of member functions to allow them to be invoked via the meta-object system
#ifndef GEOHELPER_H
#define GEOHELPER_H
#include <QObject>
#include <QMap>
#include <QGeoServiceProvider>
#include <QGeoMappingManager>
#include <QGeoSearchManager>
#include <QGeoRoutingManager>
#include <QDeclarativeEngine>
#include <QGeoRouteReply>
#include <QGeoRouteRequest>
#include <QGeoCoordinate>
#include <QDeclarativeItem>
#include <QGeoMapPolylineObject>
#include <QGeoMapPixmapObject>
#include <QGeoMapTextObject>
QTM_USE_NAMESPACE
class GeoHelper : public QObject
{
Q_OBJECT
Q_PROPERTY(QDeclarativeItem* map READ map WRITE setMap)
public:
explicit GeoHelper(QObject *parent = 0);
~GeoHelper();
QDeclarativeItem *map() const {return mapitem; }
void setMap(QDeclarativeItem *map) { mapitem = map; listRef = QDeclarativeListReference(mapitem, "objects");};
Q_INVOKABLE void findRoute(double fromLatitude, double fromLongitude, double toLatitude, double toLongitude);
Q_INVOKABLE void findAddress(double latitude, double longitude);
Q_INVOKABLE void findCoordinates(QString street, QString city, QString country = QString("FINLAND"));
Q_INVOKABLE void clearMap();
Q_INVOKABLE void removeFromMap(QString id);
Q_INVOKABLE void drawPolyline(QString id, QString coordinateArr);
Q_INVOKABLE void drawImage(QString id, double latitude, double longitude, QString imagepath, int xOffset, int yOffset);
Q_INVOKABLE void drawText(QString id, double latitude, double longitude, QString text);
Q_INVOKABLE void findObjectsInCoordinates(double latitude, double longitude);
signals:
void searchError(const QString &error);
void routingError(const QString &error);
void searchReply(const QString &reply);
void routingReply(const QString &reply);
void geomapobjectSelected(QString id, bool selected);
void debugMsg(const QString &reply);
private slots:
void searchErrorSlot(QGeoSearchReply *reply, QGeoSearchReply::Error error, QString errorString = QString());
void searchFinishedSlot(QGeoSearchReply *reply);
void routingErrorSlot(QGeoRouteReply *reply, QGeoRouteReply::Error error, QString errorString);
void routingFinishedSlot(QGeoRouteReply * reply);
private:
QGeoServiceProvider* provider;
QGeoMappingManager* mappingManager;
QGeoSearchManager* searchManager;
QGeoRoutingManager* routingManager;
QDeclarativeContext* context;
QDeclarativeItem* mapitem;
QMap<QString, QGeoMapObject *> mapobjects;
QDeclarativeListReference listRef;
};
#endif // GEOHELPER_H
Source file
geohelper source code
#include "geohelper.h"
#include <QScriptEngine>
#include <QScriptValue>
#include <QScriptValueIterator>
#include <QDeclarativeListReference>
#include <QGeoMapRouteObject>
GeoHelper::GeoHelper(QObject *parent) :
QObject(parent)
{
provider = new QGeoServiceProvider("nokia");
mappingManager = provider->mappingManager();
searchManager = provider->searchManager();
routingManager = provider->routingManager();
mapitem = NULL;
QObject::connect(searchManager, SIGNAL(error(QGeoSearchReply *, QGeoSearchReply::Error, QString)), this, SLOT(searchErrorSlot(QGeoSearchReply *, QGeoSearchReply::Error, QString)));
QObject::connect(searchManager, SIGNAL(finished(QGeoSearchReply*)), this, SLOT(searchFinishedSlot(QGeoSearchReply*)));
QObject::connect(routingManager, SIGNAL(error(QGeoRouteReply*, QGeoRouteReply::Error, QString)), this, SLOT(routingErrorSlot(QGeoRouteReply*, QGeoRouteReply::Error, QString)));
QObject::connect(routingManager, SIGNAL(finished(QGeoRouteReply*)), this, SLOT(routingFinishedSlot(QGeoRouteReply*)));
}
GeoHelper::~GeoHelper()
{
clearMap();
if (provider)
{
delete provider;
provider = NULL;
}
}
void GeoHelper::searchErrorSlot(QGeoSearchReply *reply, QGeoSearchReply::Error error, QString errorString)
{
emit searchError(errorString);
}
void GeoHelper::searchFinishedSlot(QGeoSearchReply *reply)
{
if (reply->error() == QGeoSearchReply::NoError)
{
QScriptEngine scriptEngine;
QScriptValue replyObject = scriptEngine.newArray();
QList<QGeoPlace> places = reply->places();
for (int i = 0; i < places.count(); i++)
{
QScriptValue placeObject = scriptEngine.newObject();
QScriptValue coordinateObject = scriptEngine.newObject();
QGeoCoordinate coordinate = places[i].coordinate();
coordinateObject.setProperty("latitude", QScriptValue(coordinate.latitude()));
coordinateObject.setProperty("longitude", QScriptValue(coordinate.longitude()));
placeObject.setProperty("coordinate", coordinateObject);
QScriptValue addressObject = scriptEngine.newObject();
QGeoAddress address = places[i].address();
if (!address.isEmpty())
{
addressObject.setProperty("country", address.country());
addressObject.setProperty("countryCode", address.countryCode());
addressObject.setProperty("state", address.state());
addressObject.setProperty("county", address.county());
addressObject.setProperty("city", address.city());
addressObject.setProperty("district", address.district());
addressObject.setProperty("street", address.street());
addressObject.setProperty("postcode", address.postcode());
}
placeObject.setProperty("address", addressObject);
replyObject.setProperty(i, placeObject);
}
QScriptValue fun = scriptEngine.evaluate("(function(a) { return JSON.stringify(a); })");
QScriptValueList args;
args << replyObject;
QScriptValue result = fun.call(QScriptValue(), args);
emit searchReply(result.toString());
}
}
void GeoHelper::routingErrorSlot(QGeoRouteReply *reply, QGeoRouteReply::Error error, QString errorString)
{
emit routingError(errorString);
}
void GeoHelper::routingFinishedSlot(QGeoRouteReply * reply)
{
if (reply->error() == QGeoRouteReply::NoError)
{
QScriptEngine scriptEngine;
QScriptValue replyObject = scriptEngine.newArray();
QList<QGeoCoordinate> waypoints = reply->request().waypoints();
double lat1 = 0;
double lon1 = 0;
double lat2 = 0;
double lon2 = 0;
if (waypoints.count() > 0)
{
/*
QString msg = QString("lat %1, lon %2 => lat %3, lon %4").
arg(waypoints.at(0).latitude()).arg(waypoints.at(0).longitude()).
arg(waypoints.at((waypoints.count()-1)).latitude()).arg(waypoints.at((waypoints.count()-1)).longitude());
emit routingError(msg);
*/
lat1 = waypoints.at(0).latitude();
lon1 = waypoints.at(0).longitude();
lat2 = waypoints.at((waypoints.count()-1)).latitude();
lon2 = waypoints.at((waypoints.count()-1)).longitude();
}
for (int i = 0; i < reply->routes().size(); ++i)
{
QScriptValue routeObject = scriptEngine.newObject();
QGeoRoute route = reply->routes().at(i);
routeObject.setProperty("distance", QScriptValue(route.distance()));
routeObject.setProperty("travelTime", QScriptValue(route.travelTime()));
routeObject.setProperty("lat1", QScriptValue(lat1));
routeObject.setProperty("lon1", QScriptValue(lon1));
routeObject.setProperty("lat2", QScriptValue(lat2));
routeObject.setProperty("lon2", QScriptValue(lon2));
QScriptValue pathObject = scriptEngine.newArray();
QList<QGeoCoordinate> path = route.path();
for (int p = 0; p < path.length(); p++)
{
QScriptValue coordinateObject = scriptEngine.newObject();
coordinateObject.setProperty("latitude", QScriptValue(path[p].latitude()));
coordinateObject.setProperty("longitude", QScriptValue(path[p].longitude()));
pathObject.setProperty(p, coordinateObject);
}
routeObject.setProperty("path", pathObject);
replyObject.setProperty(i, routeObject);
}
QScriptValue fun = scriptEngine.evaluate("(function(a) { return JSON.stringify(a); })");
QScriptValueList args;
args << replyObject;
QScriptValue result = fun.call(QScriptValue(), args);
emit routingReply(result.toString());
}
}
// ------------- Q_INVOKABLE METHODS -------
void GeoHelper::removeFromMap(QString id)
{
if (mapobjects.contains(id))
{
QGeoMapObject *obj = mapobjects.take(id);
if (obj != NULL)
{
delete obj;
obj = NULL;
}
// Now we have to construct the map's objects list again
// this is because the objects list does not have a method
// to remove a single object.
for (int i = 0; i < listRef.count(); i++)
listRef.at(i)->deleteLater();
listRef.clear();
QStringList keys = mapobjects.keys();
foreach (QString id, keys)
{
emit debugMsg("lisaa uudestaan " + id);
QGeoMapObject *obj = mapobjects.value(id);
if (obj != NULL)
{
if (obj->type() == QGeoMapObject::PolylineType)
{
QGeoMapPolylineObject *newobj = new QGeoMapPolylineObject;
newobj->setPath(((QGeoMapPolylineObject *)obj)->path());
newobj->setPen(QPen(QBrush(Qt::blue), 4));
newobj->setObjectName(obj->objectName());
listRef.append(newobj);
}
else if (obj->type() == QGeoMapObject::PixmapType)
{
QGeoMapPixmapObject *newobj = new QGeoMapPixmapObject;
newobj->setCoordinate(((QGeoMapPixmapObject *)obj)->coordinate());
newobj->setPixmap(((QGeoMapPixmapObject *)obj)->pixmap());
newobj->setOffset(QPoint(-10,-34));
newobj->setObjectName(obj->objectName());
listRef.append(newobj);
}
}
}
}
}
void GeoHelper::clearMap()
{
QStringList keys = mapobjects.keys();
foreach (QString id, keys)
{
QGeoMapObject *obj = mapobjects.take(id);
if (obj != NULL)
{
delete obj;
obj = NULL;
}
}
mapobjects.clear();
for (int i = 0; i < listRef.count(); i++)
listRef.at(i)->deleteLater();
listRef.clear();
}
void GeoHelper::drawPolyline(QString id, QString coordinateArr)
{
/*
[
{"latitude":61.4735985,"longitude":23.7550697},
{"latitude":61.4735985,"longitude":23.7550697}
]
*/
if (mapitem != NULL)
{
removeFromMap(id);
QScriptValue sc;
QScriptEngine engine;
sc = engine.evaluate("(" + QString(coordinateArr) + ")");
if (sc.isArray())
{
QScriptValueIterator it(sc);
QList<QGeoCoordinate> coordinates;
while (it.hasNext())
{
it.next();
if (it.value().property("latitude").toString() != "" && it.value().property("longitude").toString() != "")
{
coordinates << QGeoCoordinate(it.value().property("latitude").toNumber(),it.value().property("longitude").toNumber());
}
}
QGeoMapPolylineObject *obj = new QGeoMapPolylineObject;
obj->setPath(coordinates);
obj->setPen(QPen(QBrush(Qt::blue), 4));
obj->setObjectName(id);
listRef.append(obj);
// keep a copy to construct the map objects list again
QGeoMapPolylineObject *copyobj = new QGeoMapPolylineObject;
copyobj->setPath(coordinates);
copyobj->setPen(QPen(QBrush(Qt::blue), 4));
copyobj->setObjectName(id);
mapobjects.insert(id,copyobj);
}
}
}
void GeoHelper::drawImage(QString id, double latitude, double longitude, QString imagepath, int xOffset, int yOffset)
{
if (mapitem != NULL)
{
//emit debugMsg(QString("offset: %1, %2").arg(xOffset).arg(yOffset));
removeFromMap(id);
QGeoMapPixmapObject *obj = new QGeoMapPixmapObject;
obj->setCoordinate(QGeoCoordinate(latitude,longitude));
obj->setPixmap(imagepath);
obj->setOffset(QPoint(xOffset,yOffset));
//obj->setOffset(QPoint(-10,-34));
obj->setObjectName(id);
listRef.append(obj);
// keep a copy to construct the map objects list again
QGeoMapPixmapObject *copyobj = new QGeoMapPixmapObject;
copyobj->setCoordinate(QGeoCoordinate(latitude,longitude));
copyobj->setPixmap(imagepath);
copyobj->setOffset(QPoint(xOffset,yOffset));
//copyobj->setOffset(QPoint(-10,-34));
copyobj->setObjectName(id);
mapobjects.insert(id,copyobj);
}
}
QBrush usebrush(Qt::darkRed);
QPen usepen(usebrush,1);
QFont usefont("Terminal", 12);
void GeoHelper::drawText(QString id, double latitude, double longitude, QString text)
{
if (mapitem != NULL)
{
//emit debugMsg(QString("offset: %1, %2").arg(xOffset).arg(yOffset));
removeFromMap(id);
QGeoMapTextObject *obj = new QGeoMapTextObject;
obj->setCoordinate(QGeoCoordinate(latitude,longitude));
obj->setText(text);
obj->setFont(usefont);
obj->setOffset(QPoint(20,-10));
obj->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
obj->setBrush(usebrush);
obj->setPen(usepen);
obj->setObjectName(id);
listRef.append(obj);
// keep a copy to construct the map objects list again
QGeoMapTextObject *copyobj = new QGeoMapTextObject;
copyobj->setCoordinate(QGeoCoordinate(latitude,longitude));
copyobj->setText(text);
copyobj->setFont(usefont);
copyobj->setOffset(QPoint(20,-10));
copyobj->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
copyobj->setBrush(usebrush);
copyobj->setPen(usepen);
copyobj->setObjectName(id);
mapobjects.insert(id,copyobj);
}
}
void GeoHelper::findObjectsInCoordinates(double latitude, double longitude)
{
QGeoCoordinate coord(latitude, longitude);
for (int i = 0; i < listRef.count(); i++)
{
if ( ((QGeoMapObject *)listRef.at(i))->contains(coord))
{
emit geomapobjectSelected(listRef.at(i)->objectName(), true);
}
}
}
void GeoHelper::findRoute(double fromLatitude, double fromLongitude, double toLatitude, double toLongitude)
{
QGeoRouteRequest *geoRouteRequest = new QGeoRouteRequest(QGeoCoordinate(fromLatitude, fromLongitude), QGeoCoordinate(toLatitude, toLongitude));
routingManager->calculateRoute(*geoRouteRequest);
}
void GeoHelper::findAddress(double latitude, double longitude)
{
QGeoCoordinate location(latitude,longitude);
searchManager->reverseGeocode(location);
}
void GeoHelper::findCoordinates(QString street, QString city, QString country)
{
/*
NOTE! This geocode method is not capable to handle the number of the street address.
But the use of the plain search alternative seems to work.
QGeoAddress address;
address.setStreet(street);
address.setCity(city);
address.setCountry(country);
searchManager->geocode(address);
*/
QString str = QString("%1,%2,%3").arg(street).arg(city).arg(country);
searchManager->search(str, QGeoSearchManager::SearchGeocode);
}
To register the C++ type in the QML system with the name GeoHelper include following code in your main.cpp file
qmlRegisterType<GeoHelper>("GeoHelper",1,0,"GeoHelper");
Import geohelper plugin in QML
import GeoHelper 1.0Example use QML
GeoHelper {
id: geohelper…
----
Geohelper developer APIs
Constructor and destructor
GeoHelper(QObject *parent = 0);
~GeoHelper();
Public slots:
void findRoute(double fromLatitude, double fromLongitude, double toLatitude, double toLongitude);
void findAddress(double latitude, double longitude);
void findCoordinates(QString street, QString city, QString country = QString("FINLAND"));
void clearMap();
void removeFromMap(QString id);
void drawPolyline(QString id, QString coordinateArr);
void drawImage(QString id, double latitude, double longitude, QString imagepath, int xOffset, int yOffset);
void drawText(QString id, double latitude, double longitude, QString text);
void findObjectsInCoordinates(double latitude, double longitude);
Public signals
void searchError(const QString &error);
void routingError(const QString &error);
void searchReply(const QString &reply);
void routingReply(const QString &reply);
void geomapobjectSelected(QString id, bool selected);
void debugMsg(const QString &reply);

