[map] Parse search request.

This commit is contained in:
VladiMihaylenko 2017-04-04 13:57:31 +03:00
parent e9b446ff43
commit d3256769d6
7 changed files with 185 additions and 53 deletions

View file

@ -51,7 +51,13 @@ bool Uri::ForEachKeyValue(TCallback const & callback) const
{
// parse query for keys and values
size_t const count = m_url.size();
for (size_t start = m_queryStart; start < count; )
size_t const queryStart = m_queryStart;
// Just a URL without parametrs.
if (queryStart == count)
return false;
for (size_t start = queryStart; start < count; )
{
size_t end = m_url.find('&', start);
if (end == string::npos)

View file

@ -317,6 +317,7 @@ void Framework::OnViewportChanged(ScreenBase const & screen)
UpdateUserViewportChanged();
m_currentModelView = screen;
m_isViewportInitialized = true;
m_trafficManager.UpdateViewport(m_currentModelView);
m_localAdsManager.UpdateViewport(m_currentModelView);
@ -1290,7 +1291,6 @@ bool Framework::SearchEverywhere(search::EverywhereSearchParams const & params)
GetPlatform().RunOnGuiThread([params, results]() { params.m_onResults(results); });
};
SetCurrentPositionIfPossible(p);
return Search(p);
}
@ -1490,14 +1490,10 @@ bool Framework::Search(search::SearchParams const & params)
if (ParseEditorDebugCommand(params))
return true;
m2::RectD const viewport = GetCurrentViewport();
if (QueryMayBeSkipped(intent, rParams, viewport))
if (QueryMayBeSkipped(intent, rParams, GetCurrentViewport()))
return false;
intent.m_params = rParams;
intent.m_viewport = viewport;
// Cancels previous search request (if any) and initiates new search request.
CancelQuery(intent.m_handle);
@ -1509,11 +1505,26 @@ bool Framework::Search(search::SearchParams const & params)
intent.m_params.m_minDistanceOnMapBetweenResults = eps;
}
intent.m_handle = m_searchEngine->Search(intent.m_params, intent.m_viewport);
Search(intent);
return true;
}
void Framework::Search(SearchIntent & intent) const
{
if (!m_isViewportInitialized)
{
Platform().RunOnGuiThread([this, &intent]
{
this->Search(intent);
});
return;
}
intent.m_viewport = GetCurrentViewport();
intent.m_handle = m_searchEngine->Search(intent.m_params, intent.m_viewport);
}
void Framework::SetCurrentPositionIfPossible(search::SearchParams & params)
{
double lat;
@ -2074,6 +2085,11 @@ Framework::ParsedRoutingData Framework::GetParsedRoutingData() const
routing::FromString(m_ParsedMapApi.GetRoutingType()));
}
url_scheme::SearchRequest Framework::GetParsedSearchRequest() const
{
return m_ParsedMapApi.GetSearchRequest();
}
unique_ptr<FeatureType> Framework::GetFeatureAtPoint(m2::PointD const & mercator) const
{
unique_ptr<FeatureType> poi, line, area;

View file

@ -394,6 +394,7 @@ private:
};
unique_ptr<TapEvent> m_lastTapEvent;
bool m_isViewportInitialized = false;
void OnTapEvent(TapEvent const & tapEvent);
/// outInfo is valid only if return value is not df::SelectionShape::OBJECT_EMPTY.
@ -497,8 +498,6 @@ private:
bool m_connectToGpsTrack; // need to connect to tracker when Drape is being constructed
void Search(SearchIntent const & intent);
void SetCurrentPositionIfPossible(search::SearchParams & params);
void FillSearchResultsMarks(search::Results const & results);
@ -516,6 +515,7 @@ private:
SearchIntent m_searchIntents[static_cast<size_t>(search::Mode::Count)];
bool Search(search::SearchParams const & params);
void Search(SearchIntent & intent) const;
// Returns true when |params| and |viewport| are almost the same as
// the latest search query's params and viewport in the |intent|.
@ -624,6 +624,7 @@ public:
};
ParsedRoutingData GetParsedRoutingData() const;
url_scheme::SearchRequest GetParsedSearchRequest() const;
private:
// TODO(vng): Uncomment when needed.

View file

