diff options
-rw-r--r-- | coding/uri.cpp | 8 | ||||
-rw-r--r-- | map/framework.cpp | 30 | ||||
-rw-r--r-- | map/framework.hpp | 5 | ||||
-rw-r--r-- | map/map_tests/mwm_url_tests.cpp | 26 | ||||
-rw-r--r-- | map/mwm_url.cpp | 144 | ||||
-rw-r--r-- | map/mwm_url.hpp | 17 | ||||
-rw-r--r-- | xcode/map/map.xcodeproj/project.pbxproj | 4 |
7 files changed, 183 insertions, 51 deletions
diff --git a/coding/uri.cpp b/coding/uri.cpp index 4b98a96839..4894e7df9f 100644 --- a/coding/uri.cpp +++ b/coding/uri.cpp @@ -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) diff --git a/map/framework.cpp b/map/framework.cpp index 725f02f5c7..8ae00581a9 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -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; diff --git a/map/framework.hpp b/map/framework.hpp index 875337792a..b57c45ad4d 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -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. diff --git a/map/map_tests/mwm_url_tests.cpp b/map/map_tests/mwm_url_tests.cpp index 0d1261bd47..80d8d680ef 100644 --- a/map/map_tests/mwm_url_tests.cpp +++ b/map/map_tests/mwm_url_tests.cpp @@ -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; diff --git a/map/mwm_url.cpp b/map/mwm_url.cpp index 593f9a3ea8..ea7c0dec67 100644 --- a/map/mwm_url.cpp +++ b/map/mwm_url.cpp @@ -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; - } - - vector<ApiPoint> points; - if (!uri.ForEachKeyValue(bind(&ParsedMapApi::AddKeyValue, this, _1, _2, ref(points)))) - return ParsingResult::Incorrect; + if (pattern.size() != 0) + return ParsingResult::Incorrect; - if (points.empty()) - return ParsingResult::Incorrect; + if (m_routePoints.size() != 2) + { + ASSERT(false, ()); + 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::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; } - - 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(); diff --git a/map/mwm_url.hpp b/map/mwm_url.hpp index 3192ed7727..8ac94d1b68 100644 --- a/map/mwm_url.hpp +++ b/map/mwm_url.hpp @@ -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; diff --git a/xcode/map/map.xcodeproj/project.pbxproj b/xcode/map/map.xcodeproj/project.pbxproj index c873d680be..78cca016a4 100644 --- a/xcode/map/map.xcodeproj/project.pbxproj +++ b/xcode/map/map.xcodeproj/project.pbxproj @@ -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 */, |