diff options
author | satorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-18 11:36:58 +0000 |
---|---|---|
committer | satorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-18 11:36:58 +0000 |
commit | 965b13238fb7a4d716a6f8946117ddb2672da33d (patch) | |
tree | 997fd3e2b21749a7f16aac1ebc9d654cb2a6fc27 /chrome/browser | |
parent | c155674b09a87b07848971906ca596fc788dd627 (diff) | |
download | chromium_src-965b13238fb7a4d716a6f8946117ddb2672da33d.zip chromium_src-965b13238fb7a4d716a6f8946117ddb2672da33d.tar.gz chromium_src-965b13238fb7a4d716a6f8946117ddb2672da33d.tar.bz2 |
Major rework of the language settings dialog.
With this changes, users can add and remove preferred languages using the
table on the left, that used to be just saying "Not yet implemented".
TEST=manually
BUG=crosbug.com/1688
Review URL: http://codereview.chromium.org/1104001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@41943 0039d316-1c4b-4281-b951-d872f2087c98
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); }; |