@ -46,6 +46,7 @@ namespace
bool GoBackOnBalloonClick() const { return m_api.GoBackOnBalloonClick(); }
int GetPointCount() const { return UserMarkControllerGuard(*m_m, type).m_controller.GetUserMarkCount(); }
vector<RoutePoint> GetRoutePoints() const { return m_api.GetRoutePoints(); }
url_scheme::SearchRequest const & GetSearchRequest() const { return m_api.GetSearchRequest(); }
string const & GetGlobalBackUrl() const { return m_api.GetGlobalBackUrl(); }
int GetApiVersion() const { return m_api.GetApiVersion(); }
bool TestLatLon(int index, double lat, double lon) const
@ -128,6 +129,31 @@ UNIT_TEST(RouteApiSmoke)
TEST(test.TestRouteType("vehicle"), ());
}
UNIT_TEST(SearchApiSmoke)
{
string const uriString = "mapsme://search?query=fff&cll=1,1&locale=ru&map";
TEST(Uri(uriString).IsValid(), ());
ApiTest test(uriString);
TEST(test.IsValid(), ());
auto const & request = test.GetSearchRequest();
TEST_EQUAL(request.m_query, "fff", ());
TEST_EQUAL(request.m_centerLat, 1, ());
TEST_EQUAL(request.m_centerLon, 1, ());
TEST_EQUAL(request.m_locale, "ru", ());
TEST(request.m_isSearchOnMap, ());
}
UNIT_TEST(SearchApiInvalidUrl)
{
Framework f;
TEST(!IsValid(f, "mapsme://search?"), ("The url must have at least search query parametr"));
TEST(!IsValid(f, "mapsme://search?query"), ("Search query can't be empty"));
TEST(IsValid(f, "mapsme://search?query=aaa&cll=1,1,1"), ("If it's wrong lat lon format then just ignore it"));
TEST(IsValid(f, "mapsme://search?query=aaa&ignoreThisParam=sure"), ("We shouldn't fail search request if there are some unsopported parameters."));
}
UNIT_TEST(MapApiInvalidUrl)
{
Framework fm;

View file

@ -22,6 +22,10 @@ namespace url_scheme
namespace
{
string const kLatLon = "ll";
string const kQuery = "query";
string const kCenterLatLon = "cll";
string const kLocale = "locale";
string const kSearchOnMap = "map";
string const kSourceLatLon = "sll";
string const kDestLatLon = "dll";
string const kZoomLevel = "z";
@ -39,6 +43,31 @@ string const kRouteTypeVehicle = "vehicle";
string const kRouteTypePedestrian = "pedestrian";
string const kRouteTypeBicycle = "bicycle";
enum class ApiURLType
{
Incorrect,
Map,
Route,
Search
};
ApiURLType URLTypeFrom(Uri const & uri)
{
auto const scheme = uri.GetScheme();
if (scheme != "mapswithme" && scheme != "mwm" && scheme != "mapsme")
return ApiURLType::Incorrect;
auto const path = uri.GetPath();
if (path == "map")
return ApiURLType::Map;
if (path == "route")
return ApiURLType::Route;
if (path == "search")
return ApiURLType::Search;
return ApiURLType::Incorrect;
}
bool ParseLatLon(string const & key, string const & value, double & lat, double & lon)
{
size_t const firstComma = value.find(',');
@ -69,6 +98,7 @@ void ParsedMapApi::SetBookmarkManager(BookmarkManager * manager)
{
m_bmManager = manager;
}
ParsedMapApi::ParsingResult ParsedMapApi::SetUriAndParse(string const & url)
{
Reset();
@ -86,53 +116,58 @@ ParsedMapApi::ParsingResult ParsedMapApi::SetUriAndParse(string const & url)
ParsedMapApi::ParsingResult ParsedMapApi::Parse(Uri const & uri)
{
string const & scheme = uri.GetScheme();
string const & path = uri.GetPath();
bool const isRoutePath = path == "route";
if ((scheme != "mapswithme" && scheme != "mwm" && scheme != "mapsme") ||
(path != "map" && !isRoutePath))
switch (URLTypeFrom(uri))
{
return ParsingResult::Incorrect;
}
if (isRoutePath)
{
m_routePoints.clear();
vector<string> pattern{kSourceLatLon, kSourceName, kDestLatLon, kDestName, kRouteType};
if (!uri.ForEachKeyValue(bind(&ParsedMapApi::RouteKeyValue, this, _1, _2, ref(pattern))))
case ApiURLType::Incorrect:
return ParsingResult::Incorrect;
if (pattern.size() != 0)
return ParsingResult::Incorrect;
if (m_routePoints.size() != 2)
case ApiURLType::Map:
{
ASSERT(false, ());
return ParsingResult::Incorrect;
vector<ApiPoint> points;
if (!uri.ForEachKeyValue(bind(&ParsedMapApi::AddKeyValue, this, _1, _2, ref(points))))
return ParsingResult::Incorrect;
if (points.empty())
return ParsingResult::Incorrect;
ASSERT(m_bmManager != nullptr, ());
UserMarkControllerGuard guard(*m_bmManager, UserMarkType::API_MARK);
for (auto const & p : points)
{
m2::PointD glPoint(MercatorBounds::FromLatLon(p.m_lat, p.m_lon));
ApiMarkPoint * mark = static_cast<ApiMarkPoint *>(guard.m_controller.CreateUserMark(glPoint));
mark->SetName(p.m_name);
mark->SetID(p.m_id);
mark->SetStyle(style::GetSupportedStyle(p.m_style, p.m_name, ""));
}
return ParsingResult::Map;
}
case ApiURLType::Route:
{
m_routePoints.clear();
vector<string> pattern{kSourceLatLon, kSourceName, kDestLatLon, kDestName, kRouteType};
if (!uri.ForEachKeyValue(bind(&ParsedMapApi::RouteKeyValue, this, _1, _2, ref(pattern))))
return ParsingResult::Incorrect;
return ParsingResult::Route;
if (pattern.size() != 0)
return ParsingResult::Incorrect;
if (m_routePoints.size() != 2)
{
ASSERT(false, ());
return ParsingResult::Incorrect;
}
return ParsingResult::Route;
}
case ApiURLType::Search:
SearchRequest request;
if (!uri.ForEachKeyValue(bind(&ParsedMapApi::SearchKeyValue, this, _1, _2, ref(request))))
return ParsingResult::Incorrect;
m_request = request;
return ParsingResult::Search;
}
vector<ApiPoint> points;
if (!uri.ForEachKeyValue(bind(&ParsedMapApi::AddKeyValue, this, _1, _2, ref(points))))
return ParsingResult::Incorrect;
if (points.empty())
return ParsingResult::Incorrect;
ASSERT(m_bmManager != nullptr, ());
UserMarkControllerGuard guard(*m_bmManager, UserMarkType::API_MARK);
for (auto const & p : points)
{
m2::PointD glPoint(MercatorBounds::FromLatLon(p.m_lat, p.m_lon));
ApiMarkPoint * mark = static_cast<ApiMarkPoint *>(guard.m_controller.CreateUserMark(glPoint));
mark->SetName(p.m_name);
mark->SetID(p.m_id);
mark->SetStyle(style::GetSupportedStyle(p.m_style, p.m_name, ""));
}
return ParsingResult::Map;
}
bool ParsedMapApi::RouteKeyValue(string key, string const & value, vector<string> & pattern)
@ -252,6 +287,37 @@ bool ParsedMapApi::AddKeyValue(string key, string const & value, vector<ApiPoint
return true;
}
bool ParsedMapApi::SearchKeyValue(string key, string const & value, SearchRequest & request)
{
if (key == kQuery)
{
if (value.empty())
return false;
request.m_query = value;
}
else if (key == kCenterLatLon)
{
double lat = 0.0;
double lon = 0.0;
if (ParseLatLon(key, value, lat, lon))
{
request.m_centerLat = lat;
request.m_centerLon = lon;
}
}
else if (key == kLocale)
{
request.m_locale = value;
}
else if (key == kSearchOnMap)
{
request.m_isSearchOnMap = true;
}
return !request.m_query.empty();
}
void ParsedMapApi::Reset()
{
m_globalBackUrl.clear();

View file

@ -28,9 +28,18 @@ struct RoutePoint
string m_name;
};
struct SearchRequest
{
string m_query;
string m_locale;
double m_centerLat = 0.0;
double m_centerLon = 0.0;
bool m_isSearchOnMap = false;
};
class Uri;
/// Handles [mapswithme|mwm]://map?params - everything related to displaying info on a map
/// Handles [mapswithme|mwm|mapsme]://map|route|search?params - everything related to displaying info on a map
class ParsedMapApi
{
public:
@ -38,7 +47,8 @@ public:
{
Incorrect,
Map,
Route
Route,
Search
};
ParsedMapApi() = default;
@ -58,13 +68,16 @@ public:
ApiMarkPoint const * GetSinglePoint() const;
vector<RoutePoint> const & GetRoutePoints() const { return m_routePoints; }
string const & GetRoutingType() const { return m_routingType; }
SearchRequest const & GetSearchRequest() const { return m_request; }
private:
ParsingResult Parse(Uri const & uri);
bool AddKeyValue(string key, string const & value, vector<ApiPoint> & points);
bool RouteKeyValue(string key, string const & value, vector<string> & pattern);
bool SearchKeyValue(string key, string const & value, SearchRequest & request);
BookmarkManager * m_bmManager = nullptr;
vector<RoutePoint> m_routePoints;
SearchRequest m_request;
string m_globalBackUrl;
string m_appTitle;
string m_routingType;

View file

@ -94,6 +94,7 @@
67F183831BD5049500AB1840 /* libminizip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 67F1837F1BD5049500AB1840 /* libminizip.a */; };
67F183841BD5049500AB1840 /* libtess2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 67F183801BD5049500AB1840 /* libtess2.a */; };
BB421D6C1E8C0031005BFA4D /* transliteration_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BB421D6A1E8C0026005BFA4D /* transliteration_test.cpp */; };
F627BFC41E8E89B600B1CBF4 /* librouting_common.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F627BFC31E8E89B600B1CBF4 /* librouting_common.a */; };
F63421F81DF9BF9100A96868 /* reachable_by_taxi_checker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F63421F61DF9BF9100A96868 /* reachable_by_taxi_checker.cpp */; };
F63421F91DF9BF9100A96868 /* reachable_by_taxi_checker.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F63421F71DF9BF9100A96868 /* reachable_by_taxi_checker.hpp */; };
F6B283031C1B03320081957A /* gps_track_collection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6B282FB1C1B03320081957A /* gps_track_collection.cpp */; };
@ -216,6 +217,7 @@
67F183851BD504ED00AB1840 /* libsystem_configuration.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsystem_configuration.tbd; path = usr/lib/system/libsystem_configuration.tbd; sourceTree = SDKROOT; };
67F183871BD5050900AB1840 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
BB421D6A1E8C0026005BFA4D /* transliteration_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = transliteration_test.cpp; sourceTree = "<group>"; };
F627BFC31E8E89B600B1CBF4 /* librouting_common.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = librouting_common.a; path = "/Users/v.mikhaylenko/mapsme/omim/xcode/routing_common/../../../omim-build/xcode/Debug/librouting_common.a"; sourceTree = "<absolute>"; };
F63421F61DF9BF9100A96868 /* reachable_by_taxi_checker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reachable_by_taxi_checker.cpp; sourceTree = "<group>"; };
F63421F71DF9BF9100A96868 /* reachable_by_taxi_checker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = reachable_by_taxi_checker.hpp; sourceTree = "<group>"; };
F6B282FB1C1B03320081957A /* gps_track_collection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gps_track_collection.cpp; sourceTree = "<group>"; };
@ -240,6 +242,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F627BFC41E8E89B600B1CBF4 /* librouting_common.a in Frameworks */,
674231CB1DF984F600913FEB /* libtraffic.a in Frameworks */,
34DDA1811DBE5DF40088A609 /* libpartners_api.a in Frameworks */,
34DDA1821DBE5DF40088A609 /* libtracking.a in Frameworks */,
@ -291,6 +294,7 @@
34DDA17E1DBE5DF40088A609 /* Frameworks */ = {
isa = PBXGroup;
children = (
F627BFC31E8E89B600B1CBF4 /* librouting_common.a */,
674231CA1DF984F600913FEB /* libtraffic.a */,
34DDA17F1DBE5DF40088A609 /* libpartners_api.a */,
34DDA1801DBE5DF40088A609 /* libtracking.a */,