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.
5 package org.chromium.chrome.browser.infobar;
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.Gravity;
13 import android.view.LayoutInflater;
14 import android.view.View;
15 import android.view.View.OnClickListener;
16 import android.view.ViewGroup;
17 import android.widget.AdapterView;
18 import android.widget.ArrayAdapter;
19 import android.widget.Button;
20 import android.widget.FrameLayout;
21 import android.widget.LinearLayout;
22 import android.widget.Spinner;
23 import android.widget.TextView;
26 import org.chromium.chrome.browser.infobar.InfoBar;
27 import org.chromium.chrome.browser.infobar.InfoBarLayout;
28 import org.chromium.chrome.R;
30 import java.util.ArrayList;
31 import java.util.List;
34 * Language panel shown in the translate infobar.
36 public class TranslateLanguagePanel
37 implements TranslateSubPanel, AdapterView.OnItemSelectedListener {
39 private static final int LANGUAGE_TYPE_SOURCE = 0;
40 private static final int LANGUAGE_TYPE_TARGET = 1;
43 private Spinner mSourceSpinner;
44 private Spinner mTargetSpinner;
46 // Items that are not interacted with.
47 // Provided by the caller, the new languages will be set here if the user
49 private final TranslateOptions mOptions;
51 // This object will be used to keep the state for the time the
52 // panel is opened it can be totally discarded in the end if the user
54 private TranslateOptions mSessionOptions;
56 private LanguageArrayAdapter mSourceAdapter;
57 private LanguageArrayAdapter mTargetAdapter;
59 private final SubPanelListener mListener;
62 * Display language drop downs so they can be picked as source or
63 * target for a translation.
65 * @param listener triggered when the panel is closed
66 * @param options will be modified with the new languages selected.
68 public TranslateLanguagePanel(SubPanelListener listener, TranslateOptions options) {
71 mSessionOptions = new TranslateOptions(mOptions);
75 public void createContent(Context context, InfoBarLayout layout) {
76 mSourceSpinner = null;
77 mTargetSpinner = null;
79 String changeLanguage = context.getString(R.string.translate_infobar_change_languages);
80 TextView panelMessage = (TextView) layout.findViewById(R.id.infobar_message);
81 panelMessage.setText(changeLanguage);
83 // Set up the spinners.
84 createSpinners(context);
85 layout.addGroup(mSourceSpinner, mTargetSpinner);
87 // Set up the buttons.
88 layout.addButtons(context.getString(R.string.translate_button_done),
89 context.getString(R.string.cancel));
93 public void onButtonClicked(boolean primary) {
95 mOptions.setSourceLanguage(mSessionOptions.sourceLanguageIndex());
96 mOptions.setTargetLanguage(mSessionOptions.targetLanguageIndex());
98 mListener.onPanelClosed(InfoBar.ACTION_TYPE_NONE);
101 private void createSpinners(Context context) {
102 mSourceAdapter = new LanguageArrayAdapter(context, R.layout.translate_spinner,
103 LANGUAGE_TYPE_SOURCE);
104 mTargetAdapter = new LanguageArrayAdapter(context, R.layout.translate_spinner,
105 LANGUAGE_TYPE_TARGET);
107 // Determine how wide each spinner needs to be to avoid truncating its children.
108 mSourceAdapter.addAll(createSpinnerLanguages(-1));
109 mTargetAdapter.addAll(createSpinnerLanguages(-1));
110 mSourceAdapter.measureWidthRequiredForView();
111 mTargetAdapter.measureWidthRequiredForView();
113 // Create the spinners.
114 mSourceSpinner = new Spinner(context);
115 mTargetSpinner = new Spinner(context);
116 mSourceSpinner.setOnItemSelectedListener(this);
117 mTargetSpinner.setOnItemSelectedListener(this);
118 mSourceSpinner.setAdapter(mSourceAdapter);
119 mTargetSpinner.setAdapter(mTargetAdapter);
123 private void reloadSpinners() {
124 mSourceAdapter.clear();
125 mTargetAdapter.clear();
127 int sourceAvoidLanguage = mSessionOptions.targetLanguageIndex();
128 int targetAvoidLanguage = mSessionOptions.sourceLanguageIndex();
129 mSourceAdapter.addAll(createSpinnerLanguages(sourceAvoidLanguage));
130 mTargetAdapter.addAll(createSpinnerLanguages(targetAvoidLanguage));
132 int originalSourceSelection = mSourceSpinner.getSelectedItemPosition();
133 int newSourceSelection = getSelectionPosition(LANGUAGE_TYPE_SOURCE);
134 if (originalSourceSelection != newSourceSelection)
135 mSourceSpinner.setSelection(newSourceSelection);
137 int originalTargetSelection = mTargetSpinner.getSelectedItemPosition();
138 int newTargetSelection = getSelectionPosition(LANGUAGE_TYPE_TARGET);
139 if (originalTargetSelection != newTargetSelection)
140 mTargetSpinner.setSelection(newTargetSelection);
143 private int getSelectionPosition(int languageType) {
144 int position = languageType == LANGUAGE_TYPE_SOURCE ? mSessionOptions.sourceLanguageIndex()
145 : mSessionOptions.targetLanguageIndex();
147 // Since the source and target languages cannot appear in both spinners, the index for the
148 // source language can be off by one if comes after the target language alphabetically (and
150 int opposite = languageType == LANGUAGE_TYPE_SOURCE ? mSessionOptions.targetLanguageIndex()
151 : mSessionOptions.sourceLanguageIndex();
152 if (opposite < position) position -= 1;
158 public void onItemSelected(AdapterView<?> adapter, View view, int position, long id) {
159 Spinner spinner = (Spinner) adapter;
160 int newId = ((SpinnerLanguageElement) spinner.getSelectedItem()).getLanguageId();
161 if (spinner == mSourceSpinner) {
162 mSessionOptions.setSourceLanguage(newId);
164 mSessionOptions.setTargetLanguage(newId);
170 public void onNothingSelected(AdapterView<?> adapter) {
174 * Determines what languages will be shown in the Spinner.
175 * @param avoidLanguage Index of the language to avoid. Use -1 to display all languages.
177 private ArrayList<SpinnerLanguageElement> createSpinnerLanguages(int avoidLanguage) {
178 ArrayList<SpinnerLanguageElement> result = new ArrayList<SpinnerLanguageElement>();
179 List<String> languages = mSessionOptions.allLanguages();
180 for (int i = 0; i < languages.size(); ++i) {
181 if (i != avoidLanguage) {
182 result.add(new SpinnerLanguageElement(languages.get(i), i));
189 * The drop down view displayed to show the currently selected value.
191 private static class LanguageArrayAdapter extends ArrayAdapter<SpinnerLanguageElement> {
192 private final SpannableString mTextTemplate;
193 private int mMinimumWidth;
195 public LanguageArrayAdapter(Context context, int textViewResourceId,
197 super(context, textViewResourceId);
199 // Get the string that we will display inside the Spinner, indicating whether the
200 // spinner is used for the source or target language.
201 String textTemplate = languageType == LANGUAGE_TYPE_SOURCE
202 ? context.getString(R.string.translate_options_source_hint)
203 : context.getString(R.string.translate_options_target_hint);
204 mTextTemplate = new SpannableString(textTemplate);
205 mTextTemplate.setSpan(
206 new ForegroundColorSpan(Color.GRAY), 0, textTemplate.length(), 0);
209 /** Measures how large the view needs to be to avoid truncating its children. */
210 public void measureWidthRequiredForView() {
213 final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
215 FrameLayout layout = new FrameLayout(getContext());
216 TextView estimator = (TextView) LayoutInflater.from(getContext()).inflate(
217 R.layout.infobar_text, null);
218 layout.addView(estimator);
219 for (int i = 0; i < getCount(); ++i) {
220 estimator.setText(getStringForLanguage(i));
221 estimator.measure(spec, spec);
222 mMinimumWidth = Math.max(mMinimumWidth, estimator.getMeasuredWidth());
227 public View getDropDownView(int position, View convertView, ViewGroup parent) {
229 if (!(convertView instanceof TextView)) {
230 result = (TextView) LayoutInflater.from(getContext()).inflate(
231 R.layout.infobar_spinner_item, null);
233 result = (TextView) convertView;
236 String language = ((SpinnerLanguageElement) getItem(position)).toString();
237 result.setText(language);
242 public View getView(int position, View convertView, ViewGroup parent) {
244 if (!(convertView instanceof TextView)) {
245 result = (TextView) LayoutInflater.from(getContext()).inflate(
246 R.layout.infobar_text, null);
248 result = (TextView) convertView;
250 result.setEllipsize(TextUtils.TruncateAt.END);
251 result.setMaxLines(1);
252 result.setText(getStringForLanguage(position));
253 result.setMinWidth(mMinimumWidth);
257 private CharSequence getStringForLanguage(int position) {
258 // The spinners prepend a string to show if they're for the source or target language.
259 String language = getItem(position).toString();
260 SpannableString lang = new SpannableString(language);
261 lang.setSpan(new ForegroundColorSpan(Color.BLACK), 0, lang.length(), 0);
262 return TextUtils.expandTemplate(mTextTemplate, lang);
267 * The element that goes inside the spinner.
269 private static class SpinnerLanguageElement {
270 private final String mLanguageName;
271 private final int mLanguageId;
273 public SpinnerLanguageElement(String languageName, int languageId) {
274 mLanguageName = languageName;
275 mLanguageId = languageId;
278 public int getLanguageId() {
283 * This is the text displayed in the spinner element so make sure no debug information
287 public String toString() {
288 return mLanguageName;