diff options
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/chromeos/options/language_config_view.cc | 437 | ||||
-rw-r--r-- | chrome/browser/chromeos/options/language_config_view.h | 31 |
2 files changed, 340 insertions, 128 deletions
diff --git a/chrome/browser/chromeos/options/language_config_view.cc b/chrome/browser/chromeos/options/language_config_view.cc index 2aea165..8982f16 100644 --- a/chrome/browser/chromeos/options/language_config_view.cc +++ b/chrome/browser/chromeos/options/language_config_view.cc @@ -4,42 +4,119 @@ #include "chrome/browser/chromeos/options/language_config_view.h" +#include <algorithm> #include <utility> #include <vector> +#include "app/gfx/font.h" #include "app/l10n_util.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/cros/language_library.h" #include "chrome/browser/chromeos/options/language_hangul_config_view.h" +#include "chrome/browser/language_combobox_model.h" #include "grit/generated_resources.h" #include "grit/locale_settings.h" -#include "views/controls/button/checkbox.h" +#include "views/controls/combobox/combobox.h" #include "views/controls/label.h" +#include "views/fill_layout.h" #include "views/grid_layout.h" #include "views/standard_layout.h" #include "views/window/window.h" namespace chromeos { +using views::ColumnSet; +using views::GridLayout; -// This is a checkbox associated with input language information. -class LanguageCheckbox : public views::Checkbox { +// The view implements a dialog for adding a language. +class AddLanguageView : public views::View, + public views::Combobox::Listener, + public views::DialogDelegate { public: - explicit LanguageCheckbox(const InputLanguage& language) - : views::Checkbox(UTF8ToWide(language.display_name)), - language_(language) { + explicit AddLanguageView(LanguageConfigView* parent_view) + : parent_view_(parent_view), + language_combobox_(NULL), + selected_index_(0) { } - const InputLanguage& language() const { - return language_; + // views::DialogDelegate overrides: + virtual bool Accept() { + std::string language_selected = language_combobox_model_-> + GetLocaleFromIndex(selected_index_); + parent_view_->OnAddLanguage(language_selected); + return true; + } + + virtual std::wstring GetWindowTitle() const { + return l10n_util::GetString( + IDS_OPTIONS_SETTINGS_LANGUAGES_LANGUAGES); + } + + // views::WindowDelegate overrides: + virtual bool IsModal() const { return true; } + virtual views::View* GetContentsView() { return this; } + + // views::Combobox::Listener overrides: + virtual void ItemChanged(views::Combobox* combobox, + int prev_index, + int new_index) { + selected_index_ = new_index; + } + + // views::View overrides: + virtual void Layout() { + language_combobox_->SetBounds(0, 0, width(), height()); + } + + virtual void ViewHierarchyChanged(bool is_add, views::View* parent, + views::View* child) { + if (is_add && child == this) + Init(); } private: - InputLanguage language_; - DISALLOW_COPY_AND_ASSIGN(LanguageCheckbox); + void Init() { + language_combobox_model_.reset(CreateLanguageComboboxModel()); + language_combobox_ = new views::Combobox(language_combobox_model_.get()); + language_combobox_->SetSelectedItem(selected_index_); + language_combobox_->set_listener(this); + SetLayoutManager(new views::FillLayout); + AddChildView(language_combobox_); + } + + // Creates the language combobox model from the supported languages. + LanguageComboboxModel* CreateLanguageComboboxModel() { + // GetSupportedLanguages() never return NULL. + scoped_ptr<InputLanguageList> supported_language_list( + LanguageLibrary::Get()->GetSupportedLanguages()); + + std::set<std::string> language_set; + for (size_t i = 0; i < supported_language_list->size(); ++i) { + const InputLanguage& language = supported_language_list->at(i); + language_set.insert(language.language_code); + } + const std::vector<std::string> language_codes(language_set.begin(), + language_set.end()); + // LanguageComboboxModel sorts languages by their display names. + return new LanguageComboboxModel(NULL, language_codes); + } + + LanguageConfigView* parent_view_; + + // Combobox and its corresponding model. + scoped_ptr<LanguageComboboxModel> language_combobox_model_; + views::Combobox* language_combobox_; + // The index of the selected item in the combobox. + int selected_index_; + + DISALLOW_COPY_AND_ASSIGN(AddLanguageView); }; LanguageConfigView::LanguageConfigView() - : contents_(NULL), + : root_container_(NULL), + right_container_(NULL), + add_language_button_(NULL), + remove_language_button_(NULL), hangul_configure_button_(NULL), preferred_language_table_(NULL) { } @@ -54,43 +131,24 @@ void LanguageConfigView::ButtonPressed( NULL, gfx::Rect(), new LanguageHangulConfigView()); window->SetIsAlwaysOnTop(true); window->Show(); - } else if (std::find(language_checkboxes_.begin(), - language_checkboxes_.end(), - sender) != language_checkboxes_.end()) { - LanguageCheckbox* checkbox = static_cast<LanguageCheckbox*>(sender); - const InputLanguage& language = checkbox->language(); - // Check if the checkbox is now being checked. - if (checkbox->checked()) { - // TODO(yusukes): limit the number of active languages so the pop-up menu - // of the language_menu_button does not overflow. - - // Try to activate the language. - if (!LanguageLibrary::Get()->ActivateLanguage(language.category, - language.id)) { - // Activation should never fail (failure means something is broken), - // but if it fails we just revert the checkbox and ignore the error. - // TODO(satorux): Implement a better error handling if it becomes - // necessary. - checkbox->SetChecked(false); - LOG(ERROR) << "Failed to activate language: " - << language.display_name; - } - } else { - // Try to deactivate the language. - if (!LanguageLibrary::Get()->DeactivateLanguage(language.category, - language.id)) { - // See a comment above about the activation failure. - checkbox->SetChecked(true); - LOG(ERROR) << "Failed to deactivate language: " - << language.display_name; - } - } + } else if (sender == static_cast<views::Button*>(add_language_button_)) { + views::Window* window = views::Window::CreateChromeWindow( + NULL, gfx::Rect(), new AddLanguageView(this)); + window->SetIsAlwaysOnTop(true); + window->Show(); + } else if (sender == static_cast<views::Button*>(remove_language_button_)) { + const int row = preferred_language_table_->GetFirstSelectedRow(); + const std::string& language_code = preferred_language_codes_[row]; + DeactivateInputLanguagesFor(language_code); + // Remove the language code and the row from the table. + preferred_language_codes_.erase(preferred_language_codes_.begin() + row); + preferred_language_table_->OnItemsRemoved(row, 1); } } void LanguageConfigView::Layout() { // Not sure why but this is needed to show contents in the dialog. - contents_->SetBounds(0, 0, width(), height()); + root_container_->SetBounds(0, 0, width(), height()); } std::wstring LanguageConfigView::GetWindowTitle() const { @@ -113,122 +171,257 @@ void LanguageConfigView::ViewHierarchyChanged( } } +views::View* LanguageConfigView::CreatePerLanguageConfigView( + const std::string& language_code) { + views::View* contents = new views::View; + GridLayout* layout = new GridLayout(contents); + contents->SetLayoutManager(layout); + + // Set up column sets for the grid layout. + const int kTitleColumnSetId = 1; + ColumnSet* column_set = layout->AddColumnSet(kTitleColumnSetId); + column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); + + const int kDoubleColumnSetId = 2; + column_set = layout->AddColumnSet(kDoubleColumnSetId); + column_set->AddPaddingColumn(0, kUnrelatedControlHorizontalSpacing); + column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); + column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); + + // Create the title label. + views::Label* title_label = new views::Label( + l10n_util::GetString( + IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD)); + const gfx::Font bold_font = + title_label->GetFont().DeriveFont(0, gfx::Font::BOLD); + title_label->SetFont(bold_font); + + // Add the title label. + layout->StartRow(0, kTitleColumnSetId); + layout->AddView(title_label); + layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); + + // Add input method names and configuration buttons. + // TODO(satorux): Implement ways to activate/deactivate individual input + // methods. For instance a language can have multiple input methods. + scoped_ptr<InputLanguageList> supported_language_list( + LanguageLibrary::Get()->GetSupportedLanguages()); + + for (size_t i = 0; i < supported_language_list->size(); ++i) { + const InputLanguage& language = supported_language_list->at(i); + if (language.language_code == language_code) { + layout->StartRow(0, kDoubleColumnSetId); + layout->AddView(new views::Label(UTF8ToWide(language.display_name))); + // TODO(satorux): For now, we special case the hangul input + // method. We'll generalize this. + if (language_code == "ko") { + hangul_configure_button_ = new views::NativeButton( + this, + l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_CONFIGURE)); + layout->AddView(hangul_configure_button_); + } + } + } + + return contents; +} + void LanguageConfigView::OnSelectionChanged() { - // TODO(satorux): Implement this. + right_container_->RemoveAllChildViews(true); // Delete the child views. + + const int row = preferred_language_table_->GetFirstSelectedRow(); + const std::string& language_code = preferred_language_codes_[row]; + // TODO(satorux): For now, don't allow users to remove English. + if (language_code == "en") { + remove_language_button_->SetEnabled(false); + } else { + remove_language_button_->SetEnabled(true); + } + + // Add the per language config view to the right area. + right_container_->AddChildView(CreatePerLanguageConfigView(language_code)); + // Let the parent container layout again. This is needed to the the + // contents on the right to display. + root_container_->Layout(); } std::wstring LanguageConfigView::GetText(int row, int column_id) { - return L"Not yet implemented"; + if (row >= 0 && row < static_cast<int>(preferred_language_codes_.size())) { + const string16 language_name = l10n_util::GetDisplayNameForLocale( + preferred_language_codes_[row], + g_browser_process->GetApplicationLocale(), + true); + return UTF16ToWide(language_name); + } + NOTREACHED(); + return L""; } void LanguageConfigView::SetObserver(TableModelObserver* observer) { + // We don't need the observer for the table mode, since we implement the + // table model as part of the LanguageConfigView class. + // http://crbug.com/38266 } int LanguageConfigView::RowCount() { - return 1; + // Returns the number of rows of the language table. + return preferred_language_codes_.size(); } - -// TODO(satorux): Refactor the function. void LanguageConfigView::Init() { - using views::ColumnSet; - using views::GridLayout; - - if (contents_) return; // Already initialized. - contents_ = new views::View; - AddChildView(contents_); - - // Set up the layout manager for the outer contents. We'll place the - // preferred language table on the left, and anything else on the right. - GridLayout* outer_layout = new GridLayout(contents_); - contents_->SetLayoutManager(outer_layout); - outer_layout->SetInsets(kPanelVertMargin, kPanelHorizMargin, - kPanelVertMargin, kPanelHorizMargin); - - // Set up the column set for the outer contents. - const int kOuterColumnSetId = 0; - ColumnSet* column_set = outer_layout->AddColumnSet(kOuterColumnSetId); + if (root_container_) return; // Already initialized. + root_container_ = new views::View; + AddChildView(root_container_); + + // Set up the layout manager for the root container. We'll place the + // language table on the left, and the per language config on the right. + GridLayout* root_layout = new GridLayout(root_container_); + root_container_->SetLayoutManager(root_layout); + root_layout->SetInsets(kPanelVertMargin, kPanelHorizMargin, + kPanelVertMargin, kPanelHorizMargin); + + // Set up column sets for the grid layout. + const int kRootColumnSetId = 0; + ColumnSet* column_set = root_layout->AddColumnSet(kRootColumnSetId); + column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0, + GridLayout::FIXED, 300, 0); + column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); + column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0, + GridLayout::USE_PREF, 0, 0); + root_layout->StartRow(1 /* expand */, kRootColumnSetId); + + // Initialize the language codes currently activated. + InitPreferredLanguageCodes(); + + // Set up the container for the contents on the right. Just adds a + // place holder here. This will get replaced in OnSelectionChanged(). + right_container_ = new views::View; + right_container_->SetLayoutManager(new views::FillLayout); + right_container_->AddChildView(new views::View); + + // Add the contents on the left and the right. + root_layout->AddView(CreateContentsOnLeft()); + root_layout->AddView(right_container_); + + // Select the first row in the language table. + // There should be at least one language in the table. + CHECK(!preferred_language_codes_.empty()); + preferred_language_table_->SelectRow(0); +} + +void LanguageConfigView::InitPreferredLanguageCodes() { + scoped_ptr<InputLanguageList> active_language_list( + LanguageLibrary::Get()->GetActiveLanguages()); + + for (size_t i = 0; i < active_language_list->size(); ++i) { + const InputLanguage& language = active_language_list->at(i); + // Add the language if any input language is activated. + if (std::find(preferred_language_codes_.begin(), + preferred_language_codes_.end(), + language.language_code) == + preferred_language_codes_.end()) { + preferred_language_codes_.push_back(language.language_code); + } + } +} + +views::View* LanguageConfigView::CreateContentsOnLeft() { + views::View* contents = new views::View; + GridLayout* layout = new GridLayout(contents); + contents->SetLayoutManager(layout); + + // Set up column sets for the grid layout. + const int kTableColumnSetId = 1; + ColumnSet* column_set = layout->AddColumnSet(kTableColumnSetId); column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, GridLayout::USE_PREF, 0, 0); - column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); - column_set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0, + + const int kButtonsColumnSetId = 2; + column_set = layout->AddColumnSet(kButtonsColumnSetId); + column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0, + GridLayout::USE_PREF, 0, 0); + column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0, GridLayout::USE_PREF, 0, 0); - // Set up the preferred language table. + // Create the language table. std::vector<TableColumn> columns; TableColumn column(0, l10n_util::GetString( IDS_OPTIONS_SETTINGS_LANGUAGES_LANGUAGES), - TableColumn::LEFT, -1 /* width */, 0 /* percent */); + TableColumn::LEFT, -1, 0); columns.push_back(column); preferred_language_table_ = new views::TableView2(this, columns, views::TEXT_ONLY, true, true, true); + // Set the observer so OnSelectionChanged() will be invoked when a + // selection is changed in the table. preferred_language_table_->SetObserver(this); - // Add the preferred language table. - outer_layout->StartRow(1 /* expand */, kOuterColumnSetId); - outer_layout->AddView(preferred_language_table_); + // Add the language table. + layout->StartRow(1 /* expand vertically */, kTableColumnSetId); + layout->AddView(preferred_language_table_); - // Set up the container for the contents on the right. - views::View* right_contents = new views::View; - GridLayout* layout = new GridLayout(right_contents); - right_contents->SetLayoutManager(layout); - outer_layout->AddView(right_contents); + // Create the add and remove buttons. + add_language_button_ = new views::NativeButton( + this, l10n_util::GetString( + IDS_OPTIONS_SETTINGS_LANGUAGES_ADD_BUTTON)); + remove_language_button_ = new views::NativeButton( + this, l10n_util::GetString( + IDS_OPTIONS_SETTINGS_LANGUAGES_REMOVE_BUTTON)); - // Set up the single column set. - const int kSingleColumnSetId = 1; - column_set = layout->AddColumnSet(kSingleColumnSetId); - column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, - GridLayout::USE_PREF, 0, 0); + // Add the add and remove buttons. + layout->StartRow(0, kButtonsColumnSetId); + layout->AddView(add_language_button_); + layout->AddView(remove_language_button_); - // Set up the double column set. - const int kDoubleColumnSetId = 2; - column_set = layout->AddColumnSet(kDoubleColumnSetId); - column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, - GridLayout::USE_PREF, 0, 0); - column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); - column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, - GridLayout::USE_PREF, 0, 0); + return contents; +} - // GetActiveLanguages() and GetSupportedLanguages() never return NULL. +void LanguageConfigView::OnAddLanguage(const std::string& language_code) { + if (std::find(preferred_language_codes_.begin(), + preferred_language_codes_.end(), + language_code) == preferred_language_codes_.end()) { + // Append the language to the list of language codes. + preferred_language_codes_.push_back(language_code); + // Update the language table accordingly. + preferred_language_table_->OnItemsAdded(RowCount() - 1, 1); + preferred_language_table_->SelectRow(RowCount() - 1); + + // Activate the first input language associated with the language. + scoped_ptr<InputLanguageList> supported_language_list( + LanguageLibrary::Get()->GetSupportedLanguages()); + for (size_t i = 0; i < supported_language_list->size(); ++i) { + const InputLanguage& language = supported_language_list->at(i); + if (language.language_code == language_code) { + LanguageLibrary::Get()->ActivateLanguage(language.category, + language.id); + break; + } + } + } +} + +void LanguageConfigView::DeactivateInputLanguagesFor( + const std::string& language_code) { scoped_ptr<InputLanguageList> active_language_list( LanguageLibrary::Get()->GetActiveLanguages()); - scoped_ptr<InputLanguageList> supported_language_list( - LanguageLibrary::Get()->GetSupportedLanguages()); - for (size_t i = 0; i < supported_language_list->size(); ++i) { - const InputLanguage& language = supported_language_list->at(i); - // Check if |language| is active. Note that active_language_list is - // small (usually a couple), so scanning here is fine. - const bool language_is_active = - (std::find(active_language_list->begin(), - active_language_list->end(), - language) != active_language_list->end()); - // Create a checkbox. - LanguageCheckbox* language_checkbox = new LanguageCheckbox(language); - language_checkbox->SetChecked(language_is_active); - language_checkbox->set_listener(this); - language_checkboxes_.push_back(language_checkbox); - - // We use two columns. Start a column if the counter is an even number. - if (i % 2 == 0) { - layout->StartRow(0, kDoubleColumnSetId); + for (size_t i = 0; i < active_language_list->size(); ++i) { + const InputLanguage& language = active_language_list->at(i); + if (language.language_code == language_code) { + LanguageLibrary::Get()->DeactivateLanguage(language.category, + language.id); } - // Add the checkbox to the layout manager. - layout->AddView(language_checkbox); - } - - // Add the configure button for the Hangul IME. - // TODO(satorux): We'll have better UI for this soon. - layout->StartRow(0, kDoubleColumnSetId); - hangul_configure_button_ = new views::NativeButton( - this, l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_CONFIGURE)); - layout->AddView(new views::Label( - l10n_util::GetString(IDS_OPTIONS_SETTINGS_HANGUL_IME_TEXT))); - layout->AddView(hangul_configure_button_); + } + // Switch back to the US English. + LanguageLibrary::Get()->ChangeLanguage( + chromeos::LANGUAGE_CATEGORY_XKB, "USA"); } } // namespace chromeos diff --git a/chrome/browser/chromeos/options/language_config_view.h b/chrome/browser/chromeos/options/language_config_view.h index 84388d2..7c006da 100644 --- a/chrome/browser/chromeos/options/language_config_view.h +++ b/chrome/browser/chromeos/options/language_config_view.h @@ -18,7 +18,6 @@ namespace chromeos { -class LanguageCheckbox; class LanguageHangulConfigView; class PreferredLanguageTableModel; // A dialog box for showing a password textfield. @@ -59,16 +58,36 @@ class LanguageConfigView : public TableModel, virtual void SetObserver(TableModelObserver* observer); virtual int RowCount(); + // Invoked when a language is added from the add button. + void OnAddLanguage(const std::string& language_code); + private: - // Initializes UI. + // Initializes the view. void Init(); - views::View* contents_; - views::NativeButton* hangul_configure_button_; - std::vector<views::Button*> language_checkboxes_; + // Initializes the preferred language table codes based on the active + // input languages. + void InitPreferredLanguageCodes(); + + // Creates the contents on the left, including the language table. + views::View* CreateContentsOnLeft(); + + // Creates the per-language config view. + views::View* CreatePerLanguageConfigView(const std::string& language_code); - // A table for preferred languages and its model. + // Deactivates the input languages for the given language code. + void DeactivateInputLanguagesFor(const std::string& language_code); + + // The codes of the preferred languages. + std::vector<std::string> preferred_language_codes_; + + views::View* root_container_; + views::View* right_container_; + views::NativeButton* add_language_button_; + views::NativeButton* remove_language_button_; + views::NativeButton* hangul_configure_button_; views::TableView2* preferred_language_table_; + DISALLOW_COPY_AND_ASSIGN(LanguageConfigView); }; |