×
Namespaces

Variants
Actions
(Difference between revisions)

Landmarks/web client example using Carbide.c++ and UI designer

From Nokia Developer Wiki
Jump to: navigation, search
petrosoi (Talk | contribs)
(Example code on using Carbide.c++ to create a UI and application logic)
hamishwillee (Talk | contribs)
m (Hamishwillee - Bot update - Fix reviewer approved and ArticleMetaData)
(10 intermediate revisions by 7 users not shown)
Line 1: Line 1:
= Scope and introduction =
+
{{ArticleMetaData <!-- v1.1 -->
 +
|sourcecode= [[Media:Examplecode.zip]] [[Media:Myexample_sisfile.zip]]
 +
|installfile= <!-- Link to installation file (e.g. [[Media:The Installation File.sis]]) -->
 +
|devices= <!-- Devices tested against - e.g. ''devices=Nokia 6131 NFC, Nokia C7-00'') -->
 +
|sdk= <!-- SDK(s) built and tested against (e.g. [http://linktosdkdownload/ Qt SDK 1.1.4]) -->
 +
|platform= <!-- Compatible platforms - e.g. Symbian^1 and later, Qt 4.6 and later -->
 +
|devicecompatability= <!-- Compatible devices e.g.: All* (must have internal GPS) -->
 +
|dependencies= <!-- Any other/external dependencies e.g.: Google Maps Api v1.0 -->
 +
|signing= <!-- Signing requirements - empty or one of: Self-Signed, DevCert, Manufacturer -->
 +
|capabilities= <!-- Capabilities required by the article/code example (e.g. Location, NetworkServices. -->
 +
|keywords= <!-- APIs, classes and methods (e.g. QSystemScreenSaver, QList, CBase -->
 +
|id= <!-- Article Id (Knowledge base articles only) -->
 +
|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= 20070626
 +
|author= [[User:Petrosoi]]
 +
}}
 +
[[Category:Location]][[Category:Symbian C++]][[Category:UI]]
  
This article will walk through the steps of developing a small S60 application
+
{{FeaturedArticle|timestamp=20090301}}
that sends a HTTP-query to a web service to fetch landmarks information.
+
Application UI is created using Carbide UI designer.
+
  
The example code is not meant to be of commercial quality and is targeted only for educational purposes.
 
  
Basic Carbide.c++ and S60 C++ understanding is assumed from the readers.
+
= Scope and introduction =
 +
 
 +
This article will walk developers through the steps for developing a small S60 application
 +
that sends an HTTP query to a Web service to fetch landmarks information.
 +
The application UI is created using the Carbide UI designer. Example code is not intended to be of commercial quality and is provided for educational purposes only. A basic understanding of Carbide.c++ and S60 C++ is assumed.
 
* Building, setting build configurations, launching the debugger
 
* Building, setting build configurations, launching the debugger
 
* Basic S60 C++ development concepts  
 
* Basic S60 C++ development concepts  
Line 14: Line 38:
 
== Functionality ==
 
== Functionality ==
  
* Querying the last known position from the default positioning module
+
* Querying the last-known position from the default positioning module
* Sending a HTTP query to [http://www.gps-waypoints.net/ GPS Waypoints] client API
+
* Sending an HTTP query to the [http://www.gps-waypoints.net/ GPS Waypoints] client API
** The query requests information of the traffic cameras closest to the last known position
+
** Query requests information from the traffic cameras closest to the last-known position
 
* Parsing the query results
 
* Parsing the query results
 
** Creating landmark objects
 
** Creating landmark objects
 
** Filling UI listbox data with query results
 
** Filling UI listbox data with query results
** Adding the query results to the landmarks database on the device
+
** Adding query results to the landmarks database on the device
  
  
 
=== Omissions ===
 
=== Omissions ===
  
* Checking for exising landmarks with the same information
+
* Checking for existing landmarks with the same information
 
* Error handling
 
* Error handling
 
* Code cleanup
 
* Code cleanup
Line 32: Line 56:
 
=== Compatibility ===
 
=== Compatibility ===
  
* Tested on Nokia N95 and S60 3rd Edition FP1 emulator
+
* Tested on the Nokia N95 mobile device and S60 3rd Edition, Feature Pack 1 (FP1) emulator
** You need to have a valid access point configured to connect to the internet
+
** Developers need to have a valid access point configured to connect to the Internet.
** The device should have been used to receive proper location data at least once before running the application
+
** The device should be used to receive proper location data at least once before running the application.
  
  
== Future Plans ==
+
== Future plans ==
  
 
* Better integration with Landmarks API classes
 
* Better integration with Landmarks API classes
  
* Integration with S60 Map&Navigation functionality may be added at a later phase.
+
* Possible integration with S60 Map&Navigation functionality at a later phase
 
** Depending on API availability
 
** Depending on API availability
  
* Carbide building and debugging 101 may be added to this article
+
* Carbide building and debugging 101 may be added to this article.
  
  
Line 55: Line 79:
 
[[Image:Myexample_sisfile.zip]]
 
[[Image:Myexample_sisfile.zip]]
  
Please note that you will need a valid Developer Certificate from [http://www.symbiansigned.com Symbian Signed] program to sign the installation file if you want to run the application on a real device.
+
Developers will need a valid Developer Certificate from the [https://www.symbiansigned.com/app/page Symbian Signed] programme to sign the installation file if they want to run the application on a real device.
  
  
Line 63: Line 87:
 
= Creating the application project and UI =
 
= Creating the application project and UI =
  
* Create a new project in Carbide.c++ by choosing <i>File -> New -> Project -> Symbian OS C++ Project</i>
+
* Create a new project in Carbide.c++ by choosing <i>File -> New -> Project -> Symbian OS C++ Project</i>.
* Choose <i>S60 3rd Edition GUI Application with UI Designer</i> as the template
+
* Choose <i>S60 3rd Edition GUI Application with UI Designer</i> as the template.
* Enter a name for your project and select S60 3rd Edition FP1 as the default SDK
+
* Enter a name for your project and select S60 3rd Edition, FP1 as the default SDK.
  
 
[[Image:SNAG-0000.png]]
 
[[Image:SNAG-0000.png]]
  
  
* Select <i>List Box Design</i> as the UI design and <i>Double Number</i> as the list box type
+
* Select <i>List Box Design</i> as the UI design and <i>Double Number</i> as the listbox type.
  
 
[[Image:SNAG-0001.png]]
 
[[Image:SNAG-0001.png]]
Line 78: Line 102:
  
 
* You may accept the default values for:
 
* You may accept the default values for:
** Name for your base class
+
** Name for your base class;
** View switching support
+
** View switching support;
** Application UID
+
** Application UID;
** Project directories
+
** Project directories.
  
  
 
== Design the UI ==
 
== Design the UI ==
  
The application UI consists of a single view, which is populated by a list box control used for showing the landmarks data from a web query.
+
The application UI consists of a single view, which is populated by a listbox control used for showing the landmarks data from a Web query.
  
 
[[Image:SNAG-0011.png|Empty listbox]]  [[Image:SNAG-0012.png|Listbox with data]]
 
[[Image:SNAG-0011.png|Empty listbox]]  [[Image:SNAG-0012.png|Listbox with data]]
Line 100: Line 124:
 
Your new (still empty) UI design opens up in Carbide after creating the project.
 
Your new (still empty) UI design opens up in Carbide after creating the project.
  
* Click on the status pane title to change the text
+
* Click on the status pane title to change the text.
  
 
[[Image:SNAG-0014.png]]
 
[[Image:SNAG-0014.png]]
Line 107: Line 131:
 
=== Adding menu items ===
 
=== Adding menu items ===
  
* Add the items shown in the image below to the menu, predefined by the Carbide UI Designer
+
* Add the items shown in the image below to the menu, predefined by the Carbide UI Designer.
  
 
[[Image:SNAG-0015.png]]
 
[[Image:SNAG-0015.png]]
Line 114: Line 138:
 
=== Adding notes ===
 
=== Adding notes ===
  
* Add three notes to your UI design by dragging and dropping <i>Standard Note</i> objects from UI control palatte.
+
* Add three notes to the UI design by dragging and dropping <i>Standard Note</i> objects from the UI control palette:
** Information note on where the data is downloaded
+
** Information note on where the data is downloaded;
** Confirmation note of a successful HTTP-transaction
+
** Confirmation note of a successful HTTP transaction;
** Error note for the case when user attempts to add landmarks without first performing a HTTP-query
+
** Error note for the case when user attempts to add landmarks without first performing an HTTP query.
* Use the note property tab to define the note type and text
+
* Use the note property tab to define the note type and text.
  
  
Line 126: Line 150:
 
=== Adding a Web Client ===
 
=== Adding a Web Client ===
  
* Drag and drop a <i>Web Client</i> component (offers painless HTTP-connectivity) to the UI design.
+
* Drag and drop a <i>Web Client</i> component (offers painless HTTP connectivity) to the UI design.
** Select the default values for the event handler functions for <i>bodyReceived</i> and <i>transactionSucceeded</i> events
+
** Select the default values for the event handler functions for <i>bodyReceived</i> and <i>transactionSucceeded</i> events.
  
  
Line 135: Line 159:
 
=== Handling simple menu commands ===
 
=== Handling simple menu commands ===
  
* Set the <i>Exit</i> command to use command ID <code>EAknCmdExit</code>
+
* Set the <i>Exit</i> command to use command ID <code>EAknCmdExit</code>.
  
 
[[Image:SNAG-0019.png]]
 
[[Image:SNAG-0019.png]]
  
  
* Set a event handling function for the ''About'' menu item from the ''Events'' pane and navigate to the handler code.
+
* Set an event-handling function for the ''About'' menu item from the ''Events'' pane and navigate to the handler code.
  
 
[[Image:SNAG-0020.png]]
 
[[Image:SNAG-0020.png]]
  
  
* Among other code Carbide has generated wrappers for launching the notes you defined earlier.
+
* Among other code, Carbide has generated wrappers for launching the notes you defined earlier.
  
 
Your ''About'' menu item event handler should be similar to this:
 
Your ''About'' menu item event handler should be similar to this:
Line 177: Line 201:
 
 
 
/**
 
/**
* Appends data from the web query to the data buffer
+
* Appends data from the Web query to the data buffer
 
*  
 
*  
 
* @return void
 
* @return void
Line 185: Line 209:
 
 
 
/**
 
/**
* Resets the landmark array and emties the data buffer
+
* Resets the landmark array and empties the data buffer
 
*  
 
*  
 
* @return void
 
* @return void
Line 228: Line 252:
  
  
=== Appending data incrementally from a running HTTP-query ===  
+
=== Appending data incrementally from a running HTTP query ===  
 
 
 
<code cpp>void CGPSPOIsManager::AppendL( const TDesC8& aData )  
 
<code cpp>void CGPSPOIsManager::AppendL( const TDesC8& aData )  
Line 251: Line 275:
  
 
The sample application logic contains parsing functionality to handle the received data:
 
The sample application logic contains parsing functionality to handle the received data:
* If the following gives you the creeps, ''TLex'' class offers convenient string parsing.
+
* If the following makes you uncomfortable, the ''TLex'' class offers convenient string parsing.
  
 
<code cpp>void CGPSPOIsManager::CreateItemsL()
 
<code cpp>void CGPSPOIsManager::CreateItemsL()
Line 300: Line 324:
  
 
* ''singleline'' should now contain a string representing a single landmark item.
 
* ''singleline'' should now contain a string representing a single landmark item.
* Create a landmark object and fill it with values from the string
+
* Create a landmark object and fill it with values from the string.
* Add the filled landmark object to the array used for containing the items
+
* Add the filled landmark object to the array used for containing the items.
 
   
 
   
 
<code cpp>
 
<code cpp>
Line 334: Line 358:
  
  
* Parse attributes from the landmark item
+
* Parse attributes from the landmark item.
  
 
<code cpp>
 
<code cpp>
Line 364: Line 388:
  
  
* Set some attributes of the landmark object
+
* Set some attributes of the landmark object.
** Please check SDK documentation on what attributes are available
+
** Please check SDK documentation on what attributes are available.
  
 
<code cpp>
 
<code cpp>
Line 432: Line 456:
 
== UI changes for using the application logic ==
 
== UI changes for using the application logic ==
  
* An object of the application logic class has to be owned by some if the UI classes
+
* An object of the application logic class has to be owned by some of the UI classes.
** The sample app creates the object in the application UI class and defines methods for setting a pointer to the model to the listbox class.
+
** The sample application creates the object in the application UI class and defines methods for setting a pointer to the model to the listbox class.
*** Usually setting the model pointer would be done in construction phase, but Carbide may generate some funky code to recreate overloaded constructors if the UI is modified.
+
*** Usually setting the model pointer would be done in the construction phase, but Carbide may generate some funky code to recreate overloaded constructors if the UI is modified.
  
  
Line 491: Line 515:
 
== Updating project settings ==
 
== Updating project settings ==
  
The location and landmarks related functionality requires some link libraries as well as some capabilities to be added to project definitions.
+
The location and landmarks-related functionality requires some link libraries as well as some capabilities to be added to project definitions.
 
This is probably a good time to tweak the settings.
 
This is probably a good time to tweak the settings.
  
* Open ''Options'' tab on your project's mmp file and set the following capabilities for your project:
+
* Open the ''Options'' tab on your project's mmp file and set the following capabilities for your project:
** ''LocalServices Location NetworkServices ReadDeviceData ReadUserData WriteDeviceData WriteUserData''
+
** ''LocalServices Location NetworkServices ReadDeviceData ReadUserData WriteDeviceData WriteUserData''.
*** Please note that you will need a Developer Certificate from [http://www.symbiansigned.com Symbian Signed] program to sign an application for these capabilities   
+
*** Please note that you will need a Developer Certificate from the [https://www.symbiansigned.com/app/page Symbian Signed] programme to sign an application for these capabilities.    
* Add ''lbs'' and ''eposlandmarks'' libraries to your project on the ''Libraries'' tab of your mmp file
+
* Add ''lbs'' and ''eposlandmarks'' libraries to your project on the ''Libraries'' tab of your mmp file.
  
  
 
= Getting position information and issuing the HTTP query =
 
= Getting position information and issuing the HTTP query =
  
With the application logic mostly in place, we can configure our HTTP-query behavior.
+
With the application logic mostly in place, you can configure your HTTP-query behaviour.
  
Carbide UI Designer generates code that eases the pain of issuing and handling the web queries. The code is generated to ''CWebClientEngine'' class, which by default uses the view issuing the queries as an observer to the progress of the queries.
+
Carbide UI Designer generates code that eases the pain of issuing and handling the Web queries. The code is generated to the ''CWebClientEngine'' class, which by default uses the view issuing the queries as an observer to the progress of the queries.
  
The HTTP-query is initiated from the ''Search...'' menu item. Carbide has generated a function placeholder to the listbox class for handling that menu command.
+
The HTTP query is initiated from the ''Search...'' menu item. Carbide has generated a function placeholder to the listbox class for handling that menu command.
  
 
<code cpp>
 
<code cpp>
Line 523: Line 547:
 
''http://www.gps-waypoints.net/gps/gwnapi/get_closest_waypoints.php?api_key=[YOURAPIKEY]&lat=[LATCOORDINATE]&lon=[LONCOORDINATE]&type=100006&distance=[RADIUS]&limit=[LIMIT]''
 
''http://www.gps-waypoints.net/gps/gwnapi/get_closest_waypoints.php?api_key=[YOURAPIKEY]&lat=[LATCOORDINATE]&lon=[LONCOORDINATE]&type=100006&distance=[RADIUS]&limit=[LIMIT]''
  
You can get an API key by registering to the website. The sample application limits the search results to 5 items and uses 10000 km as the search radius.
+
You can get an API key by registering to the Web site. The sample application limits the search results to five items and uses 10,000 km as the search radius.
  
I used a test key for the API calls: NNVALVOGTYHXAQC.
+
We used a test key for the API calls: NNVALVOGTYHXAQC.
  
  
== Getting last known position information ==
+
== Getting last-known-position information ==
  
The sample app contains the position fetching implementation inside the listbox class. You should probably implement this functionality inside your application model and use active objects to handle the async position fetching call.
+
The sample application contains the position-fetching implementation inside the listbox class. You should probably implement this functionality inside your application model and use active objects to handle the async position-fetching call.
  
  
=== Connecting to positioning server and opening the default positioning module ===
+
=== Connecting to the positioning server and opening the default positioning module ===
  
 
<code cpp>
 
<code cpp>
Line 578: Line 602:
  
  
=== Getting the last known position ===
+
=== Getting the last-known position ===
  
The sample code obtains the last known position in the event handler of the ''Search...'' menu item.
+
The sample code obtains the last-known position in the event handler of the ''Search...'' menu item.
  
 
<code cpp>
 
<code cpp>
Line 639: Line 663:
 
= Handling HTTP-query results =
 
= Handling HTTP-query results =
  
The Web Client encapsulation will notify it's observer (our listbox view class) on the progress of the query.
+
The Web Client encapsulation will notify its observer (our listbox view class) on the progress of the query.
  
In the UI design phase, we defined that we are interested in handling the ''bodyReceived'' and ''transactionSucceeded'' events.
+
In the UI design phase, we indicated that we are interested in handling the ''bodyReceived'' and ''transactionSucceeded'' events.
  
  
 
== Handling increments of body data ==
 
== Handling increments of body data ==
  
When a part of the HTTP-query result body has been received, we want to add it to the data buffer maintained by our model.
+
When a part of the HTTP-query result body has been received, you want to add it to the data buffer maintained by your model.
  
 
<code cpp>
 
<code cpp>
Line 676: Line 700:
  
  
== Handling a succesful transaction ==
+
== Handling a successful transaction ==
  
  
When the HTTP-transaction has completed, we want to ask our model to parse the data and construct the landmark objects.
+
When the HTTP transaction has completed, ask your model to parse the data and construct the landmark objects.
  
 
<code cpp>
 
<code cpp>
Line 765: Line 789:
 
= Wrap-up =
 
= Wrap-up =
  
You should now be able to build, run or debug the application.
+
You should now be able to build, run, or debug the application.
As mentioned, you will need a valid Developer Certificate to sign the application if you want to run in on a real device.
+
As a reminder, you will need a valid Developer Certificate to sign the application if you want to run it on a real device.
 +
 
 +
== Related Links: ==
 +
 
 +
* [[How to use Landmarks API]]
 +
* [[How to select and show a landmark]]
 +
* [[How to compact local landmark databases]]
 +
* [[How to export landmarks from database to file]]
 +
* [[How to import landmarks from file to database]]
 +
* [[Execution of landmark operations]]
 +
* [[How to obtain and save current location]]
 +
* [[Retrieving location information]]
 +
 
 +
[[Category:S60]][[Category:Carbide.c++]]
 +
[[Category:HTTP]][[Category:Code Examples]]

Revision as of 08:14, 2 February 2012

Article Metadata
Code ExampleArticle
Created: petrosoi (26 Jun 2007)
Last edited: hamishwillee (02 Feb 2012)
Featured Article
01 Mar
2009


Contents

Scope and introduction

This article will walk developers through the steps for developing a small S60 application that sends an HTTP query to a Web service to fetch landmarks information. The application UI is created using the Carbide UI designer. Example code is not intended to be of commercial quality and is provided for educational purposes only. A basic understanding of Carbide.c++ and S60 C++ is assumed.

  • Building, setting build configurations, launching the debugger
  • Basic S60 C++ development concepts


Functionality

  • Querying the last-known position from the default positioning module
  • Sending an HTTP query to the GPS Waypoints client API
    • Query requests information from the traffic cameras closest to the last-known position
  • Parsing the query results
    • Creating landmark objects
    • Filling UI listbox data with query results
    • Adding query results to the landmarks database on the device


Omissions

  • Checking for existing landmarks with the same information
  • Error handling
  • Code cleanup


Compatibility

  • Tested on the Nokia N95 mobile device and S60 3rd Edition, Feature Pack 1 (FP1) emulator
    • Developers need to have a valid access point configured to connect to the Internet.
    • The device should be used to receive proper location data at least once before running the application.


Future plans

  • Better integration with Landmarks API classes
  • Possible integration with S60 Map&Navigation functionality at a later phase
    • Depending on API availability
  • Carbide building and debugging 101 may be added to this article.


Source code and installation file

File:Examplecode.zip


File:Myexample sisfile.zip

Developers will need a valid Developer Certificate from the Symbian Signed programme to sign the installation file if they want to run the application on a real device.




Creating the application project and UI

  • Create a new project in Carbide.c++ by choosing File -> New -> Project -> Symbian OS C++ Project.
  • Choose S60 3rd Edition GUI Application with UI Designer as the template.
  • Enter a name for your project and select S60 3rd Edition, FP1 as the default SDK.

SNAG-0000.png


  • Select List Box Design as the UI design and Double Number as the listbox type.

SNAG-0001.png

SNAG-0005.png


  • You may accept the default values for:
    • Name for your base class;
    • View switching support;
    • Application UID;
    • Project directories.


Design the UI

The application UI consists of a single view, which is populated by a listbox control used for showing the landmarks data from a Web query.

Empty listbox Listbox with data

Menu




Status pane text manipulation

Your new (still empty) UI design opens up in Carbide after creating the project.

  • Click on the status pane title to change the text.

SNAG-0014.png


Adding menu items

  • Add the items shown in the image below to the menu, predefined by the Carbide UI Designer.

SNAG-0015.png


Adding notes

  • Add three notes to the UI design by dragging and dropping Standard Note objects from the UI control palette:
    • Information note on where the data is downloaded;
    • Confirmation note of a successful HTTP transaction;
    • Error note for the case when user attempts to add landmarks without first performing an HTTP query.
  • Use the note property tab to define the note type and text.


SNAG-0017.png


Adding a Web Client

  • Drag and drop a Web Client component (offers painless HTTP connectivity) to the UI design.
    • Select the default values for the event handler functions for bodyReceived and transactionSucceeded events.


SNAG-0018.png


Handling simple menu commands

  • Set the Exit command to use command ID
    EAknCmdExit
    .

SNAG-0019.png


  • Set an event-handling function for the About menu item from the Events pane and navigate to the handler code.

SNAG-0020.png


  • Among other code, Carbide has generated wrappers for launching the notes you defined earlier.

Your About menu item event handler should be similar to this:

/** 
* Handle the selected event.
* @param aCommand the command id invoked
* @return ETrue if the command was handled, EFalse if not
*/

TBool CMyExampleListBoxView::HandleAboutMenuItemSelectedL( TInt aCommand )
{
RunNote1L();
return ETrue;
}
  • Set default named event handling functions for the Search... and Add... menu items as well. Don't implement the event handlers just yet.


Adding application logic

Interface

Most of the application logic is handled by a separate class, containing the following public interface:

  static CGPSPOIsManager* NewL();
static CGPSPOIsManager* NewLC();
virtual ~CGPSPOIsManager();
 
/**
* Appends data from the Web query to the data buffer
*
* @return void
* @param aData 8 bit descriptor result of HTTP query
*/

void AppendL( const TDesC8& aData );
 
/**
* Resets the landmark array and empties the data buffer
*
* @return void
*/

void Reset();
 
/**
* Handle to the array containing pointers to landmark objects
*
* @return void
*/

RArray< CPosLandmark* > Items();
 
/**
* Creates landmark items from the search results.
* Calls the parsing functions to parse the comma separated data
*
* @return void
*/

void CreateItemsL();
 
/**
* Adds the search result landmarks to the landmark database
*
* @return TInt
*/

TInt AddToDbL();


Implementation

Source and header files for this class need to be added to the Carbide project manually. The main functionality is explained below, while the link to the full source code of the class is linked to in this article.


Connecting to the default landmarks database

void CGPSPOIsManager::ConstructL() 
{
// Open Landmarks database
iLmDb = CPosLandmarkDatabase::OpenL();
...


Appending data incrementally from a running HTTP query

void CGPSPOIsManager::AppendL( const TDesC8& aData ) 
{
// append the received data to the data buffer
TInt newLength = iDatabuf.Length() + aData.Length();
if (iDatabuf.MaxLength() < newLength)
{
iDatabuf.ReAllocL( newLength );
}
iDatabuf.Append( aData );
}


Parsing the HTTP-query result and creating landmark objects

The GPS Waypoints client API provides landmark objects formatted as:

#id, lat,lon,name,desc,location,(speed limit) ,(bearing),type,

Fields of an individual item are separated by commas and items are separated by a line break.

The sample application logic contains parsing functionality to handle the received data:

  • If the following makes you uncomfortable, the TLex class offers convenient string parsing.
void CGPSPOIsManager::CreateItemsL()
{
// create landmarks from the received data
// parse until all items have called parseiteml
TInt ret = 0;
while ( ret != KErrNotFound )
{
ret = ParseItemL( ret );
}
}
 
TInt CGPSPOIsManager::ParseItemL( TInt aPosInBuf )
{
if ( aPosInBuf >= iDatabuf.Length() )
return KErrNotFound;
return ParseCSVItemL( aPosInBuf );
}
 
TInt CGPSPOIsManager::ParseCSVItemL( TInt aPosInBuf )
{
// GPS waypoints provides data as comma separated values...
// ...with line breaks between the result items
 
// work with remaining data
TPtrC8 remainder = iDatabuf.Right( iDatabuf.Length() - aPosInBuf );
 
// locate a line change
TInt ret = remainder.Locate( '\n' );
 
// no more line changes (new items) left
if ( ret == KErrNotFound )
return ret;
 
// single line without the line change
TPtrC8 singleline = remainder.Left( ret );
 
// resume parsing after the \n
TInt newindex = aPosInBuf + ret + 1;
 
// comment lines start with #
if ( remainder.Left( 1 ).Compare( KMyComment ) == 0 )
return newindex;
 
...
  • singleline should now contain a string representing a single landmark item.
  • Create a landmark object and fill it with values from the string.
  • Add the filled landmark object to the array used for containing the items.
	// pass singleline to item constructor
// item should parse and create itself
// ...add item to itemarray
//TBool eos = EFalse;
TInt linepos = 0;
iItemIndex = EMyLmId;
iLat = 0;
iLong = 0;
CPosLandmark* landmark = CPosLandmark::NewL();
while ( linepos >= 0 )
{
// if linepos == -1 => end of line
// else continue at linepos
// => increment linepos beyond the found ,
linepos = ParseCSVFieldL( linepos, singleline );
 
// increase itemindex after setting the value of a field in a landmark
 
SetLandMarkItemL( landmark );
iItemIndex++;
}
 
// add landmark to items
//landmark->SetPartialL( 0 );
iItems.Append( landmark );
return newindex;
}


  • Parse attributes from the landmark item.
TInt CGPSPOIsManager::ParseCSVFieldL( TInt aLinePos, TPtrC8& aLine )
{
// Get an attribute of a search result item to iToken
 
TPtrC8 remainder = aLine.Right( aLine.Length() - aLinePos );
TInt pos = remainder.Locate( TChar(',') );
 
// no more fields to read
if ( pos < 0 )
return pos;
 
// Copy the single token
if ( iToken.Length() < pos + 1 )
iToken.ReAllocL( pos + 1 );
 
iToken.Copy( remainder.Left( pos ) );
 
// if the last ',' was the last character in the line
TInt ret = aLinePos + pos + 1;
if ( ret >= aLine.Length() )
return -1;
else
return ret;
}


  • Set some attributes of the landmark object.
    • Please check SDK documentation on what attributes are available.
TInt CGPSPOIsManager::SetLandMarkItemL( CPosLandmark* aLandmark )
{
// only name, desc and coordinates handled in this case
 
switch ( iItemIndex )
{
case EMyLmName:
{
aLandmark->SetLandmarkNameL( iToken );
break;
}
case EMyLmDesc:
{
aLandmark->SetLandmarkDescriptionL( iToken );
break;
}
case EMyLmLat:
{
TLex lex( iToken );
lex.Val( iLat );
break;
}
case EMyLmLon:
{
TLex lex( iToken );
lex.Val( iLong );
TCoordinate coord( iLat, iLong );
TLocality lmlocality( coord, 10 );
aLandmark->SetPositionL( lmlocality );
break;
}
case EMyLmLocation:
{
break;
}
case EMyLmSpeed:
case EMyLmBearing:
case EMyLmType:
case EMyLmId:
default:
break;
}
return 0;
}


Adding landmarks to the database

TInt CGPSPOIsManager::AddToDbL()
{
TInt ret = 0;
// add landmarks to the database
for ( TInt i = 0; i < iItems.Count(); i++ )
{
iLmDb->AddLandmarkL( *iItems[i] );
ret++;
}
return ret;
}


UI changes for using the application logic

  • An object of the application logic class has to be owned by some of the UI classes.
    • The sample application creates the object in the application UI class and defines methods for setting a pointer to the model to the listbox class.
      • Usually setting the model pointer would be done in the construction phase, but Carbide may generate some funky code to recreate overloaded constructors if the UI is modified.


Changes to the application UI class

// header file
#include "CGPSPOIsManager.h"
...
CGPSPOIsManager* iModel;
 
// source file
CMyExampleAppUi::~CMyExampleAppUi()
{
// [[[ begin generated region: do not modify [Generated Contents]
// ]]] end generated region [Generated Contents]
delete iModel;
iModel = NULL;
}
 
// [[[ begin generated function: do not modify
void CMyExampleAppUi::InitializeContainersL()
{
iMyExampleListBoxView = CMyExampleListBoxView::NewL();
 
// this added after UI code generation
iMyExampleListBoxView->SetAppModel( iModel );
 
 
...
 
void CMyExampleAppUi::ConstructL()
{
iModel = CGPSPOIsManager::NewL();
 
...

Changes to the listbox class

// header file
class CGPSPOIsManager;
...
CGPSPOIsManager* iModel;
 
...
 
// source file
void CMyExampleListBoxView::SetAppModel( CGPSPOIsManager* aModel )
{
iModel = aModel;
}

Updating project settings

The location and landmarks-related functionality requires some link libraries as well as some capabilities to be added to project definitions. This is probably a good time to tweak the settings.

  • Open the Options tab on your project's mmp file and set the following capabilities for your project:
    • LocalServices Location NetworkServices ReadDeviceData ReadUserData WriteDeviceData WriteUserData.
      • Please note that you will need a Developer Certificate from the Symbian Signed programme to sign an application for these capabilities.
  • Add lbs and eposlandmarks libraries to your project on the Libraries tab of your mmp file.


Getting position information and issuing the HTTP query

With the application logic mostly in place, you can configure your HTTP-query behaviour.

Carbide UI Designer generates code that eases the pain of issuing and handling the Web queries. The code is generated to the CWebClientEngine class, which by default uses the view issuing the queries as an observer to the progress of the queries.

The HTTP query is initiated from the Search... menu item. Carbide has generated a function placeholder to the listbox class for handling that menu command.

TBool CMyExampleListBoxView::HandleSearch_closest_camerasMenuItemSelectedL( TInt aCommand )
{
// TODO: implement selected event handler
return ETrue;
}


HTTP-query format

The query format for getting traffic camera items from GPS Waypoints client API is:

http://www.gps-waypoints.net/gps/gwnapi/get_closest_waypoints.php?api_key=[YOURAPIKEY]&lat=[LATCOORDINATE]&lon=[LONCOORDINATE]&type=100006&distance=[RADIUS]&limit=[LIMIT]

You can get an API key by registering to the Web site. The sample application limits the search results to five items and uses 10,000 km as the search radius.

We used a test key for the API calls: NNVALVOGTYHXAQC.


Getting last-known-position information

The sample application contains the position-fetching implementation inside the listbox class. You should probably implement this functionality inside your application model and use active objects to handle the async position-fetching call.


Connecting to the positioning server and opening the default positioning module

// header file
#include <lbs.h>
 
...
 
RPositionServer iPosServer;
RPositioner iPositioner;
 
 
//source file
 
#include <lbspositioninfo.h>
#include "CGPSPOIsManager.h"
 
...
 
// destructor
 
iPositioner.Close();
iPosServer.Close();
 
...
 
// ConstructL
 
TInt err = iPosServer.Connect();
 
TPositionModuleId moduleid;
err = iPosServer.GetDefaultModuleId( moduleid );
err = iPositioner.Open( iPosServer, moduleid );
 
if ( err == KErrNone )
{
_LIT( KMyData, "MyExample");
iPositioner.SetRequestor(
CRequestorBase::ERequestorService,
CRequestorBase::EFormatApplication,
KMyData );
}


Getting the last-known position

The sample code obtains the last-known position in the event handler of the Search... menu item.

/** 
* Handle the selected event.
* @param aCommand the command id invoked
* @return ETrue if the command was handled, EFalse if not
*/

TBool CGPSPOIsSearchViewView::HandleSurroundingPOIsSelectedL( TInt aCommand )
{
// The ResetListL method has been added
// to empty the listbox
iMyExampleListBox->ResetListL();
iMyExampleListBox->ListBox()->SetCurrentItemIndex(0);
 
_LIT8( KSearchURL, "http://www.gps-waypoints.net/gps/gwnapi/get_closest_waypoints.php?api_key=NNVALVOGTYHXAQC&lat=%f&lon=%f&type=100006&distance=10000&limit=5" );
 
// get the last known position
TRequestStatus status;
TPositionInfo posinfo;
 
// use an AO in a real life app
iPositioner.GetLastKnownPosition( posinfo, status );
User::WaitForRequest( status );
 
TPosition position;
posinfo.GetPosition( position );
 
...


Issuing the HTTP query

...
 
 
// create the search url
RBuf8 rbuf;
rbuf.CreateMax( KSearchURL().Length()*2 );
 
// format the search string to include the position info
rbuf.Format( KSearchURL, position.Latitude(), position.Longitude() );
 
iModel->Reset();
 
// generated by Carbide => encapsulates the HTTP-query
IssueHTTPGetL( &rbuf );
 
rbuf.Close();
 
return ETrue;
}


Handling HTTP-query results

The Web Client encapsulation will notify its observer (our listbox view class) on the progress of the query.

In the UI design phase, we indicated that we are interested in handling the bodyReceived and transactionSucceeded events.


Handling increments of body data

When a part of the HTTP-query result body has been received, you want to add it to the data buffer maintained by your model.

/**
* ClientBodyReceivedL()
* Called when a part of the HTTP body is received.
* @param aBodyData: Part of the body data received. (e.g. part of
* the received HTML page)
*/

void CMyExampleListBoxView::ClientBodyReceivedL(
CWebClientEngine& anEngine,
const TDesC8& aBodyData )
{
// [[[ begin generated region: do not modify [Generated Code]
HandleWebClient1BodyReceivedL( anEngine, aBodyData );
// ]]] end generated region [Generated Code]
 
}
/**
* Handle the bodyReceived event.
*/

void CMyExampleListBoxView::HandleWebClient1BodyReceivedL(
CWebClientEngine& /*anEngine*/,
const TDesC8& aBodyData)
{
iModel->AppendL( aBodyData );
}


Handling a successful transaction

When the HTTP transaction has completed, ask your model to parse the data and construct the landmark objects.

/**
* ClientTransactionSucceededL()
* Called to notify that a transaction completed successfully
* See TTransactionEvent::ESucceeded
*/

void CMyExampleListBoxView::ClientTransactionSucceededL(
CWebClientEngine& anEngine )
{
// [[[ begin generated region: do not modify [Generated Code]
HandleWebClient1TransactionSucceededL( anEngine );
// ]]] end generated region [Generated Code]
 
}
/**
* Handle the transactionSucceeded event.
*/

void CMyExampleListBoxView::HandleWebClient1TransactionSucceededL(
CWebClientEngine& /*anEngine*/ )
{
// show a note to indicate transaction completion
// the note was defined in the UI design phase and
// Carbide has generated wrapper code for it
RunTransactionCompleteL();
 
// ask the model to parse the data and create landmarks
iModel->CreateItemsL();
 
iMyExampleListBox->ResetListL();
 
RArray< CPosLandmark* > items = iModel->Items();
 
// populate listbox here
for ( TInt i = 0; i < items.Count(); i++ )
{
TBuf<256> buf;
TPtrC lmname;
TPtrC lmdesc;
CPosLandmark* lmark = items[ i ];
lmark->GetLandmarkName( lmname );
lmark->GetLandmarkDescription( lmdesc );
 
// These functions generated by Carbide
iMyExampleListBox->CreateListBoxItemL( buf, i+1,
lmname, lmdesc );
iMyExampleListBox->AddListBoxItemL( iMyExampleListBox->ListBox(), buf );
}
iMyExampleListBox->ListBox()->DrawDeferred();
}


Adding landmarks to the database

A menu item for adding the query results to the landmarks database was defined in the UI design phase.

Modify the event handler method to add the landmarks.

/** 
* Handle the selected event.
* @param aCommand the command id invoked
* @return ETrue if the command was handled, EFalse if not
*/

TBool CMyExampleListBoxView::HandleAdd_to_landmarksMenuItemSelectedL( TInt aCommand )
{
if ( iModel->Items().Count() == 0 )
RunNote2L();
else
{
iMyExampleListBox->ResetListL();
iMyExampleListBox->ListBox()->SetCurrentItemIndex(0);
iMyExampleListBox->ListBox()->DrawDeferred();
 
TInt ret = iModel->AddToDbL();
iModel->Reset();
}
return ETrue;
}


Wrap-up

You should now be able to build, run, or debug the application. As a reminder, you will need a valid Developer Certificate to sign the application if you want to run it on a real device.

Related Links:

95 page views in the last 30 days.
×