|
S60 3rd Edition SDK for Symbian OS Example Applications Guide |
1. About this Example
2. Prerequisites
3. Application Output
4. Design and Implementation
5. Error Situations
6. Summary
7. Class Hierarchy
Creating landmarks Removing landmarks Reading landmarks completely Reading landmarks partially Editing landmarks Updating a landmark to the current location Sorting landmarks Filtering out a subset of landmarks Creating categories Removing categories Reading categories Renaming categories Sorting categories Filtering out a subset of categories Initializing the default landmark database Observing and handling database events Visualizing the progress of an asynchronous landmark function in a progress dialog
The structure of the tutorial is based on the architecture of the Landmark reference application.
Another way to create a new landmark is to select the New landmark item and then the sub menu item Current location in the Options menu. A location is then acquired before the landmark editor is launched. The editor's location fields will be automatically configured with data based on the location that was acquired. If no location was acquired, the fields will be blank and the reason to the acquisition failure will be displayed in an Information note.
When editing a landmark, the location fields Latitude, Longitude, Altitude, Horizontal accuracy, and Vertical accuracy can be manually edited or automatically updated by selecting the item Fetch current location from the Options menu. A location is then acquired and the location fields in the editor are updated according to the location that was retrieved. If the location retrieval failed for some reason, the location fields will not be modified but the reason to the acquisition failure will be displayed in an Information note.
A landmark can belong to one or several landmark categories. When editing the Categories field, a markable list of the categories can be launched by selecting the menu item Edit categories. In the list, categories can be added/removed from a landmark by using the Selection key and the Arrow up and Arrow down keys. The left softkey Ok finishes selecting categories. Pressing the softkey Done back in the editor dialog opens a query asking whether to save the changes. If No is pressed, then no changes are applied to the landmark.
This procedure is described in detail in Sections 4.2.2 and 4.2.13.
The figure shows that the application can be logically divided into two components: the application UI and the application engine. The application UI is dependent on the application engine that is in turn dependent on the Landmarks APIs. Throughout this document, all the classes that are a part of Landmarks API are indicated with blue color and the classes that are a part of Landmarks Search API are indicated with red color.
Class | Description
|
This interface should be implemented by classes that are interested in handling database events.
| |
Many operations offered by the application engine are asynchronous. Classes in the application UI that invoke these functions need to be notified when these asynchronous operations are completed. MLandmarksOperationObserver is a generic callback interface implemented by such classes.
| |
CLandmarksAppUi inherits from CAknViewAppUi, which indicates that this is a view-based application. It creates the two application views for displaying landmarks and categories as well as the application engine. It also initializes the landmarks database if necessary. For this reason, it implements the MLandmarksOperationObserver interface to be notified when initialization is completed. It takes care of application global events such as exiting the application and switching views.
| |
This is the view displaying landmarks. It has CLandmarksContainer that is responsible for the graphical components of the view. It handles commands from the menu items such as deleting landmarks, editing landmarks, creating blank landmarks and creating landmarks based on the current location. To be able to fetch the current location, it implements the MLandmarksOperationObserver interface that is notified when an asynchronous location acquisition request is completed.
| |
CLandmarksContainer contains a listbox displaying landmark names and a search field for filtering the displayed landmarks. The listbox is dependent on the search field and the responsibility of this class is to update the listbox and the listbox model with new landmarks whenever the search field has been updated or an event from the database has been reported. Since filtering is an asynchronous process, it implements MLandmarksOperationObserver to be notified about the progress of the filter process. It also implements the MLandmarksDbObserver interface to be notified about database events.
| |
This is the data model for the listbox with landmarks. The model consists of a list of the landmark IDs, a list of the landmark icons and a list of the landmark names.
| |
This is the view displaying categories. It has CLandmarksCategoriesContainer that is responsible for the graphical components of the view. It handles commands from the menu items such as deleting, renaming and creating categories.
| |
CLandmarksCategoriesContainer contains a listbox displaying category names and a search field for filtering the displayed categories. The listbox is dependent on the search field and the responsibility of this class is to update the listbox and the listbox model with new categories whenever the search field has been updated or an event from the database has been reported. Since filtering is an asynchronous process, it implements MLandmarksOperationObserver to be notified about the progress of the filtering process. It also implements the MLandmarksDbObserver interface to be notified about database events.
| |
This is the data model for the listbox with categories. The model consists of a list of the category IDs, a list of the category icons and a list of the category names.
| |
This is an abstract class defining the look and behavior of the view containers. It takes care of creating and destroying the graphical components of a view container.
| |
This is the view displaying a landmark's information. It does not show empty fields. If 'Edit' left softkey is pressed it opens editor dialog using CLandmarksEditDialog.
| |
This container controls a listbox, which displays landmark's information. It is used by CLandmarkInfoView and it uses CLandmarksInfoModel. This class is another candidate to be a listener of MLandmarksDbObserver. If some changes happen to the landmark being shown, the view can be updated. However, for simplicity's sake, this is not implemented.
| |
This is the data model for the landmark's information view. It provides methods for building the container's listbox items.
| |
This class is a dialog for editing a specific landmark. It allows the user to update a landmark to the current location. For this reason, it implements MLandmarksOperationObserver to be notified when a location retrieval is completed. It is also used when a new landmark is being created, in which case an empty landmark is edited.
| |
This class is not shown in figure 15 for simplicity. It is used by CLandmarksEditDialog to allow the changing of landmark categories. It is derived from the CAknMarkableListDialog class.
| |
This class is inherits from CActive and is responsible for acquiring the current location. Location Acquisition API is used for this purpose. It first tries to utilize the default positioning module. If this fails, it tries to fetch the last known location. If that also fails, no location is returned. During the location retrieval, a Wait note is displayed where the user can cancel the operation. |
Class | Description
|
This class provides the interface to the application engine. It encapsulates the whole engine and can be seen as a wrapper since it contains no complex logic but forwards most requests to the appropriate engine class.
| |
Inside the application engine, there is only one instance of the CPosLandmarkDatabase class. Each instance of CPosLandmarkDatabase accepts only one database observer. The CLandmarksDbEventHandler instance is the object that is notified when an event has occurred. The task for this object is to allow several other objects to register for database events and to notify them whenever such an event occurs.
| |
This is an abstract base class for view engines. View engines are active objects, which explains why this class inherits from CActive. It has a CLandmarksLmOpWrapper instance to monitor the execution progress of asynchronous Landmarks Framework functions. It contains a CPosLandmarkSearch instance to be able to search for landmarks and categories and it handles setting the priority of a view engine. A view engine should have low priority when its corresponding view is deactivated and normal priority when its view is activated.
| |
This view engine serves the Landmarks view. All the functions this view needs to execute are implemented by this class, e.g. filtering landmarks, reading landmarks, removing landmarks, etc.
| |
This view engine serves the Categories view. All the functions this view needs to execute are implemented by this class, e.g. filtering categories, creating categories, committing categories, etc.
| |
As stated before, several time-consuming operations in the Landmarks Framework return a handle to themselves when executed. Such a handle is an instance of the CPosLmOperation class and makes it possible to execute the operation incrementally. CPosLmOpWrapper is an active object that wraps a CPosLmOperation instance. Its task is to take care of the incremental execution. |
A filter change is caught by the application UI that is the initiator of a filter operation Filtering can be split into two sub-operations: searching/sorting and reading. Filtering must be done incrementally in order to keep the UI ready to respond to user activity. The filtering operation must be carried out by active objects since the Landmarks Framework requires this. In order to update the UI as fast as possible, all the landmarks that match a specific filter cannot be read before updating the UI. Since reading is done incrementally, it is better if the landmarks read so far are displayed. As the number of read landmarks increases, the list is dynamically updated in the background. Only the name field and the icon field of a landmark need to be read. This implies that it is sufficient to read landmarks partially.
All these criteria end up in the following filtering algorithm:
1. The initial state is that the list of landmarks is updated.
2. The list needs to be updated either because the filter has changed or because a database event has been reported.
3. The application UI initiates the application engine to start a search and sort operation. This operation is done asynchronously and incrementally.
4. The search/sort operation may be cancelled for some reason (for example, the filter might have changed) and the application UI cancels the search operation in the application engine and returns to the initial state to wait for a new event.
5. The incremental search/sort operation is not ready and another step of the incremental search has to be executed.
6. The search/sort operation is completed and the reading of the found landmarks can be started.
7. The application UI is notified about the search result and the list displaying the old landmarks is emptied.
8. If no items are found, the application UI returns to the initial state.
9. If there are any landmarks matching the filter, the application UI initiates the application engine to start a landmark read operation.
10. Reading landmarks is done asynchronously, incrementally and partially. Reading landmarks partially means that a subset of all the landmark attributes is read. In this case, only the landmark name and the landmark icon are read.
11. The read operation may also be cancelled for some reason (for example, the filter might have changed) and the application UI cancels the operation in the application engine and returns to the initial state to wait for a new event.
12. If less than one page of landmarks has been read, the reading of landmarks continues incrementally.
13. If a complete page of landmarks has been read, these landmarks can be displayed before reading the next page. This decreases the response time considerably.
14. The application UI is notified that a new page of landmarks has been successfully read and the page is appended to the list.
15. If there are more landmarks to be read, reading is continued.
16. If there are no more landmarks to read, the application UI returns to the initial state.
Transition | Description
|
1 | When acquiring a location, first the default positioning module is used.
|
2 | If the default positioning module succeeds, the location is accepted.
|
3 | If the request for the current location is cancelled, no location is acquired.
|
4 | If the default positioning module fails to acquire the location, an attempt to acquire the last known location is made.
|
5 | If acquiring the last known location succeeds, the location is accepted.
|
6-7 | If acquiring the last known location fails for some reason, no location is acquired. |
Message | Description
|
1-3 | Before creating any views, the CLandmarksAppUi instance creates the application engine.
|
4-5 | When the Landmarks view engine is created, partial read parameters are set.
|
6 | The Categories view engine is created.
|
7-8 | Before the database can be utilized by any view, it must be initialized. This is done asynchronously.
|
9-11 | When the database has been initialized, it is safe to create and activate the views. Note: CLandmarksInfoView is also created at this stage.
|
12-13 | When the Landmarks view is activated for the first, time its container is created. During the construction, the container registers itself as an observer of database events. This procedure is repeated by the Categories view when it is activated for the first time.
|
14 | The last step of the initialization is to start populating the listbox with landmarks. |
Message | Description
|
1-3 | During the construction of CLandmarksEngine, a new CPosLmPartialReadParameters instance is created.
|
4 | The attributes to set are landmark name and landmark icon as this is the only information displayed in the listbox. Note that these partial read parameters have impact when reading landmarks partially. When reading a landmark completely, they have no impact at all.
|
5 | The new partial read parameters are set to the database. |
Message | Description
|
1-4 | During the construction of CLandmarksAppUi, it tries to start initializing the database if needed.
|
5-6 | If the database needs to be initialized, a database initialization operation is prepared and an operation handle is returned.
|
7 | The incremental initialization is started by executing the next step.
|
8-9 | If the database needs to be initialized, CLandmarksAppUi creates and launches a progress dialog. Otherwise, no action is taken since the database is already prepared for use.
|
10-12 | The first incremental step of the initialization process is completed and the CLandmarksAppUi instance is notified. It handles this event by updating the progress bar according to the progress status of the operation.
|
13 | The next step of the initialization is executed.
|
14-16 | Step 10-13 are repeated until the initialization process is totally completed. Finally, the progress dialog is dismissed. |
Message | Description
|
1-2 | During the application startup, the view containers are registered as database observers to the application engine.
|
3-4 | If there is no database event handler, it is dynamically created. During the construction, it starts to listen for database events.
|
5-6 | Whenever an event is generated, the database event handler catches and distributes the event to all registered observers, i.e. the view containers.
|
7 | The view containers investigate the event and start to refresh their contents if necessary.
|
8 | When the database event handler has distributed the event to all registered observers, it immediately starts listening for new events. |
Message | Description
|
1-2 | A write operation is going to be performed and the size of the database is retrieved.
|
3-4 | The usage of the database is investigated and if the database usage is below a certain level, a compact operation is requested.
|
5 | The compact operation can be executed asynchronously or synchronously. In this case, it is executed synchronously and it is automatically deleted by the framework. |
Message | Description
|
1-3 | The user has activated the menu command for adding a landmark. The framework generates an event that is handled by the Landmarks view. A new landmark object instance is created in memory.
|
4-6 | The edit dialog is created and started.
|
7 | The current location is acquired if the user creates a landmark based on the current location and the blank landmark is updated with this location. If no location was acquired, the landmark remains blank.
|
8-12 | The user edits the landmark’s fields and then accepts the changes. The data from the input fields is saved to the landmark.
|
13-14 | The landmark is stored in the database.
|
15 | Since a write operation has taken place in the database, the level of obsolete contents is checked and the database is compacted if necessary. |
Message | Description
|
1 | The user has activated the menu command for adding a landmark based on the current location. The framework generates an event that is handled by the Landmarks view.
|
2-4 | A request is made to acquire the current location. A Wait note is created and launched.
|
5-7 | If not already initialized, a connection is established with Location Server, a sub-session to the default positioning module is opened and this application is set as the location requestor.
|
8 | The default positioning module is requested to retrieve a location.
|
9-10 | The default positioning module completes the request and the status is checked. If the request was not successful, another trial is made to acquire the last known location.
|
11-12 | The request for the last known location is completed and the status is checked. The Wait note is dismissed.
|
13 | The caller that requested the current location is notified with the status of the request. |
Message | Description
|
1 | The user has activated the menu command for deleting a landmark. The framework generates an event that is handled by the Landmarks view.
|
2-3 | The ID of the selected landmark is fetched from the listbox model.
|
4-6 | The selected landmark is read and its name is extracted. A query dialog is launched asking the user to confirm if the landmark should be deleted.
|
7-8 | If the query is accepted, the landmark is removed from the database.
|
9 | Since a write operation has taken place in the database, the level of obsolete contents must be checked. If necessary, the database should be compacted to prevent unrestrained growth. |
Message | Description
|
1-2 | The user has updated the filter in the search field of the Landmarks view. Since CLandmarksContainer is observing the search field, it is notified by the framework. The container handles this event by initiating a new landmark search operation with the current filter.
|
3-4 | The application engine prepares the search operation by constructing the search criteria; only those landmarks whose name contains the filter will be qualified as matches.
|
5-6 | The search/sort operation is created. Note the second parameter indicating that the found matches should be sorted by name in ascending order. Since searching is a heavy operation, an operation handle is returned.
|
7 | The first step of the search/sort operation is executed.
|
8-9 | The first step of the search/sort operation is completed and the next step is started if the operation was not fully completed.
|
10-15 | The last step of the search/sort operation is completed and the matches are retrieved. First an iterator is retrieved, and from this iterator, an array of landmark ids is fetched. The container that initiated the search operation is notified that the sorted matches can be fetched.
|
16-18 | The observer fetches the filtered landmarks and initiates a read operation.
|
19-21 | One page of landmarks is prepared to be partially read. Only the name and the icon of the landmarks will be read. The first incremental step of reading the page is started.
|
22-23 | The first incremental step of reading a page of landmarks is completed. If all the landmarks in the page were not read, the next step of the read operation is executed.
|
24-29 | When the page has been completely read, the container that initiated the read operation is notified. The container fetches the landmarks and updates its listbox of landmarks by appending the current page to it.
|
30-32 | The next page of landmarks is prepared to be read and the procedure of reading a page of landmarks is repeated.
|
33-34 | When there are no more landmarks to read, the container is notified that the read operation is ready. |
Another method to filter landmarks is to use the CPosLmDisplayData class from Landmarks Search API along with the CPosLandmarksSearch class. This approach allows the receiving of a landmark's data already during the search operation and avoiding the additional step of reading landmarks.
Message | Description
|
1 | The user has activated the menu command for renaming a category. The framework generates an event that is handled by the Categories view.
|
2-6 | The ID of the selected category is fetched from the listbox model.
|
7-10 | A request is sent to the application engine to read the selected category from the database. The category is read and returned.
|
11 | The name of the category is extracted and a text query editor is launched and initialized with the category name.
|
12 | When the name has been edited and the dialog dismissed, the category is updated with the new name.
|
13-14 | The category is committed to the database.
|
15 | Since a write operation has taken place in the database, the level of obsolete contents must be checked. If necessary, the database should be compacted to prevent unrestrained growth. |
|
© Nokia 2006 |