Sophie

Sophie

distrib > Mageia > 5 > i586 > media > core-release > by-pkgid > 50facae208d4a6f280e44a513b104320 > files > 1935

qt-mobility-doc-1.2.0-13.mga5.noarch.rpm

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- mapsdemo.qdoc -->
  <title>Qt Mobility 1.2: Part 2 - Searching for locations</title>
  <link rel="stylesheet" type="text/css" href="style/offline.css" />
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="content"> 
    <a href="index.html" class="qtref"><span>QtMobility Reference Documentation</span></a>
  </div>
  <div class="breadcrumb toolblock">
    <ul>
      <li class="first"><a href="index.html">Home</a></li>
      <!--  Breadcrumbs go here -->
<li>Part 2 - Searching for locations</li>
    </ul>
  </div>
</div>
<div class="content mainContent">
  <link rel="prev" href="tutorials-mapsdemo-part1.html" />
  <link rel="next" href="tutorials-mapsdemo-part3.html" />
  <link rel="start" href="tutorials-mapsdemo.html" />
<p class="naviNextPrevious headerNavi">
<a class="prevPage" href="tutorials-mapsdemo-part1.html">Part 1 - The Map Widget</a>
<a class="nextPage" href="tutorials-mapsdemo-part3.html">Part 3 - Listening to satellites</a>
</p><p/>
<div class="toc">
<h3><a name="toc">Contents</a></h3>
<ul>
<li class="level2"><a href="#search-classes">Search classes</a></li>
<li class="level2"><a href="#gui-with-search-dialog">GUI with search dialog</a></li>
<li class="level2"><a href="#adding-details-to-search-markers">Adding details to search markers</a></li>
<li class="level2"><a href="#limiting-search-area">Limiting search area</a></li>
<li class="level2"><a href="#reverse-geocode">Reverse geocode</a></li>
</ul>
</div>
<h1 class="title">Part 2 - Searching for locations</h1>
<span class="subtitle"></span>
<!-- $$$tutorials-mapsdemo-part2.html-description -->
<div class="descr"> <a name="details"></a>
<p>Now that we have a basic map widget, we want to add the capability to search for addresses and locations and create markers for them on the map.</p>
<a name="search-classes"></a>
<h3>Search classes</h3>
<p>Searching in the Location API is handled by use of the <a href="qgeosearchmanager.html">QGeoSearchManager</a>, which we obtain in similar fashion to the MappingManager (in main() in part 1). As we want to create markers for search results and then be able to remove them for the next search (or perhaps other operations), we need some way to organise collections of markers.</p>
<p>To do this, we introduce a new class, MarkerManager:</p>
<pre class="cpp"> <span class="keyword">class</span> MarkerManagerPrivate;
 <span class="keyword">class</span> MarkerManager : <span class="keyword">public</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qobject.html">QObject</a></span>
 {
     Q_OBJECT
 <span class="keyword">public</span>:
     <span class="keyword">explicit</span> MarkerManager(<span class="type"><a href="qgeosearchmanager.html">QGeoSearchManager</a></span> <span class="operator">*</span>sm<span class="operator">,</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qobject.html">QObject</a></span> <span class="operator">*</span>parent<span class="operator">=</span><span class="number">0</span>);
     <span class="operator">~</span>MarkerManager();

 <span class="keyword">public</span> <span class="keyword">slots</span>:
     <span class="type">void</span> setMap(<span class="type"><a href="qgraphicsgeomap.html">QGraphicsGeoMap</a></span> <span class="operator">*</span>map);
     <span class="type">void</span> setMyLocation(<span class="type"><a href="qgeocoordinate.html">QGeoCoordinate</a></span> coord);
     <span class="type">void</span> search(<span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span> query);
     <span class="type">void</span> removeSearchMarkers();

 <span class="keyword">signals</span>:
     <span class="type">void</span> searchError(<span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span><span class="operator">::</span>Error error<span class="operator">,</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span> errorString);
     <span class="type">void</span> searchFinished();

 <span class="keyword">private</span>:
     MarkerManagerPrivate <span class="operator">*</span>d;

 <span class="keyword">private</span> <span class="keyword">slots</span>:
     <span class="type">void</span> replyFinished(<span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span> <span class="operator">*</span>reply);
 };</pre>
<p>The MarkerManager tracks both the &quot;My Location&quot; marker and a list of search result markers. Implementing the My Location portion is nothing new:</p>
<pre class="cpp"> <span class="keyword">class</span> MarkerManagerPrivate
 {
 <span class="keyword">public</span>:
     Marker <span class="operator">*</span>myLocation;
     <span class="type"><a href="http://qt.nokia.com/doc/4.7/qlist.html">QList</a></span><span class="operator">&lt;</span>Marker<span class="operator">*</span><span class="operator">&gt;</span> searchMarkers;

     <span class="type"><a href="qgraphicsgeomap.html">QGraphicsGeoMap</a></span> <span class="operator">*</span>map;
     <span class="type"><a href="qgeosearchmanager.html">QGeoSearchManager</a></span> <span class="operator">*</span>searchManager;

     <span class="type"><a href="http://qt.nokia.com/doc/4.7/qset.html">QSet</a></span><span class="operator">&lt;</span><span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span><span class="operator">*</span><span class="operator">&gt;</span> forwardReplies;
 };

 MarkerManager<span class="operator">::</span>MarkerManager(<span class="type"><a href="qgeosearchmanager.html">QGeoSearchManager</a></span> <span class="operator">*</span>searchManager<span class="operator">,</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qobject.html">QObject</a></span> <span class="operator">*</span>parent) :
     <span class="type"><a href="http://qt.nokia.com/doc/4.7/qobject.html">QObject</a></span>(parent)<span class="operator">,</span>
     d(<span class="keyword">new</span> MarkerManagerPrivate)
 {
     d<span class="operator">-</span><span class="operator">&gt;</span>myLocation <span class="operator">=</span> <span class="keyword">new</span> Marker(Marker<span class="operator">::</span>MyLocationMarker);
     d<span class="operator">-</span><span class="operator">&gt;</span>searchManager <span class="operator">=</span> searchManager;
 }

 MarkerManager<span class="operator">::</span><span class="operator">~</span>MarkerManager()
 {
     <span class="keyword">if</span> (d<span class="operator">-</span><span class="operator">&gt;</span>map)
         d<span class="operator">-</span><span class="operator">&gt;</span>map<span class="operator">-</span><span class="operator">&gt;</span>removeMapObject(m_myLocation);
     <span class="keyword">delete</span> d<span class="operator">-</span><span class="operator">&gt;</span>myLocation;
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 }

 <span class="type">void</span> MarkerManager<span class="operator">::</span>setMap(<span class="type"><a href="qgraphicsgeomap.html">QGraphicsGeoMap</a></span> <span class="operator">*</span>map)
 {
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
     d<span class="operator">-</span><span class="operator">&gt;</span>map <span class="operator">=</span> map;
     d<span class="operator">-</span><span class="operator">&gt;</span>map<span class="operator">-</span><span class="operator">&gt;</span>addMapObject(d<span class="operator">-</span><span class="operator">&gt;</span>myLocation);
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 }

 <span class="type">void</span> MarkerManager<span class="operator">::</span>setMyLocation(<span class="type"><a href="qgeocoordinate.html">QGeoCoordinate</a></span> coord)
 {
     d<span class="operator">-</span><span class="operator">&gt;</span>myLocation<span class="operator">-</span><span class="operator">&gt;</span>setCoordinate(coord);
 }</pre>
<p>To implement searching, we call the QGeoSearchManager::search method, which returns a <a href="qgeosearchreply.html">QGeoSearchReply</a>. This reply object emits a signal finished() when the search results are available. It can also be constructed already finished, and we need to check for this first before connecting the signals.</p>
<p>We make use of the searchManager's version of the <i>finished()</i> signal, as it gives out the necessary <a href="qgeosearchreply.html">QGeoSearchReply</a>* parameter so that we can have one slot to handle both the case where the reply is constructed already finished, and the case where the signal fires later.</p>
<pre class="cpp"> MarkerManager<span class="operator">::</span>MarkerManager(<span class="type"><a href="qgeosearchmanager.html">QGeoSearchManager</a></span> <span class="operator">*</span>searchManager<span class="operator">,</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qobject.html">QObject</a></span> <span class="operator">*</span>parent) :
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 {
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
     connect(d<span class="operator">-</span><span class="operator">&gt;</span>searchManager<span class="operator">,</span> SIGNAL(finished(<span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span><span class="operator">*</span>))<span class="operator">,</span>
             <span class="keyword">this</span><span class="operator">,</span> SLOT(replyFinished(<span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span><span class="operator">*</span>)));
 }

 <span class="type">void</span> MarkerManager<span class="operator">::</span>search(<span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span> query)
 {
     <span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span> <span class="operator">*</span>reply <span class="operator">=</span> d<span class="operator">-</span><span class="operator">&gt;</span>searchManager<span class="operator">-</span><span class="operator">&gt;</span>search(query);

     d<span class="operator">-</span><span class="operator">&gt;</span>forwardReplies<span class="operator">.</span>insert(reply);
     <span class="keyword">if</span> (reply<span class="operator">-</span><span class="operator">&gt;</span>isFinished()) {
         replyFinished(reply);
     } <span class="keyword">else</span> {
         connect(reply<span class="operator">,</span> SIGNAL(error(<span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span><span class="operator">::</span>Error<span class="operator">,</span><span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span>))<span class="operator">,</span>
                 <span class="keyword">this</span><span class="operator">,</span> SIGNAL(searchError(<span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span><span class="operator">::</span>Error<span class="operator">,</span><span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span>)));
     }
 }</pre>
<p>The <a href="qgeosearchreply.html">QGeoSearchReply</a> yields its results as a list of <a href="qgeoplace.html">QGeoPlace</a> instances. While these hold quite a bit of information, for now we'll just be using them for their coordinates.</p>
<pre class="cpp"> <span class="type">void</span> MarkerManager<span class="operator">::</span>replyFinished(<span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span> <span class="operator">*</span>reply)
 {
     <span class="keyword">if</span> (<span class="operator">!</span>d<span class="operator">-</span><span class="operator">&gt;</span>forwardReplies<span class="operator">.</span>contains(reply))
         <span class="keyword">return</span>;

     <span class="comment">// generate the markers and add them to the map</span>
     foreach (<span class="type"><a href="qgeoplace.html">QGeoPlace</a></span> place<span class="operator">,</span> reply<span class="operator">-</span><span class="operator">&gt;</span>places()) {
         Marker <span class="operator">*</span>m <span class="operator">=</span> <span class="keyword">new</span> Marker(Marker<span class="operator">::</span>SearchMarker);
         m<span class="operator">-</span><span class="operator">&gt;</span>setCoordinate(place<span class="operator">.</span>coordinate());
         d<span class="operator">-</span><span class="operator">&gt;</span>searchMarkers<span class="operator">.</span>append(m);

         <span class="keyword">if</span> (d<span class="operator">-</span><span class="operator">&gt;</span>map) {
             d<span class="operator">-</span><span class="operator">&gt;</span>map<span class="operator">-</span><span class="operator">&gt;</span>addMapObject(m);
             <span class="comment">// also zoom out until marker is visible</span>
             <span class="keyword">while</span> (<span class="operator">!</span>d<span class="operator">-</span><span class="operator">&gt;</span>map<span class="operator">-</span><span class="operator">&gt;</span>viewport()<span class="operator">.</span>contains(place<span class="operator">.</span>coordinate()))
                 d<span class="operator">-</span><span class="operator">&gt;</span>map<span class="operator">-</span><span class="operator">&gt;</span>setZoomLevel(d<span class="operator">-</span><span class="operator">&gt;</span>map<span class="operator">-</span><span class="operator">&gt;</span>zoomLevel()<span class="operator">-</span><span class="number">1</span>);
         }
     }

     d<span class="operator">-</span><span class="operator">&gt;</span>forwardReplies<span class="operator">.</span>remove(reply);
     reply<span class="operator">-</span><span class="operator">&gt;</span>deleteLater();

     <span class="keyword">emit</span> searchFinished();
 }</pre>
<p>Next, we add two methods to MapsWidget to keep track of a MarkerManager instance associated with its map:</p>
<pre class="cpp"> <span class="keyword">class</span> MapsWidget : <span class="keyword">public</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qwidget.html">QWidget</a></span>
 {
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 <span class="keyword">public</span>:
     <span class="type">void</span> setMarkerManager(MarkerManager <span class="operator">*</span>markerManager);
     MarkerManager <span class="operator">*</span>markerManager() <span class="keyword">const</span>;

     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 };

 <span class="keyword">class</span> MapsWidgetPrivate
 {
 <span class="keyword">public</span>:
     MarkerManager <span class="operator">*</span>markerManager;
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 };</pre>
<p>And then add two small sections of code to connect them together:</p>
<pre class="cpp"> <span class="type">void</span> MapsWidget<span class="operator">::</span>initialize(<span class="type"><a href="qgeomappingmanager.html">QGeoMappingManager</a></span> <span class="operator">*</span>manager)
 {
     d<span class="operator">-</span><span class="operator">&gt;</span>map <span class="operator">=</span> <span class="keyword">new</span> GeoMap(manager<span class="operator">,</span> <span class="keyword">this</span>);
     <span class="keyword">if</span> (d<span class="operator">-</span><span class="operator">&gt;</span>markerManager)
         d<span class="operator">-</span><span class="operator">&gt;</span>markerManager<span class="operator">-</span><span class="operator">&gt;</span>setMap(d<span class="operator">-</span><span class="operator">&gt;</span>map);
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 }

 <span class="type">void</span> MapsWidget<span class="operator">::</span>setMarkerManager(MarkerManager <span class="operator">*</span>markerManager)
 {
     d<span class="operator">-</span><span class="operator">&gt;</span>markerManager <span class="operator">=</span> markerManager;
     <span class="keyword">if</span> (d<span class="operator">-</span><span class="operator">&gt;</span>map)
         d<span class="operator">-</span><span class="operator">&gt;</span>markerManager<span class="operator">-</span><span class="operator">&gt;</span>setMap(d<span class="operator">-</span><span class="operator">&gt;</span>map);
 }</pre>
<p>Now we have basic search capability added to our code. But we still have no GUI to drive it, and so we'll focus on that in the next section.</p>
<a name="gui-with-search-dialog"></a>
<h3>GUI with search dialog</h3>
<p>Next we'll build a GUI around our map widget and add a search dialog to make use of the code we just wrote. Our finished GUI looks like this:</p>
<p class="centerAlign"><img src="images/mapsdemo-searchgui.png" alt="" /></p><p>We won't cover building the GUI in too much detail (that being the subject of other tutorials), but the complete code is in the finished MapsDemo example in the QtMobility distribution.</p>
<p>Our GUI consists of a <a href="http://qt.nokia.com/doc/4.7/qmainwindow.html">QMainWindow</a> containing our MapsWidget and a <a href="http://qt.nokia.com/doc/4.7/qmenubar.html">QMenuBar</a>. On the <a href="http://qt.nokia.com/doc/4.7/qmenubar.html">QMenuBar</a> is an option for zooming to the current &quot;My Location&quot;, and a menu for performing search operations.</p>
<p>Also part of the GUI is the dialog box displayed when selecting &quot;Search for address or name&quot; -- this is a simple <a href="http://qt.nokia.com/doc/4.7/qdialog.html">QDialog</a> subclass with a <a href="http://qt.nokia.com/doc/4.7/qformlayout.html">QFormLayout</a> and a <a href="http://qt.nokia.com/doc/4.7/qdialogbuttonbox.html">QDialogButtonBox</a>.</p>
<p>In the <a href="http://qt.nokia.com/doc/4.7/designer-to-know.html">MainWindow</a> constructor, we simply set up the menubar and MapsWidget and other UI details. All initialization of Location-based details are in the MainWindow::initialize() slot. For the moment, we will simply assume that initialize() is called directly from the constructor (the purpose of this decoupling will be explained later).</p>
<pre class="cpp"> <span class="type">void</span> MainWindow<span class="operator">::</span>initialize()
 {
     <span class="keyword">if</span> (serviceProvider)
         <span class="keyword">delete</span> serviceProvider;

     <span class="type"><a href="http://qt.nokia.com/doc/4.7/qlist.html">QList</a></span><span class="operator">&lt;</span><span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span><span class="operator">&gt;</span> providers <span class="operator">=</span> <span class="type"><a href="qgeoserviceprovider.html">QGeoServiceProvider</a></span><span class="operator">::</span>availableServiceProviders();
     <span class="keyword">if</span> (providers<span class="operator">.</span>size() <span class="operator">&lt;</span> <span class="number">1</span>) {
         <span class="type"><a href="http://qt.nokia.com/doc/4.7/qmessagebox.html">QMessageBox</a></span><span class="operator">::</span>information(<span class="keyword">this</span><span class="operator">,</span> tr(<span class="string">&quot;Maps Demo&quot;</span>)<span class="operator">,</span>
                                  tr(<span class="string">&quot;No service providers are available&quot;</span>));
         <span class="type"><a href="http://qt.nokia.com/doc/4.7/qcoreapplication.html">QCoreApplication</a></span><span class="operator">::</span>quit();
         <span class="keyword">return</span>;
     }

     serviceProvider <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qgeoserviceprovider.html">QGeoServiceProvider</a></span>(providers<span class="operator">[</span><span class="number">0</span><span class="operator">]</span>);
     <span class="keyword">if</span> (serviceProvider<span class="operator">-</span><span class="operator">&gt;</span>error() <span class="operator">!</span><span class="operator">=</span> <span class="type"><a href="qgeoserviceprovider.html">QGeoServiceProvider</a></span><span class="operator">::</span>NoError) {
         <span class="type"><a href="http://qt.nokia.com/doc/4.7/qmessagebox.html">QMessageBox</a></span><span class="operator">::</span>information(<span class="keyword">this</span><span class="operator">,</span> tr(<span class="string">&quot;Maps Demo&quot;</span>)<span class="operator">,</span>
                                  tr(<span class="string">&quot;Error loading geoservice plugin: %1&quot;</span>)<span class="operator">.</span>arg(providers<span class="operator">[</span><span class="number">0</span><span class="operator">]</span>));
         <span class="type"><a href="http://qt.nokia.com/doc/4.7/qcoreapplication.html">QCoreApplication</a></span><span class="operator">::</span>quit();
         <span class="keyword">return</span>;
     }

     mapsWidget<span class="operator">-</span><span class="operator">&gt;</span>initialize(serviceProvider<span class="operator">-</span><span class="operator">&gt;</span>mappingManager());
     markerManager <span class="operator">=</span> <span class="keyword">new</span> MarkerManager(serviceProvider<span class="operator">-</span><span class="operator">&gt;</span>searchManager());
     mapsWidget<span class="operator">-</span><span class="operator">&gt;</span>setMarkerManager(markerManager);

     connect(markerManager<span class="operator">,</span> SIGNAL(searchError(<span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span><span class="operator">::</span>Error<span class="operator">,</span><span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span>))<span class="operator">,</span>
             <span class="keyword">this</span><span class="operator">,</span> SLOT(showErrorMessage(<span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span><span class="operator">::</span>Error<span class="operator">,</span><span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span>)));

     mapsWidget<span class="operator">-</span><span class="operator">&gt;</span>setMyLocation(<span class="type"><a href="qgeocoordinate.html">QGeoCoordinate</a></span>(<span class="operator">-</span><span class="number">27.5796</span><span class="operator">,</span> <span class="number">153.1</span>));
 }</pre>
<p>As you can see, this performs more or less the same actions as our old code in main() from part 1 of the tutorial did. It fetches the first available service provider, then initializes the MapsWidget and MarkerManager using the appropriate Manager instances.</p>
<p>Additionally, we've added a setMyLocation() method to MapsWidget which simply calls the current MarkerManager's method of the same name, plus centreing the view on the marker.</p>
<p>The &quot;Search for address or name&quot; menu item sets off the showSearchDialog() slot:</p>
<pre class="cpp"> <span class="type">void</span> MainWindow<span class="operator">::</span>showSearchDialog()
 {
     SearchDialog sd;
     <span class="keyword">if</span> (sd<span class="operator">.</span>exec() <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qdialog.html">QDialog</a></span><span class="operator">::</span>Accepted) {
         <span class="keyword">if</span> (markerManager) {
             markerManager<span class="operator">-</span><span class="operator">&gt;</span>removeSearchMarkers();
             markerManager<span class="operator">-</span><span class="operator">&gt;</span>search(sd<span class="operator">.</span>searchTerms());
         }
     }
 }</pre>
<p>Which uses the methods on MarkerManager that we defined previously. So now we have a basic searchable mapping application. However, there is one big piece of functionality missing for a searchable map: consider if we had a provider that allowed us to search for local businesses. We might type in a business name in the Search dialog and press OK, and then be presented with tens or hundreds of businesses that match the name we typed from all around the world. Some of these results might not even be the kind of business we were looking for (partial text matches etc).</p>
<p>This can be solved with the addition of two key features: viewing the extra details about search results that we're currently throwing away; and adding the ability to limit the search area.</p>
<a name="adding-details-to-search-markers"></a>
<h3>Adding details to search markers</h3>
<p>First up, we'll add some additional properties to the Marker class:</p>
<pre class="cpp"> <span class="keyword">class</span> Marker : <span class="keyword">public</span> <span class="type"><a href="qgeomappixmapobject.html">QGeoMapPixmapObject</a></span>
 {
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 <span class="keyword">public</span>:
     <span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span> name() <span class="keyword">const</span>;
     <span class="type">void</span> setName(<span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span> name);

     <span class="type"><a href="qgeoaddress.html">QGeoAddress</a></span> address() <span class="keyword">const</span>;
     <span class="type">void</span> setAddress(<span class="type"><a href="qgeoaddress.html">QGeoAddress</a></span> addr);

     <span class="type">bool</span> moveable() <span class="keyword">const</span>;
     <span class="type">void</span> setMoveable(<span class="type">bool</span> moveable);
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 };

 <span class="keyword">class</span> MarkerPrivate
 {
 <span class="keyword">public</span>:
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
     <span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span> name;
     <span class="type">bool</span> moveable;
     <span class="type"><a href="qgeoaddress.html">QGeoAddress</a></span> address;
 };</pre>
<p>And add code to MarkerManager to set them from search results:</p>
<pre class="cpp"> <span class="type">void</span> MarkerManager<span class="operator">::</span>replyFinished(<span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span> <span class="operator">*</span>reply)
 {
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
     foreach (<span class="type"><a href="qgeoplace.html">QGeoPlace</a></span> place<span class="operator">,</span> reply<span class="operator">-</span><span class="operator">&gt;</span>places()) {
         Marker <span class="operator">*</span>m <span class="operator">=</span> <span class="keyword">new</span> Marker(Marker<span class="operator">::</span>SearchMarker);

         m<span class="operator">-</span><span class="operator">&gt;</span>setCoordinate(place<span class="operator">.</span>coordinate());
         <span class="keyword">if</span> (place<span class="operator">.</span>isLandmark()) {
             <span class="type"><a href="qlandmark.html">QLandmark</a></span> lm(place);
             m<span class="operator">-</span><span class="operator">&gt;</span>setName(lm<span class="operator">.</span>name());
         } <span class="keyword">else</span> {
             m<span class="operator">-</span><span class="operator">&gt;</span>setName(<span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span>(<span class="string">&quot;%1, %2&quot;</span>)<span class="operator">.</span>arg(place<span class="operator">.</span>address()<span class="operator">.</span>street())
                                         <span class="operator">.</span>arg(place<span class="operator">.</span>address()<span class="operator">.</span>city()));
         }
         m<span class="operator">-</span><span class="operator">&gt;</span>setAddress(place<span class="operator">.</span>address());
         m<span class="operator">-</span><span class="operator">&gt;</span>setMoveable(<span class="keyword">false</span>);
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span></pre>
<p>So now the data is available from the Marker objects. We want to show this to the user somehow, though, and the best means of doing this is probably a dialog box. We're going to do a dialog box that appears when the user clicks a marker, so we'll have to add click detection to MapsWidget and GeoMap, first.</p>
<p>We already have methods for handling mouse presses and releases over the map widget, so we will modify these. Add two private fields and a signal to GeoMap:</p>
<pre class="cpp"> <span class="keyword">class</span> GeoMap : <span class="keyword">public</span> <span class="type"><a href="qgraphicsgeomap.html">QGraphicsGeoMap</a></span>
 {
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 <span class="keyword">signals</span>:
     <span class="type">void</span> clicked(Marker <span class="operator">*</span>marker);

 <span class="keyword">private</span>:
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
     <span class="type">bool</span> markerPressed;
     <span class="type"><a href="qgeomapobject.html">QGeoMapObject</a></span> <span class="operator">*</span>pressed;
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 };</pre>
<p>We set the <tt>markerPressed</tt> flag when the mouse has been pressed over a map object, and set <tt>pressed</tt> to the map object in question.</p>
<pre class="cpp"> <span class="type">void</span> GeoMap<span class="operator">::</span>mousePressEvent(<span class="type"><a href="http://qt.nokia.com/doc/4.7/qgraphicsscenemouseevent.html">QGraphicsSceneMouseEvent</a></span> <span class="operator">*</span>event)
 {
     panActive <span class="operator">=</span> <span class="keyword">true</span>;

     markerPressed <span class="operator">=</span> <span class="keyword">false</span>;
     <span class="type"><a href="http://qt.nokia.com/doc/4.7/qlist.html">QList</a></span><span class="operator">&lt;</span><span class="type"><a href="qgeomapobject.html">QGeoMapObject</a></span><span class="operator">*</span><span class="operator">&gt;</span> objects <span class="operator">=</span> mapObjectsAtScreenPosition(event<span class="operator">-</span><span class="operator">&gt;</span>pos());
     <span class="keyword">if</span> (objects<span class="operator">.</span>size() <span class="operator">&gt;</span> <span class="number">0</span>) {
         pressed <span class="operator">=</span> objects<span class="operator">.</span>first();
         markerPressed <span class="operator">=</span> <span class="keyword">true</span>;
     }

     event<span class="operator">-</span><span class="operator">&gt;</span>accept();
 }

 <span class="type">void</span> GeoMap<span class="operator">::</span>mouseReleaseEvent(<span class="type"><a href="http://qt.nokia.com/doc/4.7/qgraphicsscenemouseevent.html">QGraphicsSceneMouseEvent</a></span> <span class="operator">*</span>event)
 {
     panActive <span class="operator">=</span> <span class="keyword">false</span>;

     <span class="keyword">if</span> (markerPressed) {
         <span class="comment">// check if we're still over the object</span>
         <span class="type"><a href="http://qt.nokia.com/doc/4.7/qlist.html">QList</a></span><span class="operator">&lt;</span><span class="type"><a href="qgeomapobject.html">QGeoMapObject</a></span><span class="operator">*</span><span class="operator">&gt;</span> objects <span class="operator">=</span> mapObjectsAtScreenPosition(event<span class="operator">-</span><span class="operator">&gt;</span>pos());
         <span class="keyword">if</span> (objects<span class="operator">.</span>contains(pressed)) {
             Marker <span class="operator">*</span>m <span class="operator">=</span> <span class="keyword">dynamic_cast</span><span class="operator">&lt;</span>Marker<span class="operator">*</span><span class="operator">&gt;</span>(pressed);
             <span class="keyword">if</span> (m)
                 <span class="keyword">emit</span> clicked(m);
         }

         markerPressed <span class="operator">=</span> <span class="keyword">false</span>;
     }

     event<span class="operator">-</span><span class="operator">&gt;</span>accept();
 }</pre>
<p>Finally, we need to pass this clicked() signal up through MapsWidget so that we can use it from outside. We do this by adding a signal and connecting GeoMap's signal to the signal on MapsWidget with the same name.</p>
<pre class="cpp"> <span class="keyword">class</span> MapsWidget : <span class="keyword">public</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qwidget.html">QWidget</a></span>
 {
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 <span class="keyword">signals</span>:
     <span class="type">void</span> markerClicked(Marker <span class="operator">*</span>m);
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
 };

 <span class="type">void</span> MapsWidget<span class="operator">::</span>initialize(<span class="type"><a href="qgeomappingmanager.html">QGeoMappingManager</a></span> <span class="operator">*</span>manager)
 {
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
     connect(d<span class="operator">-</span><span class="operator">&gt;</span>map<span class="operator">,</span> SIGNAL(clicked(Marker<span class="operator">*</span>))<span class="operator">,</span>
             <span class="keyword">this</span><span class="operator">,</span> SIGNAL(markerClicked(Marker<span class="operator">*</span>)));
 }</pre>
<p>Now that's done, creating a dialog box to display the address information is relatively trivial. The MarkerDialog class contains a <a href="http://qt.nokia.com/doc/4.7/qlineedit.html">QLineEdit</a> for the name field, a readonly <a href="http://qt.nokia.com/doc/4.7/qlabel.html">QLabel</a> for the address, and two QDoubleSpinBoxes for latitude and longitude.</p>
<p>We connect up the MapsWidget's markerClicked() signal to a slot in <a href="http://qt.nokia.com/doc/4.7/designer-to-know.html">MainWindow</a>:</p>
<pre class="cpp"> <span class="type">void</span> MainWindow<span class="operator">::</span>showMarkerDialog(Marker <span class="operator">*</span>marker)
 {
     MarkerDialog md(marker);
     <span class="keyword">if</span> (md<span class="operator">.</span>exec() <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qdialog.html">QDialog</a></span><span class="operator">::</span>Accepted) {
         marker<span class="operator">-</span><span class="operator">&gt;</span>setName(md<span class="operator">.</span>markerName());
         <span class="type"><a href="qgeocoordinate.html">QGeoCoordinate</a></span> c(md<span class="operator">.</span>latitude()<span class="operator">,</span> md<span class="operator">.</span>longitude());
         marker<span class="operator">-</span><span class="operator">&gt;</span>setCoordinate(c);
     }
 }</pre>
<p>And now clicking on markers on the map yields a simple editing dialog box, so our first task is complete.</p>
<a name="limiting-search-area"></a>
<h3>Limiting search area</h3>
<p>The <a href="qgeosearchmanager.html">QGeoSearchManager</a>'s search() method already comes with support for limited search areas -- by setting up a <a href="qgeoboundingarea.html">QGeoBoundingArea</a> we can take advantage of this functionality.</p>
<p>Firstly, we'll modify the MarkerManager's search() method:</p>
<pre class="cpp"> <span class="comment">// declaration</span>
 <span class="type">void</span> search(<span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span> query<span class="operator">,</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qtglobal.html#qreal-typedef">qreal</a></span> radius<span class="operator">=</span><span class="operator">-</span><span class="number">1</span>);

 <span class="comment">// implementation</span>
 <span class="type">void</span> MarkerManager<span class="operator">::</span>search(<span class="type"><a href="http://qt.nokia.com/doc/4.7/qstring.html">QString</a></span> query<span class="operator">,</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qtglobal.html#qreal-typedef">qreal</a></span> radius)
 {
     <span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span> <span class="operator">*</span>reply;
     <span class="keyword">if</span> (radius <span class="operator">&gt;</span> <span class="number">0</span>) {
         <span class="type"><a href="qgeoboundingcircle.html">QGeoBoundingCircle</a></span> boundingCircle(m_myLocation<span class="operator">-</span><span class="operator">&gt;</span>coordinate()<span class="operator">,</span> radius);
         reply <span class="operator">=</span> d<span class="operator">-</span><span class="operator">&gt;</span>searchManager<span class="operator">-</span><span class="operator">&gt;</span>search(query<span class="operator">,</span>
                                          <span class="type"><a href="qgeosearchmanager.html">QGeoSearchManager</a></span><span class="operator">::</span>SearchAll<span class="operator">,</span>
                                          <span class="operator">-</span><span class="number">1</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span>
                                          boundingCircle);
     } <span class="keyword">else</span> {
         reply <span class="operator">=</span> d<span class="operator">-</span><span class="operator">&gt;</span>searchManager<span class="operator">-</span><span class="operator">&gt;</span>search(query);
     }

     <span class="keyword">if</span> (reply<span class="operator">-</span><span class="operator">&gt;</span>isFinished()) {
       <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span></pre>
<p>And now we need to modify the UI to expose this to the user. There are a few ways of doing this, but the option we'll take is to expose a <a href="http://qt.nokia.com/doc/4.7/qcombobox.html">QComboBox</a> with some preset distances. This is easier to use on touch screen devices, especially, where entering numbers often takes much more effort from the user than selecting an option.</p>
<pre class="cpp"> <span class="comment">// in SearchDialog constructor</span>
 whereCombo <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qcombobox.html">QComboBox</a></span>();
 whereCombo<span class="operator">-</span><span class="operator">&gt;</span>addItem(tr(<span class="string">&quot;Nearby (&lt;10km)&quot;</span>)<span class="operator">,</span> <span class="number">10000</span>);
 whereCombo<span class="operator">-</span><span class="operator">&gt;</span>addItem(tr(<span class="string">&quot;Within 30 mins drive of me (&lt;25km)&quot;</span>)<span class="operator">,</span> <span class="number">25000</span>);
 whereCombo<span class="operator">-</span><span class="operator">&gt;</span>addItem(tr(<span class="string">&quot;Within 100km of me&quot;</span>)<span class="operator">,</span> <span class="number">100000</span>);
 whereCombo<span class="operator">-</span><span class="operator">&gt;</span>addItem(tr(<span class="string">&quot;Anywhere in the world&quot;</span>)<span class="operator">,</span> <span class="operator">-</span><span class="number">1</span>);
 whereCombo<span class="operator">-</span><span class="operator">&gt;</span>setCurrentIndex(<span class="number">1</span>);
 formLayout<span class="operator">-</span><span class="operator">&gt;</span>addRow(tr(<span class="string">&quot;Where&quot;</span>)<span class="operator">,</span> whereCombo);</pre>
<p>Then to get the radius value to put into search, we simply take the user data from the <a href="http://qt.nokia.com/doc/4.7/qcombobox.html">QComboBox</a>, convert it to a qreal and pass it through.</p>
<p>So we now have a searchable map, with clickable markers and the ability to limit the search radius. The last feature we'll cover that relates to searching is the so-called &quot;reverse geocode&quot; technique.</p>
<a name="reverse-geocode"></a>
<h3>Reverse geocode</h3>
<p>Currently, if you click the My Location icon on our map application, a blank address is displayed. We can add the capability here to turn the current coordinates of the marker into an approximate address, and the technique is known as &quot;reverse geocode&quot; searching.</p>
<p>To implement this, we'll hook into the coordinateChanged() signal of the Marker object:</p>
<pre class="cpp"> MarkerManager<span class="operator">::</span>MarkerManager(<span class="type"><a href="qgeosearchmanager.html">QGeoSearchManager</a></span> <span class="operator">*</span>searchManager<span class="operator">,</span> <span class="type"><a href="http://qt.nokia.com/doc/4.7/qobject.html">QObject</a></span> <span class="operator">*</span>parent) :
     <span class="type"><a href="http://qt.nokia.com/doc/4.7/qobject.html">QObject</a></span>(parent)<span class="operator">,</span>
     d(<span class="keyword">new</span> MarkerManagerPrivate)
 {
     d<span class="operator">-</span><span class="operator">&gt;</span>searchManager <span class="operator">=</span> searchManager;
     d<span class="operator">-</span><span class="operator">&gt;</span>myLocation <span class="operator">=</span> <span class="keyword">new</span> Marker(Marker<span class="operator">::</span>MyLocationMarker);
     d<span class="operator">-</span><span class="operator">&gt;</span>myLocation<span class="operator">-</span><span class="operator">&gt;</span>setName(<span class="string">&quot;Me&quot;</span>);

     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>

     <span class="comment">// hook the coordinateChanged() signal for reverse geocoding</span>
     connect(d<span class="operator">-</span><span class="operator">&gt;</span>myLocation<span class="operator">,</span> SIGNAL(coordinateChanged(<span class="type"><a href="qgeocoordinate.html">QGeoCoordinate</a></span>))<span class="operator">,</span>
             <span class="keyword">this</span><span class="operator">,</span> SLOT(myLocationChanged(<span class="type"><a href="qgeocoordinate.html">QGeoCoordinate</a></span>)));
 }</pre>
<p>Then we perform the reverse lookup in the myLocationChanged() slot. This looks quite similar to the original search() method, with good reason, as the reverse geocode lookup is simply a special kind of search call.</p>
<pre class="cpp"> <span class="type">void</span> MarkerManager<span class="operator">::</span>myLocationChanged(<span class="type"><a href="qgeocoordinate.html">QGeoCoordinate</a></span> location)
 {
     <span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span> <span class="operator">*</span>reply <span class="operator">=</span> d<span class="operator">-</span><span class="operator">&gt;</span>searchManager<span class="operator">-</span><span class="operator">&gt;</span>reverseGeocode(location);

     d<span class="operator">-</span><span class="operator">&gt;</span>reverseReplies<span class="operator">.</span>insert(reply);
     <span class="keyword">if</span> (reply<span class="operator">-</span><span class="operator">&gt;</span>isFinished())
         reverseReplyFinished(reply);
 }

 <span class="type">void</span> MarkerManager<span class="operator">::</span>reverseReplyFinished(<span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span> <span class="operator">*</span>reply)
 {
     <span class="keyword">if</span> (<span class="operator">!</span>d<span class="operator">-</span><span class="operator">&gt;</span>reverseReplies<span class="operator">.</span>contains(reply))
         <span class="keyword">return</span>;

     <span class="keyword">if</span> (reply<span class="operator">-</span><span class="operator">&gt;</span>places()<span class="operator">.</span>size() <span class="operator">&gt;</span> <span class="number">0</span>) {
         <span class="type"><a href="qgeoplace.html">QGeoPlace</a></span> place <span class="operator">=</span> reply<span class="operator">-</span><span class="operator">&gt;</span>places()<span class="operator">.</span>first();
         d<span class="operator">-</span><span class="operator">&gt;</span>myLocation<span class="operator">-</span><span class="operator">&gt;</span>setAddress(place<span class="operator">.</span>address());
     }

     reply<span class="operator">-</span><span class="operator">&gt;</span>deleteLater();
 }</pre>
<p>However, this isn't going to work very well with a GPS updating myLocation on a regular basis and a slow network connection, as the requests will pile up and the geocoded coordinates will lag behind the reported ones by quite a margin. A simple scheme to solve this relies only on two boolean flags:</p>
<pre class="cpp"> <span class="keyword">class</span> MarkerManagerPrivate
 {
 <span class="keyword">public</span>:
     <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
     <span class="comment">// a reverse geocode request is currently running</span>
     <span class="type">bool</span> revGeocodeRunning;
     <span class="comment">// a request is currently running, and my location has changed</span>
     <span class="comment">// since it started (ie, the request is stale)</span>
     <span class="type">bool</span> myLocHasMoved;
 };

 <span class="type">void</span> MarkerManager<span class="operator">::</span>myLocationChanged(<span class="type"><a href="qgeocoordinate.html">QGeoCoordinate</a></span> location)
 {
     <span class="keyword">if</span> (d<span class="operator">-</span><span class="operator">&gt;</span>revGeocodeRunning) {
         d<span class="operator">-</span><span class="operator">&gt;</span>myLocHasMoved <span class="operator">=</span> <span class="keyword">true</span>;
     } <span class="keyword">else</span> {
         <span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span> <span class="operator">*</span>reply <span class="operator">=</span> d<span class="operator">-</span><span class="operator">&gt;</span>searchManager<span class="operator">-</span><span class="operator">&gt;</span>reverseGeocode(location);
         d<span class="operator">-</span><span class="operator">&gt;</span>reverseReplies<span class="operator">.</span>insert(reply);

         d<span class="operator">-</span><span class="operator">&gt;</span>myLocHasMoved <span class="operator">=</span> <span class="keyword">false</span>;

         <span class="keyword">if</span> (reply<span class="operator">-</span><span class="operator">&gt;</span>isFinished()) {
             d<span class="operator">-</span><span class="operator">&gt;</span>revGeocodeRunning <span class="operator">=</span> <span class="keyword">false</span>;
             reverseReplyFinished(reply);
         } <span class="keyword">else</span> {
             d<span class="operator">-</span><span class="operator">&gt;</span>revGeocodeRunning <span class="operator">=</span> <span class="keyword">true</span>;
         }
     }
 }

 <span class="type">void</span> MarkerManager<span class="operator">::</span>reverseReplyFinished(<span class="type"><a href="qgeosearchreply.html">QGeoSearchReply</a></span> <span class="operator">*</span>reply)
 {
     <span class="keyword">if</span> (<span class="operator">!</span>d<span class="operator">-</span><span class="operator">&gt;</span>reverseReplies<span class="operator">.</span>contains(reply))
         <span class="keyword">return</span>;

     <span class="comment">// set address, as before</span>

     d<span class="operator">-</span><span class="operator">&gt;</span>revGeocodeRunning <span class="operator">=</span> <span class="keyword">false</span>;
     <span class="keyword">if</span> (d<span class="operator">-</span><span class="operator">&gt;</span>myLocHasMoved)
         myLocationChanged(d<span class="operator">-</span><span class="operator">&gt;</span>myLocation<span class="operator">-</span><span class="operator">&gt;</span>coordinate());

     d<span class="operator">-</span><span class="operator">&gt;</span>reverseReplies<span class="operator">.</span>remove(reply);
     reply<span class="operator">-</span><span class="operator">&gt;</span>deleteLater();
 }</pre>
<p>A reverse geocode request is only sent if the previous one has finished -- if it hasn't finished, a flag is set so that the location will be refreshed at the conclusion of the previous request. This is far from a perfect scheme, but in practise it works quite well.</p>
<p>At the end of part 2 now, we have a searchable map with a simple GUI, clickable markers, the ability to limit search radius about our location, and reverse geocoding to work out the address of where we are. This is already quite a bit of useful functionality, but we will continue to extend it further.</p>
<p>In part 3, we will add support for using platform positioning methods such as GPS, and in part 4 we will add the ability to fetch directions to a given destination. Finally, in part 5 we will cover a number of points about means for achieving a better user experience on mobile platforms.</p>
</div>
<!-- @@@tutorials-mapsdemo-part2.html -->
<p class="naviNextPrevious footerNavi">
<a class="prevPage" href="tutorials-mapsdemo-part1.html">Part 1 - The Map Widget</a>
<a class="nextPage" href="tutorials-mapsdemo-part3.html">Part 3 - Listening to satellites</a>
</p>
  <div class="ft">
    <span></span>
  </div>
</div> 
<div class="footer">
  <p>
     <acronym title="Copyright">&copy;</acronym> 2008-2011 Nokia Corporation and/or its
     subsidiaries. Nokia, Qt and their respective logos are trademarks of Nokia Corporation 
     in Finland and/or other countries worldwide.</p>
  <p>
     All other trademarks are property of their respective owners. <a title="Privacy Policy"
     href="http://qt.nokia.com/about/privacy-policy">Privacy Policy</a></p>
  <br />
  <p>
    Licensees holding valid Qt Commercial licenses may use this document in accordance with the    Qt Commercial License Agreement provided with the Software or, alternatively, in accordance    with the terms contained in a written agreement between you and Nokia.</p>
  <p>
    Alternatively, this document may be used under the terms of the <a href="http://www.gnu.org/licenses/fdl.html">GNU
    Free Documentation License version 1.3</a>
    as published by the Free Software Foundation.</p>
</div>
</body>
</html>