blob: 1da1d7dc973b31d86361909906558efe3077c524 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.infobar;
import android.content.Context;
import android.graphics.Color;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import org.chromium.chrome.browser.infobar.InfoBar;
import org.chromium.chrome.browser.infobar.InfoBarLayout;
import org.chromium.chrome.R;
import java.util.ArrayList;
import java.util.List;
/**
* Language panel shown in the translate infobar.
*/
public class TranslateLanguagePanel
implements TranslateSubPanel, AdapterView.OnItemSelectedListener {
private static final int LANGUAGE_TYPE_SOURCE = 0;
private static final int LANGUAGE_TYPE_TARGET = 1;
// UI elements.
private Spinner mSourceSpinner;
private Spinner mTargetSpinner;
// Items that are not interacted with.
// Provided by the caller, the new languages will be set here if the user
// clicks "done".
private final TranslateOptions mOptions;
// This object will be used to keep the state for the time the
// panel is opened it can be totally discarded in the end if the user
// clicks "cancel".
private TranslateOptions mSessionOptions;
private LanguageArrayAdapter mSourceAdapter;
private LanguageArrayAdapter mTargetAdapter;
private final SubPanelListener mListener;
/**
* Display language drop downs so they can be picked as source or
* target for a translation.
*
* @param listener triggered when the panel is closed
* @param options will be modified with the new languages selected.
*/
public TranslateLanguagePanel(SubPanelListener listener, TranslateOptions options) {
mListener = listener;
mOptions = options;
mSessionOptions = new TranslateOptions(mOptions);
}
@Override
public void createContent(Context context, InfoBarLayout layout) {
mSourceSpinner = null;
mTargetSpinner = null;
String changeLanguage = context.getString(R.string.translate_infobar_change_languages);
TextView panelMessage = (TextView) layout.findViewById(R.id.infobar_message);
panelMessage.setText(changeLanguage);
// Set up the spinners.
createSpinners(context);
layout.addGroup(mSourceSpinner, mTargetSpinner);
// Set up the buttons.
layout.addButtons(context.getString(R.string.translate_button_done),
context.getString(R.string.cancel));
}
@Override
public void onButtonClicked(boolean primary) {
if (primary) {
mOptions.setSourceLanguage(mSessionOptions.sourceLanguageIndex());
mOptions.setTargetLanguage(mSessionOptions.targetLanguageIndex());
}
mListener.onPanelClosed(InfoBar.ACTION_TYPE_NONE);
}
private void createSpinners(Context context) {
mSourceAdapter = new LanguageArrayAdapter(context, R.layout.translate_spinner,
LANGUAGE_TYPE_SOURCE);
mTargetAdapter = new LanguageArrayAdapter(context, R.layout.translate_spinner,
LANGUAGE_TYPE_TARGET);
// Determine how wide each spinner needs to be to avoid truncating its children.
mSourceAdapter.addAll(createSpinnerLanguages(-1));
mTargetAdapter.addAll(createSpinnerLanguages(-1));
mSourceAdapter.measureWidthRequiredForView();
mTargetAdapter.measureWidthRequiredForView();
// Create the spinners.
mSourceSpinner = new Spinner(context);
mTargetSpinner = new Spinner(context);
mSourceSpinner.setOnItemSelectedListener(this);
mTargetSpinner.setOnItemSelectedListener(this);
mSourceSpinner.setAdapter(mSourceAdapter);
mTargetSpinner.setAdapter(mTargetAdapter);
reloadSpinners();
}
private void reloadSpinners() {
mSourceAdapter.clear();
mTargetAdapter.clear();
int sourceAvoidLanguage = mSessionOptions.targetLanguageIndex();
int targetAvoidLanguage = mSessionOptions.sourceLanguageIndex();
mSourceAdapter.addAll(createSpinnerLanguages(sourceAvoidLanguage));
mTargetAdapter.addAll(createSpinnerLanguages(targetAvoidLanguage));
int originalSourceSelection = mSourceSpinner.getSelectedItemPosition();
int newSourceSelection = getSelectionPosition(LANGUAGE_TYPE_SOURCE);
if (originalSourceSelection != newSourceSelection)
mSourceSpinner.setSelection(newSourceSelection);
int originalTargetSelection = mTargetSpinner.getSelectedItemPosition();
int newTargetSelection = getSelectionPosition(LANGUAGE_TYPE_TARGET);
if (originalTargetSelection != newTargetSelection)
mTargetSpinner.setSelection(newTargetSelection);
}
private int getSelectionPosition(int languageType) {
int position = languageType == LANGUAGE_TYPE_SOURCE ? mSessionOptions.sourceLanguageIndex()
: mSessionOptions.targetLanguageIndex();
// Since the source and target languages cannot appear in both spinners, the index for the
// source language can be off by one if comes after the target language alphabetically (and
// vice versa).
int opposite = languageType == LANGUAGE_TYPE_SOURCE ? mSessionOptions.targetLanguageIndex()
: mSessionOptions.sourceLanguageIndex();
if (opposite < position) position -= 1;
return position;
}
@Override
public void onItemSelected(AdapterView<?> adapter, View view, int position, long id) {
Spinner spinner = (Spinner) adapter;
int newId = ((SpinnerLanguageElement) spinner.getSelectedItem()).getLanguageId();
if (spinner == mSourceSpinner) {
mSessionOptions.setSourceLanguage(newId);
} else {
mSessionOptions.setTargetLanguage(newId);
}
reloadSpinners();
}
@Override
public void onNothingSelected(AdapterView<?> adapter) {
}
/**
* Determines what languages will be shown in the Spinner.
* @param avoidLanguage Index of the language to avoid. Use -1 to display all languages.
*/
private ArrayList<SpinnerLanguageElement> createSpinnerLanguages(int avoidLanguage) {
ArrayList<SpinnerLanguageElement> result = new ArrayList<SpinnerLanguageElement>();
List<String> languages = mSessionOptions.allLanguages();
for (int i = 0; i < languages.size(); ++i) {
if (i != avoidLanguage) {
result.add(new SpinnerLanguageElement(languages.get(i), i));
}
}
return result;
}
/**
* The drop down view displayed to show the currently selected value.
*/
private static class LanguageArrayAdapter extends ArrayAdapter<SpinnerLanguageElement> {
private final SpannableString mTextTemplate;
private int mMinimumWidth;
public LanguageArrayAdapter(Context context, int textViewResourceId,
int languageType) {
super(context, textViewResourceId);
// Get the string that we will display inside the Spinner, indicating whether the
// spinner is used for the source or target language.
String textTemplate = languageType == LANGUAGE_TYPE_SOURCE
? context.getString(R.string.translate_options_source_hint)
: context.getString(R.string.translate_options_target_hint);
mTextTemplate = new SpannableString(textTemplate);
mTextTemplate.setSpan(
new ForegroundColorSpan(Color.GRAY), 0, textTemplate.length(), 0);
}
/** Measures how large the view needs to be to avoid truncating its children. */
public void measureWidthRequiredForView() {
mMinimumWidth = 0;
final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
FrameLayout layout = new FrameLayout(getContext());
TextView estimator = (TextView) LayoutInflater.from(getContext()).inflate(
R.layout.infobar_text, null);
layout.addView(estimator);
for (int i = 0; i < getCount(); ++i) {
estimator.setText(getStringForLanguage(i));
estimator.measure(spec, spec);
mMinimumWidth = Math.max(mMinimumWidth, estimator.getMeasuredWidth());
}
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
TextView result;
if (!(convertView instanceof TextView)) {
result = (TextView) LayoutInflater.from(getContext()).inflate(
R.layout.infobar_spinner_item, null);
} else {
result = (TextView) convertView;
}
String language = ((SpinnerLanguageElement) getItem(position)).toString();
result.setText(language);
return result;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView result;
if (!(convertView instanceof TextView)) {
result = (TextView) LayoutInflater.from(getContext()).inflate(
R.layout.infobar_text, null);
} else {
result = (TextView) convertView;
}
result.setEllipsize(TextUtils.TruncateAt.END);
result.setMaxLines(1);
result.setText(getStringForLanguage(position));
result.setMinWidth(mMinimumWidth);
return result;
}
private CharSequence getStringForLanguage(int position) {
// The spinners prepend a string to show if they're for the source or target language.
String language = getItem(position).toString();
SpannableString lang = new SpannableString(language);
lang.setSpan(new ForegroundColorSpan(Color.BLACK), 0, lang.length(), 0);
return TextUtils.expandTemplate(mTextTemplate, lang);
}
}
/**
* The element that goes inside the spinner.
*/
private static class SpinnerLanguageElement {
private final String mLanguageName;
private final int mLanguageId;
public SpinnerLanguageElement(String languageName, int languageId) {
mLanguageName = languageName;
mLanguageId = languageId;
}
public int getLanguageId() {
return mLanguageId;
}
/**
* This is the text displayed in the spinner element so make sure no debug information
* is added.
*/
@Override
public String toString() {
return mLanguageName;
}
}
}