diff options
Diffstat (limited to 'map')
-rw-r--r-- | map/bookmark.cpp | 554 | ||||
-rw-r--r-- | map/bookmark.hpp | 50 | ||||
-rw-r--r-- | map/bookmark_manager.cpp | 612 | ||||
-rw-r--r-- | map/bookmark_manager.hpp | 48 | ||||
-rw-r--r-- | map/framework.cpp | 4 | ||||
-rw-r--r-- | map/map_tests/bookmarks_test.cpp | 220 | ||||
-rw-r--r-- | map/map_tests/kmz_unarchive_test.cpp | 28 | ||||
-rw-r--r-- | map/map_tests/search_api_tests.cpp | 21 | ||||
-rw-r--r-- | map/place_page_info.cpp | 6 | ||||
-rw-r--r-- | map/place_page_info.hpp | 6 | ||||
-rw-r--r-- | map/search_api.cpp | 9 | ||||
-rw-r--r-- | map/search_api.hpp | 4 | ||||
-rw-r--r-- | map/track.cpp | 37 | ||||
-rw-r--r-- | map/track.hpp | 28 | ||||
-rw-r--r-- | map/user_mark_layer.hpp | 2 |
15 files changed, 663 insertions, 966 deletions
diff --git a/map/bookmark.cpp b/map/bookmark.cpp index 116db07216..b0f735c6ed 100644 --- a/map/bookmark.cpp +++ b/map/bookmark.cpp @@ -3,7 +3,7 @@ #include "map/bookmark_manager.hpp" #include "map/track.hpp" -#include "base/scope_guard.hpp" +#include "kml/serdes.hpp" #include "geometry/mercator.hpp" @@ -19,6 +19,7 @@ #include "platform/platform.hpp" +#include "base/scope_guard.hpp" #include "base/stl_add.hpp" #include "base/string_utils.hpp" @@ -27,25 +28,28 @@ #include <iterator> #include <map> #include <memory> +#include <kml/serdes_binary.hpp> Bookmark::Bookmark(m2::PointD const & ptOrg) : Base(ptOrg, UserMark::BOOKMARK) , m_groupId(df::kInvalidMarkGroupId) -{} +{ + m_data.m_point = ptOrg; +} -Bookmark::Bookmark(BookmarkData const & data, m2::PointD const & ptOrg) - : Base(ptOrg, UserMark::BOOKMARK) +Bookmark::Bookmark(kml::BookmarkData const & data) + : Base(data.m_point, UserMark::BOOKMARK) , m_data(data) , m_groupId(df::kInvalidMarkGroupId) {} -void Bookmark::SetData(BookmarkData const & data) +void Bookmark::SetData(kml::BookmarkData const & data) { SetDirty(); m_data = data; } -BookmarkData const & Bookmark::GetData() const +kml::BookmarkData const & Bookmark::GetData() const { return m_data; } @@ -57,7 +61,6 @@ dp::Anchor Bookmark::GetAnchor() const drape_ptr<df::UserPointMark::SymbolNameZoomInfo> Bookmark::GetSymbolNames() const { - auto const name = GetType(); auto symbol = make_unique_dp<SymbolNameZoomInfo>(); symbol->insert(std::make_pair(1 /* zoomLevel */, "bookmark-default-xs")); symbol->insert(std::make_pair(8 /* zoomLevel */, "bookmark-default-s")); @@ -68,53 +71,70 @@ drape_ptr<df::UserPointMark::SymbolNameZoomInfo> Bookmark::GetSymbolNames() cons df::ColorConstant Bookmark::GetColor() const { - //TODO(@darina): Use new colors instead of GetType(). - auto const type = GetType(); - if (type == "placemark-red") - return "BookmarkRed"; - if (type == "placemark-blue") - return "BookmarkBlue"; - if (type == "placemark-purple") - return "BookmarkPurple"; - if (type == "placemark-yellow") - return "BookmarkYellow"; - if (type == "placemark-pink") - return "BookmarkPink"; - if (type == "placemark-brown") - return "BookmarkBrown"; - if (type == "placemark-green") - return "BookmarkGreen"; - if (type == "placemark-orange") - return "BookmarkOrange"; - - return "BookmarkRed"; -} - -bool Bookmark::HasCreationAnimation() const -{ - return true; + switch (m_data.m_color.m_predefinedColor) + { + case kml::PredefinedColor::Red: + return "BookmarkRed"; + case kml::PredefinedColor::Blue: + return "BookmarkBlue"; + case kml::PredefinedColor::Purple: + return "BookmarkPurple"; + case kml::PredefinedColor::Yellow: + return "BookmarkYellow"; + case kml::PredefinedColor::Pink: + return "BookmarkPink"; + case kml::PredefinedColor::Brown: + return "BookmarkBrown"; + case kml::PredefinedColor::Green: + return "BookmarkGreen"; + case kml::PredefinedColor::Orange: + return "BookmarkOrange"; + case kml::PredefinedColor::None: + case kml::PredefinedColor::Count: + return "BookmarkRed"; + } } -std::string const & Bookmark::GetName() const +std::string Bookmark::GetIcon() const { - return m_data.GetName(); + switch (m_data.m_color.m_predefinedColor) + { + case kml::PredefinedColor::Red: + return "placemark-red"; + case kml::PredefinedColor::Blue: + return "placemark-blue"; + case kml::PredefinedColor::Purple: + return "placemark-purple"; + case kml::PredefinedColor::Yellow: + return "placemark-yellow"; + case kml::PredefinedColor::Pink: + return "placemark-pink"; + case kml::PredefinedColor::Brown: + return "placemark-brown"; + case kml::PredefinedColor::Green: + return "placemark-green"; + case kml::PredefinedColor::Orange: + return "placemark-orange"; + case kml::PredefinedColor::None: + case kml::PredefinedColor::Count: + return "placemark-red"; + } } -void Bookmark::SetName(std::string const & name) +bool Bookmark::HasCreationAnimation() const { - SetDirty(); - m_data.SetName(name); + return true; } -std::string const & Bookmark::GetType() const +std::string Bookmark::GetName() const { - return m_data.GetType(); + return kml::GetDefaultStr(m_data.m_name); } -void Bookmark::SetType(std::string const & type) +void Bookmark::SetName(std::string const & name) { SetDirty(); - m_data.SetType(type); + kml::SetDefaultStr(m_data.m_name, name); } m2::RectD Bookmark::GetViewport() const @@ -122,34 +142,35 @@ m2::RectD Bookmark::GetViewport() const return m2::RectD(GetPivot(), GetPivot()); } -std::string const & Bookmark::GetDescription() const +std::string Bookmark::GetDescription() const { - return m_data.GetDescription(); + return kml::GetDefaultStr(m_data.m_description); } void Bookmark::SetDescription(std::string const & description) { - m_data.SetDescription(description); + SetDirty(); + kml::SetDefaultStr(m_data.m_description, description); } -time_t Bookmark::GetTimeStamp() const +kml::Timestamp Bookmark::GetTimeStamp() const { - return m_data.GetTimeStamp(); + return m_data.m_timestamp; } -void Bookmark::SetTimeStamp(time_t timeStamp) +void Bookmark::SetTimeStamp(kml::Timestamp timeStamp) { - m_data.SetTimeStamp(timeStamp); + m_data.m_timestamp = timeStamp; } -double Bookmark::GetScale() const +uint8_t Bookmark::GetScale() const { - return m_data.GetScale(); + return m_data.m_viewportScale; } -void Bookmark::SetScale(double scale) +void Bookmark::SetScale(uint8_t scale) { - m_data.SetScale(scale); + m_data.m_viewportScale = scale; } df::MarkGroupID Bookmark::GetGroupId() const @@ -171,425 +192,78 @@ void Bookmark::Detach() BookmarkCategory::BookmarkCategory(std::string const & name, df::MarkGroupID groupId, bool autoSave) : Base(UserMark::Type::BOOKMARK) , m_groupId(groupId) - , m_name(name) , m_autoSave(autoSave) -{} - -BookmarkCategory::~BookmarkCategory() { + SetName(name); } -void BookmarkCategory::SetName(std::string const & name) +BookmarkCategory::BookmarkCategory(kml::CategoryData const & data, df::MarkGroupID groupId, bool autoSave) + : Base(UserMark::Type::BOOKMARK) + , m_groupId(groupId) + , m_autoSave(autoSave) + , m_data(data) { - SetDirty(); - m_name = name; + Base::SetIsVisible(m_data.m_visible); } -namespace +BookmarkCategory::~BookmarkCategory() { - std::string const kPlacemark = "Placemark"; - std::string const kStyle = "Style"; - std::string const kDocument = "Document"; - std::string const kStyleMap = "StyleMap"; - std::string const kStyleUrl = "styleUrl"; - std::string const kPair = "Pair"; - - std::string const kDefaultTrackColor = "DefaultTrackColor"; - float const kDefaultTrackWidth = 5.0f; - - std::string PointToString(m2::PointD const & org) - { - double const lon = MercatorBounds::XToLon(org.x); - double const lat = MercatorBounds::YToLat(org.y); - - ostringstream ss; - ss.precision(8); - - ss << lon << "," << lat; - return ss.str(); - } +} - enum GeometryType - { - GEOMETRY_TYPE_UNKNOWN, - GEOMETRY_TYPE_POINT, - GEOMETRY_TYPE_LINE - }; +void BookmarkCategory::SetIsVisible(bool isVisible) +{ + Base::SetIsVisible(isVisible); + m_data.m_visible = isVisible; } -class KMLParser +void BookmarkCategory::SetName(std::string const & name) { - // Fixes icons which are not supported by MapsWithMe. - std::string GetSupportedBMType(std::string const & s) const - { - // Remove leading '#' symbol. - ASSERT(!s.empty(), ()); - std::string const result = s.substr(1); - return style::GetSupportedStyle(result, m_name, style::GetDefaultStyle()); - } + SetDirty(); + kml::SetDefaultStr(m_data.m_name, name); +} - KMLData & m_data; - - std::vector<std::string> m_tags; - GeometryType m_geometryType; - m2::PolylineD m_points; - dp::Color m_trackColor; - - std::string m_styleId; - std::string m_mapStyleId; - std::string m_styleUrlKey; - std::map<std::string, dp::Color> m_styleUrl2Color; - std::map<std::string, std::string> m_mapStyle2Style; - - std::string m_name; - std::string m_type; - std::string m_description; - time_t m_timeStamp; - - m2::PointD m_org; - double m_scale; - - void Reset() - { - m_name.clear(); - m_description.clear(); - m_org = m2::PointD(0.0, 0.0); - m_type.clear(); - m_scale = -1.0; - m_timeStamp = my::INVALID_TIME_STAMP; - - m_trackColor = df::GetColorConstant(kDefaultTrackColor); - m_styleId.clear(); - m_mapStyleId.clear(); - m_styleUrlKey.clear(); - - m_points.Clear(); - m_geometryType = GEOMETRY_TYPE_UNKNOWN; - } - - bool ParsePoint(std::string const & s, char const * delim, m2::PointD & pt) - { - // order in string is: lon, lat, z - strings::SimpleTokenizer iter(s, delim); - if (iter) - { - double lon; - if (strings::to_double(*iter, lon) && MercatorBounds::ValidLon(lon) && ++iter) - { - double lat; - if (strings::to_double(*iter, lat) && MercatorBounds::ValidLat(lat)) - { - pt = MercatorBounds::FromLatLon(lat, lon); - return true; - } - } - } - - return false; - } - - void SetOrigin(std::string const & s) - { - m_geometryType = GEOMETRY_TYPE_POINT; - - m2::PointD pt; - if (ParsePoint(s, ", \n\r\t", pt)) - m_org = pt; - } - - void ParseLineCoordinates(std::string const & s, char const * blockSeparator, char const * coordSeparator) - { - m_geometryType = GEOMETRY_TYPE_LINE; - - strings::SimpleTokenizer tupleIter(s, blockSeparator); - while (tupleIter) - { - m2::PointD pt; - if (ParsePoint(*tupleIter, coordSeparator, pt)) - { - if (m_points.GetSize() == 0 || !(pt - m_points.Back()).IsAlmostZero()) - m_points.Add(pt); - } - ++tupleIter; - } - } - - bool MakeValid() - { - if (GEOMETRY_TYPE_POINT == m_geometryType) - { - if (MercatorBounds::ValidX(m_org.x) && MercatorBounds::ValidY(m_org.y)) - { - // set default name - if (m_name.empty()) - m_name = PointToString(m_org); - - // set default pin - if (m_type.empty()) - m_type = "placemark-red"; - - return true; - } - return false; - } - else if (GEOMETRY_TYPE_LINE == m_geometryType) - { - return m_points.GetSize() > 1; - } - - return false; - } - - void ParseColor(std::string const & value) - { - std::string fromHex = FromHex(value); - ASSERT(fromHex.size() == 4, ("Invalid color passed")); - // Color positions in HEX – aabbggrr - m_trackColor = dp::Color(fromHex[3], fromHex[2], fromHex[1], fromHex[0]); - } - - bool GetColorForStyle(std::string const & styleUrl, dp::Color & color) - { - if (styleUrl.empty()) - return false; - - // Remove leading '#' symbol - auto it = m_styleUrl2Color.find(styleUrl.substr(1)); - if (it != m_styleUrl2Color.end()) - { - color = it->second; - return true; - } - return false; - } - -public: - KMLParser(KMLData & data) - : m_data(data) - { - Reset(); - } - - ~KMLParser() - { - } - - bool Push(std::string const & name) - { - m_tags.push_back(name); - return true; - } - - void AddAttr(std::string const & attr, std::string const & value) - { - std::string attrInLowerCase = attr; - strings::AsciiToLower(attrInLowerCase); - - if (IsValidAttribute(kStyle, value, attrInLowerCase)) - m_styleId = value; - else if (IsValidAttribute(kStyleMap, value, attrInLowerCase)) - m_mapStyleId = value; - } - - bool IsValidAttribute(std::string const & type, std::string const & value, - std::string const & attrInLowerCase) const - { - return (GetTagFromEnd(0) == type && !value.empty() && attrInLowerCase == "id"); - } - - std::string const & GetTagFromEnd(size_t n) const - { - ASSERT_LESS(n, m_tags.size(), ()); - return m_tags[m_tags.size() - n - 1]; - } - - void Pop(std::string const & tag) - { - ASSERT_EQUAL(m_tags.back(), tag, ()); - - if (tag == kPlacemark) - { - if (MakeValid()) - { - if (GEOMETRY_TYPE_POINT == m_geometryType) - { - m_data.m_bookmarks.emplace_back(std::make_unique<Bookmark>( - BookmarkData(m_name, m_type, m_description, m_scale, m_timeStamp), m_org)); - } - else if (GEOMETRY_TYPE_LINE == m_geometryType) - { - Track::Params params; - params.m_colors.push_back({ kDefaultTrackWidth, m_trackColor }); - params.m_name = m_name; - - m_data.m_tracks.emplace_back(std::make_unique<Track>(m_points, params)); - } - } - Reset(); - } - else if (tag == kStyle) - { - if (GetTagFromEnd(1) == kDocument) - { - if (!m_styleId.empty()) - { - m_styleUrl2Color[m_styleId] = m_trackColor; - m_trackColor = df::GetColorConstant(kDefaultTrackColor); - } - } - } - - m_tags.pop_back(); - } - - void CharData(std::string value) - { - strings::Trim(value); - - size_t const count = m_tags.size(); - if (count > 1 && !value.empty()) - { - std::string const & currTag = m_tags[count - 1]; - std::string const & prevTag = m_tags[count - 2]; - // TODO: Check this condition, why not count > 2? - std::string const ppTag = count > 3 ? m_tags[count - 3] : std::string(); - - if (prevTag == kDocument) - { - if (currTag == "name") - m_data.m_name = value; - else if (currTag == "visibility") - m_data.m_visible = value != "0"; - } - else if (prevTag == kPlacemark) - { - if (currTag == "name") - m_name = value; - else if (currTag == "styleUrl") - { - // Bookmark draw style. - m_type = GetSupportedBMType(value); - - // Check if url is in styleMap map. - if (!GetColorForStyle(value, m_trackColor)) - { - // Remove leading '#' symbol. - std::string styleId = m_mapStyle2Style[value.substr(1)]; - if (!styleId.empty()) - GetColorForStyle(styleId, m_trackColor); - } - } - else if (currTag == "description") - m_description = value; - } - else if (prevTag == "LineStyle" && currTag == "color") - { - ParseColor(value); - } - else if (ppTag == kStyleMap && prevTag == kPair && currTag == kStyleUrl && - m_styleUrlKey == "normal") - { - if (!m_mapStyleId.empty()) - m_mapStyle2Style[m_mapStyleId] = value; - } - else if (ppTag == kStyleMap && prevTag == kPair && currTag == "key") - { - m_styleUrlKey = value; - } - else if (ppTag == kPlacemark) - { - if (prevTag == "Point") - { - if (currTag == "coordinates") - SetOrigin(value); - } - else if (prevTag == "LineString") - { - if (currTag == "coordinates") - ParseLineCoordinates(value, " \n\r\t", ","); - } - else if (prevTag == "gx:Track") - { - if (currTag == "gx:coord") - ParseLineCoordinates(value, "\n\r\t", " "); - } - else if (prevTag == "ExtendedData") - { - if (currTag == "mwm:scale") - { - if (!strings::to_double(value, m_scale)) - m_scale = -1.0; - } - } - else if (prevTag == "TimeStamp") - { - if (currTag == "when") - m_timeStamp = my::StringToTimestamp(value); - } - else if (currTag == kStyleUrl) - { - GetColorForStyle(value, m_trackColor); - } - } - else if (ppTag == "MultiGeometry") - { - if (prevTag == "Point") - { - if (currTag == "coordinates") - SetOrigin(value); - } - else if (prevTag == "LineString") - { - if (currTag == "coordinates") - ParseLineCoordinates(value, " \n\r\t", ","); - } - else if (prevTag == "gx:Track") - { - if (currTag == "gx:coord") - ParseLineCoordinates(value, "\n\r\t", " "); - } - } - else if (ppTag == "gx:MultiTrack") - { - if (prevTag == "gx:Track") - { - if (currTag == "gx:coord") - ParseLineCoordinates(value, "\n\r\t", " "); - } - } - } - } -}; +std::string BookmarkCategory::GetName() const +{ + return kml::GetDefaultStr(m_data.m_name); +} std::string BookmarkCategory::GetDefaultType() { return style::GetDefaultStyle(); } -std::unique_ptr<KMLData> LoadKMLFile(std::string const & file) +std::unique_ptr<kml::FileData> LoadKMLFile(std::string const & file, bool useBinary) { try { - auto data = LoadKMLData(std::make_unique<FileReader>(file)); - if (data) - data->m_file = file; - return data; + return LoadKMLData(FileReader(file), useBinary); } catch (std::exception const & e) { - LOG(LDEBUG, ("Error while loading bookmarks from", file, e.what())); + LOG(LWARNING, ("Error while loading bookmarks from", file, e.what())); } return nullptr; } -std::unique_ptr<KMLData> LoadKMLData(ReaderPtr<Reader> const & reader) +std::unique_ptr<kml::FileData> LoadKMLData(Reader const & reader, bool useBinary) { - auto data = std::make_unique<KMLData>(); - ReaderSource<ReaderPtr<Reader> > src(reader); - KMLParser parser(*data); - if (!ParseXML(src, parser, true)) + auto data = std::make_unique<kml::FileData>(); + try + { + if (useBinary) + { + kml::binary::DeserializerKml des(*data.get()); + des.Deserialize(reader); + } + else + { + kml::DeserializerKml des(*data.get()); + des.Deserialize(reader); + } + } + catch (FileReader::Exception const & exc) { - LOG(LDEBUG, ("XML read error. Probably, incorrect file encoding.")); + LOG(LWARNING, ("KML ", useBinary ? "binary" : "text", " deserialization failure: ", exc.what())); data.reset(); } return data; diff --git a/map/bookmark.hpp b/map/bookmark.hpp index 8076f7c087..ade2be8606 100644 --- a/map/bookmark.hpp +++ b/map/bookmark.hpp @@ -4,6 +4,8 @@ #include "map/user_mark.hpp" #include "map/user_mark_layer.hpp" +#include "kml/types.hpp" + #include "coding/reader.hpp" #include "geometry/point2d.hpp" @@ -25,6 +27,7 @@ namespace anim class BookmarkManager; +/* class BookmarkData { public: @@ -69,6 +72,7 @@ private: double m_scale; ///< Viewport scale. -1.0 - is a default value (no scale set). time_t m_timeStamp; }; +*/ class Bookmark : public UserMark { @@ -76,39 +80,38 @@ class Bookmark : public UserMark public: Bookmark(m2::PointD const & ptOrg); - Bookmark(BookmarkData const & data, m2::PointD const & ptOrg); + Bookmark(kml::BookmarkData const & data); - void SetData(BookmarkData const & data); - BookmarkData const & GetData() const; + void SetData(kml::BookmarkData const & data); + kml::BookmarkData const & GetData() const; dp::Anchor GetAnchor() const override; drape_ptr<SymbolNameZoomInfo> GetSymbolNames() const override; df::ColorConstant GetColor() const override; + // TODO(darina): Remove this method after UI refactoring. + std::string GetIcon() const; bool HasCreationAnimation() const override; - std::string const & GetName() const; + std::string GetName() const; void SetName(std::string const & name); - /// @return Now its a bookmark color - name of icon file - std::string const & GetType() const; - void SetType(std::string const & type); m2::RectD GetViewport() const; - std::string const & GetDescription() const; + std::string GetDescription() const; void SetDescription(std::string const & description); /// @return my::INVALID_TIME_STAMP if bookmark has no timestamp - time_t GetTimeStamp() const; - void SetTimeStamp(time_t timeStamp); + kml::Timestamp GetTimeStamp() const; + void SetTimeStamp(kml::Timestamp timeStamp); - double GetScale() const; - void SetScale(double scale); + uint8_t GetScale() const; + void SetScale(uint8_t scale); df::MarkGroupID GetGroupId() const override; void Attach(df::MarkGroupID groupId); void Detach(); private: - BookmarkData m_data; + kml::BookmarkData m_data; df::MarkGroupID m_groupId; }; @@ -118,36 +121,37 @@ class BookmarkCategory : public UserMarkLayer public: BookmarkCategory(std::string const & name, df::MarkGroupID groupId, bool autoSave); + BookmarkCategory(kml::CategoryData const & data, df::MarkGroupID groupId, bool autoSave); ~BookmarkCategory() override; static std::string GetDefaultType(); df::MarkGroupID GetID() const { return m_groupId; } + void SetIsVisible(bool isVisible) override; void SetName(std::string const & name); void SetFileName(std::string const & fileName) { m_file = fileName; } - std::string const & GetName() const { return m_name; } + std::string GetName() const; std::string const & GetFileName() const { return m_file; } void EnableAutoSave(bool enable) { m_autoSave = enable; } bool IsAutoSaveEnabled() const { return m_autoSave; } + kml::CategoryData const & GetCategoryData() const { return m_data; } + private: df::MarkGroupID const m_groupId; - std::string m_name; // Stores file name from which bookmarks were loaded. std::string m_file; bool m_autoSave = true; + kml::CategoryData m_data; }; -struct KMLData +struct CategoryFileInfo { - std::string m_name; - std::string m_file; - std::vector<std::unique_ptr<Bookmark>> m_bookmarks; - std::vector<std::unique_ptr<Track>> m_tracks; - bool m_visible = true; + std::string m_filePath; + std::unique_ptr<kml::FileData> m_data; }; -std::unique_ptr<KMLData> LoadKMLFile(std::string const & file); -std::unique_ptr<KMLData> LoadKMLData(ReaderPtr<Reader> const & reader); +std::unique_ptr<kml::FileData> LoadKMLFile(std::string const & file, bool useBinary); +std::unique_ptr<kml::FileData> LoadKMLData(Reader const & reader, bool useBinary); diff --git a/map/bookmark_manager.cpp b/map/bookmark_manager.cpp index cf05e17cbf..53d0be541b 100644 --- a/map/bookmark_manager.cpp +++ b/map/bookmark_manager.cpp @@ -20,6 +20,7 @@ #include "coding/file_writer.hpp" #include "coding/hex.hpp" #include "coding/internal/file_data.hpp" +#include "coding/multilang_utf8_string.hpp" #include "coding/zip_creator.hpp" #include "coding/zip_reader.hpp" @@ -351,48 +352,46 @@ bool IsMigrationCompleted() return isCompleted; } -void MigrateIfNeeded() +bool MigrateIfNeeded() { if (IsMigrationCompleted()) - return; + return true; - GetPlatform().RunTask(Platform::Thread::File, []() + std::string const dir = GetPlatform().SettingsDir(); + Platform::FilesList files; + Platform::GetFilesByExt(dir, BOOKMARKS_FILE_EXTENSION, files); + if (files.empty()) { - std::string const dir = GetPlatform().SettingsDir(); - Platform::FilesList files; - Platform::GetFilesByExt(dir, BOOKMARKS_FILE_EXTENSION, files); - if (files.empty()) - { - auto const newBookmarksDir = GetBookmarksDirectory(); - if (!GetPlatform().IsFileExistsByFullPath(newBookmarksDir)) - UNUSED_VALUE(GetPlatform().MkDirChecked(newBookmarksDir)); - OnMigrationSuccess(0 /* originalCount */, 0 /* convertedCount */); - return; - } + auto const newBookmarksDir = GetBookmarksDirectory(); + if (!GetPlatform().IsFileExistsByFullPath(newBookmarksDir)) + UNUSED_VALUE(GetPlatform().MkDirChecked(newBookmarksDir)); + OnMigrationSuccess(0 /* originalCount */, 0 /* convertedCount */); + return true; + } - for (auto & f : files) - f = my::JoinFoldersToPath(dir, f); + for (auto & f : files) + f = my::JoinFoldersToPath(dir, f); - std::string failedStage; - auto const backupDir = CheckAndCreateBackupFolder(); - if (backupDir.empty() || !BackupBookmarks(backupDir, files)) - { - OnMigrationFailure("backup"); - return; - } + std::string failedStage; + auto const backupDir = CheckAndCreateBackupFolder(); + if (backupDir.empty() || !BackupBookmarks(backupDir, files)) + { + OnMigrationFailure("backup"); + return false; + } - size_t convertedCount; - if (!ConvertBookmarks(files, convertedCount)) - { - OnMigrationFailure("conversion"); - return; - } + size_t convertedCount; + if (!ConvertBookmarks(files, convertedCount)) + { + OnMigrationFailure("conversion"); + return false; + } - //TODO(@darina): Uncomment after KMB integration. - //for (auto const & f : files) - // my::DeleteFileX(f); - OnMigrationSuccess(files.size(), convertedCount); - }); + //TODO(@darina): Uncomment after KMB integration. + //for (auto const & f : files) + // my::DeleteFileX(f); + OnMigrationSuccess(files.size(), convertedCount); + return true; } } // namespace migration @@ -468,29 +467,29 @@ void BookmarkManager::DeleteUserMark(df::MarkID markId) m_userMarks.erase(it); } -Bookmark * BookmarkManager::CreateBookmark(m2::PointD const & ptOrg, BookmarkData const & bmData) +Bookmark * BookmarkManager::CreateBookmark(kml::BookmarkData const & bmData) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); - return AddBookmark(std::make_unique<Bookmark>(bmData, ptOrg)); + return AddBookmark(std::make_unique<Bookmark>(bmData)); } -Bookmark * BookmarkManager::CreateBookmark(m2::PointD const & ptOrg, BookmarkData & bm, df::MarkGroupID groupId) +Bookmark * BookmarkManager::CreateBookmark(kml::BookmarkData & bm, df::MarkGroupID groupId) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); GetPlatform().GetMarketingService().SendMarketingEvent(marketing::kBookmarksBookmarkAction, {{"action", "create"}}); - bm.SetTimeStamp(time(0)); - bm.SetScale(df::GetDrawTileScale(m_viewport)); + bm.m_timestamp = std::chrono::system_clock::now(); + bm.m_viewportScale = static_cast<uint8_t>(df::GetZoomLevel(m_viewport.GetScale())); - auto * bookmark = CreateBookmark(ptOrg, bm); + auto * bookmark = CreateBookmark(bm); bookmark->Attach(groupId); auto * group = GetBmCategory(groupId); group->AttachUserMark(bookmark->GetId()); group->SetIsVisible(true); m_lastCategoryUrl = group->GetFileName(); - m_lastType = bm.GetType(); + m_lastType = bookmark->GetIcon(); SaveState(); return bookmark; @@ -543,10 +542,10 @@ void BookmarkManager::DeleteBookmark(df::MarkID bmId) m_bookmarks.erase(groupIt); } -Track * BookmarkManager::CreateTrack(m2::PolylineD const & polyline, Track::Params const & p) +Track * BookmarkManager::CreateTrack(kml::TrackData const & trackData) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); - return AddTrack(std::make_unique<Track>(polyline, p)); + return AddTrack(std::make_unique<Track>(trackData)); } Track const * BookmarkManager::GetTrack(df::LineID trackId) const @@ -623,7 +622,7 @@ void BookmarkManager::NotifyChanges() if (IsBookmarkCategory(groupId)) { if (GetBmCategory(groupId)->IsAutoSaveEnabled()) - SaveToKMLFile(groupId); + SaveBookmarkCategoryToFile(groupId); isBookmarks = true; } } @@ -693,7 +692,7 @@ void BookmarkManager::ClearGroup(df::MarkGroupID groupId) group->Clear(); } -std::string const & BookmarkManager::GetCategoryName(df::MarkGroupID categoryId) const +std::string BookmarkManager::GetCategoryName(df::MarkGroupID categoryId) const { ASSERT_THREAD_CHECKER(m_threadChecker, ()); return GetBmCategory(categoryId)->GetName(); @@ -705,7 +704,7 @@ void BookmarkManager::SetCategoryName(df::MarkGroupID categoryId, std::string co GetBmCategory(categoryId)->SetName(name); } -std::string const & BookmarkManager::GetCategoryFileName(df::MarkGroupID categoryId) const +std::string BookmarkManager::GetCategoryFileName(df::MarkGroupID categoryId) const { ASSERT_THREAD_CHECKER(m_threadChecker, ()); return GetBmCategory(categoryId)->GetFileName(); @@ -733,7 +732,7 @@ UserMark const * BookmarkManager::FindMarkInRect(df::MarkGroupID groupId, m2::An void BookmarkManager::SetIsVisible(df::MarkGroupID groupId, bool visible) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); - return GetGroup(groupId)->SetIsVisible(visible); + GetGroup(groupId)->SetIsVisible(visible); } bool BookmarkManager::IsVisible(df::MarkGroupID groupId) const @@ -812,6 +811,82 @@ void BookmarkManager::ClearCategories() m_tracks.clear(); } +std::shared_ptr<BookmarkManager::KMLDataCollection> BookmarkManager::LoadBookmarksKML(std::vector<std::string> & filePaths) +{ + std::string const dir = GetPlatform().SettingsDir(); + Platform::FilesList files; + Platform::GetFilesByExt(dir, BOOKMARKS_FILE_EXTENSION, files); + + auto collection = std::make_shared<KMLDataCollection>(); + collection->reserve(files.size()); + filePaths.reserve(files.size()); + for (auto const & file : files) + { + auto const filePath = dir + file; + auto kmlData = std::make_unique<kml::FileData>(); + try + { + kml::DeserializerKml des(*kmlData); + FileReader reader(filePath); + des.Deserialize(reader); + } + catch (FileReader::Exception const &exc) + { + LOG(LDEBUG, ("KML deserialization failure: ", exc.what(), "file", filePath)); + continue; + } + if (m_needTeardown) + break; + filePaths.push_back(filePath); + collection->emplace_back(filePath, std::move(kmlData)); + + /*auto kmlData = LoadKMLFile(filePath); + + if (m_needTeardown) + break; + + if (kmlData) + { + filePaths.push_back(filePath); + collection->emplace_back(filePath, std::move(kmlData)); + }*/ + } + return collection; +} + +std::shared_ptr<BookmarkManager::KMLDataCollection> BookmarkManager::LoadBookmarksKMB(std::vector<std::string> & filePaths) +{ + std::string const dir = GetPlatform().SettingsDir(); + Platform::FilesList files; + Platform::GetFilesByExt(dir, kBookmarksExt, files); + + auto collection = std::make_shared<KMLDataCollection>(); + collection->reserve(files.size()); + filePaths.reserve(files.size()); + + for (auto const & file : files) + { + auto const filePath = dir + file; + auto kmlData = std::make_unique<kml::FileData>(); + try + { + kml::binary::DeserializerKml des(*kmlData); + FileReader reader(filePath); + des.Deserialize(reader); + } + catch (FileReader::Exception const &exc) + { + LOG(LDEBUG, ("KML binary deserialization failure: ", exc.what(), "file", filePath)); + continue; + } + if (m_needTeardown) + break; + filePaths.push_back(filePath); + collection->emplace_back(filePath, std::move(kmlData)); + } + return collection; +} + void BookmarkManager::LoadBookmarks() { ASSERT_THREAD_CHECKER(m_threadChecker, ()); @@ -819,30 +894,13 @@ void BookmarkManager::LoadBookmarks() m_loadBookmarksFinished = false; NotifyAboutStartAsyncLoading(); - migration::MigrateIfNeeded(); GetPlatform().RunTask(Platform::Thread::File, [this]() { - std::string const dir = GetPlatform().SettingsDir(); - Platform::FilesList files; - Platform::GetFilesByExt(dir, BOOKMARKS_FILE_EXTENSION, files); - - auto collection = std::make_shared<KMLDataCollection>(); - collection->reserve(files.size()); + bool const migrated = migration::MigrateIfNeeded(); std::vector<std::string> filePaths; - filePaths.reserve(files.size()); - for (auto const & file : files) - { - auto const filePath = dir + file; - auto kmlData = LoadKMLFile(filePath); - if (m_needTeardown) - return; - - if (kmlData != nullptr) - { - filePaths.push_back(filePath); - collection->emplace_back(std::move(kmlData)); - } - } + auto collection = migrated ? LoadBookmarksKMB(filePaths) : LoadBookmarksKML(filePaths); + if (m_needTeardown) + return; NotifyAboutFinishAsyncLoading(std::move(collection)); GetPlatform().RunTask(Platform::Thread::Gui, [this, filePaths]() { m_bookmarkCloud.Init(filePaths); }); @@ -851,6 +909,11 @@ void BookmarkManager::LoadBookmarks() LoadState(); } +void BookmarkManager::MigrateAndLoadBookmarks() +{ + +} + void BookmarkManager::LoadBookmark(std::string const & filePath, bool isTemporaryFile) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); @@ -868,33 +931,65 @@ void BookmarkManager::LoadBookmarkRoutine(std::string const & filePath, bool isT NotifyAboutStartAsyncLoading(); GetPlatform().RunTask(Platform::Thread::File, [this, filePath, isTemporaryFile]() { - auto collection = std::make_shared<KMLDataCollection >(); - auto const fileSavePath = GetKMLPath(filePath); - if (m_needTeardown) - return; + bool const migrated = migration::IsMigrationCompleted(); + auto collection = std::make_shared<KMLDataCollection>(); + auto kmlData = std::make_unique<kml::FileData>(); + std::string fileSavePath; - if (!fileSavePath) - { - NotifyAboutFile(false /* success */, filePath, isTemporaryFile); - } - else + try { - auto kmlData = LoadKMLFile(fileSavePath.get()); + auto const savePath = GetKMLPath(filePath); if (m_needTeardown) return; + if (savePath) + { + kml::DeserializerKml des(*kmlData); + FileReader reader(fileSavePath); + des.Deserialize(reader); + fileSavePath = savePath.get(); + } + } + catch (FileReader::Exception const & exc) + { + LOG(LDEBUG, ("KML deserialization failure: ", exc.what(), "file", filePath)); + } + if (m_needTeardown) + return; - bool const dataExists = (kmlData != nullptr); - if (dataExists) - collection->emplace_back(std::move(kmlData)); + if (migrated) + { + std::string fileName = fileSavePath; + my::DeleteFileX(fileSavePath); + my::GetNameFromFullPath(fileName); + my::GetNameWithoutExt(fileName); + fileSavePath = GenerateValidAndUniqueFilePathForKMB(fileName); - NotifyAboutFile(dataExists, filePath, isTemporaryFile); + try + { + kml::binary::SerializerKml ser(*kmlData); + FileWriter writer(fileSavePath); + ser.Serialize(writer); + } + catch (FileWriter::Exception const & exc) + { + my::DeleteFileX(fileSavePath); + LOG(LDEBUG, ("KML binary serialization failure: ", exc.what(), "file", fileSavePath)); + fileSavePath.clear(); + } } + if (m_needTeardown) + return; + + if (!fileSavePath.empty()) + collection->emplace_back(fileSavePath, std::move(kmlData)); + NotifyAboutFile(!fileSavePath.empty() /* success */, filePath, isTemporaryFile); NotifyAboutFinishAsyncLoading(std::move(collection)); - if (fileSavePath) + if (!fileSavePath.empty()) { + // TODO(darina): should we use the cloud only for KMB? GetPlatform().RunTask(Platform::Thread::Gui, - [this, fileSavePath]() { m_bookmarkCloud.Init({fileSavePath.get()}); }); + [this, fileSavePath]() { m_bookmarkCloud.Init({fileSavePath}); }); } }); } @@ -976,9 +1071,11 @@ boost::optional<std::string> BookmarkManager::GetKMLPath(std::string const & fil ZipFileReader::FileListT files; ZipFileReader::FilesList(filePath, files); std::string kmlFileName; + std::string ext; for (size_t i = 0; i < files.size(); ++i) { - if (GetFileExt(files[i].first) == BOOKMARKS_FILE_EXTENSION) + ext = GetFileExt(files[i].first); + if (ext == BOOKMARKS_FILE_EXTENSION) { kmlFileName = files[i].first; break; @@ -1011,14 +1108,14 @@ void BookmarkManager::MoveBookmark(df::MarkID bmID, df::MarkGroupID curGroupID, AttachBookmark(bmID, newGroupID); } -void BookmarkManager::UpdateBookmark(df::MarkID bmID, BookmarkData const & bm) +void BookmarkManager::UpdateBookmark(df::MarkID bmID, kml::BookmarkData const & bm) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); auto * bookmark = GetBookmarkForEdit(bmID); bookmark->SetData(bm); ASSERT(bookmark->GetGroupId() != df::kInvalidMarkGroupId, ()); - m_lastType = bm.GetType(); + m_lastType = bookmark->GetIcon(); SaveState(); } @@ -1040,25 +1137,33 @@ std::string BookmarkManager::LastEditedBMType() const return (m_lastType.empty() ? BookmarkCategory::GetDefaultType() : m_lastType); } -BookmarkCategory * BookmarkManager::GetBmCategory(df::MarkGroupID categoryId) const +BookmarkCategory const * BookmarkManager::GetBmCategory(df::MarkGroupID categoryId) const +{ + ASSERT_THREAD_CHECKER(m_threadChecker, ()); + ASSERT(IsBookmarkCategory(categoryId), ()); + auto const it = m_categories.find(categoryId); + return (it != m_categories.end() ? it->second.get() : nullptr); +} + +BookmarkCategory * BookmarkManager::GetBmCategory(df::MarkGroupID categoryId) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); ASSERT(IsBookmarkCategory(categoryId), ()); auto const it = m_categories.find(categoryId); - return (it != m_categories.end() ? it->second.get() : 0); + return (it != m_categories.end() ? it->second.get() : nullptr); } void BookmarkManager::SendBookmarksChanges() { if (m_callbacks.m_createdBookmarksCallback != nullptr) { - std::vector<std::pair<df::MarkID, BookmarkData>> marksInfo; + std::vector<std::pair<df::MarkID, kml::BookmarkData>> marksInfo; GetBookmarksData(m_changesTracker.GetCreatedMarkIds(), marksInfo); m_callbacks.m_createdBookmarksCallback(marksInfo); } if (m_callbacks.m_updatedBookmarksCallback != nullptr) { - std::vector<std::pair<df::MarkID, BookmarkData>> marksInfo; + std::vector<std::pair<df::MarkID, kml::BookmarkData>> marksInfo; GetBookmarksData(m_changesTracker.GetUpdatedMarkIds(), marksInfo); m_callbacks.m_updatedBookmarksCallback(marksInfo); } @@ -1077,7 +1182,7 @@ void BookmarkManager::SendBookmarksChanges() } void BookmarkManager::GetBookmarksData(df::MarkIDSet const & markIds, - std::vector<std::pair<df::MarkID, BookmarkData>> & data) const + std::vector<std::pair<df::MarkID, kml::BookmarkData>> & data) const { ASSERT_THREAD_CHECKER(m_threadChecker, ()); data.clear(); @@ -1086,7 +1191,7 @@ void BookmarkManager::GetBookmarksData(df::MarkIDSet const & markIds, { auto const * bookmark = GetBookmark(markId); if (bookmark) - data.push_back(std::make_pair(markId, bookmark->GetData())); + data.emplace_back(markId, bookmark->GetData()); } } @@ -1096,6 +1201,17 @@ bool BookmarkManager::HasBmCategory(df::MarkGroupID groupId) const return m_categories.find(groupId) != m_categories.end(); } +df::MarkGroupID BookmarkManager::CreateBookmarkCategory(kml::CategoryData const & data, bool autoSave) +{ + ASSERT_THREAD_CHECKER(m_threadChecker, ()); + auto const groupId = m_nextGroupID++; + auto & cat = m_categories[groupId]; + cat = my::make_unique<BookmarkCategory>(data, groupId, autoSave); + m_bmGroupsIdList.push_back(groupId); + m_changesTracker.OnAddGroup(groupId); + return groupId; +} + df::MarkGroupID BookmarkManager::CreateBookmarkCategory(std::string const & name, bool autoSave) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); @@ -1214,13 +1330,20 @@ void BookmarkManager::CreateCategories(KMLDataCollection && dataCollection, bool for (auto const & c : m_categories) categoriesForMerge.emplace_back(c.first, c.second.get()); - for (auto & data : dataCollection) + for (auto const & data : dataCollection) { df::MarkGroupID groupId; BookmarkCategory * group = nullptr; + auto const & fileName = data.first; + auto const * fileData = data.second.get(); + auto const & categoryData = fileData->m_categoryData; + auto const it = std::find_if(categoriesForMerge.cbegin(), categoriesForMerge.cend(), - [&data](auto const & v) { return v.second->GetName() == data->m_name; }); + [categoryData](auto const & v) + { + return v.second->GetName() == kml::GetDefaultStr(categoryData.m_name); + }); bool const merge = it != categoriesForMerge.cend(); if (merge) { @@ -1229,21 +1352,21 @@ void BookmarkManager::CreateCategories(KMLDataCollection && dataCollection, bool } else { - groupId = CreateBookmarkCategory(data->m_name, false /* autoSave */); + groupId = CreateBookmarkCategory(categoryData, false /* autoSave */); loadedGroups.insert(groupId); - group = GetBmCategory(groupId); - group->SetFileName(data->m_file); - group->SetIsVisible(data->m_visible); + group->SetFileName(fileName); } - for (auto & bookmark : data->m_bookmarks) + + for (auto & bmData : fileData->m_bookmarksData) { - auto * bm = AddBookmark(std::move(bookmark)); + auto * bm = CreateBookmark(bmData); bm->Attach(groupId); group->AttachUserMark(bm->GetId()); } - for (auto & track : data->m_tracks) + for (auto & trackData : fileData->m_tracksData) { + auto track = make_unique<Track>(trackData); auto * t = AddTrack(std::move(track)); t->Attach(groupId); group->AttachTrack(t->GetId()); @@ -1251,8 +1374,8 @@ void BookmarkManager::CreateCategories(KMLDataCollection && dataCollection, bool if (merge) { // Delete file since it will be merged. - my::DeleteFileX(data->m_file); - SaveToKMLFile(groupId); + my::DeleteFileX(fileName); + SaveBookmarkCategoryToFile(groupId); } } @@ -1265,202 +1388,49 @@ void BookmarkManager::CreateCategories(KMLDataCollection && dataCollection, bool } } -namespace -{ -char const * kmlHeader = - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - "<kml xmlns=\"http://earth.google.com/kml/2.2\">\n" - "<Document>\n" - " <Style id=\"placemark-blue\">\n" - " <IconStyle>\n" - " <Icon>\n" - " <href>http://mapswith.me/placemarks/placemark-blue.png</href>\n" - " </Icon>\n" - " </IconStyle>\n" - " </Style>\n" - " <Style id=\"placemark-brown\">\n" - " <IconStyle>\n" - " <Icon>\n" - " <href>http://mapswith.me/placemarks/placemark-brown.png</href>\n" - " </Icon>\n" - " </IconStyle>\n" - " </Style>\n" - " <Style id=\"placemark-green\">\n" - " <IconStyle>\n" - " <Icon>\n" - " <href>http://mapswith.me/placemarks/placemark-green.png</href>\n" - " </Icon>\n" - " </IconStyle>\n" - " </Style>\n" - " <Style id=\"placemark-orange\">\n" - " <IconStyle>\n" - " <Icon>\n" - " <href>http://mapswith.me/placemarks/placemark-orange.png</href>\n" - " </Icon>\n" - " </IconStyle>\n" - " </Style>\n" - " <Style id=\"placemark-pink\">\n" - " <IconStyle>\n" - " <Icon>\n" - " <href>http://mapswith.me/placemarks/placemark-pink.png</href>\n" - " </Icon>\n" - " </IconStyle>\n" - " </Style>\n" - " <Style id=\"placemark-purple\">\n" - " <IconStyle>\n" - " <Icon>\n" - " <href>http://mapswith.me/placemarks/placemark-purple.png</href>\n" - " </Icon>\n" - " </IconStyle>\n" - " </Style>\n" - " <Style id=\"placemark-red\">\n" - " <IconStyle>\n" - " <Icon>\n" - " <href>http://mapswith.me/placemarks/placemark-red.png</href>\n" - " </Icon>\n" - " </IconStyle>\n" - " </Style>\n" - " <Style id=\"placemark-yellow\">\n" - " <IconStyle>\n" - " <Icon>\n" - " <href>http://mapswith.me/placemarks/placemark-yellow.png</href>\n" - " </Icon>\n" - " </IconStyle>\n" - " </Style>\n" -; - -char const * kmlFooter = - "</Document>\n" - "</kml>\n"; -} - -namespace -{ -inline void SaveStringWithCDATA(std::ostream & stream, std::string const & s) -{ - // According to kml/xml spec, we need to escape special symbols with CDATA - if (s.find_first_of("<&") != std::string::npos) - stream << "<![CDATA[" << s << "]]>"; - else - stream << s; -} - -std::string PointToString(m2::PointD const & org) +std::unique_ptr<kml::FileData> BookmarkManager::CollectBmGroupKMLData(BookmarkCategory const * group) const { - double const lon = MercatorBounds::XToLon(org.x); - double const lat = MercatorBounds::YToLat(org.y); - - ostringstream ss; - ss.precision(8); - - ss << lon << "," << lat; - return ss.str(); -} + auto kmlData = std::make_unique<kml::FileData>(); + kmlData->m_categoryData = group->GetCategoryData(); + auto const & markIds = group->GetUserMarks(); + kmlData->m_bookmarksData.reserve(markIds.size()); + for (auto it = markIds.rbegin(); it != markIds.rend(); ++it) + { + Bookmark const *bm = GetBookmark(*it); + kmlData->m_bookmarksData.emplace_back(bm->GetData()); + } + auto const & lineIds = group->GetUserLines(); + kmlData->m_tracksData.reserve(lineIds.size()); + for (auto trackId : lineIds) + { + Track const *track = GetTrack(trackId); + kmlData->m_tracksData.emplace_back(track->GetData()); + } + return kmlData; } -void BookmarkManager::SaveToKML(df::MarkGroupID groupId, std::ostream & s) +void BookmarkManager::SaveToKML(df::MarkGroupID groupId, Writer & writer, bool useBinary) const { ASSERT_THREAD_CHECKER(m_threadChecker, ()); - SaveToKML(GetBmCategory(groupId), s); + SaveToKML(GetBmCategory(groupId), writer, useBinary); } -void BookmarkManager::SaveToKML(BookmarkCategory * group, std::ostream & s) +void BookmarkManager::SaveToKML(BookmarkCategory const * group, Writer & writer, bool useBinary) const { - s << kmlHeader; - - // Use CDATA if we have special symbols in the name - s << " <name>"; - SaveStringWithCDATA(s, group->GetName()); - s << "</name>\n"; - - s << " <visibility>" << (group->IsVisible() ? "1" : "0") <<"</visibility>\n"; - - // Bookmarks are stored to KML file in reverse order, so, least recently added bookmark - // will be stored last. The reason is that when bookmarks will be loaded from the KML file, - // most recently added bookmark will be loaded last and in accordance with current logic - // will be added to the beginning of the bookmarks list. - // Thus, this method preserves LRU bookmarks order after store -> load actions. - auto const & markIds = group->GetUserMarks(); - for (auto it = markIds.rbegin(); it != markIds.rend(); ++it) + auto const kmlData = CollectBmGroupKMLData(group); + if (useBinary) { - Bookmark const * bm = GetBookmark(*it); - s << " <Placemark>\n"; - s << " <name>"; - SaveStringWithCDATA(s, bm->GetName()); - s << "</name>\n"; - - if (!bm->GetDescription().empty()) - { - s << " <description>"; - SaveStringWithCDATA(s, bm->GetDescription()); - s << "</description>\n"; - } - - time_t const timeStamp = bm->GetTimeStamp(); - if (timeStamp != my::INVALID_TIME_STAMP) - { - std::string const strTimeStamp = my::TimestampToString(timeStamp); - ASSERT_EQUAL(strTimeStamp.size(), 20, ("We always generate fixed length UTC-format timestamp")); - s << " <TimeStamp><when>" << strTimeStamp << "</when></TimeStamp>\n"; - } - - s << " <styleUrl>#" << bm->GetType() << "</styleUrl>\n" - << " <Point><coordinates>" << PointToString(bm->GetPivot()) << "</coordinates></Point>\n"; - - double const scale = bm->GetScale(); - if (scale != -1.0) - { - /// @todo Factor out to separate function to use for other custom params. - s << " <ExtendedData xmlns:mwm=\"http://mapswith.me\">\n" - << " <mwm:scale>" << bm->GetScale() << "</mwm:scale>\n" - << " </ExtendedData>\n"; - } - - s << " </Placemark>\n"; + kml::binary::SerializerKml ser(*kmlData); + ser.Serialize(writer); } - - // Saving tracks - for (auto trackId : group->GetUserLines()) + else { - Track const * track = GetTrack(trackId); - - s << " <Placemark>\n"; - s << " <name>"; - SaveStringWithCDATA(s, track->GetName()); - s << "</name>\n"; - - ASSERT_GREATER(track->GetLayerCount(), 0, ()); - - s << "<Style><LineStyle>"; - dp::Color const & col = track->GetColor(0); - s << "<color>" - << NumToHex(col.GetAlpha()) - << NumToHex(col.GetBlue()) - << NumToHex(col.GetGreen()) - << NumToHex(col.GetRed()); - s << "</color>\n"; - - s << "<width>" - << track->GetWidth(0); - s << "</width>\n"; - - s << "</LineStyle></Style>\n"; - // stop style saving - - s << " <LineString><coordinates>"; - - Track::PolylineD const & poly = track->GetPolyline(); - for (auto pt = poly.Begin(); pt != poly.End(); ++pt) - s << PointToString(*pt) << " "; - - s << " </coordinates></LineString>\n" - << " </Placemark>\n"; + kml::SerializerKml ser(*kmlData); + ser.Serialize(writer); } - - s << kmlFooter; } -bool BookmarkManager::SaveToKMLFile(df::MarkGroupID groupId) +bool BookmarkManager::SaveBookmarkCategoryToFile(df::MarkGroupID groupId) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); std::string oldFile; @@ -1471,29 +1441,33 @@ bool BookmarkManager::SaveToKMLFile(df::MarkGroupID groupId) std::string const name = RemoveInvalidSymbols(group->GetName()); std::string file = group->GetFileName(); + bool migrated = migration::IsMigrationCompleted(); + std::string const fileExt(migrated ? kBookmarksExt : BOOKMARKS_FILE_EXTENSION); + std::string const fileDir = migrated ? GetBookmarksDirectory() : GetPlatform().SettingsDir(); + + if (migrated && !GetPlatform().IsFileExistsByFullPath(fileDir) && !GetPlatform().MkDirChecked(fileDir)) + return false; + if (file.empty()) { - file = GenerateUniqueFileName(GetPlatform().SettingsDir(), name); + file = GenerateUniqueFileName(fileDir, name, fileExt); group->SetFileName(file); } std::string const fileTmp = file + ".tmp"; try { - // First, we save to the temporary file - /// @todo On Windows UTF-8 file names are not supported. - std::ofstream of(fileTmp.c_str(), std::ios_base::out | std::ios_base::trunc); - SaveToKML(group, of); - of.flush(); - - if (!of.fail()) - { - // Only after successful save we replace original file - my::DeleteFileX(file); - VERIFY(my::RenameFileX(fileTmp, file), (fileTmp, file)); + FileWriter writer(fileTmp); + SaveToKML(group, writer, migrated /* useBinary */); - return true; - } + // Only after successful save we replace original file + my::DeleteFileX(file); + VERIFY(my::RenameFileX(fileTmp, file), (fileTmp, file)); + return true; + } + catch (FileWriter::Exception const &exc) + { + LOG(LDEBUG, ("KML", migrated ? " binary" : "", " serialization failure: ", exc.what(), "file", fileTmp)); } catch (std::exception const & e) { @@ -1892,10 +1866,8 @@ std::string BookmarkManager::RemoveInvalidSymbols(std::string const & name) } // static -std::string BookmarkManager::GenerateUniqueFileName(const std::string & path, std::string name) +std::string BookmarkManager::GenerateUniqueFileName(const std::string & path, std::string name, std::string const & kmlExt) { - std::string const kmlExt(BOOKMARKS_FILE_EXTENSION); - // check if file name already contains .kml extension size_t const extPos = name.rfind(kmlExt); if (extPos != std::string::npos) @@ -1909,17 +1881,29 @@ std::string BookmarkManager::GenerateUniqueFileName(const std::string & path, st size_t counter = 1; std::string suffix; - while (Platform::IsFileExistsByFullPath(path + name + suffix + kmlExt)) + while (Platform::IsFileExistsByFullPath(my::JoinPath(path, name + suffix + kmlExt))) suffix = strings::to_string(counter++); - return (path + name + suffix + kmlExt); + return my::JoinPath(path, name + suffix + kmlExt); } // static std::string BookmarkManager::GenerateValidAndUniqueFilePathForKML(std::string const & fileName) { std::string filePath = RemoveInvalidSymbols(fileName); - filePath = GenerateUniqueFileName(GetPlatform().SettingsDir(), filePath); - return filePath; + return GenerateUniqueFileName(GetPlatform().SettingsDir(), filePath, BOOKMARKS_FILE_EXTENSION); +} + +// static +std::string BookmarkManager::GenerateValidAndUniqueFilePathForKMB(std::string const & fileName) +{ + std::string filePath = RemoveInvalidSymbols(fileName); + return GenerateUniqueFileName(GetBookmarksDirectory(), filePath, kBookmarksExt); +} + +// static +bool BookmarkManager::IsMigrated() +{ + return migration::IsMigrationCompleted(); } BookmarkManager::EditSession::EditSession(BookmarkManager & manager) @@ -1933,19 +1917,19 @@ BookmarkManager::EditSession::~EditSession() m_bmManager.OnEditSessionClosed(); } -Bookmark * BookmarkManager::EditSession::CreateBookmark(m2::PointD const & ptOrg, BookmarkData const & bm) +Bookmark * BookmarkManager::EditSession::CreateBookmark(kml::BookmarkData const & bm) { - return m_bmManager.CreateBookmark(ptOrg, bm); + return m_bmManager.CreateBookmark(bm); } -Bookmark * BookmarkManager::EditSession::CreateBookmark(m2::PointD const & ptOrg, BookmarkData & bm, df::MarkGroupID groupId) +Bookmark * BookmarkManager::EditSession::CreateBookmark(kml::BookmarkData & bm, df::MarkGroupID groupId) { - return m_bmManager.CreateBookmark(ptOrg, bm, groupId); + return m_bmManager.CreateBookmark(bm, groupId); } -Track * BookmarkManager::EditSession::CreateTrack(m2::PolylineD const & polyline, Track::Params const & p) +Track * BookmarkManager::EditSession::CreateTrack(kml::TrackData const & trackData) { - return m_bmManager.CreateTrack(polyline, p); + return m_bmManager.CreateTrack(trackData); } Bookmark * BookmarkManager::EditSession::GetBookmarkForEdit(df::MarkID markId) @@ -1984,7 +1968,7 @@ void BookmarkManager::EditSession::MoveBookmark( m_bmManager.MoveBookmark(bmID, curGroupID, newGroupID); } -void BookmarkManager::EditSession::UpdateBookmark(df::MarkID bmId, BookmarkData const & bm) +void BookmarkManager::EditSession::UpdateBookmark(df::MarkID bmId, kml::BookmarkData const & bm) { return m_bmManager.UpdateBookmark(bmId, bm); } diff --git a/map/bookmark_manager.hpp b/map/bookmark_manager.hpp index ccb07d7cce..00cd184c89 100644 --- a/map/bookmark_manager.hpp +++ b/map/bookmark_manager.hpp @@ -4,6 +4,8 @@ #include "map/cloud.hpp" #include "map/user_mark_layer.hpp" +#include "kml/types.hpp" + #include "drape_frontend/drape_engine_safe_ptr.hpp" #include "geometry/any_rect2d.hpp" @@ -35,7 +37,7 @@ class BookmarkManager final using TracksCollection = std::map<df::LineID, std::unique_ptr<Track>>; public: - using KMLDataCollection = std::vector<std::unique_ptr<KMLData>>; + using KMLDataCollection = std::vector<std::pair<std::string, std::unique_ptr<kml::FileData>>>; using AsyncLoadingStartedCallback = std::function<void()>; using AsyncLoadingFinishedCallback = std::function<void()>; @@ -52,8 +54,8 @@ public: struct Callbacks { using GetStringsBundleFn = std::function<StringsBundle const &()>; - using CreatedBookmarksCallback = std::function<void(std::vector<std::pair<df::MarkID, BookmarkData>> const &)>; - using UpdatedBookmarksCallback = std::function<void(std::vector<std::pair<df::MarkID, BookmarkData>> const &)>; + using CreatedBookmarksCallback = std::function<void(std::vector<std::pair<df::MarkID, kml::BookmarkData>> const &)>; + using UpdatedBookmarksCallback = std::function<void(std::vector<std::pair<df::MarkID, kml::BookmarkData>> const &)>; using DeletedBookmarksCallback = std::function<void(std::vector<df::MarkID> const &)>; template <typename StringsBundleGetter, typename CreateListener, typename UpdateListener, typename DeleteListener> @@ -83,9 +85,9 @@ public: return m_bmManager.CreateUserMark<UserMarkT>(ptOrg); } - Bookmark * CreateBookmark(m2::PointD const & ptOrg, BookmarkData const & bm); - Bookmark * CreateBookmark(m2::PointD const & ptOrg, BookmarkData & bm, df::MarkGroupID groupId); - Track * CreateTrack(m2::PolylineD const & polyline, Track::Params const & p); + Bookmark * CreateBookmark(kml::BookmarkData const & bm); + Bookmark * CreateBookmark(kml::BookmarkData & bm, df::MarkGroupID groupId); + Track * CreateTrack(kml::TrackData const & trackData); template <typename UserMarkT> UserMarkT * GetMarkForEdit(df::MarkID markId) @@ -110,7 +112,7 @@ public: void SetIsVisible(df::MarkGroupID groupId, bool visible); void MoveBookmark(df::MarkID bmID, df::MarkGroupID curGroupID, df::MarkGroupID newGroupID); - void UpdateBookmark(df::MarkID bmId, BookmarkData const & bm); + void UpdateBookmark(df::MarkID bmId, kml::BookmarkData const & bm); void AttachBookmark(df::MarkID bmId, df::MarkGroupID groupId); void DetachBookmark(df::MarkID bmId, df::MarkGroupID groupId); @@ -159,10 +161,11 @@ public: bool IsVisible(df::MarkGroupID groupId) const; + df::MarkGroupID CreateBookmarkCategory(kml::CategoryData const & data, bool autoSae = true); df::MarkGroupID CreateBookmarkCategory(std::string const & name, bool autoSave = true); - std::string const & GetCategoryName(df::MarkGroupID categoryId) const; - std::string const & GetCategoryFileName(df::MarkGroupID categoryId) const; + std::string GetCategoryName(df::MarkGroupID categoryId) const; + std::string GetCategoryFileName(df::MarkGroupID categoryId) const; df::GroupIDCollection const & GetBmGroupsIdList() const { return m_bmGroupsIdList; } bool HasBmCategory(df::MarkGroupID groupId) const; @@ -175,12 +178,15 @@ public: UserMark const * FindMarkInRect(df::MarkGroupID groupId, m2::AnyRectD const & rect, double & d) const; /// Scans and loads all kml files with bookmarks in WritableDir. + std::shared_ptr<KMLDataCollection> LoadBookmarksKML(std::vector<std::string> & filePaths); + std::shared_ptr<KMLDataCollection> LoadBookmarksKMB(std::vector<std::string> & filePaths); void LoadBookmarks(); void LoadBookmark(std::string const & filePath, bool isTemporaryFile); + void MigrateAndLoadBookmarks(); /// Uses the same file name from which was loaded, or /// creates unique file name on first save and uses it every time. - bool SaveToKMLFile(df::MarkGroupID groupId); + bool SaveBookmarkCategoryToFile(df::MarkGroupID groupId); StaticMarkPoint & SelectionMark() { return *m_selectionMark; } StaticMarkPoint const & SelectionMark() const { return *m_selectionMark; } @@ -254,11 +260,13 @@ public: void CancelCloudRestoring(); /// These functions are public for unit tests only. You shouldn't call them from client code. - void SaveToKML(df::MarkGroupID groupId, std::ostream & s); + void SaveToKML(df::MarkGroupID groupId, Writer & writer, bool useBinary) const; void CreateCategories(KMLDataCollection && dataCollection, bool autoSave = true); static std::string RemoveInvalidSymbols(std::string const & name); - static std::string GenerateUniqueFileName(const std::string & path, std::string name); + static std::string GenerateUniqueFileName(std::string const & path, std::string name, std::string const & fileExt); static std::string GenerateValidAndUniqueFilePathForKML(std::string const & fileName); + static std::string GenerateValidAndUniqueFilePathForKMB(std::string const & fileName); + static bool IsMigrated(); private: class MarksChangesTracker : public df::UserMarksProvider @@ -352,15 +360,15 @@ private: UserMark * GetUserMarkForEdit(df::MarkID markId); void DeleteUserMark(df::MarkID markId); - Bookmark * CreateBookmark(m2::PointD const & ptOrg, BookmarkData const & bm); - Bookmark * CreateBookmark(m2::PointD const & ptOrg, BookmarkData & bm, df::MarkGroupID groupId); + Bookmark * CreateBookmark(kml::BookmarkData const & bm); + Bookmark * CreateBookmark(kml::BookmarkData & bm, df::MarkGroupID groupId); Bookmark * GetBookmarkForEdit(df::MarkID markId); void AttachBookmark(df::MarkID bmId, df::MarkGroupID groupId); void DetachBookmark(df::MarkID bmId, df::MarkGroupID groupId); void DeleteBookmark(df::MarkID bmId); - Track * CreateTrack(m2::PolylineD const & polyline, Track::Params const & p); + Track * CreateTrack(kml::TrackData const & trackData); void AttachTrack(df::LineID trackId, df::MarkGroupID groupId); void DetachTrack(df::LineID trackId, df::MarkGroupID groupId); @@ -374,13 +382,14 @@ private: void ClearCategories(); void MoveBookmark(df::MarkID bmID, df::MarkGroupID curGroupID, df::MarkGroupID newGroupID); - void UpdateBookmark(df::MarkID bmId, BookmarkData const & bm); + void UpdateBookmark(df::MarkID bmId, kml::BookmarkData const & bm); UserMark const * GetMark(df::MarkID markId) const; UserMarkLayer const * GetGroup(df::MarkGroupID groupId) const; UserMarkLayer * GetGroup(df::MarkGroupID groupId); - BookmarkCategory * GetBmCategory(df::MarkGroupID categoryId) const; + BookmarkCategory const * GetBmCategory(df::MarkGroupID categoryId) const; + BookmarkCategory * GetBmCategory(df::MarkGroupID categoryId); Bookmark * AddBookmark(std::unique_ptr<Bookmark> && bookmark); Track * AddTrack(std::unique_ptr<Track> && track); @@ -401,10 +410,11 @@ private: void SendBookmarksChanges(); void GetBookmarksData(df::MarkIDSet const & markIds, - std::vector<std::pair<df::MarkID, BookmarkData>> & data) const; + std::vector<std::pair<df::MarkID, kml::BookmarkData>> & data) const; void CheckAndCreateDefaultCategory(); - void SaveToKML(BookmarkCategory * group, std::ostream & s); + std::unique_ptr<kml::FileData> CollectBmGroupKMLData(BookmarkCategory const * group) const; + void SaveToKML(BookmarkCategory const * group, Writer & writer, bool useBinary) const; void OnSynchronizationStarted(Cloud::SynchronizationType type); void OnSynchronizationFinished(Cloud::SynchronizationType type, Cloud::SynchronizationResult result, diff --git a/map/framework.cpp b/map/framework.cpp index fb5f3a28d9..a525b3df20 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -418,10 +418,10 @@ Framework::Framework(FrameworkParams const & params) m_bmManager = make_unique<BookmarkManager>(BookmarkManager::Callbacks( [this]() -> StringsBundle const & { return m_stringsBundle; }, - [this](vector<pair<df::MarkID, BookmarkData>> const & marks) { + [this](vector<pair<df::MarkID, kml::BookmarkData>> const & marks) { GetSearchAPI().OnBookmarksCreated(marks); }, - [this](vector<pair<df::MarkID, BookmarkData>> const & marks) { + [this](vector<pair<df::MarkID, kml::BookmarkData>> const & marks) { GetSearchAPI().OnBookmarksUpdated(marks); }, [this](vector<df::MarkID> const & marks) { GetSearchAPI().OnBookmarksDeleted(marks); })); diff --git a/map/map_tests/bookmarks_test.cpp b/map/map_tests/bookmarks_test.cpp index fd04b1141d..990eb91b38 100644 --- a/map/map_tests/bookmarks_test.cpp +++ b/map/map_tests/bookmarks_test.cpp @@ -145,24 +145,24 @@ void CheckBookmarks(BookmarkManager const & bmManager, df::MarkGroupID groupId) auto it = markIds.rbegin(); Bookmark const * bm = bmManager.GetBookmark(*it++); TEST_EQUAL(bm->GetName(), "Nebraska", ()); - TEST_EQUAL(bm->GetType(), "placemark-red", ()); + TEST_EQUAL(bm->GetIcon(), "placemark-red", ()); TEST_EQUAL(bm->GetDescription(), "", ()); - TEST_EQUAL(bm->GetTimeStamp(), my::INVALID_TIME_STAMP, ()); + TEST_EQUAL(kml::ToSecondsSinceEpoch(bm->GetTimeStamp()), 0, ()); bm = bmManager.GetBookmark(*it++); TEST_EQUAL(bm->GetName(), "Monongahela National Forest", ()); - TEST_EQUAL(bm->GetType(), "placemark-pink", ()); + TEST_EQUAL(bm->GetIcon(), "placemark-pink", ()); TEST_EQUAL(bm->GetDescription(), "Huttonsville, WV 26273<br>", ()); - TEST_EQUAL(bm->GetTimeStamp(), 524214643, ()); + TEST_EQUAL(kml::ToSecondsSinceEpoch(bm->GetTimeStamp()), 524214643, ()); bm = bmManager.GetBookmark(*it++); m2::PointD org = bm->GetPivot(); TEST_ALMOST_EQUAL_ULPS(MercatorBounds::XToLon(org.x), 27.566765, ()); TEST_ALMOST_EQUAL_ULPS(MercatorBounds::YToLat(org.y), 53.900047, ()); TEST_EQUAL(bm->GetName(), "From: Минск, Минская область, Беларусь", ()); - TEST_EQUAL(bm->GetType(), "placemark-blue", ()); + TEST_EQUAL(bm->GetIcon(), "placemark-blue", ()); TEST_EQUAL(bm->GetDescription(), "", ()); - TEST_EQUAL(bm->GetTimeStamp(), 888888888, ()); + TEST_EQUAL(kml::ToSecondsSinceEpoch(bm->GetTimeStamp()), 888888888, ()); bm = bmManager.GetBookmark(*it++); org = bm->GetPivot(); @@ -170,7 +170,7 @@ void CheckBookmarks(BookmarkManager const & bmManager, df::MarkGroupID groupId) TEST_ALMOST_EQUAL_ULPS(MercatorBounds::YToLat(org.y), 53.89306, ()); TEST_EQUAL(bm->GetName(), "<MWM & Sons>", ()); TEST_EQUAL(bm->GetDescription(), "Amps & <brackets>", ()); - TEST_EQUAL(bm->GetTimeStamp(), my::INVALID_TIME_STAMP, ()); + TEST_EQUAL(kml::ToSecondsSinceEpoch(bm->GetTimeStamp()), 0, ()); } } // namespace @@ -179,8 +179,9 @@ UNIT_CLASS_TEST(Runner, Bookmarks_ImportKML) BookmarkManager bmManager((BookmarkManager::Callbacks(bmCallbacks))); BookmarkManager::KMLDataCollection kmlDataCollection; - kmlDataCollection.emplace_back(LoadKMLData(make_unique<MemReader>(kmlString, strlen(kmlString)))); - TEST(kmlDataCollection[0], ()); + kmlDataCollection.emplace_back(""/* filePath */, + LoadKMLData(MemReader(kmlString, strlen(kmlString)), false /* useBinary */)); + TEST(kmlDataCollection.back().second, ()); bmManager.CreateCategories(std::move(kmlDataCollection), false /* autoSave */); TEST_EQUAL(bmManager.GetBmGroupsIdList().size(), 1, ()); @@ -199,7 +200,8 @@ UNIT_CLASS_TEST(Runner, Bookmarks_ExportKML) BookmarkManager bmManager((BookmarkManager::Callbacks(bmCallbacks))); BookmarkManager::KMLDataCollection kmlDataCollection; - kmlDataCollection.emplace_back(LoadKMLData(make_unique<MemReader>(kmlString, strlen(kmlString)))); + kmlDataCollection.emplace_back(""/* filePath */, + LoadKMLData(MemReader(kmlString, strlen(kmlString)), false /* useBinary */)); bmManager.CreateCategories(std::move(kmlDataCollection), false /* autoSave */); TEST_EQUAL(bmManager.GetBmGroupsIdList().size(), 1, ()); @@ -212,9 +214,11 @@ UNIT_CLASS_TEST(Runner, Bookmarks_ExportKML) bmManager.GetEditSession().SetIsVisible(groupId1, true); TEST_EQUAL(bmManager.IsVisible(groupId1), true, ()); - ofstream of(fileName); - bmManager.SaveToKML(groupId1, of); - of.close(); + { + LOG(LWARNING, ("SaveToKML (", fileName, ")")); + FileWriter writer(fileName); + bmManager.SaveToKML(groupId1, writer, false /* useBinary */); + } bmManager.GetEditSession().ClearGroup(groupId1); TEST_EQUAL(bmManager.GetUserMarkIds(groupId1).size(), 0, ()); @@ -224,8 +228,8 @@ UNIT_CLASS_TEST(Runner, Bookmarks_ExportKML) TEST_EQUAL(bmManager.GetBmGroupsIdList().size(), 0, ()); kmlDataCollection.clear(); - kmlDataCollection.emplace_back(LoadKMLData(make_unique<FileReader>(fileName))); - TEST(kmlDataCollection[0], ()); + kmlDataCollection.emplace_back("", LoadKMLData(FileReader(fileName), false /* useBinary */)); + TEST(kmlDataCollection.back().second, ()); bmManager.CreateCategories(std::move(kmlDataCollection), false /* autoSave */); TEST_EQUAL(bmManager.GetBmGroupsIdList().size(), 1, ()); @@ -237,9 +241,10 @@ UNIT_CLASS_TEST(Runner, Bookmarks_ExportKML) bmManager.GetEditSession().DeleteBmCategory(groupId2); TEST_EQUAL(bmManager.HasBmCategory(groupId2), false, ()); + LOG(LWARNING, ("LoadKMLFile(", fileName, ")")); kmlDataCollection.clear(); - kmlDataCollection.emplace_back(LoadKMLFile(fileName)); - TEST(kmlDataCollection[0], ()); + kmlDataCollection.emplace_back("", LoadKMLFile(fileName, false /* useBinary */)); + TEST(kmlDataCollection.back().second, ()); bmManager.CreateCategories(std::move(kmlDataCollection), false /* autoSave */); TEST_EQUAL(bmManager.GetBmGroupsIdList().size(), 1, ()); @@ -247,7 +252,7 @@ UNIT_CLASS_TEST(Runner, Bookmarks_ExportKML) auto const groupId3 = bmManager.GetBmGroupsIdList().front(); CheckBookmarks(bmManager, groupId3); - TEST(bmManager.SaveToKMLFile(groupId3), ()); + TEST(bmManager.SaveBookmarkCategoryToFile(groupId3), ()); // old file shouldn't be deleted if we save bookmarks with new category name uint64_t dummy; TEST(my::GetFileSize(fileName, dummy), ()); @@ -303,17 +308,21 @@ UNIT_TEST(Bookmarks_Timestamp) BookmarkManager & bmManager = fm.GetBookmarkManager(); - BookmarkData b1("name", "type"); + kml::BookmarkData b1; + kml::SetDefaultStr(b1.m_name, "name"); + b1.m_point = orgPoint; auto cat1 = bmManager.CreateBookmarkCategory(arrCat[0], false /* autoSave */); - Bookmark const * pBm1 = bmManager.GetEditSession().CreateBookmark(orgPoint, b1, cat1); - TEST_NOT_EQUAL(pBm1->GetTimeStamp(), my::INVALID_TIME_STAMP, ()); + Bookmark const * pBm1 = bmManager.GetEditSession().CreateBookmark(b1, cat1); + TEST_NOT_EQUAL(kml::ToSecondsSinceEpoch(pBm1->GetTimeStamp()), 0, ()); - BookmarkData b2("newName", "newType"); - Bookmark const * pBm2 = bmManager.GetEditSession().CreateBookmark(orgPoint, b2, cat1); + kml::BookmarkData b2; + kml::SetDefaultStr(b2.m_name, "newName"); + b2.m_point = orgPoint; + Bookmark const * pBm2 = bmManager.GetEditSession().CreateBookmark(b2, cat1); auto cat2 = bmManager.CreateBookmarkCategory(arrCat[0], false /* autoSave */); - Bookmark const * pBm3 = bmManager.GetEditSession().CreateBookmark(orgPoint, b2, cat2); + Bookmark const * pBm3 = bmManager.GetEditSession().CreateBookmark(b2, cat2); // Check bookmarks order here. First added should be in the bottom of the list. auto const firstId = * bmManager.GetUserMarkIds(cat1).rbegin(); @@ -322,17 +331,14 @@ UNIT_TEST(Bookmarks_Timestamp) Bookmark const * pBm01 = bmManager.GetBookmark(pBm1->GetId()); TEST_EQUAL(pBm01->GetName(), "name", ()); - TEST_EQUAL(pBm01->GetType(), "type", ()); Bookmark const * pBm02 = bmManager.GetBookmark(pBm2->GetId()); TEST_EQUAL(pBm02->GetName(), "newName", ()); - TEST_EQUAL(pBm02->GetType(), "newType", ()); Bookmark const * pBm03 = bmManager.GetBookmark(pBm3->GetId()); TEST_EQUAL(pBm03->GetName(), "newName", ()); - TEST_EQUAL(pBm03->GetType(), "newType", ()); TEST_EQUAL(bmManager.GetUserMarkIds(cat1).size(), 2, ()); TEST_EQUAL(bmManager.GetUserMarkIds(cat2).size(), 1, ()); @@ -358,14 +364,18 @@ UNIT_TEST(Bookmarks_Getting) auto const cat2 = bmManager.CreateBookmarkCategory(arrCat[1], false /* autoSave */); auto const cat3 = bmManager.CreateBookmarkCategory(arrCat[2], false /* autoSave */); - BookmarkData bm("1", "placemark-red"); - auto const * pBm1 = bmManager.GetEditSession().CreateBookmark(m2::PointD(38, 20), bm, cat1); + kml::BookmarkData bm; + kml::SetDefaultStr(bm.m_name, "1"); + bm.m_point = m2::PointD(38, 20); + auto const * pBm1 = bmManager.GetEditSession().CreateBookmark(bm, cat1); - bm = BookmarkData("2", "placemark-red"); - auto const * pBm2 = bmManager.GetEditSession().CreateBookmark(m2::PointD(41, 20), bm, cat2); + kml::SetDefaultStr(bm.m_name, "2"); + bm.m_point = m2::PointD(41, 20); + auto const * pBm2 = bmManager.GetEditSession().CreateBookmark(bm, cat2); - bm = BookmarkData("3", "placemark-red"); - auto const * pBm3 = bmManager.GetEditSession().CreateBookmark(m2::PointD(41, 40), bm, cat3); + kml::SetDefaultStr(bm.m_name, "3"); + bm.m_point = m2::PointD(41, 40); + auto const * pBm3 = bmManager.GetEditSession().CreateBookmark(bm, cat3); TEST_NOT_EQUAL(pBm1->GetGroupId(), pBm2->GetGroupId(), ()); TEST_NOT_EQUAL(pBm1->GetGroupId(), pBm3->GetGroupId(), ()); @@ -384,8 +394,10 @@ UNIT_TEST(Bookmarks_Getting) mark = GetBookmark(fm, m2::PointD(41, 40)); TEST_EQUAL(bmManager.GetCategoryName(mark->GetGroupId()), "cat3", ()); - bm = BookmarkData("4", "placemark-blue"); - auto const * pBm4 = bmManager.GetEditSession().CreateBookmark(m2::PointD(41, 40), bm, cat3); + kml::SetDefaultStr(bm.m_name, "4"); + bm.m_point = m2::PointD(41, 40); + bm.m_color.m_predefinedColor = kml::PredefinedColor::Blue; + auto const * pBm4 = bmManager.GetEditSession().CreateBookmark(bm, cat3); TEST_EQUAL(pBm3->GetGroupId(), pBm4->GetGroupId(), ()); @@ -394,7 +406,7 @@ UNIT_TEST(Bookmarks_Getting) // Should find last added valid result, there two results with the // same coordinates 3 and 4, but 4 was added later. TEST_EQUAL(mark->GetName(), "4", ()); - TEST_EQUAL(mark->GetType(), "placemark-blue", ()); + TEST_EQUAL(mark->GetIcon(), "placemark-blue", ()); TEST_EQUAL(bmManager.GetUserMarkIds(mark->GetGroupId()).size(), 2, ()); bmManager.GetEditSession().DeleteBookmark(mark->GetId()); @@ -462,31 +474,32 @@ UNIT_TEST(Bookmarks_IllegalFileName) UNIT_TEST(Bookmarks_UniqueFileName) { string const BASE = "SomeUniqueFileName"; - string const FILENAME = BASE + BOOKMARKS_FILE_EXTENSION; + string const FILEBASE = "./" + BASE; + string const FILENAME = FILEBASE + BOOKMARKS_FILE_EXTENSION; { FileWriter file(FILENAME); file.Write(FILENAME.data(), FILENAME.size()); } - string gen = BookmarkManager::GenerateUniqueFileName("", BASE); + string gen = BookmarkManager::GenerateUniqueFileName(".", BASE, BOOKMARKS_FILE_EXTENSION); TEST_NOT_EQUAL(gen, FILENAME, ()); - TEST_EQUAL(gen, BASE + "1.kml", ()); + TEST_EQUAL(gen, FILEBASE + "1.kml", ()); string const FILENAME1 = gen; { FileWriter file(FILENAME1); file.Write(FILENAME1.data(), FILENAME1.size()); } - gen = BookmarkManager::GenerateUniqueFileName("", BASE); + gen = BookmarkManager::GenerateUniqueFileName(".", BASE, BOOKMARKS_FILE_EXTENSION); TEST_NOT_EQUAL(gen, FILENAME, ()); TEST_NOT_EQUAL(gen, FILENAME1, ()); - TEST_EQUAL(gen, BASE + "2.kml", ()); + TEST_EQUAL(gen, FILEBASE + "2.kml", ()); FileWriter::DeleteFileX(FILENAME); FileWriter::DeleteFileX(FILENAME1); - gen = BookmarkManager::GenerateUniqueFileName("", BASE); + gen = BookmarkManager::GenerateUniqueFileName(".", BASE, BOOKMARKS_FILE_EXTENSION); TEST_EQUAL(gen, FILENAME, ()); } @@ -505,22 +518,26 @@ UNIT_TEST(Bookmarks_AddingMoving) auto const cat1 = bmManager.CreateBookmarkCategory(arrCat[0], false /* autoSave */); auto const cat2 = bmManager.CreateBookmarkCategory(arrCat[1], false /* autoSave */); - BookmarkData bm("name", "placemark-red"); - auto const * pBm1 = bmManager.GetEditSession().CreateBookmark(globalPoint, bm, cat1); + kml::BookmarkData bm; + kml::SetDefaultStr(bm.m_name, "name"); + bm.m_point = globalPoint; + auto const * pBm1 = bmManager.GetEditSession().CreateBookmark(bm, cat1); Bookmark const * mark = GetBookmarkPxPoint(fm, pixelPoint); TEST_EQUAL(bmManager.GetCategoryName(mark->GetGroupId()), "cat1", ()); - bm = BookmarkData("name2", "placemark-blue"); - auto const * pBm11 = bmManager.GetEditSession().CreateBookmark(globalPoint, bm, cat1); + kml::SetDefaultStr(bm.m_name, "name2"); + bm.m_color.m_predefinedColor = kml::PredefinedColor::Blue; + auto const * pBm11 = bmManager.GetEditSession().CreateBookmark(bm, cat1); TEST_EQUAL(pBm1->GetGroupId(), pBm11->GetGroupId(), ()); mark = GetBookmarkPxPoint(fm, pixelPoint); TEST_EQUAL(bmManager.GetCategoryName(mark->GetGroupId()), "cat1", ()); TEST_EQUAL(mark->GetName(), "name2", ()); - TEST_EQUAL(mark->GetType(), "placemark-blue", ()); + TEST_EQUAL(mark->GetIcon(), "placemark-blue", ()); // Edit name, type and category of bookmark - bm = BookmarkData("name3", "placemark-green"); - auto const * pBm2 = bmManager.GetEditSession().CreateBookmark(globalPoint, bm, cat2); + kml::SetDefaultStr(bm.m_name, "name3"); + bm.m_color.m_predefinedColor = kml::PredefinedColor::Green; + auto const * pBm2 = bmManager.GetEditSession().CreateBookmark(bm, cat2); TEST_NOT_EQUAL(pBm1->GetGroupId(), pBm2->GetGroupId(), ()); TEST_EQUAL(bmManager.GetBmGroupsIdList().size(), 2, ()); mark = GetBookmarkPxPoint(fm, pixelPoint); @@ -528,7 +545,7 @@ UNIT_TEST(Bookmarks_AddingMoving) TEST_EQUAL(bmManager.GetUserMarkIds(cat1).size(), 2, ("Bookmark wasn't moved from one category to another")); TEST_EQUAL(mark->GetName(), "name2", ()); - TEST_EQUAL(mark->GetType(), "placemark-blue", ()); + TEST_EQUAL(mark->GetIcon(), "placemark-blue", ()); DeleteCategoryFiles(arrCat); } @@ -567,7 +584,8 @@ UNIT_CLASS_TEST(Runner, Bookmarks_InnerFolder) BookmarkManager bmManager((BookmarkManager::Callbacks(bmCallbacks))); BookmarkManager::KMLDataCollection kmlDataCollection; - kmlDataCollection.emplace_back(LoadKMLData(make_unique<MemReader>(kmlString2, strlen(kmlString2)))); + kmlDataCollection.emplace_back("" /* filePath */, + LoadKMLData(MemReader(kmlString2, strlen(kmlString2)), false /* useBinary */)); bmManager.CreateCategories(std::move(kmlDataCollection), false /* autoSave */); auto const & groupIds = bmManager.GetBmGroupsIdList(); TEST_EQUAL(groupIds.size(), 1, ()); @@ -578,14 +596,15 @@ UNIT_CLASS_TEST(Runner, BookmarkCategory_EmptyName) { BookmarkManager bmManager((BookmarkManager::Callbacks(bmCallbacks))); auto const catId = bmManager.CreateBookmarkCategory("", false /* autoSave */); - auto bm = BookmarkData("", "placemark-red"); - bmManager.GetEditSession().CreateBookmark(m2::PointD(0, 0), bm, catId); + kml::BookmarkData bm; + bm.m_point = m2::PointD(0, 0); + bmManager.GetEditSession().CreateBookmark(bm, catId); - TEST(bmManager.SaveToKMLFile(catId), ()); + TEST(bmManager.SaveBookmarkCategoryToFile(catId), ()); bmManager.GetEditSession().SetCategoryName(catId, "xxx"); - TEST(bmManager.SaveToKMLFile(catId), ()); + TEST(bmManager.SaveBookmarkCategoryToFile(catId), ()); vector<string> const arrFiles = {"Bookmarks", "xxx"}; DeleteCategoryFiles(arrFiles); @@ -615,11 +634,11 @@ char const * kmlString3 = return false; if (b1.GetDescription() != b2.GetDescription()) return false; - if (b1.GetType() != b2.GetType()) + if (b1.GetIcon() != b2.GetIcon()) return false; - if (!m2::AlmostEqualULPs(b1.GetPivot(), b2.GetPivot())) + if (b1.GetScale() != b2.GetScale()) return false; - if (!my::AlmostEqualULPs(b1.GetScale(), b2.GetScale())) + if (!m2::AlmostEqualULPs(b1.GetPivot(), b2.GetPivot())) return false; // do not check timestamp @@ -631,7 +650,8 @@ UNIT_CLASS_TEST(Runner, Bookmarks_SpecialXMLNames) { BookmarkManager bmManager((BookmarkManager::Callbacks(bmCallbacks))); BookmarkManager::KMLDataCollection kmlDataCollection; - kmlDataCollection.emplace_back(LoadKMLData(make_unique<MemReader>(kmlString3, strlen(kmlString3)))); + kmlDataCollection.emplace_back("" /* filePath */, + LoadKMLData(MemReader(kmlString3, strlen(kmlString3)), false /* useBinary */)); bmManager.CreateCategories(std::move(kmlDataCollection), false /* autoSave */); auto const & groupIds = bmManager.GetBmGroupsIdList(); @@ -639,7 +659,7 @@ UNIT_CLASS_TEST(Runner, Bookmarks_SpecialXMLNames) auto const catId = groupIds.front(); auto const expectedName = "3663 and M & J Seafood Branches"; TEST_EQUAL(bmManager.GetUserMarkIds(catId).size(), 1, ()); - TEST(bmManager.SaveToKMLFile(catId), ()); + TEST(bmManager.SaveBookmarkCategoryToFile(catId), ()); TEST_EQUAL(bmManager.GetCategoryName(catId), expectedName, ()); // change category name to avoid merging it with the second one @@ -648,7 +668,7 @@ UNIT_CLASS_TEST(Runner, Bookmarks_SpecialXMLNames) editSession.SetCategoryName(catId, "test"); kmlDataCollection.clear(); - kmlDataCollection.emplace_back(LoadKMLFile(fileName)); + kmlDataCollection.emplace_back(fileName, LoadKMLFile(fileName, BookmarkManager::IsMigrated())); bmManager.CreateCategories(std::move(kmlDataCollection), false /* autoSave */); TEST_EQUAL(bmManager.GetBmGroupsIdList().size(), 2, ()); auto const catId2 = bmManager.GetBmGroupsIdList().back(); @@ -672,8 +692,8 @@ UNIT_CLASS_TEST(Runner, TrackParsingTest_1) string const kmlFile = GetPlatform().TestsDataPathForFile("kml-with-track-kml.test"); BookmarkManager bmManager((BookmarkManager::Callbacks(bmCallbacks))); BookmarkManager::KMLDataCollection kmlDataCollection; - kmlDataCollection.emplace_back(LoadKMLFile(kmlFile)); - TEST(kmlDataCollection[0], ("KML can't be loaded")); + kmlDataCollection.emplace_back(kmlFile, LoadKMLFile(kmlFile, false /* useBinary */)); + TEST(kmlDataCollection.back().second, ("KML can't be loaded")); bmManager.CreateCategories(std::move(kmlDataCollection), false /* autoSave */); TEST_EQUAL(bmManager.GetBmGroupsIdList().size(), 1, ()); @@ -705,9 +725,9 @@ UNIT_CLASS_TEST(Runner, TrackParsingTest_2) string const kmlFile = GetPlatform().TestsDataPathForFile("kml-with-track-from-google-earth.test"); BookmarkManager bmManager((BookmarkManager::Callbacks(bmCallbacks))); BookmarkManager::KMLDataCollection kmlDataCollection; - kmlDataCollection.emplace_back(LoadKMLFile(kmlFile)); + kmlDataCollection.emplace_back(kmlFile, LoadKMLFile(kmlFile, false /* useBinary */)); - TEST(kmlDataCollection[0], ("KML can't be loaded")); + TEST(kmlDataCollection.back().second, ("KML can't be loaded")); bmManager.CreateCategories(std::move(kmlDataCollection), false /* autoSave */); TEST_EQUAL(bmManager.GetBmGroupsIdList().size(), 1, ()); @@ -743,12 +763,12 @@ UNIT_CLASS_TEST(Runner, Bookmarks_Listeners) deletedMarks.clear(); }; - auto const onCreate = [&createdMarksResult](std::vector<std::pair<df::MarkID, BookmarkData>> const &marks) + auto const onCreate = [&createdMarksResult](std::vector<std::pair<df::MarkID, kml::BookmarkData>> const &marks) { for (auto const & markPair : marks) createdMarksResult.insert(markPair.first); }; - auto const onUpdate = [&updatedMarksResult](std::vector<std::pair<df::MarkID, BookmarkData>> const &marks) + auto const onUpdate = [&updatedMarksResult](std::vector<std::pair<df::MarkID, kml::BookmarkData>> const &marks) { for (auto const & markPair : marks) updatedMarksResult.insert(markPair.first); @@ -774,13 +794,15 @@ UNIT_CLASS_TEST(Runner, Bookmarks_Listeners) { auto editSession = bmManager.GetEditSession(); - auto * bookmark0 = editSession.CreateBookmark( - m2::PointD(0.0, 0.0), BookmarkData("name 0", "type 0")); + kml::BookmarkData data; + kml::SetDefaultStr(data.m_name, "name 0"); + data.m_point = m2::PointD(0.0, 0.0); + auto * bookmark0 = editSession.CreateBookmark(data); editSession.AttachBookmark(bookmark0->GetId(), catId); createdMarks.insert(bookmark0->GetId()); - auto * bookmark1 = editSession.CreateBookmark( - m2::PointD(0.0, 0.0), BookmarkData("name 1", "type 1")); + kml::SetDefaultStr(data.m_name, "name 1"); + auto * bookmark1 = editSession.CreateBookmark(data); editSession.AttachBookmark(bookmark1->GetId(), catId); createdMarks.insert(bookmark1->GetId()); @@ -801,8 +823,10 @@ UNIT_CLASS_TEST(Runner, Bookmarks_Listeners) editSession.DeleteBookmark(markId0); deletedMarks.insert(markId0); - auto * bookmark1 = editSession.CreateBookmark( - m2::PointD(0.0, 0.0), BookmarkData("name 5", "type 5")); + kml::BookmarkData data; + kml::SetDefaultStr(data.m_name, "name 5"); + data.m_point = m2::PointD(0.0, 0.0); + auto * bookmark1 = editSession.CreateBookmark(data); createdMarks.insert(bookmark1->GetId()); } checkNotifications(); @@ -811,65 +835,71 @@ UNIT_CLASS_TEST(Runner, Bookmarks_Listeners) UNIT_CLASS_TEST(Runner, Bookmarks_AutoSave) { BookmarkManager bmManager((BookmarkManager::Callbacks(bmCallbacks))); + kml::BookmarkData data; df::MarkID bmId0; auto const catId = bmManager.CreateBookmarkCategory("test"); + data.m_point = m2::PointD(0.0, 0.0); { + kml::SetDefaultStr(data.m_name, "name 0"); auto editSession = bmManager.GetEditSession(); - bmId0 = editSession.CreateBookmark(m2::PointD(0.0, 0.0), BookmarkData("name 0", "type 0"))->GetId(); + bmId0 = editSession.CreateBookmark(data)->GetId(); editSession.AttachBookmark(bmId0, catId); } auto const fileName = bmManager.GetCategoryFileName(catId); - auto kmlData = LoadKMLFile(fileName); + auto kmlData = LoadKMLFile(fileName, BookmarkManager::IsMigrated()); TEST(kmlData != nullptr, ()); - TEST_EQUAL(kmlData->m_bookmarks.size(), 1, ()); - TEST_EQUAL(kmlData->m_bookmarks.front()->GetName(), "name 0", ()); + TEST_EQUAL(kmlData->m_bookmarksData.size(), 1, ()); + TEST_EQUAL(kml::GetDefaultStr(kmlData->m_bookmarksData.front().m_name), "name 0", ()); { auto editSession = bmManager.GetEditSession(); editSession.GetBookmarkForEdit(bmId0)->SetName("name 0 renamed"); - auto bmId = editSession.CreateBookmark(m2::PointD(0.0, 0.0), BookmarkData("name 1", "type 1"))->GetId(); + kml::SetDefaultStr(data.m_name, "name 1"); + auto bmId = editSession.CreateBookmark(data)->GetId(); editSession.AttachBookmark(bmId, catId); - bmId = editSession.CreateBookmark(m2::PointD(0.0, 0.0), BookmarkData("name 2", "type 2"))->GetId(); + kml::SetDefaultStr(data.m_name, "name 2"); + bmId = editSession.CreateBookmark(data)->GetId(); editSession.AttachBookmark(bmId, catId); - bmId = editSession.CreateBookmark(m2::PointD(0.0, 0.0), BookmarkData("name 3", "type 3"))->GetId(); + kml::SetDefaultStr(data.m_name, "name 3"); + bmId = editSession.CreateBookmark(data)->GetId(); editSession.AttachBookmark(bmId, catId); - kmlData = LoadKMLFile(fileName); + kmlData = LoadKMLFile(fileName, BookmarkManager::IsMigrated()); TEST(kmlData != nullptr, ()); - TEST_EQUAL(kmlData->m_bookmarks.size(), 1, ()); - TEST_EQUAL(kmlData->m_bookmarks.front()->GetName(), "name 0", ()); + TEST_EQUAL(kmlData->m_bookmarksData.size(), 1, ()); + TEST_EQUAL(kml::GetDefaultStr(kmlData->m_bookmarksData.front().m_name), "name 0", ()); } - kmlData = LoadKMLFile(fileName); + kmlData = LoadKMLFile(fileName, BookmarkManager::IsMigrated()); TEST(kmlData != nullptr, ()); - TEST_EQUAL(kmlData->m_bookmarks.size(), 4, ()); - TEST_EQUAL(kmlData->m_bookmarks.front()->GetName(), "name 0 renamed", ()); + TEST_EQUAL(kmlData->m_bookmarksData.size(), 4, ()); + TEST_EQUAL(kml::GetDefaultStr(kmlData->m_bookmarksData.front().m_name), "name 0 renamed", ()); bmManager.GetEditSession().DeleteBookmark(bmId0); - kmlData = LoadKMLFile(fileName); + kmlData = LoadKMLFile(fileName, BookmarkManager::IsMigrated()); TEST(kmlData != nullptr, ()); - TEST_EQUAL(kmlData->m_bookmarks.size(), 3, ()); - TEST_EQUAL(kmlData->m_bookmarks.front()->GetName(), "name 1", ()); + TEST_EQUAL(kmlData->m_bookmarksData.size(), 3, ()); + TEST_EQUAL(kml::GetDefaultStr(kmlData->m_bookmarksData.front().m_name), "name 1", ()); auto const catId2 = bmManager.CreateBookmarkCategory("test 2"); auto const movedBmId = *bmManager.GetUserMarkIds(catId).begin(); bmManager.GetEditSession().MoveBookmark(movedBmId, catId, catId2); - kmlData = LoadKMLFile(fileName); + kmlData = LoadKMLFile(fileName, BookmarkManager::IsMigrated()); TEST(kmlData != nullptr, ()); - TEST_EQUAL(kmlData->m_bookmarks.size(), 2, ()); - TEST_EQUAL(kmlData->m_bookmarks.front()->GetName(), "name 1", ()); + TEST_EQUAL(kmlData->m_bookmarksData.size(), 2, ()); + TEST_EQUAL(kml::GetDefaultStr(kmlData->m_bookmarksData.front().m_name), "name 1", ()); auto const fileName2 = bmManager.GetCategoryFileName(catId2); - auto kmlData2 = LoadKMLFile(fileName2); + auto kmlData2 = LoadKMLFile(fileName2, BookmarkManager::IsMigrated()); TEST(kmlData2 != nullptr, ()); - TEST_EQUAL(kmlData2->m_bookmarks.size(), 1, ()); - TEST_EQUAL(kmlData2->m_bookmarks.front()->GetName(), "name 3", ()); + TEST_EQUAL(kmlData2->m_bookmarksData.size(), 1, ()); + TEST_EQUAL(kml::GetDefaultStr(kmlData2->m_bookmarksData.front().m_name), "name 3", ()); TEST(my::DeleteFileX(fileName), ()); TEST(my::DeleteFileX(fileName2), ()); diff --git a/map/map_tests/kmz_unarchive_test.cpp b/map/map_tests/kmz_unarchive_test.cpp index aa06ced362..1655b5f5d0 100644 --- a/map/map_tests/kmz_unarchive_test.cpp +++ b/map/map_tests/kmz_unarchive_test.cpp @@ -35,27 +35,27 @@ UNIT_TEST(KMZ_UnzipTest) MY_SCOPE_GUARD(fileGuard, bind(&FileWriter::DeleteFileX, kmlFile)); ZipFileReader::UnzipFile(kmzFile, "doc.kml", kmlFile); - auto kmlData = LoadKMLData(make_unique<FileReader>(kmlFile)); + auto kmlData = LoadKMLData(FileReader(kmlFile), false /* useBinary */); TEST(kmlData != nullptr, ()); TEST_EQUAL(files.size(), 6, ("KMZ file wrong number of files")); - TEST_EQUAL(kmlData->m_bookmarks.size(), 6, ("Category wrong number of bookmarks")); + TEST_EQUAL(kmlData->m_bookmarksData.size(), 6, ("Category wrong number of bookmarks")); { - Bookmark const * bm = kmlData->m_bookmarks[0].get(); - TEST_EQUAL(bm->GetName(), ("Lahaina Breakwall"), ("KML wrong name!")); - TEST_EQUAL(bm->GetType(), "placemark-red", ("KML wrong type!")); - TEST_ALMOST_EQUAL_ULPS(bm->GetPivot().x, -156.6777046791284, ("KML wrong org x!")); - TEST_ALMOST_EQUAL_ULPS(bm->GetPivot().y, 21.34256685860084, ("KML wrong org y!")); - TEST_EQUAL(bm->GetScale(), -1, ("KML wrong scale!")); + Bookmark const bm(kmlData->m_bookmarksData[0]); + TEST_EQUAL(bm.GetName(), ("Lahaina Breakwall"), ("KML wrong name!")); + TEST_EQUAL(bm.GetIcon(), "placemark-red", ("KML wrong type!")); + TEST_ALMOST_EQUAL_ULPS(bm.GetPivot().x, -156.6777046791284, ("KML wrong org x!")); + TEST_ALMOST_EQUAL_ULPS(bm.GetPivot().y, 21.34256685860084, ("KML wrong org y!")); + TEST_EQUAL(bm.GetScale(), 0, ("KML wrong scale!")); } { - Bookmark const * bm = kmlData->m_bookmarks[1].get(); - TEST_EQUAL(bm->GetName(), ("Seven Sacred Pools, Kipahulu"), ("KML wrong name!")); - TEST_EQUAL(bm->GetType(), "placemark-red", ("KML wrong type!")); - TEST_ALMOST_EQUAL_ULPS(bm->GetPivot().x, -156.0405130750025, ("KML wrong org x!")); - TEST_ALMOST_EQUAL_ULPS(bm->GetPivot().y, 21.12480639056074, ("KML wrong org y!")); - TEST_EQUAL(bm->GetScale(), -1, ("KML wrong scale!")); + Bookmark const bm(kmlData->m_bookmarksData[1]); + TEST_EQUAL(bm.GetName(), ("Seven Sacred Pools, Kipahulu"), ("KML wrong name!")); + TEST_EQUAL(bm.GetIcon(), "placemark-red", ("KML wrong type!")); + TEST_ALMOST_EQUAL_ULPS(bm.GetPivot().x, -156.0405130750025, ("KML wrong org x!")); + TEST_ALMOST_EQUAL_ULPS(bm.GetPivot().y, 21.12480639056074, ("KML wrong org y!")); + TEST_EQUAL(bm.GetScale(), 0, ("KML wrong scale!")); } } diff --git a/map/map_tests/search_api_tests.cpp b/map/map_tests/search_api_tests.cpp index 8dead29ba5..489642ca0a 100644 --- a/map/map_tests/search_api_tests.cpp +++ b/map/map_tests/search_api_tests.cpp @@ -133,15 +133,18 @@ UNIT_CLASS_TEST(SearchAPITest, MultipleViewportsRequests) UNIT_CLASS_TEST(SearchAPITest, BookmarksSearch) { - vector<pair<df::MarkID, BookmarkData>> marks; - - marks.emplace_back( - 0, BookmarkData("R&R dinner" /* name */, "cafe" /* type */, - "They've got a cherry pie there that'll kill ya!" /* description */)); - marks.emplace_back(1, BookmarkData("Silver Mustang Casino" /* name */, "casino" /* type */, - "Joyful place, owners Bradley and Rodney are very friendly!")); - marks.emplace_back(2, BookmarkData("Great Northern Hotel" /* name */, "hotel" /* type */, - "Clean place with a reasonable price" /* description */)); + vector<pair<df::MarkID, kml::BookmarkData>> marks; + + kml::BookmarkData data; + kml::SetDefaultStr(data.m_name, "R&R dinner"); + kml::SetDefaultStr(data.m_description, "They've got a cherry pie there that'll kill ya!"); + marks.emplace_back(0, data); + kml::SetDefaultStr(data.m_name, "Silver Mustang Casino"); + kml::SetDefaultStr(data.m_description, "Joyful place, owners Bradley and Rodney are very friendly!"); + marks.emplace_back(1, data); + kml::SetDefaultStr(data.m_name, "Great Northern Hotel"); + kml::SetDefaultStr(data.m_description, "Clean place with a reasonable price"); + marks.emplace_back(2, data); m_api.OnBookmarksCreated(marks); promise<vector<df::MarkID>> promise; diff --git a/map/place_page_info.cpp b/map/place_page_info.cpp index 8fa50608ff..0270157cff 100644 --- a/map/place_page_info.cpp +++ b/map/place_page_info.cpp @@ -52,7 +52,7 @@ void Info::SetFromFeatureType(FeatureType const & ft) m_sortedTypes.SortBySpec(); if (IsBookmark()) { - m_uiTitle = m_bookmarkData.GetName(); + m_uiTitle = kml::GetDefaultStr(m_bookmarkData.m_name); std::string secondary; if (m_customName.empty()) @@ -152,7 +152,7 @@ void Info::SetCustomName(std::string const & name) { if (IsBookmark()) { - m_uiTitle = GetBookmarkData().GetName(); + m_uiTitle = kml::GetDefaultStr(GetBookmarkData().m_name); m_uiSubtitle = m_bookmarkCategoryName; } else @@ -167,7 +167,7 @@ void Info::SetCustomNameWithCoordinates(m2::PointD const & mercator, std::string { if (IsBookmark()) { - m_uiTitle = GetBookmarkData().GetName(); + m_uiTitle = kml::GetDefaultStr(GetBookmarkData().m_name); m_uiSubtitle = m_bookmarkCategoryName; } else diff --git a/map/place_page_info.hpp b/map/place_page_info.hpp index f627212689..6062b70d84 100644 --- a/map/place_page_info.hpp +++ b/map/place_page_info.hpp @@ -126,8 +126,8 @@ public: df::MarkGroupID GetBookmarkCategoryId() const { return m_markGroupId; } std::string const & GetBookmarkCategoryName() const { return m_bookmarkCategoryName; } void SetBookmarkCategoryName(std::string const & name) { m_bookmarkCategoryName = name; } - void SetBookmarkData(BookmarkData const & data) { m_bookmarkData = data; } - BookmarkData const & GetBookmarkData() const { return m_bookmarkData; } + void SetBookmarkData(kml::BookmarkData const & data) { m_bookmarkData = data; } + kml::BookmarkData const & GetBookmarkData() const { return m_bookmarkData; } /// Api void SetApiId(std::string const & apiId) { m_apiId = apiId; } @@ -247,7 +247,7 @@ private: df::MarkGroupID m_markGroupId = df::kInvalidMarkGroupId;; /// Bookmark category name. Empty, if it's not bookmark; std::string m_bookmarkCategoryName; - BookmarkData m_bookmarkData; + kml::BookmarkData m_bookmarkData; /// Api ID passed for the selected object. It's automatically included in api url below. std::string m_apiId; diff --git a/map/search_api.cpp b/map/search_api.cpp index 890efbcea0..2d7e3afbf9 100644 --- a/map/search_api.cpp +++ b/map/search_api.cpp @@ -55,7 +55,7 @@ bookmarks::Id MarkIDToBookmarkId(df::MarkID id) df::MarkID BookmarkIdToMarkID(bookmarks::Id id) { return static_cast<df::MarkID>(id); } -void AppendBookmarkIdDocs(vector<pair<df::MarkID, BookmarkData>> const & marks, +void AppendBookmarkIdDocs(vector<pair<df::MarkID, kml::BookmarkData>> const & marks, vector<BookmarkIdDoc> & result) { result.reserve(result.size() + marks.size()); @@ -64,8 +64,7 @@ void AppendBookmarkIdDocs(vector<pair<df::MarkID, BookmarkData>> const & marks, { auto const & id = mark.first; auto const & data = mark.second; - result.emplace_back(MarkIDToBookmarkId(id), - bookmarks::Doc(data.GetName(), data.GetDescription(), data.GetType())); + result.emplace_back(MarkIDToBookmarkId(id), bookmarks::Doc(data)); } } @@ -369,14 +368,14 @@ ProductInfo SearchAPI::GetProductInfo(Result const & result) const return m_delegate.GetProductInfo(result); } -void SearchAPI::OnBookmarksCreated(vector<pair<df::MarkID, BookmarkData>> const & marks) +void SearchAPI::OnBookmarksCreated(vector<pair<df::MarkID, kml::BookmarkData>> const & marks) { vector<BookmarkIdDoc> data; AppendBookmarkIdDocs(marks, data); m_engine.OnBookmarksCreated(data); } -void SearchAPI::OnBookmarksUpdated(vector<pair<df::MarkID, BookmarkData>> const & marks) +void SearchAPI::OnBookmarksUpdated(vector<pair<df::MarkID, kml::BookmarkData>> const & marks) { vector<BookmarkIdDoc> data; AppendBookmarkIdDocs(marks, data); diff --git a/map/search_api.hpp b/map/search_api.hpp index 06af3d9da2..9cbe9ab345 100644 --- a/map/search_api.hpp +++ b/map/search_api.hpp @@ -141,8 +141,8 @@ public: search::Results::ConstIter end) override; search::ProductInfo GetProductInfo(search::Result const & result) const override; - void OnBookmarksCreated(std::vector<std::pair<df::MarkID, BookmarkData>> const & marks); - void OnBookmarksUpdated(std::vector<std::pair<df::MarkID, BookmarkData>> const & marks); + void OnBookmarksCreated(std::vector<std::pair<df::MarkID, kml::BookmarkData>> const & marks); + void OnBookmarksUpdated(std::vector<std::pair<df::MarkID, kml::BookmarkData>> const & marks); void OnBookmarksDeleted(std::vector<df::MarkID> const & marks); private: diff --git a/map/track.cpp b/map/track.cpp index 265f88cf54..cb054448b8 100644 --- a/map/track.cpp +++ b/map/track.cpp @@ -13,38 +13,41 @@ df::LineID GetNextUserLineId() static std::atomic<uint32_t> nextLineId(0); return static_cast<df::LineID>(++nextLineId); } + } // namespace -Track::Track(Track::PolylineD const & polyline, Track::Params const & p) +Track::Track(kml::TrackData const & data) : df::UserLineMark(GetNextUserLineId()) - , m_polyline(polyline) - , m_params(p) + , m_data(data) , m_groupID(0) { - ASSERT_GREATER(m_polyline.GetSize(), 1, ()); + ASSERT_GREATER(m_data.m_points.size(), 1, ()); } string const & Track::GetName() const { - return m_params.m_name; + return kml::GetDefaultStr(m_data.m_name); } m2::RectD Track::GetLimitRect() const { - return m_polyline.GetLimitRect(); + m2::RectD rect; + for (auto const & point : m_data.m_points) + rect.Add(point); + return rect; } double Track::GetLengthMeters() const { double res = 0.0; - auto i = m_polyline.Begin(); - double lat1 = MercatorBounds::YToLat(i->y); - double lon1 = MercatorBounds::XToLon(i->x); - for (++i; i != m_polyline.End(); ++i) + auto it = m_data.m_points.begin(); + double lat1 = MercatorBounds::YToLat(it->y); + double lon1 = MercatorBounds::XToLon(it->x); + for (++it; it != m_data.m_points.end(); ++it) { - double const lat2 = MercatorBounds::YToLat(i->y); - double const lon2 = MercatorBounds::XToLon(i->x); + double const lat2 = MercatorBounds::YToLat(it->y); + double const lon2 = MercatorBounds::XToLon(it->x); res += ms::DistanceOnEarth(lat1, lon1, lat2, lon2); lat1 = lat2; lon1 = lon2; @@ -60,17 +63,17 @@ df::RenderState::DepthLayer Track::GetDepthLayer() const size_t Track::GetLayerCount() const { - return m_params.m_colors.size(); + return m_data.m_layers.size(); } -dp::Color const & Track::GetColor(size_t layerIndex) const +dp::Color Track::GetColor(size_t layerIndex) const { - return m_params.m_colors[layerIndex].m_color; + return dp::Color(m_data.m_layers[layerIndex].m_color.m_rgba); } float Track::GetWidth(size_t layerIndex) const { - return m_params.m_colors[layerIndex].m_lineWidth; + return static_cast<float>(m_data.m_layers[layerIndex].m_lineWidth); } float Track::GetDepth(size_t layerIndex) const @@ -80,7 +83,7 @@ float Track::GetDepth(size_t layerIndex) const std::vector<m2::PointD> const & Track::GetPoints() const { - return m_polyline.GetPoints(); + return m_data.m_points; } void Track::Attach(df::MarkGroupID groupId) diff --git a/map/track.hpp b/map/track.hpp index afa4fc202c..7bb774fe8b 100644 --- a/map/track.hpp +++ b/map/track.hpp @@ -1,5 +1,7 @@ #pragma once +#include "kml/types.hpp" + #include "drape_frontend/user_marks_provider.hpp" #include "drape/color.hpp" @@ -18,34 +20,22 @@ class Track : public df::UserLineMark DISALLOW_COPY_AND_MOVE(Track); public: - using PolylineD = m2::PolylineD; - - struct TrackOutline - { - float m_lineWidth; - dp::Color m_color; - }; - - struct Params - { - buffer_vector<TrackOutline, 2> m_colors; - string m_name; - }; - - explicit Track(PolylineD const & polyline, Params const & p); + explicit Track(kml::TrackData const & data); bool IsDirty() const override { return m_isDirty; } void ResetChanges() const override { m_isDirty = false; } + kml::TrackData const & GetData() const { return m_data; } + //void SetData(kml::TrackData const & data) { m_data = data; } + string const & GetName() const; - PolylineD const & GetPolyline() const { return m_polyline; } m2::RectD GetLimitRect() const; double GetLengthMeters() const; int GetMinZoom() const override { return 1; } df::RenderState::DepthLayer GetDepthLayer() const override; size_t GetLayerCount() const override; - dp::Color const & GetColor(size_t layerIndex) const override; + dp::Color GetColor(size_t layerIndex) const override; float GetWidth(size_t layerIndex) const override; float GetDepth(size_t layerIndex) const override; std::vector<m2::PointD> const & GetPoints() const override; @@ -55,8 +45,8 @@ public: void Detach(); private: - PolylineD m_polyline; - Params m_params; + kml::TrackData m_data; + df::MarkGroupID m_groupID; mutable bool m_isDirty = true; }; diff --git a/map/user_mark_layer.hpp b/map/user_mark_layer.hpp index 53a3046fc1..4f5f481b7d 100644 --- a/map/user_mark_layer.hpp +++ b/map/user_mark_layer.hpp @@ -39,7 +39,7 @@ public: void Clear(); bool IsEmpty() const; - void SetIsVisible(bool isVisible); + virtual void SetIsVisible(bool isVisible); protected: void SetDirty() { m_isDirty = true; } |