Searching landmarks
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::NewL()
.
Configuring search
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::SetMaxNumOfMatches()
. 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::SetMaxNumOfMatches()
.
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::StartLandmarkSearchL()
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::StartLandmarkSearchL()
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.
Related APIs
CPosLandmarkSearch
CPosLandmarkSearch::SetMaxNumOfMatches()
CPosLandmarkSearch::StartLandmarkSearchL()
CPosLmIdListCriteria
KPosLmMaxNumOfMatchesUnlimited
TPosLmSortPref
Specifying search criteria
In order to specify what landmarks to search for the client uses
criterion classes. The criteria are passed to
CPosLandmarkSearch::StartLandmarkSearchL()
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:
-
By category ID: A category in a landmark database is identified
by an ID, which is unique within the database.
-
By global category: There is a globally defined list of categories,
which can be used in multiple databases. The client can specify one
of these by global ID.
-
By category name: The client can specify the name of the category.
The name search is case sensitive. Wild card patterns are not supported.
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:
-
-90 ≤ South Latitude ≤ North Latitude ≤ +90
-
-180 ≤ West Longitude < +180
-
-180 ≤ East Longitude ≤ +180
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::SetMaxNumOfMatches()
.
It is often a good idea to specify a maximum distance to narrow
down the search. This is done by calling
CPosLmNearestCriteria::SetMaxDistance()
.
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::SetUseCoverageRadius()
. 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::AddArgument()
.
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:
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.
Related APIs
CPosLandmarkSearch::SetMaxNumOfMatches()
CPosLandmarkSearch::StartLandmarkSearchL()
CPosLmAreaCriteria
CPosLmCategoryCriteria
CPosLmCompositeCriteria
CPosLmCompositeCriteria::AddArgument()
CPosLmIdListCriteria
CPosLmNearestCriteria
CPosLmNearestCriteria::SetMaxDistance()
CPosLmNearestCriteria::SetUseCoverageRadius()
CPosLmTextCriteria
Executing search
A search for landmarks is started by calling
CPosLandmarkSearch::StartLandmarkSearchL()
.
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::ExecuteL()
runs the operation all at once
and CPosLmOperation::NextStep()
runs the operation
incrementally. When the search is complete, the client must delete
the CPosLmOperation
object.
Instead of calling
CPosLmOperation::ExecuteL()
, 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::NextStep()
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::NextStep()
. 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::MatchIteratorL()
. 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.
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 following example shows how to use composite criterion to search
for landmark which start from latter "A" or " A" (space + A)”, Example
result for this type of search can be 'Apple' & ' My Apple' both.
// Create the composite criterion
CPosLmCompositeCriteria* compCrit = CPosLmCompositeCriteria::NewLC(
CPosLmCompositeCriteria::ECompositionOR );
// Create the Text criterion and add it to composite
_LIT( KFirstTextPattern, "A" );
CPosLmTextCriteria* criteria1 = CPosLmTextCriteria::NewLC();
criteria1->SetTextL(KFirstTextPattern);
criteria1->SetAttributesToSearch(CPosLandmark::ELandmarkName);
User::LeaveIfError( compCrit->AddArgument( criteria1 ) );
// Ownership of the text criterion has been passed to the composite
CleanupStack::Pop(criteria1);
// Create the text search criterion and add it to composite
_LIT( KSecondTextPattern, " A" );
CPosLmTextCriteria* textCrit = CPosLmTextCriteria::NewLC();
textCrit->SetTextL( KSecondTextPattern );
textCrit->SetAttributesToSearch(CPosLandmark::ELandmarkName);
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
Related APIs
CPosLandmarkSearch
CPosLandmarkSearch::MatchIteratorL()
CPosLandmarkSearch::StartLandmarkSearchL()
CPosLmOperation
CPosLmOperation::ExecuteL()
CPosLmOperation::NextStep()
ExecuteAndDeleteLD()
KErrNone
KPosLmOperationNotComplete
TRequestStatus
Retrieving displayable results
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::SetDisplayData()
. 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::SetPartialReadParametersL()
. 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::UnsetPartialReadParametersL()
.
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::UnsetDisplayData()
.
If display data has been set before the search is started, all
matches from the search can be retrieved by calling
CPosLmDisplayData::DisplayItem()
for all the indexes in the interval [0, CPosLmDisplayData::Count()
- 1]. By calling CPosLmDisplayItem::Landmark()
or CPosLmDisplayItem::Category()
, the client
gets access to the match.
During a search,
CPosLmDisplayData::NewItemIndex()
can be called repeatedly to get the index of each new match found
and CPosLmDisplayData::DisplayItem()
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.
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;
}
Related APIs
CPosLandmarkSearch::SetDisplayData()
CPosLandmarkSearch::UnsetDisplayData()
CPosLmDisplayData
CPosLmDisplayData::Count()
CPosLmDisplayData::DisplayItem()
CPosLmDisplayData::NewItemIndex()
CPosLmDisplayData::SetPartialReadParametersL()
CPosLmDisplayData::UnsetPartialReadParametersL()
CPosLmDisplayItem::Category()
CPosLmDisplayItem::Landmark()
CSearchHandler
Related APIs
CPosLandmarkDatabase
CPosLandmarkSearch
CPosLandmarkSearch::NewL()
Searching categories
A search for landmark categories is started by calling
CPosLandmarkSearch::StartCategorySearchL()
. 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::StartCategorySearchL()
takes CPosLandmarkCategory::TCategorySortPref
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 );
Related APIs
CPosLandmarkCategory::TCategorySortPref
CPosLandmarkSearch::StartCategorySearchL()
CPosLmCatNameCriteria