#include "platform/settings.hpp" #include "platform/location.hpp" #include "platform/platform.hpp" #include "defines.hpp" #include "coding/reader_streambuf.hpp" #include "coding/file_writer.hpp" #include "coding/file_reader.hpp" #include "geometry/rect2d.hpp" #include "geometry/any_rect2d.hpp" #include "base/logging.hpp" #include "std/cmath.hpp" #include "std/iostream.hpp" #include "std/sstream.hpp" namespace { constexpr char kDelimChar = '='; } // namespace namespace settings { char const * kLocationStateMode = "LastLocationStateMode"; char const * kMeasurementUnits = "Units"; StringStorage::StringStorage() { try { string settingsPath = GetPlatform().SettingsPathForFile(SETTINGS_FILE_NAME); LOG(LINFO, ("Settings path:", settingsPath)); ReaderStreamBuf buffer(make_unique(settingsPath)); istream stream(&buffer); string line; while (getline(stream, line)) { if (line.empty()) continue; size_t const delimPos = line.find(kDelimChar); if (delimPos == string::npos) continue; string const key = line.substr(0, delimPos); string const value = line.substr(delimPos + 1); if (!key.empty() && !value.empty()) m_values[key] = value; } } catch (RootException const & ex) { LOG(LWARNING, ("Loading settings:", ex.Msg())); } } void StringStorage::Save() const { try { FileWriter file(GetPlatform().SettingsPathForFile(SETTINGS_FILE_NAME)); for (auto const & value : m_values) { string line(value.first); line += kDelimChar; line += value.second; line += '\n'; file.Write(line.data(), line.size()); } } catch (RootException const & ex) { // Ignore all settings saving exceptions. LOG(LWARNING, ("Saving settings:", ex.Msg())); } } StringStorage & StringStorage::Instance() { static StringStorage inst; return inst; } void StringStorage::Clear() { lock_guard guard(m_mutex); m_values.clear(); Save(); } bool StringStorage::GetValue(string const & key, string & outValue) const { lock_guard guard(m_mutex); auto const found = m_values.find(key); if (found == m_values.end()) return false; outValue = found->second; return true; } void StringStorage::SetValue(string const & key, string && value) { lock_guard guard(m_mutex); m_values[key] = move(value); Save(); } void StringStorage::DeleteKeyAndValue(string const & key) { lock_guard guard(m_mutex); auto const found = m_values.find(key); if (found != m_values.end()) { m_values.erase(found); Save(); } } //////////////////////////////////////////////////////////////////////////////////////////// template <> string ToString(string const & str) { return str; } template <> bool FromString(string const & strIn, string & strOut) { strOut = strIn; return true; } namespace impl { template bool FromStringArray(string const & s, T(&arr)[N]) { istringstream in(s); size_t count = 0; while (count < N && in >> arr[count]) { if (!isfinite(arr[count])) return false; ++count; } return (!in.fail() && count == N); } } // namespace impl template <> string ToString(m2::AnyRectD const & rect) { ostringstream out; out.precision(12); m2::PointD glbZero(rect.GlobalZero()); out << glbZero.x << " " << glbZero.y << " "; out << rect.Angle().val() << " "; m2::RectD const & r = rect.GetLocalRect(); out << r.minX() << " " << r.minY() << " " << r.maxX() << " " << r.maxY(); return out.str(); } template <> bool FromString(string const & str, m2::AnyRectD & rect) { double val[7]; if (!impl::FromStringArray(str, val)) return false; // Will get an assertion in DEBUG and false return in RELEASE. m2::RectD const r(val[3], val[4], val[5], val[6]); if (!r.IsValid()) return false; rect = m2::AnyRectD(m2::PointD(val[0], val[1]), ang::AngleD(val[2]), r); return true; } template <> string ToString(m2::RectD const & rect) { ostringstream stream; stream.precision(12); stream << rect.minX() << " " << rect.minY() << " " << rect.maxX() << " " << rect.maxY(); return stream.str(); } template <> bool FromString(string const & str, m2::RectD & rect) { double val[4]; if (!impl::FromStringArray(str, val)) return false; // Will get an assertion in DEBUG and false return in RELEASE. rect = m2::RectD(val[0], val[1], val[2], val[3]); return rect.IsValid(); } template <> string ToString(bool const & v) { return v ? "true" : "false"; } template <> bool FromString(string const & str, bool & v) { if (str == "true") v = true; else if (str == "false") v = false; else return false; return true; } namespace impl { template string ToStringScalar(T const & v) { ostringstream stream; stream.precision(12); stream << v; return stream.str(); } template bool FromStringScalar(string const & str, T & v) { istringstream stream(str); if (stream) { stream >> v; return !stream.fail(); } else return false; } } // namespace impl template <> string ToString(double const & v) { return impl::ToStringScalar(v); } template <> bool FromString(string const & str, double & v) { return impl::FromStringScalar(str, v); } template <> string ToString(int32_t const & v) { return impl::ToStringScalar(v); } template <> bool FromString(string const & str, int32_t & v) { return impl::FromStringScalar(str, v); } template <> string ToString(int64_t const & v) { return impl::ToStringScalar(v); } template <> bool FromString(string const & str, int64_t & v) { return impl::FromStringScalar(str, v); } template <> string ToString(uint32_t const & v) { return impl::ToStringScalar(v); } template <> string ToString(uint64_t const & v) { return impl::ToStringScalar(v); } template <> bool FromString(string const & str, uint32_t & v) { return impl::FromStringScalar(str, v); } template <> bool FromString(string const & str, uint64_t & v) { return impl::FromStringScalar(str, v); } namespace impl { template string ToStringPair(TPair const & value) { ostringstream stream; stream.precision(12); stream << value.first << " " << value.second; return stream.str(); } template bool FromStringPair(string const & str, TPair & value) { istringstream stream(str); if (stream) { stream >> value.first; if (stream) { stream >> value.second; return !stream.fail(); } } return false; } } // namespace impl typedef pair IPairT; typedef pair DPairT; template <> string ToString(IPairT const & v) { return impl::ToStringPair(v); } template <> bool FromString(string const & s, IPairT & v) { return impl::FromStringPair(s, v); } template <> string ToString(DPairT const & v) { return impl::ToStringPair(v); } template <> bool FromString(string const & s, DPairT & v) { return impl::FromStringPair(s, v); } template <> string ToString(measurement_utils::Units const & v) { switch (v) { // The value "Foot" is left here for compatibility with old settings.ini files. case measurement_utils::Units::Imperial: return "Foot"; case measurement_utils::Units::Metric: return "Metric"; } } template <> bool FromString(string const & s, measurement_utils::Units & v) { if (s == "Metric") v = measurement_utils::Units::Metric; else if (s == "Foot") v = measurement_utils::Units::Imperial; else return false; return true; } template <> string ToString(location::EMyPositionMode const & v) { switch (v) { case location::PendingPosition: return "PendingPosition"; case location::NotFollow: return "NotFollow"; case location::NotFollowNoPosition: return "NotFollowNoPosition"; case location::Follow: return "Follow"; case location::FollowAndRotate: return "FollowAndRotate"; default: return "Pending"; } } template <> bool FromString(string const & s, location::EMyPositionMode & v) { if (s == "PendingPosition") v = location::PendingPosition; else if (s == "NotFollow") v = location::NotFollow; else if (s == "NotFollowNoPosition") v = location::NotFollowNoPosition; else if (s == "Follow") v = location::Follow; else if (s == "FollowAndRotate") v = location::FollowAndRotate; else return false; return true; } bool IsFirstLaunchForDate(int date) { constexpr char const * kFirstLaunchKey = "FirstLaunchOnDate"; int savedDate; if (!Get(kFirstLaunchKey, savedDate) || savedDate < date) { Set(kFirstLaunchKey, date); return true; } else return false; } } // namespace settings