×
Namespaces

Variants
Actions
(Difference between revisions)

QML Geohelper Plugin

From Nokia Developer Wiki
Jump to: navigation, search
jahartik (Talk | contribs)
(Created page with 'Category:Qt MobilityCategory:Qt Quick __NOTOC__ __NOEDITSECTION__ {{CodeSnippet |id=... |platform=... |devices=... |category=... |subcategory=... |creationdate=... |keywo…')
 
hamishwillee (Talk | contribs)
m (Text replace - "<code cpp>" to "<code cpp-qt>")
 
(23 intermediate revisions by 4 users not shown)
Line 1: Line 1:
[[Category:Qt Mobility]][[Category:Qt Quick]]
+
[[Category:Qt]][[Category:Qt Mobility]][[Category:Qt Quick]][[Category:Symbian]]
__NOTOC__
+
{{ArticleMetaData <!-- v1.2 -->
__NOEDITSECTION__
+
|sourcecode= <!-- Link to example source code (e.g. [[Media:The Code Example ZIP.zip]]) -->
{{CodeSnippet
+
|installfile= <!-- Link to installation file (e.g. [[Media:The Installation File.sis]]) -->
|id=...
+
|devices= N8, E7, C7
|platform=...
+
|sdk= <!-- SDK(s) built and tested against (e.g. [http://linktosdkdownload/ Nokia Qt SDK 1.1]) -->
|devices=...
+
|platform= Symbian 3
|category=...
+
|devicecompatability= <!-- Compatible devices (e.g.: All* (must have GPS) ) -->
|subcategory=...
+
|dependencies= <!-- Any other/external dependencies e.g.: Google Maps Api v1.0 -->
|creationdate=...
+
|signing= <!-- Empty or one of Self-Signed, DevCert, Manufacturer -->
|keywords=...
+
|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
 
}}
 
}}
  
Line 15: Line 28:
  
  
''Delete the guidance text written in italics.''
 
  
 
==Overview==
 
==Overview==
  
{{Abstract|An abstract (line or paragraph) describing very briefly what the article delivers - for example "This article defines the standard boilerplate text for a new code example"}}
+
{{Abstract|Geohelper plug-in to expose Qt mobility location geoservice APIs to QML environment}}
  
''Delete the texts that do not apply.''
+
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 {{Icode|void GeoHelper::removeFromMap(QString id)}}
  
 
This snippet can be self-signed.
 
This snippet can be self-signed.
  
[or]
+
==Preconditions==
  
This snippet requires XXX capabilities. Self-signing is not possible because a Developer Certificate is needed.
+
[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
  
[or]
 
  
This snippets requires XXX capabilities. Self-signing is not possible because a Developer Certificate, Publisher ID, and device manufacturer approval are required.
+
==Pro file ==
  
 +
The following capabilities and libraries are required:
  
==Preconditions==
+
<code cpp-qt>
 +
CAPABILITY:
 +
symbian:TARGET.CAPABILITY = NetworkServices Location ReadUserData WriteUserData
 +
CONFIG += mobility
 +
MOBILITY = location
 +
</code>
  
''In complex cases you may need to provide information on the framework needed in order to implement and use the code snippet. For example, a Bluetooth connection must be established in order to use the code snippet "send a file via Bluetooth OBEX". You can refer to an already existing code example.''
+
==Header file==
  
 +
'''geohelper.h''' applying this macro to definitions of member functions to allow them to be invoked via the''' meta-object system'''
  
==MMP file (optional)==
+
<code cpp-qt>
  
The following capabilities and libraries are required:
+
#ifndef GEOHELPER_H
 +
#define GEOHELPER_H
  
CAPABILITY     
+
#include <QObject>
 +
#include <QMap>
  
 +
#include <QGeoServiceProvider>
 +
#include <QGeoMappingManager>
 +
#include <QGeoSearchManager>
 +
#include <QGeoRoutingManager>
  
LIBRARY         
+
#include <QDeclarativeEngine>
 +
#include <QGeoRouteReply>
 +
#include <QGeoRouteRequest>
  
LIBRARY        
+
#include <QGeoCoordinate>
  
<code> code </code>  
+
#include <QDeclarativeItem>
 +
#include <QGeoMapPolylineObject>
 +
#include <QGeoMapPixmapObject>
 +
#include <QGeoMapTextObject>
  
==Header file==
 
  
''Not the complete file but relevant code blocks.''
+
QTM_USE_NAMESPACE
  
<code> code </code>  
+
 
 +
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
 +
 
 +
</code>  
  
  
 
==Source file==
 
==Source file==
  
''Not the complete file but relevant code blocks.''
+
geohelper source code  
 +
 
 +
<code cpp-qt>
 +
#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);
 +
}
  
''You do not need to provide complete error handling but it should be commented as TODO for developers.''
+
</code>
  
<code> code </code>
+
To register the C++ type in the QML system with the name GeoHelper include following code in your main.cpp file
  
 +
<code cpp-qt>
 +
qmlRegisterType<GeoHelper>("GeoHelper",1,0,"GeoHelper");
 +
</code>
  
==Postconditions==
+
Import geohelper plugin in QML
 +
<code cpp-qt>
 +
import GeoHelper 1.0
 +
</code>
  
''Explain what the code snippet is expected to do.''
+
Example use QML
 +
<code cpp-qt>
 +
GeoHelper {
 +
id: geohelper…
 +
----
 +
Geohelper developer APIs
  
 +
Constructor and destructor
 +
GeoHelper(QObject *parent = 0);
 +
~GeoHelper();
  
==Test application and other attachments (optional)==
+
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);
  
''The attachments should be provided with the visible info page (Categories need to be defined, the attached file must be uploaded to Wiki, and internal Wiki links must be used). Every attachment should have its own page (however, a ZIP package can be used for multiple source code files).''
+
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);
  
[[Category:Code Examples]]
+
</code>

Latest revision as of 04:18, 11 October 2012

Article Metadata
Tested with
Devices(s): N8, E7, C7
Compatibility
Platform(s): Symbian 3
Symbian
Article
Keywords: QML, Geocoding, Location, Maps, Map objects, JSON stringify
Created: jahartik (29 Apr 2011)
Last edited: hamishwillee (11 Oct 2012)



Contents

[edit] 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.

[edit] Preconditions

Qt SDK 4.7.1 or newer and Qt mobility 1.1.0 or newer installed


[edit] Pro file

The following capabilities and libraries are required:

CAPABILITY: 
symbian:TARGET.CAPABILITY = NetworkServices Location ReadUserData WriteUserData
CONFIG += mobility
MOBILITY = location

[edit] 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


[edit] 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.0

Example 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);
This page was last modified on 11 October 2012, at 04:18.
81 page views in the last 30 days.
×