7375eb3cba8627c4b80f8c26887c47c42ca741f9
[platform/framework/web/crosswalk.git] / src / chrome / android / java / src / org / chromium / chrome / browser / infobar / TranslateLanguagePanel.java
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.infobar;
6
7 import android.content.Context;
8 import android.graphics.Color;
9 import android.text.SpannableString;
10 import android.text.TextUtils;
11 import android.text.style.ForegroundColorSpan;
12 import android.view.LayoutInflater;
13 import android.view.View;
14 import android.view.ViewGroup;
15 import android.widget.AdapterView;
16 import android.widget.ArrayAdapter;
17 import android.widget.FrameLayout;
18 import android.widget.Spinner;
19 import android.widget.TextView;
20
21 import org.chromium.chrome.R;
22
23 import java.util.ArrayList;
24 import java.util.List;
25
26 /**
27  * Language panel shown in the translate infobar.
28  */
29 public class TranslateLanguagePanel
30         implements TranslateSubPanel, AdapterView.OnItemSelectedListener {
31
32     private static final int LANGUAGE_TYPE_SOURCE = 0;
33     private static final int LANGUAGE_TYPE_TARGET = 1;
34
35     // UI elements.
36     private Spinner mSourceSpinner;
37     private Spinner mTargetSpinner;
38
39     // Items that are not interacted with.
40     // Provided by the caller, the new languages will be set here if the user
41     // clicks "done".
42     private final TranslateOptions mOptions;
43
44     // This object will be used to keep the state for the time the
45     // panel is opened it can be totally discarded in the end if the user
46     // clicks "cancel".
47     private final TranslateOptions mSessionOptions;
48
49     private LanguageArrayAdapter mSourceAdapter;
50     private LanguageArrayAdapter mTargetAdapter;
51
52     private final SubPanelListener mListener;
53
54     /**
55      * Display language drop downs so they can be picked as source or
56      * target for a translation.
57      *
58      * @param listener triggered when the panel is closed
59      * @param options will be modified with the new languages selected.
60      */
61     public TranslateLanguagePanel(SubPanelListener listener, TranslateOptions options) {
62         mListener = listener;
63         mOptions = options;
64         mSessionOptions = new TranslateOptions(mOptions);
65     }
66
67     @Override
68     public void createContent(Context context, InfoBarLayout layout) {
69         mSourceSpinner = null;
70         mTargetSpinner = null;
71
72         String changeLanguage = context.getString(R.string.translate_infobar_change_languages);
73         TextView panelMessage = (TextView) layout.findViewById(R.id.infobar_message);
74         panelMessage.setText(changeLanguage);
75
76         // Set up the spinners.
77         createSpinners(context);
78         layout.addGroup(mSourceSpinner, mTargetSpinner);
79
80         // Set up the buttons.
81         layout.addButtons(context.getString(R.string.translate_button_done),
82                 context.getString(R.string.cancel));
83     }
84
85     @Override
86     public void onButtonClicked(boolean primary) {
87         if (primary) {
88             mOptions.setSourceLanguage(mSessionOptions.sourceLanguageIndex());
89             mOptions.setTargetLanguage(mSessionOptions.targetLanguageIndex());
90         }
91         mListener.onPanelClosed(InfoBar.ACTION_TYPE_NONE);
92     }
93
94     private void createSpinners(Context context) {
95         mSourceAdapter = new LanguageArrayAdapter(context, R.layout.translate_spinner,
96                 LANGUAGE_TYPE_SOURCE);
97         mTargetAdapter = new LanguageArrayAdapter(context, R.layout.translate_spinner,
98                 LANGUAGE_TYPE_TARGET);
99
100         // Determine how wide each spinner needs to be to avoid truncating its children.
101         mSourceAdapter.addAll(createSpinnerLanguages(-1));
102         mTargetAdapter.addAll(createSpinnerLanguages(-1));
103         mSourceAdapter.measureWidthRequiredForView();
104         mTargetAdapter.measureWidthRequiredForView();
105
106         // Create the spinners.
107         mSourceSpinner = new Spinner(context);
108         mTargetSpinner = new Spinner(context);
109         mSourceSpinner.setOnItemSelectedListener(this);
110         mTargetSpinner.setOnItemSelectedListener(this);
111         mSourceSpinner.setAdapter(mSourceAdapter);
112         mTargetSpinner.setAdapter(mTargetAdapter);
113         reloadSpinners();
114     }
115
116     private void reloadSpinners() {
117         mSourceAdapter.clear();
118         mTargetAdapter.clear();
119
120         int sourceAvoidLanguage = mSessionOptions.targetLanguageIndex();
121         int targetAvoidLanguage = mSessionOptions.sourceLanguageIndex();
122         mSourceAdapter.addAll(createSpinnerLanguages(sourceAvoidLanguage));
123         mTargetAdapter.addAll(createSpinnerLanguages(targetAvoidLanguage));
124
125         int originalSourceSelection = mSourceSpinner.getSelectedItemPosition();
126         int newSourceSelection = getSelectionPosition(LANGUAGE_TYPE_SOURCE);
127         if (originalSourceSelection != newSourceSelection)
128             mSourceSpinner.setSelection(newSourceSelection);
129
130         int originalTargetSelection = mTargetSpinner.getSelectedItemPosition();
131         int newTargetSelection = getSelectionPosition(LANGUAGE_TYPE_TARGET);
132         if (originalTargetSelection != newTargetSelection)
133             mTargetSpinner.setSelection(newTargetSelection);
134     }
135
136     private int getSelectionPosition(int languageType) {
137         int position = languageType == LANGUAGE_TYPE_SOURCE ? mSessionOptions.sourceLanguageIndex()
138                 : mSessionOptions.targetLanguageIndex();
139
140         // Since the source and target languages cannot appear in both spinners, the index for the
141         // source language can be off by one if comes after the target language alphabetically (and
142         // vice versa).
143         int opposite = languageType == LANGUAGE_TYPE_SOURCE ? mSessionOptions.targetLanguageIndex()
144                 : mSessionOptions.sourceLanguageIndex();
145         if (opposite < position) position -= 1;
146
147         return position;
148     }
149
150     @Override
151     public void onItemSelected(AdapterView<?> adapter, View view, int position, long id) {
152         Spinner spinner = (Spinner) adapter;
153         int newId = ((SpinnerLanguageElement) spinner.getSelectedItem()).getLanguageId();
154         if (spinner == mSourceSpinner) {
155             mSessionOptions.setSourceLanguage(newId);
156         } else {
157             mSessionOptions.setTargetLanguage(newId);
158         }
159         reloadSpinners();
160     }
161
162     @Override
163     public void onNothingSelected(AdapterView<?> adapter) {
164     }
165
166     /**
167      * Determines what languages will be shown in the Spinner.
168      * @param avoidLanguage Index of the language to avoid.  Use -1 to display all languages.
169      */
170     private ArrayList<SpinnerLanguageElement> createSpinnerLanguages(int avoidLanguage) {
171         ArrayList<SpinnerLanguageElement> result = new ArrayList<SpinnerLanguageElement>();
172         List<String> languages = mSessionOptions.allLanguages();
173         for (int i = 0; i <  languages.size(); ++i) {
174             if (i != avoidLanguage) {
175                 result.add(new SpinnerLanguageElement(languages.get(i), i));
176             }
177         }
178         return result;
179     }
180
181     /**
182      * The drop down view displayed to show the currently selected value.
183      */
184     private static class LanguageArrayAdapter extends ArrayAdapter<SpinnerLanguageElement> {
185         private final SpannableString mTextTemplate;
186         private int mMinimumWidth;
187
188         public LanguageArrayAdapter(Context context, int textViewResourceId,
189                 int languageType) {
190             super(context, textViewResourceId);
191
192             // Get the string that we will display inside the Spinner, indicating whether the
193             // spinner is used for the source or target language.
194             String textTemplate = languageType == LANGUAGE_TYPE_SOURCE
195                     ? context.getString(R.string.translate_options_source_hint)
196                     : context.getString(R.string.translate_options_target_hint);
197             mTextTemplate = new SpannableString(textTemplate);
198             mTextTemplate.setSpan(
199                     new ForegroundColorSpan(Color.GRAY), 0, textTemplate.length(), 0);
200         }
201
202         /** Measures how large the view needs to be to avoid truncating its children. */
203         public void measureWidthRequiredForView() {
204             mMinimumWidth = 0;
205
206             final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
207
208             FrameLayout layout = new FrameLayout(getContext());
209             TextView estimator = (TextView) LayoutInflater.from(getContext()).inflate(
210                     R.layout.infobar_text, null);
211             layout.addView(estimator);
212             for (int i = 0; i < getCount(); ++i) {
213                 estimator.setText(getStringForLanguage(i));
214                 estimator.measure(spec, spec);
215                 mMinimumWidth = Math.max(mMinimumWidth, estimator.getMeasuredWidth());
216             }
217         }
218
219         @Override
220         public View getDropDownView(int position, View convertView, ViewGroup parent) {
221             TextView result;
222             if (!(convertView instanceof TextView)) {
223                 result = (TextView) LayoutInflater.from(getContext()).inflate(
224                         R.layout.infobar_spinner_item, null);
225             } else {
226                 result = (TextView) convertView;
227             }
228
229             String language = getItem(position).toString();
230             result.setText(language);
231             return result;
232         }
233
234         @Override
235         public View getView(int position, View convertView, ViewGroup parent) {
236             TextView result;
237             if (!(convertView instanceof TextView)) {
238                 result = (TextView) LayoutInflater.from(getContext()).inflate(
239                         R.layout.infobar_text, null);
240             } else {
241                 result = (TextView) convertView;
242             }
243             result.setEllipsize(TextUtils.TruncateAt.END);
244             result.setMaxLines(1);
245             result.setText(getStringForLanguage(position));
246             result.setMinWidth(mMinimumWidth);
247             return result;
248         }
249
250         private CharSequence getStringForLanguage(int position) {
251             // The spinners prepend a string to show if they're for the source or target language.
252             String language = getItem(position).toString();
253             SpannableString lang = new SpannableString(language);
254             lang.setSpan(new ForegroundColorSpan(Color.BLACK), 0, lang.length(), 0);
255             return TextUtils.expandTemplate(mTextTemplate, lang);
256         }
257     }
258
259     /**
260      * The element that goes inside the spinner.
261      */
262     private static class SpinnerLanguageElement {
263         private final String mLanguageName;
264         private final int mLanguageId;
265
266         public SpinnerLanguageElement(String languageName, int languageId) {
267             mLanguageName = languageName;
268             mLanguageId = languageId;
269         }
270
271         public int getLanguageId() {
272             return mLanguageId;
273         }
274
275         /**
276          * This is the text displayed in the spinner element so make sure no debug information
277          * is added.
278          */
279         @Override
280         public String toString() {
281             return mLanguageName;
282         }
283     }
284 }