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:
authorArsentiy Milchakov <a.milchakov@corp.mail.ru>2016-07-15 20:16:41 +0300
committerArsentiy Milchakov <a.milchakov@corp.mail.ru>2016-07-19 14:43:41 +0300
commitfe4ccf09c2c21d9b1499429f5531b765d9c928e2 (patch)
tree96aab836723ffd13cf44e4adf954c63a02513c26 /indexer
parent751e6ea7a91f0ba8e9248206a61721137504946c (diff)
Direct editing of default name is locked, editing of multilingual names is allowed, changes for android are included
Diffstat (limited to 'indexer')
-rw-r--r--indexer/editable_map_object.cpp145
-rw-r--r--indexer/editable_map_object.hpp33
-rw-r--r--indexer/indexer_tests/editable_map_object_test.cpp100
-rw-r--r--indexer/osm_editor.cpp19
-rw-r--r--indexer/osm_editor.hpp2
5 files changed, 288 insertions, 11 deletions
diff --git a/indexer/editable_map_object.cpp b/indexer/editable_map_object.cpp
index 164705edcf..3515027f97 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,54 @@
#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<string> const & mwmLanguages, vector<osm::LocalizedName> & result)
+{
+ size_t count = 0;
+ auto langCode = StringUtf8Multilang::kUnsupportedLanguageCode;
+ static size_t const kMaxCountMwmLanguages = 2;
+
+ for (auto const & language : mwmLanguages)
+ {
+ langCode = StringUtf8Multilang::GetLangIndex(language);
+ if (ExtractName(names, langCode, result))
+ ++count;
+
+ if (count >= kMaxCountMwmLanguages)
+ return count;
+ }
+
+ return count;
+}
+}
+
namespace osm
{
// LocalizedName -----------------------------------------------------------------------------------
@@ -49,14 +98,49 @@ 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;
- });
+ return GetNamesDataSource(m_name, GetMwmLanguages(), languages::GetCurrentNorm());
+}
+
+// static
+NamesDataSource EditableMapObject::GetNamesDataSource(StringUtf8Multilang const & source,
+ vector<string> const & nativeMwmLanguages,
+ string const & userLanguage)
+{
+ NamesDataSource result;
+ auto & names = result.names;
+ auto & mandatoryCount = result.mandatoryNamesCount;
+ // Push Mwm languages.
+ mandatoryCount = PushMwmLanguages(source, nativeMwmLanguages, names);
+
+ // Push user's language.
+ auto const langCode = StringUtf8Multilang::GetLangIndex(userLanguage);
+ if (ExtractName(source, langCode, names))
+ ++mandatoryCount;
+
+ // Push international language.
+ if (ExtractName(source, StringUtf8Multilang::kInternationalCode, names))
+ ++mandatoryCount;
+
+ // Push other languages.
+ source.ForEach([&names, mandatoryCount](int8_t code, string const & name) -> bool {
+ // Exclude default name.
+ if (StringUtf8Multilang::kDefaultCode == code)
+ return true;
+
+ auto const mandatoryNamesEnd = names.begin() + mandatoryCount;
+ // Exclude languages which 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 +167,49 @@ 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,
+ ("You trying to set ", name,
+ " as default, but direct editing of default name is deprecated."));
+
+ if (!Editor::Instance().WasDefaultNameSaved(GetID()) &&
+ CanUseAsDefaultName(langCode, m_name, GetMwmLanguages()))
+ {
+ m_name.AddString(StringUtf8Multilang::kDefaultCode, name);
+ }
+
+ m_name.AddString(langCode, name);
+}
+
+// static
+bool EditableMapObject::CanUseAsDefaultName(int8_t const langCode, StringUtf8Multilang const & name,
+ vector<string> const & nativeMwmLanguages)
+{
+ auto index = StringUtf8Multilang::kUnsupportedLanguageCode;
+ string unused;
+
+ // Languages priority: 1. Mwm languages 2. International language.
+ for (auto const & language : nativeMwmLanguages)
+ {
+ index = StringUtf8Multilang::GetLangIndex(language);
+
+ if (StringUtf8Multilang::kUnsupportedLanguageCode == index)
+ return false;
+
+ if (langCode == index)
+ return true;
+
+ // A name with a higher priority was added already.
+ if (name.GetString(index, unused))
+ return false;
+ }
+
+ if (langCode == StringUtf8Multilang::kInternationalCode)
+ 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..e89aa543ad 100644
--- a/indexer/editable_map_object.hpp
+++ b/indexer/editable_map_object.hpp
@@ -46,6 +46,18 @@ 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. International name
+// 4. 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 +79,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 +130,24 @@ public:
static bool ValidateWebsite(string const & site);
static bool ValidateEmail(string const & email);
+ // TODO dummy, should be removed.
+ static vector<string> const & GetMwmLanguages()
+ {
+ static vector<string> const kNativelanguagesForMwm = {"de", "fr"};
+
+ return kNativelanguagesForMwm;
+ }
+ // TODO dummy, should be removed.
+
+ // Check whether langCode can be used as default name.
+ static bool CanUseAsDefaultName(int8_t const langCode, StringUtf8Multilang const & name,
+ vector<string> const & nativeMwmLanguages);
+
+ // See comment for NamesDataSource class.
+ static NamesDataSource GetNamesDataSource(StringUtf8Multilang const & source,
+ vector<string> const & nativeMwmLanguages,
+ string 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..d281221726 100644
--- a/indexer/indexer_tests/editable_map_object_test.cpp
+++ b/indexer/indexer_tests/editable_map_object_test.cpp
@@ -125,4 +125,104 @@ UNIT_TEST(EditableMapObject_ValidateEmail)
TEST(!EditableMapObject::ValidateEmail("emai@l_.ab"), ());
TEST(!EditableMapObject::ValidateEmail("email@e#$%&'*+-/=?^`_{}|~.com"), ());
}
+
+UNIT_TEST(EditableMapObject_CanUseAsDefaultName)
+{
+ EditableMapObject emo;
+
+ TEST(EditableMapObject::CanUseAsDefaultName(StringUtf8Multilang::GetLangIndex("de"), emo.GetName(), {"de", "fr"}),
+ ("Check possibility to use Mwm language code"));
+ TEST(EditableMapObject::CanUseAsDefaultName(StringUtf8Multilang::GetLangIndex("fr"), emo.GetName(), {"de", "fr"}),
+ ("Check possibility to use Mwm language code"));
+ TEST(EditableMapObject::CanUseAsDefaultName(StringUtf8Multilang::GetLangIndex("int_name"), emo.GetName(), {"de", "fr"}),
+ ("Check possibility to use international language code"));
+
+ TEST(!EditableMapObject::CanUseAsDefaultName(100, emo.GetName(), {"de", "fr"}),
+ ("Incorrect language code is not supported"));
+ TEST(!EditableMapObject::CanUseAsDefaultName(StringUtf8Multilang::GetLangIndex("en"), emo.GetName(), {"abcd"}),
+ ("Incorrect Mwm language name is not supported"));
+ TEST(!EditableMapObject::CanUseAsDefaultName(StringUtf8Multilang::GetLangIndex("en"), emo.GetName(), {"de", "fr"}),
+ ("Can not to use language which not Mwm language or international"));
+ TEST(!EditableMapObject::CanUseAsDefaultName(StringUtf8Multilang::GetLangIndex("ru"), emo.GetName(), {"de", "fr"}),
+ ("Check possibility to use user`s language code"));
+
+ // Trying to use language codes in reverse priority.
+ StringUtf8Multilang names;
+ names.AddString(StringUtf8Multilang::GetLangIndex("int_name"), "international name");
+ emo.SetName(names);
+
+ TEST(EditableMapObject::CanUseAsDefaultName(StringUtf8Multilang::GetLangIndex("int_name"), emo.GetName(), {"de", "fr"}),
+ ("It is possible to fix typo for international language"));
+
+ names.AddString(StringUtf8Multilang::GetLangIndex("fr"), "second mwm language");
+ emo.SetName(names);
+
+ TEST(EditableMapObject::CanUseAsDefaultName(StringUtf8Multilang::GetLangIndex("fr"), emo.GetName(), {"de", "fr"}),
+ ("It is possible to fix typo"));
+ TEST(!EditableMapObject::CanUseAsDefaultName(StringUtf8Multilang::GetLangIndex("int_name"), emo.GetName(), {"de", "fr"}),
+ ("Name on language with high priority was already entered"));
+
+ names.AddString(StringUtf8Multilang::GetLangIndex("de"), "first mwm language");
+ emo.SetName(names);
+
+ TEST(EditableMapObject::CanUseAsDefaultName(StringUtf8Multilang::GetLangIndex("de"), emo.GetName(), {"de", "fr"}),
+ ("It is possible to fix typo"));
+ TEST(!EditableMapObject::CanUseAsDefaultName(StringUtf8Multilang::GetLangIndex("fr"), emo.GetName(), {"de", "fr"}),
+ ("Name on language with high priority was already entered"));
+ TEST(!EditableMapObject::CanUseAsDefaultName(StringUtf8Multilang::GetLangIndex("int_name"), emo.GetName(), {"de", "fr"}),
+ ("Name on language with high priority was already entered"));
+}
+
+UNIT_TEST(EditableMapObject_GetNamesDataSource)
+{
+ EditableMapObject emo;
+ StringUtf8Multilang names;
+ names.AddString(0, "Default name");
+ names.AddString(1, "Eng name");
+ names.AddString(7, "Int name");
+ names.AddString(6, "De name");
+ names.AddString(8, "Ru name");
+ names.AddString(9, "Sv name");
+ names.AddString(12, "By name");
+ names.AddString(14, "Ko name");
+ names.AddString(20, "It name");
+ emo.SetName(names);
+
+ auto const namesDataSource =
+ EditableMapObject::GetNamesDataSource(emo.GetName(), {"de", "fr"}, "ko");
+
+ TEST(namesDataSource.names.size() == 9, ("All names except the default should be pushed into "
+ "data source plus empty mandatory names"));
+ TEST(namesDataSource.mandatoryNamesCount == 4,
+ ("Mandatory names count should be equal == Mwm languages + user`s language + international "
+ "language"));
+ TEST(namesDataSource.names[0].m_code == 6 /*de*/,
+ ("Deutsch name should be first as first language in Mwm"));
+ TEST(namesDataSource.names[1].m_code == 3 /*fr*/,
+ ("French name should be second as second language in Mwm"));
+ TEST(namesDataSource.names[2].m_code == 14 /*ko*/,
+ ("Korean name should be third because user`s language should be followed by Mwm languages"));
+ TEST(namesDataSource.names[3].m_code == 7 /*int*/,
+ ("International name should be fourth because International language should be followed by "
+ "user`s language"));
+
+ {
+ auto const namesDataSource =
+ EditableMapObject::GetNamesDataSource(emo.GetName(), {"int_name"}, "int_name");
+ TEST(namesDataSource.names.size() == 8,
+ ("All names except the default should be pushed into data source"));
+ TEST(namesDataSource.mandatoryNamesCount == 1,
+ ("Mandatory names count should be equal == Mwm languages + user`s language + "
+ "international language. Excluding repetiton"));
+ }
+ {
+ auto const namesDataSource =
+ EditableMapObject::GetNamesDataSource(emo.GetName(), {"fr", "fr"}, "fr");
+ TEST(namesDataSource.names.size() == 9, ("All names except the default should be pushed into "
+ "data source plus empty mandatory names"));
+ TEST(namesDataSource.mandatoryNamesCount == 2,
+ ("Mandatory names count should be equal == Mwm languages + user`s language + "
+ "international language. Excluding repetiton"));
+ }
+}
} // namespace
diff --git a/indexer/osm_editor.cpp b/indexer/osm_editor.cpp
index b98f934c7c..6c9ac30912 100644
--- a/indexer/osm_editor.cpp
+++ b/indexer/osm_editor.cpp
@@ -426,6 +426,25 @@ bool Editor::IsCreatedFeature(FeatureID const & fid)
return fid.m_index >= kStartIndexForCreatedFeatures;
}
+bool Editor::WasDefaultNameSaved(FeatureID const & fid) const
+{
+ if (IsCreatedFeature(fid))
+ return false;
+
+ if (FeatureStatus::Created == GetFeatureStatus(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;
+ }
+
+ return originalFeaturePtr->HasName();
+}
+
/// 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 109b089600..d11ff810be 100644
--- a/indexer/osm_editor.hpp
+++ b/indexer/osm_editor.hpp
@@ -167,6 +167,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 in case when original feature from mwm has default name
+ bool WasDefaultNameSaved(FeatureID const & fid) const;
private:
// TODO(AlexZ): Synchronize Save call/make it on a separate thread.