The client uses CPosLandmarkSearch to search landmarks in a landmarks database.
To create a CPosLandmarkSearch
instance, the client must
specify a database to search in. A handle to an open database (CPosLandmarkDatabase
instance)
is passed to CPosLandmarkSearch
.
CPosLandmarkSearch
can be configured by setting certain
parameters described below.
Maximum number of matches
The client can set a maximum number of matches by calling CPosLandmarkSearch
.
The search operation stops if the maximum number of matches is reached.
If the client does not set a maximum, the search returns all the matches
in the database. The client can also set this explicitly by passing KPosLmMaxNumOfMatchesUnlimited
to CPosLandmarkSearch
.
Search previous matches only
If the CPosLandmarkSearch
instance has just finished
a search, the client can specify that only these matches should be considered
in the next search. This is specified by passing a boolean value to CPosLandmarkSearch
when
the search is started. In that way, the client can refine its search, for
instance, if there are too many matches.
Searching previous matches is useful if there are too many matches and the application user wants to narrow down the search before listing all matches.
It is also possible to use CPosLmIdListCriteria
to search
previous matches that are not immediate previous matches (see Search criteria).
Sort preference
The client can specify that the matching landmarks or landmark categories should be sorted.
One of CPosLandmarkSearch
method
overloads takes TPosLmSortPref
as parameter. In TPosLmSortPref,
the client can specify whether the landmarks should be sorted by name in ascending
or descending order.
In order to specify what landmarks to search for the client uses criterion
classes. The criteria are passed to CPosLandmarkSearch
when
the search is started. In this section, each criterion class is explained.
Landmarks by category
CPosLmCategoryCriteria
is used to search for landmarks,
which belong to a certain category. The category is specified in one of the
following ways:
If no category is specified, the search operation retrieves uncategorized landmarks.
The predefined global landmark categories are listed in Landmarks API Specification.
Matching text pattern
CPosLmTextCriteria
is used to search for landmarks,
which contain a certain text. The criterion is defined by providing a text
to search for and the position fields and text attributes to search in each
landmark. For example, the user can search for “Chinese” in the landmark description
and landmark name attributes.
The search is case insensitive.
If no position fields or landmark attributes to search are specified, all the position fields and landmark attributes are searched in each landmark.
Wild card characters are supported in the search string: "?" matches any single character and "*" matches zero or more consecutive characters.
Landmarks within an area
CPosLmAreaCriteria
is used to search for landmarks,
which reside in a certain area. The search area is defined by providing two
latitude and two longitude values that specify the borders of the area.
Note: This search does not consider landmark coverage radius (coverage radius is defined in Landmarks API).
The area borders must fulfill the following rules:
The east border longitude can be less than the west border longitude. This defines an area, which crosses the 180 meridian.
If the east and west border longitudes are equal, only landmarks that lie on the specified longitude are returned. Similarly, if the north and south border latitudes are equal, only landmarks that lie on the specified latitude are returned.
If west longitude is set to -180 and east longitude is set to +180, all longitudes are included in the search.
Nearest landmarks
CPosLmNearestCriteria
is used to find the landmarks,
which are closest to a certain coordinate. By default, the matches returned
in the search are sorted in an ascending distance order.
Since this operation returns all the landmarks in the database by default,
it is recommended to combine the nearest criteria with a limit on the number
of matches. The match limit is set by calling CPosLandmarkSearch
.
It is often a good idea to specify a maximum distance to narrow down the
search. This is done by calling CPosLmNearestCriteria
.
By default, the coverage radius of the landmarks is not considered in the
search; that is, the distance to the landmark center point is used. The client
can change this behavior by calling CPosLmNearestCriteria
.
If ETrue is passed to this function, coverage radius is considered; that is,
the effective distance is the distance to the landmark center point minus
the coverage radius. If the search coordinate lies within a landmark’s coverage
area, the effective distance is zero.
Composite criterion
CPosLmCompositeCriteria
is used to search for landmarks
by combining multiple search criteria. For instance, to search for all restaurants
in the area, this class can be used to combine CPosLmAreaCriteria
and CPosLmCategoryCriteria
The client combines the criteria by passing each criterion instance to CPosLmCompositeCriteria
.
If CPosLmNearestCriteria
is used and no sort preference
is specified, the result will be sorted by distance. If more than one CPosLmNearestCriteria
are
combined using CPosLmCompositeCriteria
, the sort order
will be undefined unless a sort preference is specified.
Note: It is not allowed to use nested composite criterion.
ID list
CPosLmIdListCriteria
is used if the client only wants
to search a subset of the landmarks in a database. The client passes a list
of landmark IDs to specify which landmarks to include in the search.
This criterion must be combined with other search criteria using CPosLmCompositeCriteria
(see Composite
criterion above).
For example, if this criterion is combined with CPosLmTextCriteria
,
the search operation searches the landmarks specified in the ID list criterion
and returns those that match the given text string.
Note: Only one ID list criterion is allowed in a composite criterion.
A search for landmarks is started by calling CPosLandmarkSearch
.
This function returns a CPosLmOperation
instance, which
is used to execute the search operation. The operation can either be executed
all at once or in incremental steps. An active object can be used to incrementally
run the search in the background. CPosLmOperation
runs
the operation all at once and CPosLmOperation
runs
the operation incrementally. When the search is complete, the client must
delete the CPosLmOperation
object.
Instead of calling CPosLmOperation
, the
client can call the global function ExecuteAndDeleteLD()
which
also deletes the operation object. For example:
ExecuteAndDeleteLD( search->StartLandmarkSearchL( criteria ) );
If the search is run incrementally, the client is informed of the search
progress. The client passes a TReal32 variable to CPosLmOperation
which
contains the progress when NextStep() completes.
Progress is a floating point number in the interval [0.0, 1.0]. 0.0 indicates that the operation has not started and 1.0 indicates that the operation has completed.
The client also passes TRequestStatus
to CPosLmOperation
.
The request status is set to KPosLmOperationNotComplete
if
the step has completed, but more steps are needed before the operation is
complete. The request status is KErrNone
if the operation
has finished successfully. The status is set to an error code if the operation
has failed.
The IDs of the matches from the search can be retrieved by calling CPosLandmarkSearch
.
It is possible to call it also during a search to retrieve any matches encountered
so far, but it is not guaranteed that the matches are sorted. However, the
matches in the iterator are always sorted, also during a search, if a display
data is set to CPosLandmarkSearch
before the search is
started.
The sequence diagram below shows how client searches landmarks by text criterion and reads matches from database.
Figure 4: Search landmarks sequence diagram
The following code example shows how to perform a search synchronously (not incrementally) in a landmark database.
// Create a search object and provide the CPosLandmarkDatabase object. CPosLandmarkSearch* search = CPosLandmarkSearch::NewL( *database ); CleanupStack::PushL( search ); // Create the search criterion _LIT( KSearchString, "flowers" ); CPosLmTextCriteria* crit = CPosLmTextCriteria::NewLC(); crit->SetTextL( KSearchString ); // Start the search and execute it at once. ExecuteAndDeleteLD( search->StartLandmarkSearchL( *crit ) ); CleanupStack::PopAndDestroy( crit ); // Retrieve an iterator to access the matching landmarks. CPosLmItemIterator* iter = search->MatchIteratorL(); CleanupStack::PushL( iter ); // Iterate the search matches. TPosLmItemId lmID; while ( ( lmID = iter->NextL() ) != KPosLmNullItemId ) { CPosLandmark* lm = database->ReadLandmarkLC( lmID ); // Do something with the landmark information CleanupStack::PopAndDestroy( lm ); } CleanupStack::PopAndDestroy( iter ); CleanupStack::PopAndDestroy( search );
The following example shows how to use composite criterion to search for restaurants, which contain the text “thai”.
// Create the composite criterion CPosLmCompositeCriteria* compCrit = CPosLmCompositeCriteria::NewLC( CPosLmCompositeCriteria::ECompositionAND ); // Create the category search criterion and add it to composite _LIT( KCategoryName, "restaurant" ); CPosLmCategoryCriteria* catCrit = CPosLmCategoryCriteria::NewLC(); catCrit->SetCategoryNameL( KCategoryName ); User::LeaveIfError( compCrit->AddArgument( catCrit ) ); // Ownership of the category criterion has been passed to the composite CleanupStack::Pop( catCrit ); // Create the text search criterion and add it to composite _LIT( KSearchString, "thai" ); CPosLmTextCriteria* textCrit = CPosLmTextCriteria::NewLC(); textCrit->SetTextL( KSearchString ); User::LeaveIfError( compCrit->AddArgument( textCrit ) ); // Ownership of the text criterion has been passed to the composite CleanupStack::Pop( textCrit ); // Start the search ExecuteAndDeleteLD( search->StartLandmarkSearchL( *compCrit ) ); CleanupStack::PopAndDestroy( compCrit ); // Retrieve matches
The client can specify a displayable data collection that will be populated
with the matching landmarks or landmark categories during the search. This
is done by creating a CPosLmDisplayData
instance and passing
it to CPosLandmarkSearch
. The display
data object will be reset each time a new search is started.
The client can specify that only partial landmark data will be read from
the database by calling CPosLmDisplayData
.
If the client does not set partial read parameters, full landmark data will
be read. The client can also set this explicitly by calling CPosLmDisplayData
.
When searching for categories, full category data is always read from the database.
The client can unset a previously set display data by calling CPosLandmarkSearch
.
If display data has been set before the search is started, all matches
from the search can be retrieved by calling CPosLmDisplayData
for
all the indexes in the interval [0, CPosLmDisplayData
-
1]. By calling CPosLmDisplayItem
or CPosLmDisplayItem
,
the client gets access to the match.
During a search, CPosLmDisplayData
can
be called repeatedly to get the index of each new match found and CPosLmDisplayData
can
be called for each new index. The matches in the display data are always sorted,
even during a search.
The following sequence diagram shows how to perform a search synchronously (not incrementally) in a landmark database using display data.
Figure 5: Using display data sequence diagram
The following example shows how to search a landmark database incrementally.
The client also requests to sort the matches. The implementation is encapsulated
in active object class CSearchHandler
.
class CSearchHandler : public CActive { public: // constructor and destructor static CSearchHandler* NewL(CPosLandmarkDatabase* aDb); virtual ~CSearchHandler(); public: void StartLandmarkSearchL(CPosLmSearchCriteria* aCriteria); void StartCategorySearchL(CPosLmSearchCriteria* aCriteria); void NextSearchStep(); void CleanupSearch(); public: // from CActive void RunL(); void DoCancel(); TInt RunError(TInt aError); private: CSearchHandler(CPosLandmarkDatabase* aDb); void ConstructL(); private: CPosLandmarkDatabase* iDb; CPosLandmarkSearch* iSearch; CPosLmDisplayData* iDisplayData; CPosLmOperation* iSearchOperation; TReal32 iProgress; TBool iIsSearchingForLandmarks; }; CSearchHandler::CSearchHandler( CPosLandmarkDatabase* aDb ) : CActive( EPriorityNormal ), iDb( aDb ) { } void CSearchHandler::ConstructL() { iSearch = CPosLandmarkSearch::NewL( *iDb ); iDisplayData = CPosLmDisplayData::NewL(); iSearch->SetDisplayData( *iDisplayData ); } CSearchHandler* CSearchHandler::NewL( CPosLandmarkDatabase* aDb ) { CSearchHandler* self = new (ELeave) CSearchHandler( aDb ); CleanupStack::PushL( self ); self->ConstructL(); CleanupStack::Pop(); return self; } CSearchHandler::~CSearchHandler() { Cancel(); iSearch->UnsetDisplayData(); delete iDisplayData; delete iSearch; } void CSearchHandler::StartLandmarkSearchL( CPosLmSearchCriteria* aCriteria ) { TPosLmSortPref sp( CPosLandmark::ELandmarkName, TPosLmSortPref::EAscending ); iSearchOperation = iSearch->StartLandmarkSearchL( *aCriteria, sp ); iIsSearchingForLandmarks = ETrue; // Perform the first step in the incremental search operation. NextSearchStep(); } void CSearchHandler::StartCategorySearchL( CPosLmSearchCriteria* aCriteria ) { iSearch->StartCategorySearchL( *aCriteria, CPosLmCategoryManager::ECategorySortOrderNameAscending ); iIsSearchingForLandmarks = EFalse; // Perform the first step in the incremental search operation. NextSearchStep(); } void CSearchHandler::NextSearchStep() { iSearchOperation->NextStep( iStatus, iProgress ); SetActive(); } void CSearchHandler::CleanupSearch() { // Delete the search operation. This will cancel the operation if it is not // already complete. delete iSearchOperation; iSearchOperation = NULL; } void CSearchHandler::RunL() { // Get all new matches since last step. TInt newItemIndex = iDisplayData->NewItemIndex(); while ( newItemIndex != KPosLmNoNewItems ) { CPosLmDisplayItem& item = iDisplayData->DisplayItem( newItemIndex ); if (iIsSearchingForLandmarks) { const CPosLandmark& lm = item.Landmark(); // Do something with the landmark information } else { const CPosLandmarkCategory& category = item.Category(); // Do something with the landmark category information } newItemIndex = iDisplayData->NewItemIndex(); } if ( iStatus == KPosLmOperationNotComplete ) { // The search operation has not completed. // Use value iProgress to show progress bar to the application user. // Perform the next search step NextSearchStep(); } else { // The search operation has completed. User::LeaveIfError( iStatus.Int() ); CleanupSearch(); } } void CSearchHandler::DoCancel() { CleanupSearch(); } TInt CSearchHandler::RunError( TInt /*aError*/ ) { // Notify application user of error and cleanup. CleanupSearch(); return KErrNone; }
A search for landmark categories is started by calling CPosLandmarkSearch
.
All the other steps are similar to those for searching landmarks with a few
exceptions.
Searching for categories supports only one search criterion, CPosLmCatNameCriteria
:
search for landmark categories with a certain name. Wild card characters in
the search string are supported: "?" matches any single character and "*"
matches zero or more consecutive characters. The search is case insensitive.
CPosLandmarkSearch
takes CPosLandmarkCategory
as
parameter. It can be set to no sorting, ascending by category name or descending
by category name.
Similarly to searching landmarks searching categories also supports limiting maximum amount of results and searching within previous results only.
Following code example shows how a client can search for categories, which contain word "food" (in order to find categories such as "Food and beverages", "Chinese food", etc.).
// Create a search object and provide the CPosLandmarkDatabase object. CPosCategorySearch* search = CPosCategorySearch::NewL( *database ); CleanupStack::PushL( search ); // Create the search criterion _LIT( KSearchString, "*food*" ); // using wildcards CPosLmCatNameCriteria* crit = CPosLmCatNameCriteria::NewLC(); crit->SetTextL( KSearchString ); // Start the search and execute it at once. ExecuteAndDeleteLD( search->StartLandmarkSearchL( *crit ) ); CleanupStack::PopAndDestroy( crit ); // Retrieve an iterator to access the matching landmarks. CPosLmItemIterator* iter = search->MatchIteratorL(); CleanupStack::PushL( iter ); // Iterate the search matches. TPosLmItemId categoryID; while ( ( categoryID = iter->NextL() ) != KPosLmNullItemId ) { CPosLandmarkCategory* category = database->ReadCategoryLC( categoryID ); // Do something with the category information CleanupStack::PopAndDestroy( category ); } CleanupStack::PopAndDestroy( iter ); CleanupStack::PopAndDestroy( search );
Searching for landmarks or landmark categories in multiple landmark databases is rather similar to searching in one database.
The client creates a CPosLmMultiDbSearch
instance by
passing an array containing the URIs of the landmark databases to search to CPosLmMultiDbSearch
.
The client can also change which databases to search by calling CPosLmMultiDbSearch
.
However, there are some restrictions on the criterion classes and some extra functionality needed to handle several databases:
CPosLmCategoryCriteria
is
not allowed since an ID is only valid in one landmark database.
CPosLmIdListCriteria
is not allowed since
an ID is only valid in one landmark database.
CPosLmOperation
will
never leave and CPosLmOperation
will not complete
with an error code (the only exception is when the client has an outstanding
request when canceling the search, in which case the complete code will be KErrCancel
).
Instead, CPosLmMultiDbSearch
must be checked for any errors
encountered during the search.
CPosLmMultiDbSearch
. Each
error can be fetched by calling CPosLmMultiDbSearch
and
passing the index of the error.
ReleaseLandmarkResources()
which
has the same effect as REComSession::FinalClose()
. The
most common way to release landmark resources is to call ReleaseLandmarkResources(
)
last thing in the client’s destructor. If this is not done, the client may
receive an ALLOC panic.
This example shows how to perform a search synchronously (not incrementally) in multiple landmark databases.
void SearchInDatabasesL( const CDesCArray& aDatabaseURIs ) { // Create a multi search object and provide a list of database URIs. CPosLmMultiDbSearch* search = CPosLmMultiDbSearch::NewL( aDatabaseURIs ); CleanupStack::PushL( search ); // Create a display data object. CPosLmDisplayData* displayData = CPosLmDisplayData::NewL(); CleanupStack::PushL( displayData ); // Set the display data to the search object. search->SetDisplayData( *displayData ); // Create the search criterion _LIT( KSearchString, "flowers" ); CPosLmTextCriteria* crit = CPosLmTextCriteria::NewLC(); crit->SetTextL( KSearchString ); // Start the search and execute it all at once. ExecuteAndDeleteLD( search->StartLandmarkSearchL( *crit ) ); CleanupStack::PopAndDestroy( crit ); // Check if any errors have occured. TUint numOfErrors = search->NumOfSearchErrors(); for ( TUint i = 0; i < numOfErrors; i++ ) { CPosLmMultiDbSearch::TSearchError searchError; search->GetSearchError( i, searchError ); // Do something with error } // Iterate the search matches. for ( TInt i = 0; i < displayData->Count(); i++ ) { const CPosLandmark& lm = displayData->DisplayItem( i ).Landmark(); // Do something with the landmark information } // Unset display data collection so that it is not reset by next search search->UnsetDisplayData(); CleanupStack::PopAndDestroy( displayData ); CleanupStack::PopAndDestroy( search );
Landmarks Search API uses the standard Symbian error reporting mechanism. In case of a serious error, panics are used. Otherwise, errors are reported through return codes or leaves.
Landmarks Search API uses the same panic code category as Landmarks API. The panic codes are documented in Landmarks API specification.
If there are several matches (more than 1000) in a search, a large amount of memory is needed to store the matches. It might therefore be a good idea to set a maximum number of matches before starting the search. Note, however, that it is the first found matches that are retrieved. For example, if the maximum number of matches is set when searching in sorted order, the result can be without a match although its name is in the beginning of the sort order.
There are no extensions defined to Landmarks Search API.
Landmarks are considered as important user data and this applies some access
limitations to client applications. For example, in order to be able to read
landmarks from landmark database client must have ReadUserData
capability.
The NetworkServices
is required to access network-based databases.
Whenever special capabilities are needed to utilize a class or method, they
are listed in appropriate class and method descriptions.