diff --git a/indexer/osm_editor.hpp b/indexer/osm_editor.hpp index 44acb97a05..4cc09aa847 100644 --- a/indexer/osm_editor.hpp +++ b/indexer/osm_editor.hpp @@ -2,6 +2,8 @@ #include "geometry/rect2d.hpp" +// TODO(AlexZ): Integrate editable feature into an editor. +#include "indexer/editable_map_object.hpp" #include "indexer/feature.hpp" #include "indexer/feature_meta.hpp" #include "indexer/mwm_set.hpp" diff --git a/map/api_mark_point.hpp b/map/api_mark_point.hpp index e46338e104..cfd687c1e3 100644 --- a/map/api_mark_point.hpp +++ b/map/api_mark_point.hpp @@ -28,18 +28,6 @@ public: void SetID(string const & id) { m_id = id; } - unique_ptr Copy() const override - { - return unique_ptr( - new UserMarkCopy(new ApiMarkPoint(m_name, m_id, m_style, m_ptOrg, m_container))); - } - - void FillLogEvent(UserMark::TEventContainer & details) const override - { - UserMark::FillLogEvent(details); - details.emplace("name", GetName()); - } - void SetStyle(string const & style) { m_style = style; } // StyledPoint overrides: diff --git a/map/bookmark.cpp b/map/bookmark.cpp index 9f51d3ec62..58d8b3e4c8 100644 --- a/map/bookmark.cpp +++ b/map/bookmark.cpp @@ -63,18 +63,6 @@ UserMark::Type Bookmark::GetMarkType() const return UserMark::Type::BOOKMARK; } -unique_ptr Bookmark::Copy() const -{ - return unique_ptr(new UserMarkCopy(this, false)); -} - -void Bookmark::FillLogEvent(TEventContainer & details) const -{ - UserMark::FillLogEvent(details); - details.emplace("markType", "BOOKMARK"); - details.emplace("name", GetData().GetName()); -} - bool Bookmark::RunCreationAnim() const { bool result = m_runCreationAnim; diff --git a/map/bookmark.hpp b/map/bookmark.hpp index a1ddca705f..10c6ebcf4e 100644 --- a/map/bookmark.hpp +++ b/map/bookmark.hpp @@ -82,7 +82,6 @@ public: string GetSymbolName() const override; Type GetMarkType() const override; - void FillLogEvent(TEventContainer & details) const override; bool RunCreationAnim() const override; string const & GetName() const; @@ -102,8 +101,6 @@ public: double GetScale() const; void SetScale(double scale); - unique_ptr Copy() const override; - private: BookmarkData m_data; mutable bool m_runCreationAnim; diff --git a/map/framework.cpp b/map/framework.cpp index 753c079d80..85ab4ff552 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1,5 +1,4 @@ #include "map/framework.hpp" - #include "map/ge0_parser.hpp" #include "map/geourl_process.hpp" #include "map/gps_tracker.hpp" @@ -28,6 +27,7 @@ #include "indexer/categories_holder.hpp" #include "indexer/classificator_loader.hpp" #include "indexer/drawing_rules.hpp" +#include "indexer/editable_map_object.hpp" #include "indexer/feature.hpp" #include "indexer/map_style_reader.hpp" #include "indexer/osm_editor.hpp" @@ -223,7 +223,7 @@ void Framework::OnUserPositionChanged(m2::PointD const & position) m_routingSession.SetUserCurrentPosition(position); } -void Framework::CallDrapeFunction(TDrapeFunction const & fn) +void Framework::CallDrapeFunction(TDrapeFunction const & fn) const { if (m_drapeEngine) fn(m_drapeEngine.get()); @@ -583,11 +583,62 @@ bool Framework::DeleteBmCategory(size_t index) return m_bmManager.DeleteBmCategory(index); } +void Framework::FillBookmarkInfo(Bookmark const & bmk, BookmarkAndCategory const & bac, place_page::Info & info) const +{ + FillPointInfo(bmk.GetPivot(), string(), info); + info.m_bac = bac; +} + +void Framework::FillFeatureInfo(FeatureID const & fid, place_page::Info & info) const +{ + if (!fid.IsValid()) + { + LOG(LERROR, ("FeatureID is invalid:", fid)); + return; + } + + Index::FeaturesLoaderGuard const guard(m_model.GetIndex(), fid.m_mwmId); + FeatureType ft; + guard.GetFeatureByIndex(fid.m_index, ft); + info.SetFromFeatureType(ft); + info.m_isEditable = osm::Editor::Instance().GetEditableProperties(ft).IsEditable(); +} + +void Framework::FillPointInfo(m2::PointD const & mercator, string const & customTitle, place_page::Info & info) const +{ + auto feature = GetFeatureAtPoint(mercator); + if (feature) + { + info.SetFromFeatureType(*feature); + info.m_isEditable = osm::Editor::Instance().GetEditableProperties(*feature).IsEditable(); + } + else + { + info.m_customName = customTitle.empty() ? m_stringsBundle.GetString("dropped_pin") : customTitle; + } + // This line overwrites mercator center from area feature which can be far away. + info.SetMercator(mercator); +} + +void Framework::FillApiMarkInfo(ApiMarkPoint const & api, place_page::Info & info) const +{ + FillPointInfo(api.GetPivot(), api.GetName(), info); + info.m_apiUrl = GenerateApiBackUrl(api); +} + +void Framework::FillMyPositionInfo(place_page::Info & info) const +{ + double lat, lon; + VERIFY(GetCurrentPosition(lat, lon), ()); + info.SetMercator(MercatorBounds::FromLatLon(lat, lon)); + info.m_isMyPosition = true; + info.m_customName = m_stringsBundle.GetString("my_position"); +} + void Framework::ShowBookmark(BookmarkAndCategory const & bnc) { StopLocationFollow(); - // show ballon above Bookmark const * mark = static_cast(GetBmCategory(bnc.first)->GetUserMark(bnc.second)); double scale = mark->GetScale(); @@ -595,7 +646,10 @@ void Framework::ShowBookmark(BookmarkAndCategory const & bnc) scale = scales::GetUpperComfortScale(); CallDrapeFunction(bind(&df::DrapeEngine::SetModelViewCenter, _1, mark->GetPivot(), scale, true)); - ActivateUserMark(mark, true); + + place_page::Info info; + FillBookmarkInfo(*mark, bnc, info); + ActivateMapSelection(true, df::SelectionShape::OBJECT_USER_MARK, info); } void Framework::ShowTrack(Track const & track) @@ -1059,57 +1113,46 @@ void Framework::LoadSearchResultMetadata(search::Result & res) const void Framework::ShowSearchResult(search::Result const & res) { CancelInteractiveSearch(); + StopLocationFollow(); - UserMarkControllerGuard guard(m_bmManager, UserMarkType::SEARCH_MARK); - guard.m_controller.SetIsDrawable(false); - guard.m_controller.Clear(); - guard.m_controller.SetIsVisible(true); - - int scale; - m2::PointD center; - unique_ptr ft; - + alohalytics::LogEvent("searchShowResult", {{"pos", strings::to_string(res.GetPositionInResults())}, + {"result", res.ToStringForStats()}}); + place_page::Info info; using namespace search; - using namespace feature; - - alohalytics::TStringMap const stats = {{"pos", strings::to_string(res.GetPositionInResults())}, - {"result", res.ToStringForStats()}}; - alohalytics::LogEvent("searchShowResult", stats); - + int scale; switch (res.GetResultType()) { case Result::RESULT_FEATURE: - { - ft = GetFeatureByID(res.GetFeatureID()); - scale = GetFeatureViewportScale(TypesHolder(*ft)); - center = GetCenter(*ft, scale); + FillFeatureInfo(res.GetFeatureID(), info); + scale = GetFeatureViewportScale(info.GetTypes()); break; - } case Result::RESULT_LATLON: case Result::RESULT_ADDRESS: + FillPointInfo(res.GetFeatureCenter(), res.GetString(), info); scale = scales::GetUpperComfortScale(); - center = res.GetFeatureCenter(); break; - default: + case Result::RESULT_SUGGEST_PURE: + case Result::RESULT_SUGGEST_FROM_FEATURE: ASSERT(false, ("Suggests should not be here.")); return; } - StopLocationFollow(); + m2::PointD const center = info.GetMercator(); if (m_currentModelView.isPerspective()) CallDrapeFunction(bind(&df::DrapeEngine::SetModelViewCenter, _1, center, scale, true)); else ShowRect(df::GetRectForDrawScale(scale, center)); - UserMark * mark = guard.m_controller.CreateUserMark(center); - if (ft) - mark->SetFeature(move(ft)); - else - mark->SetFeature(GetFeatureAtPoint(center)); - - ActivateUserMark(mark, false); + { + UserMarkControllerGuard guard(m_bmManager, UserMarkType::SEARCH_MARK); + guard.m_controller.SetIsDrawable(false); + guard.m_controller.Clear(); + guard.m_controller.SetIsVisible(true); + UNUSED_VALUE(guard.m_controller.CreateUserMark(center)); + } + ActivateMapSelection(false, df::SelectionShape::OBJECT_USER_MARK, info); } size_t Framework::ShowSearchResults(search::Results const & results) @@ -1226,16 +1269,9 @@ void Framework::FillSearchResultsMarks(search::Results const & results) size_t const count = results.GetCount(); for (size_t i = 0; i < count; ++i) { - using namespace search; - - Result const & r = results.GetResult(i); + search::Result const & r = results.GetResult(i); if (r.HasPoint()) - { - UserMark * mark = guard.m_controller.CreateUserMark(r.GetFeatureCenter()); - // Store feature from the search result. - // TODO(AlexZ): Refactor all usermarks code. - mark->SetFeature(GetFeatureByID(r.GetFeatureID())); - } + UNUSED_VALUE(guard.m_controller.CreateUserMark(r.GetFeatureCenter())); } } @@ -1358,16 +1394,10 @@ void Framework::CreateDrapeEngine(ref_ptr contextFactory, LoadViewport(); // In case of the engine reinitialization simulate the last tap to show selection mark. - SimulateLastTapEventIfNeeded(); -} - -void Framework::SimulateLastTapEventIfNeeded() -{ if (m_lastTapEvent) { - UserMark const * mark = OnTapEventImpl(*m_lastTapEvent); - if (mark) - ActivateUserMark(mark, true); + place_page::Info info; + ActivateMapSelection(false, OnTapEventImpl(*m_lastTapEvent, info), info); } } @@ -1546,8 +1576,8 @@ bool Framework::ShowMapForURL(string const & url) if (result != FAILED) { - // always hide current balloon here - DeactivateUserMark(); + // Always hide current map selection. + DeactivateMapSelection(true); // set viewport and stop follow mode if any StopLocationFollow(); @@ -1555,19 +1585,17 @@ bool Framework::ShowMapForURL(string const & url) if (result != NO_NEED_CLICK) { + place_page::Info info; if (apiMark) { - LOG(LINFO, ("Show API mark:", static_cast(apiMark)->GetName())); - - ActivateUserMark(apiMark, false); + FillApiMarkInfo(*apiMark, info); + ActivateMapSelection(false, df::SelectionShape::OBJECT_USER_MARK, info); } else { - PoiMarkPoint * mark = UserMarkContainer::UserMarkForPoi(); - mark->SetPtOrg(point); - // TODO(AlexZ): refactor out interface for passing PP values to UI. - mark->SetCustomName(name); - ActivateUserMark(mark, false); + UserMarkContainer::UserMarkForPoi()->SetPtOrg(point); + FillPointInfo(point, name, info); + ActivateMapSelection(false, df::SelectionShape::OBJECT_POI, info); } } @@ -1682,57 +1710,43 @@ BookmarkAndCategory Framework::FindBookmark(UserMark const * mark) const return result; } -PoiMarkPoint * Framework::GetAddressMark(m2::PointD const & globalPoint) const +void Framework::SetMapSelectionListeners(TActivateMapSelectionFn const & activator, + TDeactivateMapSelectionFn const & deactivator) { - PoiMarkPoint * mark = UserMarkContainer::UserMarkForPoi(); - mark->SetPtOrg(globalPoint); - mark->SetFeature(GetFeatureAtPoint(globalPoint)); - return mark; + m_activateMapSelectionFn = activator; + m_deactivateMapSelectionFn = deactivator; } -void Framework::ActivateUserMark(UserMark const * mark, bool needAnim) +void Framework::ActivateMapSelection(bool needAnimation, df::SelectionShape::ESelectedObject selectionType, + place_page::Info const & info) const { - if (!m_activateUserMarkFn) - return; - - if (mark) - { - m_activateUserMarkFn(mark->Copy()); - df::SelectionShape::ESelectedObject object = df::SelectionShape::OBJECT_USER_MARK; - UserMark::Type type = mark->GetMarkType(); - if (type == UserMark::Type::MY_POSITION) - object = df::SelectionShape::OBJECT_MY_POSITION; - else if (type == UserMark::Type::POI) - object = df::SelectionShape::OBJECT_POI; - - CallDrapeFunction(bind(&df::DrapeEngine::SelectObject, _1, object, mark->GetPivot(), needAnim)); - } + ASSERT_NOT_EQUAL(selectionType, df::SelectionShape::OBJECT_EMPTY, ("Empty selections are impossible.")); + CallDrapeFunction(bind(&df::DrapeEngine::SelectObject, _1, selectionType, info.GetMercator(), + needAnimation)); + if (m_activateMapSelectionFn) + m_activateMapSelectionFn(info); else - { - m_activateUserMarkFn(nullptr); - CallDrapeFunction(bind(&df::DrapeEngine::DeselectObject, _1)); - } + LOG(LWARNING, ("m_activateMapSelectionFn has not been set up.")); } -void Framework::DeactivateUserMark() +void Framework::DeactivateMapSelection(bool notifyUI) { + bool const somethingWasAlreadySelected = (m_lastTapEvent != nullptr); m_lastTapEvent.reset(); - CallDrapeFunction(bind(&df::DrapeEngine::DeselectObject, _1)); + + if (notifyUI && m_deactivateMapSelectionFn) + m_deactivateMapSelectionFn(!somethingWasAlreadySelected); + + if (somethingWasAlreadySelected) + CallDrapeFunction(bind(&df::DrapeEngine::DeselectObject, _1)); } -bool Framework::HasActiveUserMark() +void Framework::UpdatePlacePageInfoForCurrentSelection() { - if (m_drapeEngine == nullptr) - return false; + ASSERT(m_lastTapEvent, ()); - return m_drapeEngine->GetSelectedObject() != df::SelectionShape::OBJECT_EMPTY; -} - -UserMark const * Framework::GetActiveUserMark() const -{ - if (m_lastTapEvent) - return OnTapEventImpl(*m_lastTapEvent); - return nullptr; + place_page::Info info; + ActivateMapSelection(false, OnTapEventImpl(*m_lastTapEvent, info), info); } void Framework::InvalidateUserMarks() @@ -1749,33 +1763,61 @@ void Framework::InvalidateUserMarks() void Framework::OnTapEvent(df::TapInfo const & tapInfo) { - // Back up last tap event to recover selection in case of Drape reinitialization. - m_lastTapEvent.reset(new df::TapInfo(tapInfo)); - - UserMark const * mark = OnTapEventImpl(tapInfo); + bool const somethingWasAlreadySelected = (m_lastTapEvent != nullptr); + place_page::Info info; + df::SelectionShape::ESelectedObject const selection = OnTapEventImpl(tapInfo, info); + if (selection != df::SelectionShape::OBJECT_EMPTY) { - alohalytics::TStringMap details {{"isLongPress", tapInfo.m_isLong ? "1" : "0"}}; - if (mark) - mark->FillLogEvent(details); - alohalytics::Stats::Instance().LogEvent("$GetUserMark", details); - } + // Back up last tap event to recover selection in case of Drape reinitialization. + m_lastTapEvent.reset(new df::TapInfo(tapInfo)); - ActivateUserMark(mark, true); + { + ms::LatLon const ll = info.GetLatLon(); + double myLat, myLon; + double metersToTap = -1; + if (info.IsMyPosition()) + metersToTap = 0; + else if (GetCurrentPosition(myLat, myLon)) + metersToTap = ms::DistanceOnEarth(myLat, myLon, ll.lat, ll.lon); + + alohalytics::TStringMap kv = {{"longTap", tapInfo.m_isLong ? "1" : "0"}, + {"title", info.GetTitle()}, + {"bookmark", info.IsBookmark() ? "1" : "0"}, + {"meters", strings::to_string_dac(metersToTap, 0)}}; + if (info.IsFeature()) + kv["types"] = DebugPrint(info.GetTypes()); + // Older version of statistics used "$GetUserMark" event. + alohalytics::Stats::Instance().LogEvent("$SelectMapObject", kv, alohalytics::Location::FromLatLon(ll.lat, ll.lon)); + } + + ActivateMapSelection(true, selection, info); + } + else + { + alohalytics::Stats::Instance().LogEvent(somethingWasAlreadySelected ? "$DelectMapObject" : "$EmptyTapOnMap"); + // UI is always notified even if empty map is tapped, + // because empty tap event switches on/off full screen map view mode. + DeactivateMapSelection(true); + } } void Framework::InvalidateRendering() { - if (m_drapeEngine != nullptr) + if (m_drapeEngine) m_drapeEngine->Invalidate(); } -UserMark const * Framework::OnTapEventImpl(const df::TapInfo & tapInfo) const +df::SelectionShape::ESelectedObject Framework::OnTapEventImpl(df::TapInfo const & tapInfo, + place_page::Info & outInfo) const { m2::PointD const pxPoint2d = m_currentModelView.P3dtoP(tapInfo.m_pixelPoint); if (tapInfo.m_isMyPositionTapped) - return UserMarkContainer::UserMarkForMyPostion(); + { + FillMyPositionInfo(outInfo); + return df::SelectionShape::OBJECT_MY_POSITION; + } df::VisualParams const & vp = df::VisualParams::Instance(); @@ -1795,48 +1837,45 @@ UserMark const * Framework::OnTapEventImpl(const df::TapInfo & tapInfo) const return (type == UserMarkType::BOOKMARK_MARK ? bmSearchRect : rect); }); - FeatureID const & fid = tapInfo.m_featureTapped; - if (mark != nullptr) + if (mark) { - // TODO(AlexZ): Refactor out together with UserMarks. - // Do not reset feature if it's already there (e.g. from Search results). - if (nullptr == mark->GetFeature()) + switch (mark->GetMarkType()) { - const_cast(mark)->SetFeature(fid.IsValid() ? - GetFeatureByID(fid) : - GetFeatureAtPoint(mark->GetPivot())); + case UserMark::Type::API: + FillApiMarkInfo(*static_cast(mark), outInfo); + break; + case UserMark::Type::BOOKMARK: + FillBookmarkInfo(*static_cast(mark), FindBookmark(mark), outInfo); + break; + case UserMark::Type::SEARCH: + // TODO(AlexZ): Check if search results features are correcly passed to UI. + FillApiMarkInfo(*static_cast(mark), outInfo); + break; + default: + ASSERT(false, ("FindNearestUserMark returned invalid mark.")); } - return mark; + return df::SelectionShape::OBJECT_USER_MARK; } - bool needMark = false; - m2::PointD mercatorPivot; - unique_ptr feature; - - if (fid.IsValid()) + bool showMapSelection = false; + if (tapInfo.m_featureTapped.IsValid()) { - feature = GetFeatureByID(fid); - mercatorPivot = feature::GetCenter(*feature); - needMark = true; + FillFeatureInfo(tapInfo.m_featureTapped, outInfo); + showMapSelection = true; } else if (tapInfo.m_isLong) { - mercatorPivot = m_currentModelView.PtoG(pxPoint2d); - // TODO(AlexZ): Should we change mercatorPivot to found feature's center? - feature = GetFeatureAtPoint(mercatorPivot); - needMark = true; + FillPointInfo(m_currentModelView.PtoG(pxPoint2d), "", outInfo); + showMapSelection = true; } - if (needMark) + if (showMapSelection) { - PoiMarkPoint * poiMark = UserMarkContainer::UserMarkForPoi(); - poiMark->SetPtOrg(mercatorPivot); - // Set or reset feature. - poiMark->SetFeature(move(feature)); - return poiMark; + UserMarkContainer::UserMarkForPoi()->SetPtOrg(outInfo.GetMercator()); + return df::SelectionShape::OBJECT_POI; } - return nullptr; + return df::SelectionShape::OBJECT_EMPTY; } void Framework::PredictLocation(double & lat, double & lon, double accuracy, @@ -1876,7 +1915,7 @@ string Framework::CodeGe0url(double lat, double lon, double zoomLevel, string co return res; } -string Framework::GenerateApiBackUrl(ApiMarkPoint const & point) +string Framework::GenerateApiBackUrl(ApiMarkPoint const & point) const { string res = m_ParsedMapApi.GetGlobalBackUrl(); if (!res.empty()) @@ -2262,3 +2301,33 @@ bool Framework::ParseEditorDebugCommand(search::SearchParams const & params) } return false; } + +bool Framework::GetEditableMapObject(FeatureID const & fid, osm::EditableMapObject & emo) const +{ + if (!fid.IsValid()) + return false; + // TODO(AlexZ): Move this code to the Editor. + auto feature = GetFeatureByID(fid); + FeatureType & ft = *feature; + emo.SetFromFeatureType(ft); + emo.SetHouseNumber(ft.GetHouseNumber()); + emo.SetStreet(GetFeatureAddressInfo(ft).m_street); + emo.SetNearbyStreets(GetNearbyFeatureStreets(ft)); + emo.SetEditableProperties(osm::Editor::Instance().GetEditableProperties(ft)); + return true; +} + +void Framework::SaveEditedMapObject(osm::EditableMapObject const & emo) const +{ + // TODO(AlexZ): Move this code to the Editor. + auto feature = GetFeatureByID(emo.GetID()); + FeatureType & ft = *feature; + ft.ApplyPatch(emo); + osm::Editor::Instance().SaveEditedFeature(ft, emo.GetStreet(), emo.GetHouseNumber()); +} + +void Framework::DeleteFeature(FeatureID const & fid) const +{ + // TODO(AlexZ): Use FeatureID in the editor interface. + osm::Editor::Instance().DeleteFeature(*GetFeatureByID(fid)); +} diff --git a/map/framework.hpp b/map/framework.hpp index 946ba4b1f8..7fb0a9973d 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -3,6 +3,7 @@ #include "map/api_mark_point.hpp" #include "map/bookmark.hpp" #include "map/bookmark_manager.hpp" +#include "map/place_page_info.hpp" #include "map/feature_vec_model.hpp" #include "map/mwm_url.hpp" #include "map/track.hpp" @@ -42,6 +43,11 @@ #include "std/vector.hpp" #include "std/weak_ptr.hpp" +namespace osm +{ +class EditableMapObject; +} + namespace search { class Result; @@ -136,7 +142,7 @@ protected: void StopLocationFollow(); - void CallDrapeFunction(TDrapeFunction const & fn); + void CallDrapeFunction(TDrapeFunction const & fn) const; public: Framework(); @@ -237,18 +243,23 @@ public: BookmarkAndCategory FindBookmark(UserMark const * mark) const; BookmarkManager & GetBookmarkManager() { return m_bmManager; } - void ActivateUserMark(UserMark const * mark, bool needAnim); - void DeactivateUserMark(); - bool HasActiveUserMark(); +private: + void ActivateMapSelection(bool needAnimation, + df::SelectionShape::ESelectedObject selectionType, + place_page::Info const & info) const; void InvalidateUserMarks(); - PoiMarkPoint * GetAddressMark(m2::PointD const & globalPoint) const; - // TODO(AlexZ): Temporary workaround to get last active UserMark on Android. - // Refactor it out together with UserMarks. - /// @returns nullptr if there is no selection on the map. - UserMark const * GetActiveUserMark() const; +public: + void DeactivateMapSelection(bool notifyUI); + /// Used to "refresh" UI in some cases (e.g. feature editing). + void UpdatePlacePageInfoForCurrentSelection(); - using TActivateCallbackFn = function mark)>; - void SetUserMarkActivationListener(TActivateCallbackFn const & fn) { m_activateUserMarkFn = fn; } + /// Called to notify UI that object on a map was selected (UI should show Place Page, for example). + using TActivateMapSelectionFn = function; + /// Called to notify UI that object on a map was deselected (UI should hide Place Page). + /// If switchFullScreenMode is true, ui can [optionally] enter or exit full screen mode. + using TDeactivateMapSelectionFn = function; + void SetMapSelectionListeners(TActivateMapSelectionFn const & activator, + TDeactivateMapSelectionFn const & deactivator); void ResetLastTapEvent(); @@ -263,8 +274,6 @@ public: void SetCurrentCountryChangedListener(TCurrentCountryChanged const & listener); private: - /// UI callback is called when tap event is "restored" after Drape engine restart. - void SimulateLastTapEventIfNeeded(); unique_ptr m_lastTapEvent; #ifdef OMIM_OS_ANDROID unique_ptr m_lastCompassInfo; @@ -272,9 +281,12 @@ private: #endif void OnTapEvent(df::TapInfo const & tapInfo); - UserMark const * OnTapEventImpl(df::TapInfo const & tapInfo) const; + /// outInfo is valid only if return value is not df::SelectionShape::OBJECT_EMPTY. + df::SelectionShape::ESelectedObject OnTapEventImpl(df::TapInfo const & tapInfo, + place_page::Info & outInfo) const; - TActivateCallbackFn m_activateUserMarkFn; + TActivateMapSelectionFn m_activateMapSelectionFn; + TDeactivateMapSelectionFn m_deactivateMapSelectionFn; public: @@ -458,6 +470,14 @@ private: //void GetLocality(m2::PointD const & pt, search::AddressInfo & info) const; /// @returns true if command was handled by editor. bool ParseEditorDebugCommand(search::SearchParams const & params); + + void FillBookmarkInfo(Bookmark const & bmk, BookmarkAndCategory const & bac, place_page::Info & info) const; + void FillFeatureInfo(FeatureID const & fid, place_page::Info & info) const; + /// @param customTitle, if not empty, overrides any other calculated name. + void FillPointInfo(m2::PointD const & mercator, string const & customTitle, place_page::Info & info) const; + void FillApiMarkInfo(ApiMarkPoint const & api, place_page::Info & info) const; + void FillMyPositionInfo(place_page::Info & info) const; + public: /// @returns address of nearby building with house number in approx 1km distance. search::AddressInfo GetAddressInfoAtPoint(m2::PointD const & pt) const; @@ -476,6 +496,8 @@ public: using TFeatureTypeFn = function; void ForEachFeatureAtPoint(TFeatureTypeFn && fn, m2::PointD const & mercator) const; /// Set parse to false if you don't need all feature fields ready. + /// TODO(AlexZ): Refactor code which uses this method to get rid of it. + /// FeatureType instances shoud not be used outside ForEach* core methods. unique_ptr GetFeatureByID(FeatureID const & fid, bool parse = true) const; void MemoryWarning(); @@ -501,7 +523,7 @@ public: /// @name Api //@{ - string GenerateApiBackUrl(ApiMarkPoint const & point); + string GenerateApiBackUrl(ApiMarkPoint const & point) const; url_scheme::ParsedMapApi const & GetApiDataHolder() const { return m_ParsedMapApi; } private: @@ -585,6 +607,15 @@ public: void Save3dMode(bool allow3d, bool allow3dBuildings); void Load3dMode(bool & allow3d, bool & allow3dBuildings); +public: + /// @name Editor interface. + //@{ + /// @returns false if feature is invalid or can't be edited. + bool GetEditableMapObject(FeatureID const & fid, osm:: EditableMapObject & emo) const; + void SaveEditedMapObject(osm:: EditableMapObject const & emo) const; + void DeleteFeature(FeatureID const & fid) const; + //@} + private: void SetRouterImpl(routing::RouterType type); void RemoveRoute(bool deactivateFollowing); diff --git a/map/user_mark.cpp b/map/user_mark.cpp index 1a397499c5..837fe13999 100644 --- a/map/user_mark.cpp +++ b/map/user_mark.cpp @@ -3,39 +3,15 @@ #include "indexer/classificator.hpp" -namespace -{ +#include "geometry/mercator.hpp" -string ToString(UserMark::Type t) -{ - switch (t) - { - case UserMark::Type::BOOKMARK: return "BOOKMARK"; - case UserMark::Type::API: return "API"; - case UserMark::Type::MY_POSITION: return "MY_POSITION"; - case UserMark::Type::POI: return "POI"; - case UserMark::Type::SEARCH: return "SEARCH"; - case UserMark::Type::DEBUG_MARK: return "DEBUG"; - } -} - -} +#include "base/string_utils.hpp" UserMark::UserMark(m2::PointD const & ptOrg, UserMarkContainer * container) : m_ptOrg(ptOrg), m_container(container) { } -FeatureType * UserMark::GetFeature() const -{ - return m_feature.get(); -} - -void UserMark::SetFeature(unique_ptr feature) -{ - m_feature = move(feature); -} - m2::PointD const & UserMark::GetPivot() const { return m_ptOrg; @@ -73,48 +49,6 @@ ms::LatLon UserMark::GetLatLon() const return MercatorBounds::ToLatLon(m_ptOrg); } -void UserMark::FillLogEvent(UserMark::TEventContainer & details) const -{ - ms::LatLon const ll = GetLatLon(); - details.emplace("lat", strings::to_string(ll.lat)); - details.emplace("lon", strings::to_string(ll.lon)); - details.emplace("markType", ToString(GetMarkType())); - - if (m_feature) - { - string name; - m_feature->GetReadableName(name); - details.emplace("name", move(name)); - string types; - m_feature->ForEachType([&types](uint32_t type) - { - if (!types.empty()) - types += ','; - types += classif().GetReadableObjectName(type); - }); - // Older version of statistics used "type" key with AddressInfo::GetPinType() value. - details.emplace("types", move(types)); - details.emplace("metaData", m_feature->GetMetadata().Empty() ? "0" : "1"); - } -} - -UserMarkCopy::UserMarkCopy(UserMark const * srcMark, bool needDestroy) - : m_srcMark(srcMark) - , m_needDestroy(needDestroy) -{ -} - -UserMarkCopy::~UserMarkCopy() -{ - if (m_needDestroy) - delete m_srcMark; -} - -UserMark const * UserMarkCopy::GetUserMark() const -{ - return m_srcMark; -} - SearchMarkPoint::SearchMarkPoint(m2::PointD const & ptOrg, UserMarkContainer * container) : UserMark(ptOrg, container) { @@ -130,15 +64,6 @@ UserMark::Type SearchMarkPoint::GetMarkType() const return UserMark::Type::SEARCH; } -unique_ptr SearchMarkPoint::Copy() const -{ - // TODO(AlexZ): Remove this code after UserMark refactoring. - UserMark * mark = new SearchMarkPoint(m_ptOrg, m_container); - if (m_feature) - mark->SetFeature(unique_ptr(new FeatureType(*m_feature))); - return unique_ptr(new UserMarkCopy(mark)); -} - PoiMarkPoint::PoiMarkPoint(UserMarkContainer * container) : SearchMarkPoint(m2::PointD::Zero(), container) {} @@ -147,25 +72,11 @@ UserMark::Type PoiMarkPoint::GetMarkType() const return UserMark::Type::POI; } -unique_ptr PoiMarkPoint::Copy() const -{ - return unique_ptr(new UserMarkCopy(this, false)); -} void PoiMarkPoint::SetPtOrg(m2::PointD const & ptOrg) { m_ptOrg = ptOrg; } -void PoiMarkPoint::SetCustomName(string const & customName) -{ - m_customName = customName; -} - -string const & PoiMarkPoint::GetCustomName() const -{ - return m_customName; -} - MyPositionMarkPoint::MyPositionMarkPoint(UserMarkContainer * container) : PoiMarkPoint(container) { @@ -185,8 +96,3 @@ string DebugMarkPoint::GetSymbolName() const { return "api-result"; } - -unique_ptr DebugMarkPoint::Copy() const -{ - return unique_ptr(new UserMarkCopy(new DebugMarkPoint(m_ptOrg, m_container))); -} diff --git a/map/user_mark.hpp b/map/user_mark.hpp index edbb1a3042..8c607d5a43 100644 --- a/map/user_mark.hpp +++ b/map/user_mark.hpp @@ -1,11 +1,7 @@ #pragma once -#include "search/result.hpp" - #include "drape_frontend/user_marks_provider.hpp" -#include "indexer/feature.hpp" - #include "geometry/latlon.hpp" #include "geometry/point2d.hpp" @@ -34,11 +30,6 @@ public: }; UserMark(m2::PointD const & ptOrg, UserMarkContainer * container); - - /// @returns nullptr if no feature was set. - FeatureType * GetFeature() const; - void SetFeature(unique_ptr feature); - virtual ~UserMark() {} /////////////////////////////////////////////////////// @@ -53,30 +44,12 @@ public: UserMarkContainer const * GetContainer() const; ms::LatLon GetLatLon() const; virtual Type GetMarkType() const = 0; - virtual unique_ptr Copy() const = 0; // Need it to calculate POI rank from all taps to features via statistics. using TEventContainer = map; - virtual void FillLogEvent(TEventContainer & details) const; protected: m2::PointD m_ptOrg; mutable UserMarkContainer * m_container; - /// Feature which is displayed (and edited) in Place Page. - /// It is initialized after user touches this UserMark. - unique_ptr m_feature; -}; - -class UserMarkCopy -{ -public: - UserMarkCopy(UserMark const * srcMark, bool needDestroy = true); - ~UserMarkCopy(); - - UserMark const * GetUserMark() const; - -private: - UserMark const * m_srcMark; - bool m_needDestroy; }; class SearchMarkPoint : public UserMark @@ -86,8 +59,6 @@ public: string GetSymbolName() const override; UserMark::Type GetMarkType() const override; - - unique_ptr Copy() const override; }; class PoiMarkPoint : public SearchMarkPoint @@ -95,16 +66,8 @@ class PoiMarkPoint : public SearchMarkPoint public: PoiMarkPoint(UserMarkContainer * container); UserMark::Type GetMarkType() const override; - unique_ptr Copy() const override; void SetPtOrg(m2::PointD const & ptOrg); - // TODO(AlexZ): Refactor out. Now we need it to pass custom name from shared links. - void SetCustomName(string const & customName); - string const & GetCustomName() const; - -private: - // If present, should override any feature's name for this user mark. - string m_customName; }; class MyPositionMarkPoint : public PoiMarkPoint @@ -133,5 +96,4 @@ public: string GetSymbolName() const override; Type GetMarkType() const override { return UserMark::Type::DEBUG_MARK; } - unique_ptr Copy() const override; }; diff --git a/map/user_mark_container.cpp b/map/user_mark_container.cpp index 703ccd290a..98fb0475b9 100644 --- a/map/user_mark_container.cpp +++ b/map/user_mark_container.cpp @@ -113,9 +113,6 @@ void UserMarkContainer::InitStaticMarks(UserMarkContainer * container) PoiMarkPoint * UserMarkContainer::UserMarkForPoi() { ASSERT(g_selectionUserMark != NULL, ()); - // TODO(AlexZ): Refactor out UserMarks and containers. - // Consider this call as returning "new" PoiMarkPoint, so clear up old "custom name" data. - g_selectionUserMark->SetCustomName(string()); return g_selectionUserMark.get(); }