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:
-rw-r--r--android/jni/com/mapswithme/maps/editor/Editor.cpp27
-rw-r--r--android/res/layout/item_localized_name.xml4
-rw-r--r--android/res/layout/localized_name.xml37
-rw-r--r--android/src/com/mapswithme/maps/editor/Editor.java7
-rw-r--r--android/src/com/mapswithme/maps/editor/EditorFragment.java122
-rw-r--r--android/src/com/mapswithme/maps/editor/EditorHostFragment.java59
-rw-r--r--android/src/com/mapswithme/maps/editor/MultilanguageAdapter.java54
-rw-r--r--android/src/com/mapswithme/maps/editor/data/NamesDataSource.java27
-rw-r--r--coding/multilang_utf8_string.cpp5
-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
-rw-r--r--map/framework.cpp5
-rw-r--r--map/framework.hpp4
-rw-r--r--qt/editor_dialog.cpp4
17 files changed, 516 insertions, 138 deletions
diff --git a/android/jni/com/mapswithme/maps/editor/Editor.cpp b/android/jni/com/mapswithme/maps/editor/Editor.cpp
index 8b7c349cce..05361d78a3 100644
--- a/android/jni/com/mapswithme/maps/editor/Editor.cpp
+++ b/android/jni/com/mapswithme/maps/editor/Editor.cpp
@@ -33,6 +33,9 @@ jclass g_localStreetClazz;
jmethodID g_localStreetCtor;
jfieldID g_localStreetFieldDef;
jfieldID g_localStreetFieldLoc;
+jclass g_namesDataSourceClassID;
+jmethodID g_namesDataSourceConstructorID;
+
jobject ToJavaFeatureCategory(JNIEnv * env, osm::NewFeatureCategories::TName const & category)
{
@@ -85,6 +88,9 @@ Java_com_mapswithme_maps_editor_Editor_nativeInit(JNIEnv * env, jclass)
g_localStreetCtor = jni::GetConstructorID(env, g_localStreetClazz, "(Ljava/lang/String;Ljava/lang/String;)V");
g_localStreetFieldDef = env->GetFieldID(g_localStreetClazz, "defaultName", "Ljava/lang/String;");
g_localStreetFieldLoc = env->GetFieldID(g_localStreetClazz, "localizedName", "Ljava/lang/String;");
+
+ g_namesDataSourceClassID = jni::GetGlobalClassRef(env, "com/mapswithme/maps/editor/data/NamesDataSource");
+ g_namesDataSourceConstructorID = jni::GetConstructorID(env, g_namesDataSourceClassID, "([Lcom/mapswithme/maps/editor/data/LocalizedName;I)V");
}
JNIEXPORT jstring JNICALL
@@ -295,26 +301,19 @@ Java_com_mapswithme_maps_editor_Editor_nativeIsBuilding(JNIEnv * env, jclass cla
return g_editableMapObject.IsBuilding();
}
-JNIEXPORT jstring JNICALL
-Java_com_mapswithme_maps_editor_Editor_nativeGetDefaultName(JNIEnv * env, jclass)
+JNIEXPORT jobject JNICALL
+Java_com_mapswithme_maps_editor_Editor_nativeGetNamesDataSource(JNIEnv * env, jclass)
{
- return jni::ToJavaString(env, g_editableMapObject.GetDefaultName());
-}
+ auto const namesDataSource = g_editableMapObject.GetNamesDataSource();
-JNIEXPORT void JNICALL
-Java_com_mapswithme_maps_editor_Editor_nativeSetDefaultName(JNIEnv * env, jclass, jstring name)
-{
- g_editableMapObject.SetName(jni::ToNativeString(env, name), StringUtf8Multilang::kDefaultCode);
-}
+ jobjectArray names = jni::ToJavaArray(env, g_localNameClazz, namesDataSource.names, ToJavaName);
+ jint mandatoryNamesCount = namesDataSource.mandatoryNamesCount;
-JNIEXPORT jobjectArray JNICALL
-Java_com_mapswithme_maps_editor_Editor_nativeGetLocalizedNames(JNIEnv * env, jclass)
-{
- return jni::ToJavaArray(env, g_localNameClazz, g_editableMapObject.GetLocalizedNames(), ToJavaName);
+ return env->NewObject(g_namesDataSourceClassID, g_namesDataSourceConstructorID, names, mandatoryNamesCount);
}
JNIEXPORT void JNICALL
-Java_com_mapswithme_maps_editor_Editor_nativeSetLocalizedNames(JNIEnv * env, jclass, jobjectArray names)
+Java_com_mapswithme_maps_editor_Editor_nativeSetNames(JNIEnv * env, jclass, jobjectArray names)
{
int const length = env->GetArrayLength(names);
for (int i = 0; i < length; i++)
diff --git a/android/res/layout/item_localized_name.xml b/android/res/layout/item_localized_name.xml
index 3173863aa5..78db5817a0 100644
--- a/android/res/layout/item_localized_name.xml
+++ b/android/res/layout/item_localized_name.xml
@@ -8,7 +8,7 @@
android:gravity="center_vertical"
android:orientation="horizontal">
- <com.mapswithme.maps.widget.CustomTextInputLayout
+ <android.support.design.widget.TextInputLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
@@ -19,7 +19,7 @@
android:hint="@string/editor_edit_place_name_hint"
android:singleLine="true"/>
- </com.mapswithme.maps.widget.CustomTextInputLayout>
+ </android.support.design.widget.TextInputLayout>
<ImageButton
android:id="@+id/delete"
diff --git a/android/res/layout/localized_name.xml b/android/res/layout/localized_name.xml
index 00c99104f1..26471aa0ef 100644
--- a/android/res/layout/localized_name.xml
+++ b/android/res/layout/localized_name.xml
@@ -2,52 +2,47 @@
<!-- TODO set attr android:animateLayoutChanges="true"
when recyclerview-v7:23.2.1+ will be used.
RecyclerView of earlier versions doesn't have scrollTo method and hence crashes.-->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/margin_base"
android:orientation="vertical"
android:paddingEnd="@dimen/margin_base"
android:paddingLeft="@dimen/margin_base"
android:paddingRight="@dimen/margin_base"
android:paddingStart="@dimen/margin_base">
- <android.support.design.widget.TextInputLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <EditText
- android:id="@+id/input"
- style="@style/MwmWidget.Editor.FieldLayout.EditText"
- android:hint="@string/editor_edit_place_name_hint"
- android:singleLine="true"/>
-
- </android.support.design.widget.TextInputLayout>
-
<TextView
- android:id="@+id/show_langs"
+ android:id="@+id/show_additional_names"
android:layout_width="match_parent"
android:layout_height="@dimen/height_block_base"
android:background="?clickableBackground"
android:fontFamily="@string/robotoMedium"
android:gravity="center_vertical"
- android:text="@string/other_languages"
+ android:text="@string/editor_edit_place_name_hint"
android:textAppearance="@style/MwmTextAppearance.Body3"
tools:drawableRight="@drawable/ic_expand_more"
- tools:ignore="UnusedAttribute"/>
+ tools:ignore="UnusedAttribute" />
+
+ <include layout="@layout/recycler_default" />
- <include layout="@layout/recycler_default"/>
+ <TextView
+ android:id="@+id/more_names"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/height_block_base"
+ android:background="?clickableBackground"
+ android:gravity="center"
+ android:text="@string/placepage_more_button"
+ android:textAppearance="@style/MwmTextAppearance.Button" />
<TextView
android:id="@+id/add_langs"
android:layout_width="match_parent"
android:layout_height="@dimen/height_block_base"
android:background="?clickableBackground"
- android:gravity="center_vertical"
+ android:gravity="center"
android:text="@string/add_language"
- android:textAppearance="@style/MwmTextAppearance.Button"/>
+ android:textAppearance="@style/MwmTextAppearance.Button" />
</LinearLayout> \ No newline at end of file
diff --git a/android/src/com/mapswithme/maps/editor/Editor.java b/android/src/com/mapswithme/maps/editor/Editor.java
index 3bd5321189..ac879ad9e3 100644
--- a/android/src/com/mapswithme/maps/editor/Editor.java
+++ b/android/src/com/mapswithme/maps/editor/Editor.java
@@ -17,6 +17,7 @@ import com.mapswithme.maps.editor.data.FeatureCategory;
import com.mapswithme.maps.editor.data.Language;
import com.mapswithme.maps.editor.data.LocalizedName;
import com.mapswithme.maps.editor.data.LocalizedStreet;
+import com.mapswithme.maps.editor.data.NamesDataSource;
/**
@@ -101,10 +102,8 @@ public final class Editor
public static native boolean nativeIsNameEditable();
public static native boolean nativeIsBuilding();
- public static native String nativeGetDefaultName();
- public static native void nativeSetDefaultName(String name);
- public static native @NonNull LocalizedName[] nativeGetLocalizedNames();
- public static native void nativeSetLocalizedNames(@NonNull LocalizedName[] names);
+ public static native NamesDataSource nativeGetNamesDataSource();
+ public static native void nativeSetNames(@NonNull LocalizedName[] names);
public static native LocalizedName nativeMakeLocalizedName(String langCode, String name);
public static native Language[] nativeGetSupportedLanguages();
diff --git a/android/src/com/mapswithme/maps/editor/EditorFragment.java b/android/src/com/mapswithme/maps/editor/EditorFragment.java
index 8335e8f5c5..092c65c843 100644
--- a/android/src/com/mapswithme/maps/editor/EditorFragment.java
+++ b/android/src/com/mapswithme/maps/editor/EditorFragment.java
@@ -38,52 +38,51 @@ import org.solovyev.android.views.llm.LinearLayoutManager;
public class EditorFragment extends BaseMwmFragment implements View.OnClickListener, EditTextDialogFragment.OnTextSaveListener
{
- final static String LAST_LOCALIZED_NAME_INDEX = "LastLocalizedNameIndex";
+ final static String LAST_NAME_INDEX = "LastNameIndex";
private TextView mCategory;
- private View mCardName;
private View mCardAddress;
private View mCardMetadata;
- private EditText mName;
- private RecyclerView mLocalizedNames;
+ private RecyclerView mNamesView;
- private final RecyclerView.AdapterDataObserver mLocalizedNamesObserver = new RecyclerView.AdapterDataObserver()
+ private final RecyclerView.AdapterDataObserver mNamesObserver = new RecyclerView.AdapterDataObserver()
{
@Override
public void onChanged()
{
- refreshLocalizedNames();
+ refreshNamesCaption();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount)
{
- refreshLocalizedNames();
+ refreshNamesCaption();
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount)
{
- refreshLocalizedNames();
+ refreshNamesCaption();
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount)
{
- refreshLocalizedNames();
+ refreshNamesCaption();
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount)
{
- refreshLocalizedNames();
+ refreshNamesCaption();
}
};
- private MultilanguageAdapter mLocalizedNamesAdapter;
- private TextView mLocalizedShow;
- private boolean mIsLocalizedShown;
+ private MultilanguageAdapter mNamesAdapter;
+ private TextView mNamesCaption;
+ private TextView mAddLanguage;
+ private TextView mMoreLanguages;
private TextView mStreet;
private EditText mHouseNumber;
@@ -130,7 +129,6 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
initViews(view);
mCategory.setText(Editor.nativeGetCategory());
- mName.setText(Editor.nativeGetDefaultName());
final LocalizedStreet street = Editor.nativeGetStreet();
mStreet.setText(street.defaultName);
@@ -200,7 +198,6 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
refreshOpeningTime();
refreshEditableFields();
refreshResetButton();
- refreshLocalizedNames();
}
@Override
@@ -215,7 +212,6 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
if (!validateFields())
return false;
- Editor.nativeSetDefaultName(mName.getText().toString());
Editor.nativeSetHouseNumber(mHouseNumber.getText().toString());
Editor.nativeSetZipCode(mZipcode.getText().toString());
Editor.nativeSetBuildingLevels(mBuildingLevels.getText().toString());
@@ -224,7 +220,7 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
Editor.nativeSetEmail(mEmail.getText().toString());
Editor.nativeSetHasWifi(mWifi.isChecked());
Editor.nativeSetOperator(mOperator.getText().toString());
- Editor.nativeSetLocalizedNames(mParent.getLocalizedNamesAsArray());
+ Editor.nativeSetNames(mParent.getNamesAsArray());
return true;
}
@@ -287,7 +283,6 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
private void refreshEditableFields()
{
- UiUtils.showIf(Editor.nativeIsNameEditable(), mCardName);
UiUtils.showIf(Editor.nativeIsAddressEditable(), mCardAddress);
UiUtils.showIf(Editor.nativeIsBuilding(), mBlockLevels);
@@ -330,30 +325,35 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
}
}
- private void initLocalizedNameView(final View view)
+ private void initNamesView(final View view)
{
- mLocalizedNames = (RecyclerView) view.findViewById(R.id.recycler);
- mLocalizedNames.setNestedScrollingEnabled(false);
- mLocalizedNames.setLayoutManager(new LinearLayoutManager(getActivity()));
- mLocalizedNamesAdapter = new MultilanguageAdapter(mParent);
- mLocalizedNames.setAdapter(mLocalizedNamesAdapter);
- mLocalizedNamesAdapter.registerAdapterDataObserver(mLocalizedNamesObserver);
- refreshLocalizedNames();
+ mNamesCaption = (TextView) view.findViewById(R.id.show_additional_names);
+ mNamesCaption.setOnClickListener(this);
+ mAddLanguage = (TextView) view.findViewById(R.id.add_langs);
+ mAddLanguage.setOnClickListener(this);
+ mMoreLanguages = (TextView) view.findViewById(R.id.more_names);
+ mMoreLanguages.setOnClickListener(this);
+ mNamesView = (RecyclerView) view.findViewById(R.id.recycler);
+ mNamesView.setNestedScrollingEnabled(false);
+ mNamesView.setLayoutManager(new LinearLayoutManager(getActivity()));
+ mNamesAdapter = new MultilanguageAdapter(mParent);
+ mNamesView.setAdapter(mNamesAdapter);
+ mNamesAdapter.registerAdapterDataObserver(mNamesObserver);
final Bundle args = getArguments();
- if (args == null || !args.containsKey(LAST_LOCALIZED_NAME_INDEX))
+ if (args == null || !args.containsKey(LAST_NAME_INDEX))
{
- showLocalizedNames(false);
+ showAdditionalNames(false);
return;
}
- showLocalizedNames(true);
- UiUtils.waitLayout(mLocalizedNames, new ViewTreeObserver.OnGlobalLayoutListener()
+ showAdditionalNames(true);
+ UiUtils.waitLayout(mNamesView, new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout()
{
- LinearLayoutManager lm = (LinearLayoutManager) mLocalizedNames.getLayoutManager();
- int position = args.getInt(LAST_LOCALIZED_NAME_INDEX);
+ LinearLayoutManager lm = (LinearLayoutManager) mNamesView.getLayoutManager();
+ int position = args.getInt(LAST_NAME_INDEX);
View nameItem = lm.findViewByPosition(position);
@@ -378,14 +378,9 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
// TODO show icon and fill it when core will implement that
UiUtils.hide(categoryBlock.findViewById(R.id.icon));
mCategory = (TextView) categoryBlock.findViewById(R.id.name);
- mCardName = view.findViewById(R.id.cv__name);
mCardAddress = view.findViewById(R.id.cv__address);
mCardMetadata = view.findViewById(R.id.cv__metadata);
- mName = findInput(mCardName);
- view.findViewById(R.id.add_langs).setOnClickListener(this);
- mLocalizedShow = (TextView) view.findViewById(R.id.show_langs);
- mLocalizedShow.setOnClickListener(this);
- initLocalizedNameView(view);
+ initNamesView(view);
// Address
view.findViewById(R.id.block_street).setOnClickListener(this);
@@ -484,11 +479,12 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
case R.id.category:
mParent.editCategory();
break;
- case R.id.show_langs:
- showLocalizedNames(!mIsLocalizedShown);
+ case R.id.more_names:
+ case R.id.show_additional_names:
+ showAdditionalNames(!mNamesAdapter.areAdditionalLanguagesShown());
break;
case R.id.add_langs:
- mParent.addLocalizedLanguage();
+ mParent.addLanguage();
break;
case R.id.about_osm:
startActivity(new Intent((Intent.ACTION_VIEW), Uri.parse(Constants.Url.OSM_ABOUT)));
@@ -499,29 +495,43 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe
}
}
- private void refreshLocalizedNames()
+ private void showAdditionalNames(boolean show)
{
- UiUtils.showIf(mLocalizedNamesAdapter.getItemCount() > 0, mLocalizedShow);
+ mNamesAdapter.showAdditionalLanguages(show);
+
+ refreshNamesCaption();
}
- private void showLocalizedNames(boolean show)
+ private void refreshNamesCaption()
{
- mIsLocalizedShown = show;
- if (show)
- {
- UiUtils.show(mLocalizedNames);
- setLocalizedShowDrawable(R.drawable.ic_expand_less);
- }
+ if (mNamesAdapter.getNamesCount() <= mNamesAdapter.getMandatoryNamesCount())
+ setNamesArrowDrawable(null);
+ else if (mNamesAdapter.areAdditionalLanguagesShown())
+ setNamesArrowDrawable(R.drawable.ic_expand_less);
else
- {
- UiUtils.hide(mLocalizedNames);
- setLocalizedShowDrawable(R.drawable.ic_expand_more);
- }
+ setNamesArrowDrawable(R.drawable.ic_expand_more);
+
+ boolean showAddLanguage = mNamesAdapter.getNamesCount() <= mNamesAdapter.getMandatoryNamesCount() ||
+ mNamesAdapter.areAdditionalLanguagesShown();
+
+ UiUtils.showIf(showAddLanguage, mAddLanguage);
+ UiUtils.showIf(!showAddLanguage, mMoreLanguages);
+
}
- private void setLocalizedShowDrawable(@DrawableRes int right)
+ private void setNamesArrowDrawable(@DrawableRes Integer right)
{
- mLocalizedShow.setCompoundDrawablesWithIntrinsicBounds(null, null, Graphics.tint(getActivity(), right, R.attr.iconTint), null);
+ if(null == right)
+ {
+ mNamesCaption.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
+ return;
+ }
+
+ mNamesCaption.setCompoundDrawablesWithIntrinsicBounds(
+ null,
+ null,
+ Graphics.tint(getActivity(), right, R.attr.iconTint),
+ null);
}
private void refreshResetButton()
diff --git a/android/src/com/mapswithme/maps/editor/EditorHostFragment.java b/android/src/com/mapswithme/maps/editor/EditorHostFragment.java
index 116d900d61..cbc1f99547 100644
--- a/android/src/com/mapswithme/maps/editor/EditorHostFragment.java
+++ b/android/src/com/mapswithme/maps/editor/EditorHostFragment.java
@@ -25,6 +25,7 @@ import com.mapswithme.util.ConnectionState;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.Utils;
import com.mapswithme.util.statistics.Statistics;
+import com.mapswithme.maps.editor.data.NamesDataSource;
import java.util.ArrayList;
import java.util.List;
@@ -48,29 +49,33 @@ public class EditorHostFragment extends BaseMwmToolbarFragment
/**
* A list of localized names added by a user and those that were in metadata.
*/
- private static final List<LocalizedName> sLocalizedNames = new ArrayList<>();
+ private static final List<LocalizedName> sNames = new ArrayList<>();
+ /**
+ * Count of names which should always be shown.
+ */
+ private int mMandatoryNamesCount = 0;
/**
* Used in MultilanguageAdapter to show, select and remove items.
*/
- List<LocalizedName> getLocalizedNames()
+ List<LocalizedName> getNames()
{
- return sLocalizedNames;
+ return sNames;
}
- public LocalizedName[] getLocalizedNamesAsArray()
+ public LocalizedName[] getNamesAsArray()
{
- return sLocalizedNames.toArray(new LocalizedName[sLocalizedNames.size()]);
+ return sNames.toArray(new LocalizedName[sNames.size()]);
}
- void setLocalizedNames(LocalizedName[] names)
+ void setNames(LocalizedName[] names)
{
- sLocalizedNames.clear();
+ sNames.clear();
for (LocalizedName name : names)
{
if (name.code == LocalizedName.DEFAULT_LANG_CODE)
continue;
- sLocalizedNames.add(name);
+ sNames.add(name);
}
}
@@ -79,12 +84,22 @@ public class EditorHostFragment extends BaseMwmToolbarFragment
*/
void setName(String name, int index)
{
- sLocalizedNames.get(index).name = name;
+ sNames.get(index).name = name;
+ }
+
+ void addName(LocalizedName name)
+ {
+ sNames.add(name);
+ }
+
+ public int getMandatoryNamesCount()
+ {
+ return mMandatoryNamesCount;
}
- void addLocalizedName(LocalizedName name)
+ public void setMandatoryNamesCount(int mandatoryNamesCount)
{
- sLocalizedNames.add(name);
+ mMandatoryNamesCount = mandatoryNamesCount;
}
@Nullable
@@ -112,7 +127,9 @@ public class EditorHostFragment extends BaseMwmToolbarFragment
mIsNewObject = getArguments().getBoolean(EditorActivity.EXTRA_NEW_OBJECT, false);
mToolbarController.setTitle(getTitle());
- setLocalizedNames(Editor.nativeGetLocalizedNames());
+ NamesDataSource namesDataSource = Editor.nativeGetNamesDataSource();
+ setNames(namesDataSource.getNames());
+ setMandatoryNamesCount(namesDataSource.getMandatoryNamesCount());
editMapObject();
}
@@ -153,17 +170,17 @@ public class EditorHostFragment extends BaseMwmToolbarFragment
protected void editMapObject()
{
- editMapObject(false /* focusToLastLocalizedName */);
+ editMapObject(false /* focusToLastName */);
}
- protected void editMapObject(boolean focusToLastLocalizedName)
+ protected void editMapObject(boolean focusToLastName)
{
mMode = Mode.MAP_OBJECT;
((SearchToolbarController) mToolbarController).showControls(false);
mToolbarController.setTitle(getTitle());
Bundle args = new Bundle();
- if (focusToLastLocalizedName)
- args.putInt(EditorFragment.LAST_LOCALIZED_NAME_INDEX, sLocalizedNames.size() - 1);
+ if (focusToLastName)
+ args.putInt(EditorFragment.LAST_NAME_INDEX, sNames.size() - 1);
final Fragment editorFragment = Fragment.instantiate(getActivity(), EditorFragment.class.getName(), args);
getChildFragmentManager().beginTransaction()
.replace(R.id.fragment_container, editorFragment, EditorFragment.class.getName())
@@ -187,11 +204,11 @@ public class EditorHostFragment extends BaseMwmToolbarFragment
editWithFragment(Mode.CUISINE, R.string.select_cuisine, null, CuisineFragment.class, true);
}
- protected void addLocalizedLanguage()
+ protected void addLanguage()
{
Bundle args = new Bundle();
- ArrayList<String> languages = new ArrayList<>(sLocalizedNames.size());
- for (LocalizedName name : sLocalizedNames)
+ ArrayList<String> languages = new ArrayList<>(sNames.size());
+ for (LocalizedName name : sNames)
languages.add(name.lang);
args.putStringArrayList(LanguagesFragment.EXISTING_LOCALIZED_NAMES, languages);
editWithFragment(Mode.LANGUAGE, R.string.choose_language, args, LanguagesFragment.class, false);
@@ -314,7 +331,7 @@ public class EditorHostFragment extends BaseMwmToolbarFragment
@Override
public void onLanguageSelected(Language lang)
{
- addLocalizedName(Editor.nativeMakeLocalizedName(lang.code, ""));
- editMapObject(true /* focusToLastLocalizedName */);
+ addName(Editor.nativeMakeLocalizedName(lang.code, ""));
+ editMapObject(true /* focusToLastName */);
}
}
diff --git a/android/src/com/mapswithme/maps/editor/MultilanguageAdapter.java b/android/src/com/mapswithme/maps/editor/MultilanguageAdapter.java
index 4fc1eca797..7118b66ef3 100644
--- a/android/src/com/mapswithme/maps/editor/MultilanguageAdapter.java
+++ b/android/src/com/mapswithme/maps/editor/MultilanguageAdapter.java
@@ -1,28 +1,29 @@
package com.mapswithme.maps.editor;
+import android.support.design.widget.TextInputLayout;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
+import java.util.List;
+
import com.mapswithme.maps.R;
import com.mapswithme.maps.editor.data.LocalizedName;
import com.mapswithme.util.StringUtils;
import com.mapswithme.util.UiUtils;
-import java.util.List;
-
public class MultilanguageAdapter extends RecyclerView.Adapter<MultilanguageAdapter.Holder>
{
private final List<LocalizedName> mNames;
- private EditorHostFragment mHostFragment;
+ private int mMandatoryNamesCount;
+ private boolean mAdditionalLanguagesShown;
- // TODO(mgsergio): Refactor: don't pass the whole EditorHostFragment.
MultilanguageAdapter(EditorHostFragment hostFragment)
{
- mHostFragment = hostFragment;
- mNames = hostFragment.getLocalizedNames();
+ mNames = hostFragment.getNames();
+ mMandatoryNamesCount = hostFragment.getMandatoryNamesCount();
}
@Override
@@ -39,29 +40,66 @@ public class MultilanguageAdapter extends RecyclerView.Adapter<MultilanguageAdap
{
LocalizedName name = mNames.get(position);
holder.input.setText(name.name);
- holder.input.setHint(name.lang);
+ holder.inputLayout.setHint(name.langName);
}
@Override
public int getItemCount()
{
+ return mAdditionalLanguagesShown ? mNames.size() : mMandatoryNamesCount;
+ }
+
+ public int getNamesCount()
+ {
return mNames.size();
}
+ public int getMandatoryNamesCount()
+ {
+ return mMandatoryNamesCount;
+ }
+
+ public boolean areAdditionalLanguagesShown()
+ {
+ return mAdditionalLanguagesShown;
+ }
+
+ public void showAdditionalLanguages(boolean showAdditionalLanguages)
+ {
+ if(mAdditionalLanguagesShown == showAdditionalLanguages)
+ return;
+
+ mAdditionalLanguagesShown = showAdditionalLanguages;
+
+ if(mNames.size() != mMandatoryNamesCount)
+ {
+ if(showAdditionalLanguages)
+ {
+ notifyItemRangeInserted(mMandatoryNamesCount , mNames.size() - mMandatoryNamesCount);
+ }
+ else
+ {
+ notifyItemRangeRemoved(mMandatoryNamesCount, mNames.size() - mMandatoryNamesCount);
+ }
+ }
+ }
+
public class Holder extends RecyclerView.ViewHolder
{
EditText input;
+ TextInputLayout inputLayout;
public Holder(View itemView)
{
super(itemView);
input = (EditText) itemView.findViewById(R.id.input);
+ inputLayout = (TextInputLayout) input.getParent();
input.addTextChangedListener(new StringUtils.SimpleTextWatcher()
{
@Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
- mHostFragment.setName(s.toString(), getAdapterPosition());
+ mNames.get(getAdapterPosition()).name = s.toString();
}
});
diff --git a/android/src/com/mapswithme/maps/editor/data/NamesDataSource.java b/android/src/com/mapswithme/maps/editor/data/NamesDataSource.java
new file mode 100644
index 0000000000..c7f0fb0caa
--- /dev/null
+++ b/android/src/com/mapswithme/maps/editor/data/NamesDataSource.java
@@ -0,0 +1,27 @@
+package com.mapswithme.maps.editor.data;
+
+/**
+ * Class which contains array 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.
+ */
+public class NamesDataSource {
+ private LocalizedName[] mNames;
+ private int mMandatoryNamesCount;
+
+ public NamesDataSource(LocalizedName[] names, int mandatoryNamesCount) {
+ this.mNames = names;
+ this.mMandatoryNamesCount = mandatoryNamesCount;
+ }
+
+ public LocalizedName[] getNames() {
+ return mNames;
+ }
+
+ public int getMandatoryNamesCount() {
+ return mMandatoryNamesCount;
+ }
+}
diff --git a/coding/multilang_utf8_string.cpp b/coding/multilang_utf8_string.cpp
index 9c5ddc0c78..1f447eb482 100644
--- a/coding/multilang_utf8_string.cpp
+++ b/coding/multilang_utf8_string.cpp
@@ -28,6 +28,11 @@ StringUtf8Multilang::Languages const g_languages = {{ {"default", "Native for ea
}};
} // namespace
+int8_t constexpr StringUtf8Multilang::kUnsupportedLanguageCode;
+int8_t constexpr StringUtf8Multilang::kDefaultCode;
+int8_t constexpr StringUtf8Multilang::kEnglishCode;
+int8_t constexpr StringUtf8Multilang::kInternationalCode;
+
// static
StringUtf8Multilang::Languages const & StringUtf8Multilang::GetSupportedLanguages()
{
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.
diff --git a/map/framework.cpp b/map/framework.cpp
index 812761b6c2..3b37cce69d 100644
--- a/map/framework.cpp
+++ b/map/framework.cpp
@@ -3006,3 +3006,8 @@ void Framework::CreateNote(ms::LatLon const & latLon, FeatureID const & fid,
if (type == osm::Editor::NoteProblemType::PlaceDoesNotExist)
DeactivateMapSelection(true /* notifyUI */);
}
+
+bool Framework::WasDefaultNameSaved(FeatureID const & fid) const
+{
+ return osm::Editor::Instance().WasDefaultNameSaved(fid);
+}
diff --git a/map/framework.hpp b/map/framework.hpp
index 33888c5837..eae9ec20a8 100644
--- a/map/framework.hpp
+++ b/map/framework.hpp
@@ -715,5 +715,9 @@ private:
editor::UserStatsLoader m_userStatsLoader;
//@}
+public:
+ bool WasDefaultNameSaved(FeatureID const & fid) const;
+
+private:
DECLARE_THREAD_CHECKER(m_threadChecker);
};
diff --git a/qt/editor_dialog.cpp b/qt/editor_dialog.cpp
index f9e39a5eea..61856dbc16 100644
--- a/qt/editor_dialog.cpp
+++ b/qt/editor_dialog.cpp
@@ -60,7 +60,9 @@ EditorDialog::EditorDialog(QWidget * parent, osm::EditableMapObject & emo)
int namesRow = 0;
namesGrid->addWidget(defaultName, namesRow++, 0, 1, 0);
- for (osm::LocalizedName const & ln : emo.GetLocalizedNames())
+ auto const namesDataSource = emo.GetNamesDataSource();
+
+ for (osm::LocalizedName const & ln : namesDataSource.names)
{
if (ln.m_code == StringUtf8Multilang::kDefaultCode)
{