diff --git a/map/map_tests/CMakeLists.txt b/map/map_tests/CMakeLists.txt index 0ca98f3c7b..7f6d7c9e5f 100644 --- a/map/map_tests/CMakeLists.txt +++ b/map/map_tests/CMakeLists.txt @@ -16,6 +16,7 @@ set(SRC power_manager_tests.cpp search_api_tests.cpp transliteration_test.cpp + user_routes_test.cpp working_time_tests.cpp ) diff --git a/map/map_tests/user_routes_test.cpp b/map/map_tests/user_routes_test.cpp new file mode 100644 index 0000000000..639e5de87d --- /dev/null +++ b/map/map_tests/user_routes_test.cpp @@ -0,0 +1,42 @@ +#include "testing/testing.hpp" + +#include "map/routing_manager.hpp" + +#include +#include + +namespace user_routes_test +{ +using namespace std; + +#define RM_CALLBACKS { \ + static_cast(nullptr), \ + static_cast(nullptr), \ + static_cast(nullptr), \ + static_cast(nullptr), \ + static_cast(nullptr) \ + } + +class TestDelegate : public RoutingManager::Delegate +{ + void OnRouteFollow(routing::RouterType type) override + { + // Empty + } + + void RegisterCountryFilesOnRoute(std::shared_ptr ptr) const override + { + // Empty + } +}; + +UNIT_TEST(user_routes_test) +{ + TestDelegate d = TestDelegate(); + TestDelegate & dRef = d; + RoutingManager rManager(RM_CALLBACKS, dRef); + + TEST(rManager.getUserRoutes().empty(),("Found User Routes before test start")); +} + +} \ No newline at end of file diff --git a/map/routing_manager.cpp b/map/routing_manager.cpp index 7f2df863ce..2a469d87bc 100644 --- a/map/routing_manager.cpp +++ b/map/routing_manager.cpp @@ -50,6 +50,8 @@ double const kRouteScaleMultiplier = 1.5; string const kRoutePointsFile = "route_points.dat"; +string const kUserRoutesFolder = "user_routes/"; + uint32_t constexpr kInvalidTransactionId = 0; void FillTurnsDistancesForRendering(vector const & segments, @@ -109,7 +111,7 @@ RouteMarkData GetLastPassedPoint(BookmarkManager * bmManager, vector(data.m_pointType)); @@ -117,7 +119,8 @@ void SerializeRoutePoint(json_t * node, RouteMarkData const & data) ToJSONObject(*node, "subtitle", data.m_subTitle); ToJSONObject(*node, "x", data.m_position.x); ToJSONObject(*node, "y", data.m_position.y); - ToJSONObject(*node, "replaceWithMyPosition", data.m_replaceWithMyPositionAfterRestart); + ToJSONObject(*node, "replaceWithMyPosition", + keepReplaceWithMyPositionAfterRestart ? data.m_replaceWithMyPositionAfterRestart : false); } RouteMarkData DeserializeRoutePoint(json_t * node) @@ -140,18 +143,18 @@ RouteMarkData DeserializeRoutePoint(json_t * node) return data; } -string SerializeRoutePoints(vector const & points) +string SerializeRoutePoints(vector const & points, bool const keepReplaceWithMyPositionAfterRestart) { ASSERT_GREATER_OR_EQUAL(points.size(), 2, ()); auto pointsNode = base::NewJSONArray(); for (auto const & p : points) { auto pointNode = base::NewJSONObject(); - SerializeRoutePoint(pointNode.get(), p); + SerializeRoutePoint(pointNode.get(), p, keepReplaceWithMyPositionAfterRestart); json_array_append_new(pointsNode.get(), pointNode.release()); } unique_ptr buffer( - json_dumps(pointsNode.get(), JSON_COMPACT)); + json_dumps(pointsNode.get(), JSON_COMPACT | JSON_ENSURE_ASCII)); return string(buffer.get()); } @@ -1356,31 +1359,56 @@ void RoutingManager::CancelRoutePointsTransaction(uint32_t transactionId) routePoints.AddRoutePoint(std::move(markData)); } +bool RoutingManager::HasSavedUserRoute(string const fileName) const +{ + return HasSavedRoutePoints(kUserRoutesFolder + fileName + ".dat"); +} + + bool RoutingManager::HasSavedRoutePoints() const { - auto const fileName = GetPlatform().SettingsPathForFile(kRoutePointsFile); - return GetPlatform().IsFileExistsByFullPath(fileName); + return HasSavedRoutePoints(kRoutePointsFile); +} + +bool RoutingManager::HasSavedRoutePoints(string const fileName) const +{ + auto const filePath = GetPlatform().SettingsPathForFile(fileName); + return GetPlatform().IsFileExistsByFullPath(filePath); +} + +void RoutingManager::LoadUserRoutePoints(LoadRouteHandler const & handler, string const fileName) +{ + LoadRoutePoints(handler, kUserRoutesFolder + fileName + ".dat", false); } void RoutingManager::LoadRoutePoints(LoadRouteHandler const & handler) { - GetPlatform().RunTask(Platform::Thread::File, [this, handler]() + LoadRoutePoints(handler, kRoutePointsFile, true); +} + +void RoutingManager::LoadRoutePoints(LoadRouteHandler const & handler, string const & fileName, bool const deleteAfterLoading) +{ + GetPlatform().RunTask(Platform::Thread::File, [this, handler, fileName, deleteAfterLoading]() { - if (!HasSavedRoutePoints()) + if (!HasSavedRoutePoints(fileName)) { if (handler) handler(false /* success */); return; } - // Delete file after loading. - auto const fileName = GetPlatform().SettingsPathForFile(kRoutePointsFile); - SCOPE_GUARD(routePointsFileGuard, bind(&FileWriter::DeleteFileX, cref(fileName))); + auto const filePath = GetPlatform().SettingsPathForFile(fileName); + // define a lambda to delete the file based on deleteAfterLoading + auto conditionalDelete = [&]() + { + if (deleteAfterLoading) FileWriter::DeleteFileX(filePath); + }; + SCOPE_GUARD(routePointsFileGuard, conditionalDelete); string data; try { - ReaderPtr(GetPlatform().GetReader(fileName)).ReadAsString(data); + ReaderPtr(GetPlatform().GetReader(filePath)).ReadAsString(data); } catch (RootException const & ex) { @@ -1437,22 +1465,30 @@ void RoutingManager::LoadRoutePoints(LoadRouteHandler const & handler) }); } -void RoutingManager::SaveRoutePoints() +void RoutingManager::SaveUserRoutePoints(string const fileName) { + SaveRoutePoints(kUserRoutesFolder + fileName + ".dat", false); +} + +void RoutingManager::SaveRoutePoints() { + SaveRoutePoints(kRoutePointsFile, true); +} + +void RoutingManager::SaveRoutePoints(string const fileName, bool const keepReplaceWithMyPositionAfterRestart) { auto points = GetRoutePointsToSave(); if (points.empty()) { - DeleteSavedRoutePoints(); + DeleteSavedRoutePoints(fileName); return; } - GetPlatform().RunTask(Platform::Thread::File, [points = std::move(points)]() + GetPlatform().RunTask(Platform::Thread::File, [points = std::move(points), fileName, keepReplaceWithMyPositionAfterRestart]() { try { - auto const fileName = GetPlatform().SettingsPathForFile(kRoutePointsFile); - FileWriter writer(fileName); - string const pointsData = SerializeRoutePoints(points); + auto const filePath = GetPlatform().SettingsPathForFile(fileName); + FileWriter writer(filePath); + string const pointsData = SerializeRoutePoints(points, keepReplaceWithMyPositionAfterRestart); writer.Write(pointsData.c_str(), pointsData.length()); } catch (RootException const & ex) @@ -1501,18 +1537,60 @@ void RoutingManager::OnExtrapolatedLocationUpdate(location::GpsInfo const & info routeMatchingInfo); } +void RoutingManager::DeleteUserRoute(string const fileName) +{ + DeleteSavedRoutePoints(kUserRoutesFolder + fileName + ".dat"); +} + void RoutingManager::DeleteSavedRoutePoints() { - if (!HasSavedRoutePoints()) + DeleteSavedRoutePoints(kRoutePointsFile); +} + +void RoutingManager::DeleteSavedRoutePoints(string const fileName) +{ + if (!HasSavedRoutePoints(fileName)) return; - GetPlatform().RunTask(Platform::Thread::File, []() + GetPlatform().RunTask(Platform::Thread::File, [fileName = fileName]() { - auto const fileName = GetPlatform().SettingsPathForFile(kRoutePointsFile); - FileWriter::DeleteFileX(fileName); + auto const filePath = GetPlatform().SettingsPathForFile(fileName); + FileWriter::DeleteFileX(filePath); }); } +void RoutingManager::RenameUserRoute(string const oldFileName, string const newFileName) +{ + if (!HasSavedRoutePoints(kUserRoutesFolder + oldFileName + ".dat")) + return; + + if (HasSavedRoutePoints(kUserRoutesFolder + newFileName + ".dat")) + return; + + GetPlatform().RunTask(Platform::Thread::File, [oldFileName = kUserRoutesFolder + oldFileName + ".dat" , + newFileName = kUserRoutesFolder + newFileName + ".dat"]() + { + auto const oldPath = GetPlatform().SettingsPathForFile(oldFileName); + auto const newPath = GetPlatform().SettingsPathForFile(newFileName); + base::RenameFileX(oldPath, newPath); + }); +} + +vector RoutingManager::getUserRoutes() +{ + vector routeNames; + GetPlatform().GetFilesByExt(GetPlatform().SettingsPathForFile(kUserRoutesFolder), ".dat", routeNames); + + for(auto name : routeNames) + { + size_t idx = name.rfind(".dat"); + if (idx == string::npos) + continue; + name.erase(idx, 4); // erase file extension from the string + } + return routeNames/*TODO find out how this return value is able to be interpreted in java*/; +} + void RoutingManager::UpdatePreviewMode() { SetSubroutesVisibility(false /* visible */); diff --git a/map/routing_manager.hpp b/map/routing_manager.hpp index 2b42c5781d..f0b80457b7 100644 --- a/map/routing_manager.hpp +++ b/map/routing_manager.hpp @@ -304,16 +304,36 @@ public: void CancelRoutePointsTransaction(uint32_t transactionId); static uint32_t InvalidRoutePointsTransactionId(); - /// \returns true if there are route points saved in file and false otherwise. + /// \returns true if there is a user route points saved with the given name and false otherwise. + bool HasSavedUserRoute(std::string fileName) const; + /// \returns true if there are route points saved in the default file and false otherwise. bool HasSavedRoutePoints() const; - /// \brief It loads road points from file and delete file after loading. + /// \returns true if there are route points saved in file and false otherwise. + bool HasSavedRoutePoints(std::string fileName) const; /// The result of the loading will be sent via SafeCallback. using LoadRouteHandler = platform::SafeCallback; + /// \brief It loads road points from file in a user routes folder and keeps file after loading. + void LoadUserRoutePoints(LoadRouteHandler const & handler, std::string fileName); + /// \brief It loads road points from file and delete file after loading. void LoadRoutePoints(LoadRouteHandler const & handler); - /// \brief It saves route points to file. + /// \brief It loads road points from file and can be set to delete file after loading. + void LoadRoutePoints(LoadRouteHandler const & handler, std::string const& fileName, bool deleteAfterLoading); + /// \brief It saves route points to file in a user routes folder + void SaveUserRoutePoints(std::string fileName); + /// \brief It saves route points to default file. void SaveRoutePoints(); - /// \brief It deletes file with saved route points if it exists. + /// \brief It saves route points to file with the given name. + void SaveRoutePoints(std::string fileName, bool keepReplaceWithMyPositionAfterRestart); + /// \brief It deletes the user route with the user route with the given name if it exists. + void DeleteUserRoute(std::string fileName); + /// \brief It deletes the default file with saved route points if it exists. void DeleteSavedRoutePoints(); + /// \brief It deletes file with saved route points if it exists. + void DeleteSavedRoutePoints(std::string fileName); + /// \brief It renames a user route + void RenameUserRoute(std::string oldFileName, std::string newFileName); + /// \returns names of the files in the user routes folder without the .dat file extension. + std::vector getUserRoutes(); void UpdatePreviewMode(); void CancelPreviewMode();