Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorygorshenin <mipt.vi002@gmail.com>2016-07-20 22:52:09 +0300
committerGitHub <noreply@github.com>2016-07-20 22:52:09 +0300
commit612799d306a422d3b27d9cabd4388f2d54b4ccbc (patch)
tree478009719e632ef3cb97848898576d92a45db065 /indexer
parent6b872bc6ea680eb2d8aeedba7474736c5ce8b108 (diff)
parent99f189642f6c5ae0139cc36ba5ba5106680d9de5 (diff)
Merge pull request #3788 from milchakov/MAPSME-1583_default_name
[editor][ios][android] new way to edit names of place
Diffstat (limited to 'indexer')
-rw-r--r--indexer/editable_map_object.cpp139
-rw-r--r--indexer/editable_map_object.hpp22
-rw-r--r--indexer/indexer_tests/editable_map_object_test.cpp99
-rw-r--r--indexer/osm_editor.cpp18
-rw-r--r--indexer/osm_editor.hpp2
5 files changed, 269 insertions, 11 deletions
diff --git a/indexer/editable_map_object.cpp b/indexer/editable_map_object.cpp
index 164705edcf..e87414f626 100644
--- a/indexer/editable_map_object.cpp
+++ b/indexer/editable_map_object.cpp
@@ -1,6 +1,7 @@
+#include "indexer/editable_map_object.hpp"
#include "indexer/classificator.hpp"
#include "indexer/cuisines.hpp"
-#include "indexer/editable_map_object.hpp"
+#include "indexer/osm_editor.hpp"
#include "indexer/postcodes_matcher.hpp"
#include "base/macros.hpp"
@@ -9,6 +10,50 @@
#include "std/cctype.hpp"
#include "std/cmath.hpp"
+
+namespace
+{
+bool ExtractName(StringUtf8Multilang const & names, int8_t const langCode,
+ vector<osm::LocalizedName> & result)
+{
+ if (StringUtf8Multilang::kUnsupportedLanguageCode == langCode ||
+ StringUtf8Multilang::kDefaultCode == langCode)
+ {
+ return false;
+ }
+
+ // Exclude languages that are already present.
+ auto const it =
+ find_if(result.begin(), result.end(), [langCode](osm::LocalizedName const & localizedName) {
+ return localizedName.m_code == langCode;
+ });
+
+ if (result.end() != it)
+ return false;
+
+ string name;
+ names.GetString(langCode, name);
+ result.emplace_back(langCode, name);
+
+ return true;
+}
+
+size_t PushMwmLanguages(StringUtf8Multilang const & names, vector<int8_t> const & mwmLanguages,
+ vector<osm::LocalizedName> & result)
+{
+ size_t count = 0;
+ static size_t const kMaxCountMwmLanguages = 2;
+
+ for (size_t i = 0; i < mwmLanguages.size() && count < kMaxCountMwmLanguages; ++i)
+ {
+ if (ExtractName(names, mwmLanguages[i], result))
+ ++count;
+ }
+
+ return count;
+}
+} // namespace
+
namespace osm
{
// LocalizedName -----------------------------------------------------------------------------------
@@ -49,14 +94,54 @@ vector<feature::Metadata::EType> const & EditableMapObject::GetEditableFields()
StringUtf8Multilang const & EditableMapObject::GetName() const { return m_name; }
-vector<LocalizedName> EditableMapObject::GetLocalizedNames() const
+NamesDataSource EditableMapObject::GetNamesDataSource() const
{
- vector<LocalizedName> result;
- m_name.ForEach([&result](int8_t code, string const & name) -> bool
- {
- result.push_back({code, name});
- return true;
- });
+ const auto mwmInfo = GetID().m_mwmId.GetInfo();
+
+ if (!mwmInfo)
+ return NamesDataSource();
+
+ vector<int8_t> mwmLanguages;
+ mwmInfo->GetRegionData().GetLanguages(mwmLanguages);
+
+ auto const userLangCode = StringUtf8Multilang::GetLangIndex(languages::GetCurrentNorm());
+
+ return GetNamesDataSource(m_name, mwmLanguages, userLangCode);
+}
+
+// static
+NamesDataSource EditableMapObject::GetNamesDataSource(StringUtf8Multilang const & source,
+ vector<int8_t> const & mwmLanguages,
+ int8_t const userLangCode)
+{
+ NamesDataSource result;
+ auto & names = result.names;
+ auto & mandatoryCount = result.mandatoryNamesCount;
+ // Push Mwm languages.
+ mandatoryCount = PushMwmLanguages(source, mwmLanguages, names);
+
+ // Push user's language.
+ if (ExtractName(source, userLangCode, names))
+ ++mandatoryCount;
+
+ // Push other languages.
+ source.ForEach([&names, mandatoryCount](int8_t const code, string const & name) -> bool {
+ // Exclude default name.
+ if (StringUtf8Multilang::kDefaultCode == code)
+ return true;
+
+ auto const mandatoryNamesEnd = names.begin() + mandatoryCount;
+ // Exclude languages which are already in container (languages with top priority).
+ auto const it = find_if(
+ names.begin(), mandatoryNamesEnd,
+ [code](LocalizedName const & localizedName) { return localizedName.m_code == code; });
+
+ if (mandatoryNamesEnd == it)
+ names.emplace_back(code, name);
+
+ return true;
+ });
+
return result;
}
@@ -83,8 +168,42 @@ void EditableMapObject::SetName(StringUtf8Multilang const & name) { m_name = nam
void EditableMapObject::SetName(string name, int8_t langCode)
{
strings::Trim(name);
- if (!name.empty())
- m_name.AddString(langCode, name);
+ if (name.empty())
+ return;
+
+ ASSERT_NOT_EQUAL(StringUtf8Multilang::kDefaultCode, langCode,
+ ("Direct editing of default name is deprecated."));
+
+ if (!Editor::Instance().OriginalFeatureHasDefaultName(GetID()))
+ {
+ const auto mwmInfo = GetID().m_mwmId.GetInfo();
+
+ if (mwmInfo)
+ {
+ vector<int8_t> mwmLanguages;
+ mwmInfo->GetRegionData().GetLanguages(mwmLanguages);
+
+ if (CanUseAsDefaultName(langCode, mwmLanguages))
+ m_name.AddString(StringUtf8Multilang::kDefaultCode, name);
+ }
+ }
+
+ m_name.AddString(langCode, name);
+}
+
+// static
+bool EditableMapObject::CanUseAsDefaultName(int8_t const lang, vector<int8_t> const & mwmLanguages)
+{
+ for (auto const & mwmLang : mwmLanguages)
+ {
+ if (StringUtf8Multilang::kUnsupportedLanguageCode == mwmLang)
+ continue;
+
+ if (lang == mwmLang)
+ return true;
+ }
+
+ return false;
}
void EditableMapObject::SetMercator(m2::PointD const & center) { m_mercator = center; }
diff --git a/indexer/editable_map_object.hpp b/indexer/editable_map_object.hpp
index 365b23d20b..d033bc3d04 100644
--- a/indexer/editable_map_object.hpp
+++ b/indexer/editable_map_object.hpp
@@ -46,6 +46,17 @@ struct LocalizedName
string const m_name;
};
+// Class which contains vector of localized names with following priority:
+// 1. Names for Mwm languages
+// 2. User`s language name
+// 3. Other names
+// and mandatoryNamesCount - count of names which should be always shown.
+struct NamesDataSource
+{
+ vector<LocalizedName> names;
+ size_t mandatoryNamesCount = 0;
+};
+
struct LocalizedStreet
{
string m_defaultName;
@@ -67,7 +78,8 @@ public:
vector<feature::Metadata::EType> const & GetEditableFields() const;
StringUtf8Multilang const & GetName() const;
- vector<LocalizedName> GetLocalizedNames() const;
+ // See comment for NamesDataSource class.
+ NamesDataSource GetNamesDataSource() const;
LocalizedStreet const & GetStreet() const;
vector<LocalizedStreet> const & GetNearbyStreets() const;
string const & GetHouseNumber() const;
@@ -117,6 +129,14 @@ public:
static bool ValidateWebsite(string const & site);
static bool ValidateEmail(string const & email);
+ // Check whether langCode can be used as default name.
+ static bool CanUseAsDefaultName(int8_t const langCode, vector<int8_t> const & nativeMwmLanguages);
+
+ // See comment for NamesDataSource class.
+ static NamesDataSource GetNamesDataSource(StringUtf8Multilang const & source,
+ vector<int8_t> const & nativeMwmLanguages,
+ int8_t const userLanguage);
+
private:
string m_houseNumber;
LocalizedStreet m_street;
diff --git a/indexer/indexer_tests/editable_map_object_test.cpp b/indexer/indexer_tests/editable_map_object_test.cpp
index 059db03572..cfad66817d 100644
--- a/indexer/indexer_tests/editable_map_object_test.cpp
+++ b/indexer/indexer_tests/editable_map_object_test.cpp
@@ -6,6 +6,11 @@ namespace
{
using osm::EditableMapObject;
+int8_t const GetLangCode(char const * ch)
+{
+ return StringUtf8Multilang::GetLangIndex(ch);
+}
+
UNIT_TEST(EditableMapObject_SetWebsite)
{
EditableMapObject emo;
@@ -125,4 +130,98 @@ UNIT_TEST(EditableMapObject_ValidateEmail)
TEST(!EditableMapObject::ValidateEmail("emai@l_.ab"), ());
TEST(!EditableMapObject::ValidateEmail("email@e#$%&'*+-/=?^`_{}|~.com"), ());
}
+
+UNIT_TEST(EditableMapObject_CanUseAsDefaultName)
+{
+ EditableMapObject emo;
+ vector<int8_t> const nativeMwmLanguages {GetLangCode("de"), GetLangCode("fr")};
+
+ TEST(EditableMapObject::CanUseAsDefaultName(GetLangCode("de"), nativeMwmLanguages),
+ ("Check possibility to use Mwm language code"));
+ TEST(EditableMapObject::CanUseAsDefaultName(GetLangCode("fr"), nativeMwmLanguages),
+ ("Check possibility to use Mwm language code"));
+ TEST(!EditableMapObject::CanUseAsDefaultName(GetLangCode("int_name"), nativeMwmLanguages),
+ ("Check possibility to use international language code"));
+ TEST(!EditableMapObject::CanUseAsDefaultName(100, nativeMwmLanguages),
+ ("Incorrect language code is not supported"));
+ TEST(!EditableMapObject::CanUseAsDefaultName(GetLangCode("en"), {GetLangCode("abcd")}),
+ ("Incorrect Mwm language name is not supported"));
+ TEST(!EditableMapObject::CanUseAsDefaultName(GetLangCode("en"), nativeMwmLanguages),
+ ("Can not to use language which not Mwm language or international"));
+ TEST(!EditableMapObject::CanUseAsDefaultName(GetLangCode("ru"), nativeMwmLanguages),
+ ("Check possibility to use user`s language code"));
+
+ // Trying to use language codes in reverse priority.
+ StringUtf8Multilang names;
+ names.AddString(GetLangCode("fr"), "second mwm language");
+ emo.SetName(names);
+
+ TEST(EditableMapObject::CanUseAsDefaultName(GetLangCode("fr"), nativeMwmLanguages),
+ ("It is possible to fix typo"));
+
+ names.AddString(GetLangCode("de"), "first mwm language");
+ emo.SetName(names);
+
+ TEST(EditableMapObject::CanUseAsDefaultName(GetLangCode("de"), nativeMwmLanguages),
+ ("It is possible to fix typo"));
+ TEST(EditableMapObject::CanUseAsDefaultName(GetLangCode("fr"), nativeMwmLanguages),
+ ("It is possible to fix typo"));
+}
+
+UNIT_TEST(EditableMapObject_GetNamesDataSource)
+{
+ EditableMapObject emo;
+ StringUtf8Multilang names;
+
+ names.AddString(GetLangCode("default"), "Default name");
+ names.AddString(GetLangCode("en"), "Eng name");
+ names.AddString(GetLangCode("int_name"), "Int name");
+ names.AddString(GetLangCode("de"), "De name");
+ names.AddString(GetLangCode("ru"), "Ru name");
+ names.AddString(GetLangCode("sv"), "Sv name");
+ names.AddString(GetLangCode("be"), "By name");
+ names.AddString(GetLangCode("ko"), "Ko name");
+ names.AddString(GetLangCode("it"), "It name");
+ emo.SetName(names);
+
+ vector<int8_t> nativeMwmLanguages = {GetLangCode("de"), GetLangCode("fr")};
+
+ auto const namesDataSource =
+ EditableMapObject::GetNamesDataSource(emo.GetName(), nativeMwmLanguages, GetLangCode("ko"));
+
+ TEST_EQUAL(namesDataSource.names.size(), 9, ("All names except the default should be pushed into "
+ "data source plus empty mandatory names"));
+ TEST_EQUAL(namesDataSource.mandatoryNamesCount, 3,
+ ("Mandatory names count should be equal == Mwm languages + user`s language"));
+ TEST_EQUAL(namesDataSource.names[0].m_code, GetLangCode("de"),
+ ("Deutsch name should be first as first language in Mwm"));
+ TEST_EQUAL(namesDataSource.names[1].m_code, GetLangCode("fr"),
+ ("French name should be second as second language in Mwm"));
+ TEST_EQUAL(namesDataSource.names[2].m_code, GetLangCode("ko"),
+ ("Korean name should be third because user`s language should be followed by Mwm languages"));
+
+ {
+ vector<int8_t> nativeMwmLanguages = {GetLangCode("de"), GetLangCode("fr")};
+
+ auto const namesDataSource =
+ EditableMapObject::GetNamesDataSource(emo.GetName(), nativeMwmLanguages, GetLangCode("fr"));
+ TEST_EQUAL(namesDataSource.names.size(), 9,
+ ("All names except the default should be pushed into data source"));
+ TEST_EQUAL(namesDataSource.mandatoryNamesCount, 2,
+ ("Mandatory names count should be equal == Mwm languages + user`s language. "
+ "Excluding repetiton"));
+ }
+ {
+ vector<int8_t> nativeMwmLanguages = {GetLangCode("fr"), GetLangCode("fr")};
+
+ auto const namesDataSource =
+ EditableMapObject::GetNamesDataSource(emo.GetName(), nativeMwmLanguages, GetLangCode("fr"));
+ TEST_EQUAL(namesDataSource.names.size(), 9,
+ ("All names except the default should be pushed into "
+ "data source plus empty mandatory names"));
+ TEST_EQUAL(namesDataSource.mandatoryNamesCount, 1,
+ ("Mandatory names count should be equal == Mwm languages + user`s language. "
+ "Excluding repetiton"));
+ }
+}
} // namespace
diff --git a/indexer/osm_editor.cpp b/indexer/osm_editor.cpp
index 76e55a5197..1b428c35f0 100644
--- a/indexer/osm_editor.cpp
+++ b/indexer/osm_editor.cpp
@@ -426,6 +426,24 @@ bool Editor::IsCreatedFeature(FeatureID const & fid)
return fid.m_index >= kStartIndexForCreatedFeatures;
}
+bool Editor::OriginalFeatureHasDefaultName(FeatureID const & fid) const
+{
+ if (IsCreatedFeature(fid))
+ return false;
+
+ auto const originalFeaturePtr = m_getOriginalFeatureFn(fid);
+ if (!originalFeaturePtr)
+ {
+ LOG(LERROR, ("A feature with id", fid, "cannot be loaded."));
+ alohalytics::LogEvent("Editor_MissingFeature_Error");
+ return false;
+ }
+
+ auto const & names = originalFeaturePtr->GetNames();
+
+ return names.HasString(StringUtf8Multilang::kDefaultCode);
+}
+
/// Several cases should be handled while saving changes:
/// 1) a feature is not in editor's cache
/// I. a feature was created
diff --git a/indexer/osm_editor.hpp b/indexer/osm_editor.hpp
index a17da2477f..0ccfe8f264 100644
--- a/indexer/osm_editor.hpp
+++ b/indexer/osm_editor.hpp
@@ -169,6 +169,8 @@ public:
// Use GetFeatureStatus(fid) instead. This function is used when a feature is
// not yet saved and we have to know if it was modified or created.
static bool IsCreatedFeature(FeatureID const & fid);
+ // Returns true if the original feature has default name.
+ bool OriginalFeatureHasDefaultName(FeatureID const & fid) const;
private:
// TODO(AlexZ): Synchronize Save call/make it on a separate thread.