Base editor serialization.

This commit is contained in:
Alex Zolotarev 2015-12-21 20:03:04 +03:00 committed by Sergey Yershov
parent fd9434d0e8
commit 8c08017809
4 changed files with 110 additions and 20 deletions

View file

@ -16,7 +16,12 @@
namespace
{
auto constexpr kLatLonTolerance = 7;
constexpr int const kLatLonTolerance = 7;
constexpr char const * kTimestamp = "timestamp";
constexpr char const * kUploadTimestamp = "upload_timestamp";
constexpr char const * kUploadStatus = "upload_status";
constexpr char const * kUploadError = "upload_error";
constexpr char const * kHouseNumber = "addr:housenumber";
pugi::xml_node FindTag(pugi::xml_document const & document, string const & key)
{
@ -47,20 +52,16 @@ void ValidateNode(pugi::xml_node const & node)
// Check if point can be parsed. Throws if it's can't.
UNUSED_VALUE(PointFromLatLon(node));
if (!node.attribute("timestamp"))
if (!node.attribute(kTimestamp))
MYTHROW(editor::XMLFeatureNoTimestampError, ("Node has no timestamp attribute"));
}
} // namespace
namespace editor
{
char const * const XMLFeature::kLastModified = "timestamp";
char const * const XMLFeature::kHouseNumber = "addr:housenumber";
char const * const XMLFeature::kDefaultName = "name";
char const * const XMLFeature::kLocalName = "name:";
char const * const XMLFeature::kDefaultLang =
StringUtf8Multilang::GetLangByCode(StringUtf8Multilang::DEFAULT_CODE);
;
XMLFeature::XMLFeature()
{
@ -107,7 +108,7 @@ void XMLFeature::SetCenter(m2::PointD const & mercatorCenter)
string XMLFeature::GetName(string const & lang) const
{
auto const suffix = (lang == kDefaultLang || lang.empty()) ? "" : ":" + lang;
return GetTagValue("name" + suffix);
return GetTagValue(kDefaultName + suffix);
}
string XMLFeature::GetName(uint8_t const langCode) const
@ -123,7 +124,7 @@ void XMLFeature::SetName(string const & name)
void XMLFeature::SetName(string const & lang, string const & name)
{
auto const suffix = (lang == kDefaultLang || lang.empty()) ? "" : ":" + lang;
SetTagValue("name" + suffix, name);
SetTagValue(kDefaultName + suffix, name);
}
void XMLFeature::SetName(uint8_t const langCode, string const & name)
@ -143,12 +144,42 @@ void XMLFeature::SetHouse(string const & house)
time_t XMLFeature::GetModificationTime() const
{
return my::StringToTimestamp(GetRootNode().attribute("timestamp").value());
return my::StringToTimestamp(GetRootNode().attribute(kTimestamp).value());
}
void XMLFeature::SetModificationTime(time_t const time)
{
SetAttribute(kLastModified, my::TimestampToString(time));
SetAttribute(kTimestamp, my::TimestampToString(time));
}
time_t XMLFeature::GetUploadTime() const
{
return my::StringToTimestamp(GetRootNode().attribute(kUploadTimestamp).value());
}
void XMLFeature::SetUploadTime(time_t const time)
{
SetAttribute(kUploadTimestamp, my::TimestampToString(time));
}
string XMLFeature::GetUploadStatus() const
{
return GetRootNode().attribute(kUploadStatus).value();
}
void XMLFeature::SetUploadStatus(string const & status)
{
SetAttribute(kUploadStatus, status);
}
string XMLFeature::GetUploadError() const
{
return GetRootNode().attribute(kUploadError).value();
}
void XMLFeature::SetUploadError(string const & error)
{
SetAttribute(kUploadError, error);
}
bool XMLFeature::HasTag(string const & key) const
@ -210,4 +241,9 @@ pugi::xml_node XMLFeature::GetRootNode()
{
return m_document.child("node");
}
bool XMLFeature::AttachToParentNode(pugi::xml_node parent) const
{
return !parent.append_copy(GetRootNode()).empty();
}
} // namespace editor

View file

@ -21,10 +21,8 @@ DECLARE_EXCEPTION(XMLFeatureNoHeaderError, XMLFeatureError);
class XMLFeature
{
static char const * const kLastModified;
static char const * const kHouseNumber;
static char const * const kDefaultName;
static char const * const kLocalName;
static constexpr char const * kDefaultName = "name";
static constexpr char const * kLocalName = "name:";
static char const * const kDefaultLang;
public:
@ -67,8 +65,18 @@ public:
string GetHouse() const;
void SetHouse(string const & house);
/// Our and OSM modification time are equal.
time_t GetModificationTime() const;
void SetModificationTime(time_t const time = ::time(nullptr));
void SetModificationTime(time_t const time);
time_t GetUploadTime() const;
void SetUploadTime(time_t const time);
string GetUploadStatus() const;
void SetUploadStatus(string const & status);
string GetUploadError() const;
void SetUploadError(string const & error);
bool HasTag(string const & key) const;
bool HasAttribute(string const & key) const;
@ -86,6 +94,8 @@ public:
string GetAttribute(string const & key) const;
void SetAttribute(string const & key, string const & value);
bool AttachToParentNode(pugi::xml_node parent) const;
private:
pugi::xml_node const GetRootNode() const;
pugi::xml_node GetRootNode();

View file

@ -5,6 +5,8 @@
#include "platform/platform.hpp"
#include "editor/xml_feature.hpp"
#include "base/logging.hpp"
#include "std/map.hpp"
@ -16,7 +18,11 @@ using namespace pugi;
using feature::EGeomType;
using feature::Metadata;
static char constexpr const * kEditorXMLFileName = "edits.xml";
constexpr char const * kEditorXMLFileName = "edits.xml";
constexpr char const * kXmlRootNode = "mapsme";
constexpr char const * kDeleteSection = "delete";
constexpr char const * kModifySection = "modify";
constexpr char const * kCreateSection = "create";
namespace osm
{
@ -53,9 +59,47 @@ void Editor::Load(string const & fullFilePath)
// TODO(mgsergio): Implement XML deserialization into m_features.
}
void Editor::Save(string const & /*fullFilePath*/) const
void Editor::Save(string const & fullFilePath) const
{
// TODO(mgsergio): Implement XML serialization from m_features.
// Should we delete edits file if user has canceled all changes?
if (m_features.empty())
return;
xml_document doc;
xml_node root = doc.append_child(kXmlRootNode);
// Use format_version for possible future format changes.
root.append_attribute("format_version") = 1;
for (auto const & mwm : m_features)
{
xml_node mwmNode = root.append_child("mwm");
mwmNode.append_attribute("name") = mwm.first.GetInfo()->GetCountryName().c_str();
mwmNode.append_attribute("version") = mwm.first.GetInfo()->GetVersion();
xml_node deleted = mwmNode.append_child(kDeleteSection);
xml_node modified = mwmNode.append_child(kModifySection);
xml_node created = mwmNode.append_child(kCreateSection);
for (auto const & offset : mwm.second)
{
FeatureTypeInfo const & fti = offset.second;
editor::XMLFeature xf = fti.m_feature.ToXML();
xf.SetModificationTime(fti.m_modificationTimestamp);
if (fti.m_uploadAttemptTimestamp)
{
xf.SetUploadTime(fti.m_uploadAttemptTimestamp);
xf.SetUploadStatus(fti.m_uploadStatus);
xf.SetUploadError(fti.m_uploadError);
}
switch (fti.m_status)
{
case EDeleted: VERIFY(xf.AttachToParentNode(deleted), ()); break;
case EModified: VERIFY(xf.AttachToParentNode(modified), ()); break;
case ECreated: VERIFY(xf.AttachToParentNode(created), ()); break;
case EUntouched: CHECK(false, ("Not edited features shouldn't be here."));
}
}
}
if (doc && !doc.save_file(fullFilePath.c_str(), " "))
LOG(LERROR, ("Can't save map edits into", fullFilePath));
}
Editor::FeatureStatus Editor::GetFeatureStatus(MwmSet::MwmId const & mwmId, uint32_t offset) const

View file

@ -1,6 +1,6 @@
# Main application in qt.
ROOT_DIR = ..
DEPENDENCIES = map drape_frontend routing search storage indexer drape platform geometry coding base \
DEPENDENCIES = map drape_frontend routing search storage indexer drape platform editor geometry coding base \
freetype expat fribidi tomcrypt jansson protobuf osrm stats_client minizip succinct pugixml