Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

languages_page_view.cc

// Copyright (c) 2009 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.

#include <windows.h>
#include <shlobj.h>
#include <vsstyle.h>
#include <vssym32.h>

#include "chrome/browser/views/options/languages_page_view.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/string_util.h"
#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/language_combobox_model.h"
#include "chrome/browser/language_order_table_model.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/shell_dialogs.h"
#include "chrome/browser/views/restart_message_box.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/spellcheck_common.h"
#include "gfx/canvas.h"
#include "gfx/font.h"
#include "gfx/native_theme_win.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "unicode/uloc.h"
#include "views/controls/button/radio_button.h"
#include "views/controls/tabbed_pane/tabbed_pane.h"
#include "views/controls/table/table_view.h"
#include "views/grid_layout.h"
#include "views/standard_layout.h"
#include "views/widget/widget.h"
#include "views/window/window.h"

///////////////////////////////////////////////////////////////////////////////
// AddLanguageWindowView
//
// This opens another window from where a new accept language can be selected.
//
class AddLanguageWindowView : public views::View,
                              public views::Combobox::Listener,
                              public views::DialogDelegate {
 public:
  AddLanguageWindowView(LanguagesPageView* language_delegate, Profile* profile);
  views::Window* container() const { return container_; }
  void set_container(views::Window* container) {
    container_ = container;
  }

  // views::DialogDelegate methods.
  virtual bool Accept();
  virtual std::wstring GetWindowTitle() const;

  // views::WindowDelegate method.
  virtual bool IsModal() const { return true; }
  virtual views::View* GetContentsView() { return this; }

  // views::Combobox::Listener implementation:
  virtual void ItemChanged(views::Combobox* combobox,
                           int prev_index,
                           int new_index);

  // views::View overrides.
  virtual void Layout();
  virtual gfx::Size GetPreferredSize();

 protected:
  virtual void ViewHierarchyChanged(bool is_add, views::View* parent,
                                    views::View* child);

 private:
  void Init();

  // The Options dialog window.
  views::Window* container_;

  // Used for Call back to LanguagePageView that language has been selected.
  LanguagesPageView* language_delegate_;
  std::string accept_language_selected_;

  // Combobox and its corresponding model.
  scoped_ptr<LanguageComboboxModel> accept_language_combobox_model_;
  views::Combobox* accept_language_combobox_;

  // The Profile associated with this window.
  Profile* profile_;

  DISALLOW_COPY_AND_ASSIGN(AddLanguageWindowView);
};

static const int kDialogPadding = 7;
static int kDefaultWindowWidthChars = 60;
static int kDefaultWindowHeightLines = 3;

AddLanguageWindowView::AddLanguageWindowView(
    LanguagesPageView* language_delegate,
    Profile* profile)
    : profile_(profile->GetOriginalProfile()),
      language_delegate_(language_delegate),
      accept_language_combobox_(NULL) {
  Init();

  // Initialize accept_language_selected_ to the first index in drop down.
  accept_language_selected_ = accept_language_combobox_model_->
      GetLocaleFromIndex(0);
}

std::wstring AddLanguageWindowView::GetWindowTitle() const {
  return l10n_util::GetString(IDS_FONT_LANGUAGE_SETTING_LANGUAGES_TAB_TITLE);
}

bool AddLanguageWindowView::Accept() {
  if (language_delegate_) {
    language_delegate_->OnAddLanguage(accept_language_selected_);
  }
  return true;
}

void AddLanguageWindowView::ItemChanged(views::Combobox* combobox,
                                  int prev_index,
                                  int new_index) {
  accept_language_selected_ = accept_language_combobox_model_->
      GetLocaleFromIndex(new_index);
}

void AddLanguageWindowView::Layout() {
  gfx::Size sz = accept_language_combobox_->GetPreferredSize();
  accept_language_combobox_->SetBounds(kDialogPadding, kDialogPadding,
                                       width() - 2*kDialogPadding,
                                       sz.height());
}

gfx::Size AddLanguageWindowView::GetPreferredSize() {
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  const gfx::Font& font = rb.GetFont(ResourceBundle::BaseFont);
  return gfx::Size(font.ave_char_width() * kDefaultWindowWidthChars,
                   font.height() * kDefaultWindowHeightLines);
}

void AddLanguageWindowView::ViewHierarchyChanged(bool is_add,
                                                 views::View* parent,
                                                 views::View* child) {
  // Can't init before we're inserted into a Widget, because we require
  // a HWND to parent native child controls to.
  if (is_add && child == this)
    Init();
}

void AddLanguageWindowView::Init() {
  // Determine Locale Codes.
  const std::string app_locale = g_browser_process->GetApplicationLocale();
  std::vector<std::string> locale_codes;
  l10n_util::GetAcceptLanguagesForLocale(app_locale, &locale_codes);

  accept_language_combobox_model_.reset(new LanguageComboboxModel(
    profile_, locale_codes));
  accept_language_combobox_ = new views::Combobox(
      accept_language_combobox_model_.get());
  accept_language_combobox_->SetSelectedItem(0);
  accept_language_combobox_->set_listener(this);
  AddChildView(accept_language_combobox_);
}

LanguagesPageView::LanguagesPageView(Profile* profile)
    : languages_instructions_(NULL),
      languages_contents_(NULL),
      language_order_table_(NULL),
      add_button_(NULL),
      remove_button_(NULL),
      move_up_button_(NULL),
      move_down_button_(NULL),
      button_stack_(NULL),
      language_info_label_(NULL),
      ui_language_label_(NULL),
      change_ui_language_combobox_(NULL),
      change_dictionary_language_combobox_(NULL),
      enable_spellchecking_checkbox_(NULL),
      enable_autospellcorrect_checkbox_(NULL),
      dictionary_language_label_(NULL),
      OptionsPageView(profile),
      language_table_edited_(false),
      language_warning_shown_(false),
      enable_spellcheck_checkbox_clicked_(false),
      enable_autospellcorrect_checkbox_clicked_(false),
      spellcheck_language_index_selected_(-1),
      ui_language_index_selected_(-1),
      starting_ui_language_index_(-1) {
  accept_languages_.Init(prefs::kAcceptLanguages,
      profile->GetPrefs(), NULL);
  enable_spellcheck_.Init(prefs::kEnableSpellCheck,
      profile->GetPrefs(), NULL);
  enable_autospellcorrect_.Init(prefs::kEnableAutoSpellCorrect,
      profile->GetPrefs(), NULL);
}

LanguagesPageView::~LanguagesPageView() {
  if (language_order_table_)
    language_order_table_->SetModel(NULL);
}

void LanguagesPageView::ButtonPressed(
    views::Button* sender, const views::Event& event) {
  if (sender == move_up_button_) {
    OnMoveUpLanguage();
    language_table_edited_ = true;
  } else if (sender == move_down_button_) {
    OnMoveDownLanguage();
    language_table_edited_ = true;
  } else if (sender == remove_button_) {
    OnRemoveLanguage();
    language_table_edited_ = true;
  } else if (sender == add_button_) {
    views::Window::CreateChromeWindow(
        GetWindow()->GetNativeWindow(),
        gfx::Rect(),
        new AddLanguageWindowView(this, profile()))->Show();
    language_table_edited_ = true;
  } else if (sender == enable_spellchecking_checkbox_) {
    enable_spellcheck_checkbox_clicked_ = true;
  } else if (sender == enable_autospellcorrect_checkbox_) {
    enable_autospellcorrect_checkbox_clicked_ = true;
  }
}

void LanguagesPageView::OnAddLanguage(const std::string& new_language) {
  if (language_order_table_model_->Add(new_language)) {
    language_order_table_->Select(language_order_table_model_->RowCount() - 1);
    OnSelectionChanged();
  }
}

void LanguagesPageView::InitControlLayout() {
  // Define the buttons.
  add_button_ = new views::NativeButton(this, l10n_util::GetString(
      IDS_FONT_LANGUAGE_SETTING_LANGUAGES_SELECTOR_ADD_BUTTON_LABEL));
  remove_button_ = new views::NativeButton(this, l10n_util::GetString(
      IDS_FONT_LANGUAGE_SETTING_LANGUAGES_SELECTOR_REMOVE_BUTTON_LABEL));
  remove_button_->SetEnabled(false);
  move_up_button_ = new views::NativeButton(this, l10n_util::GetString(
      IDS_FONT_LANGUAGE_SETTING_LANGUAGES_SELECTOR_MOVEUP_BUTTON_LABEL));
  move_up_button_->SetEnabled(false);
  move_down_button_ = new views::NativeButton(this, l10n_util::GetString(
      IDS_FONT_LANGUAGE_SETTING_LANGUAGES_SELECTOR_MOVEDOWN_BUTTON_LABEL));
  move_down_button_->SetEnabled(false);

  languages_contents_ = new views::View;
  using views::GridLayout;
  using views::ColumnSet;

  GridLayout* layout = CreatePanelGridLayout(this);
  SetLayoutManager(layout);

  const int single_column_view_set_id = 0;
  ColumnSet* column_set = layout->AddColumnSet(single_column_view_set_id);

  // Add the instructions label.
  column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
                      GridLayout::USE_PREF, 0, 0);
  languages_instructions_ = new views::Label(
      l10n_util::GetString(
          IDS_FONT_LANGUAGE_SETTING_LANGUAGES_INSTRUCTIONS));
  languages_instructions_->SetMultiLine(true);
  languages_instructions_->SetHorizontalAlignment(
      views::Label::ALIGN_LEFT);
  layout->StartRow(0, single_column_view_set_id);
  layout->AddView(languages_instructions_);
  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);

  // Add two columns - for table, and for button stack.
  std::vector<TableColumn> columns;
  columns.push_back(TableColumn());
  language_order_table_model_.reset(new LanguageOrderTableModel);
  language_order_table_ = new views::TableView(
      language_order_table_model_.get(), columns,
      views::TEXT_ONLY, false, true, true);
  language_order_table_->SetObserver(this);

  const int double_column_view_set_id = 1;
  column_set = layout->AddColumnSet(double_column_view_set_id);
  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                        GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
                        GridLayout::USE_PREF, 0, 0);

  layout->StartRow(0, double_column_view_set_id);

  // Add the table to the the first column.
  layout->AddView(language_order_table_);

  // Now add the four buttons to the second column.
  button_stack_ = new views::View;
  GridLayout* button_stack_layout = new GridLayout(button_stack_);
  button_stack_->SetLayoutManager(button_stack_layout);

  column_set = button_stack_layout->AddColumnSet(single_column_view_set_id);
  column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1,
                        GridLayout::USE_PREF, 0, 0);
  button_stack_layout->StartRow(0, single_column_view_set_id);
  button_stack_layout->AddView(add_button_, 1, 1, GridLayout::FILL,
                               GridLayout::CENTER);
  button_stack_layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  button_stack_layout->StartRow(0, single_column_view_set_id);
  button_stack_layout->AddView(remove_button_, 1, 1, GridLayout::FILL,
                               GridLayout::CENTER);
  button_stack_layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  button_stack_layout->StartRow(0, single_column_view_set_id);
  button_stack_layout->AddView(move_up_button_, 1, 1, GridLayout::FILL,
                               GridLayout::CENTER);
  button_stack_layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  button_stack_layout->StartRow(0, single_column_view_set_id);
  button_stack_layout->AddView(move_down_button_, 1, 1, GridLayout::FILL,
                               GridLayout::CENTER);

  layout->AddView(button_stack_);

  layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing);

  language_info_label_ = new views::Label(
      l10n_util::GetString(IDS_OPTIONS_CHROME_LANGUAGE_INFO));
  language_info_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
  ui_language_label_ = new views::Label(
      l10n_util::GetString(IDS_OPTIONS_CHROME_UI_LANGUAGE));
  ui_language_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
  ui_language_model_.reset(new LanguageComboboxModel);
  change_ui_language_combobox_ =
      new views::Combobox(ui_language_model_.get());
  change_ui_language_combobox_->set_listener(this);
  dictionary_language_label_ = new views::Label(
      l10n_util::GetString(IDS_OPTIONS_CHROME_DICTIONARY_LANGUAGE));
  dictionary_language_label_->SetHorizontalAlignment(
      views::Label::ALIGN_LEFT);
  enable_spellchecking_checkbox_ = new views::Checkbox(
      l10n_util::GetString(IDS_OPTIONS_ENABLE_SPELLCHECK));
  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
  if (command_line.HasSwitch(switches::kExperimentalSpellcheckerFeatures)) {
    enable_autospellcorrect_checkbox_ = new views::Checkbox(
        l10n_util::GetString(IDS_OPTIONS_ENABLE_AUTO_SPELL_CORRECTION));
    enable_autospellcorrect_checkbox_->set_listener(this);
  }
  enable_spellchecking_checkbox_->set_listener(this);
  enable_spellchecking_checkbox_->SetMultiLine(true);

  // Determine Locale Codes.
  std::vector<std::string> spell_check_languages;
  SpellCheckCommon::SpellCheckLanguages(&spell_check_languages);
  dictionary_language_model_.reset(new LanguageComboboxModel(profile(),
      spell_check_languages));
  change_dictionary_language_combobox_ =
      new views::Combobox(dictionary_language_model_.get());
  change_dictionary_language_combobox_->set_listener(this);

  // SpellCheck language settings.
  layout->StartRow(0, single_column_view_set_id);
  layout->AddView(enable_spellchecking_checkbox_);
  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  if (command_line.HasSwitch(switches::kExperimentalSpellcheckerFeatures)) {
    layout->StartRow(0, single_column_view_set_id);
    layout->AddView(enable_autospellcorrect_checkbox_);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }
  const int double_column_view_set_2_id = 2;
  column_set = layout->AddColumnSet(double_column_view_set_2_id);
  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
                        GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                        GridLayout::USE_PREF, 0, 0);

  layout->StartRow(0, double_column_view_set_2_id);
  layout->AddView(dictionary_language_label_);
  layout->AddView(change_dictionary_language_combobox_);

  // UI language settings.
  layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing);
  layout->StartRow(0, single_column_view_set_id);
  layout->AddView(language_info_label_);
  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);

  layout->StartRow(0, double_column_view_set_2_id);
  layout->AddView(ui_language_label_);
  layout->AddView(change_ui_language_combobox_);
  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);

  // Init member prefs so we can update the controls if prefs change.
  app_locale_.Init(prefs::kApplicationLocale,
                   g_browser_process->local_state(), this);
  dictionary_language_.Init(prefs::kSpellCheckDictionary,
                            profile()->GetPrefs(), this);
}

void LanguagesPageView::NotifyPrefChanged(const std::wstring* pref_name) {
  if (!pref_name || *pref_name == prefs::kAcceptLanguages) {
    language_order_table_model_->SetAcceptLanguagesString(
        WideToASCII(accept_languages_.GetValue()));
  }
  if (!pref_name || *pref_name == prefs::kApplicationLocale) {
    int index = ui_language_model_->GetSelectedLanguageIndex(
        prefs::kApplicationLocale);
    if (-1 == index) {
      // The pref value for locale isn't valid.  Use the current app locale
      // (which is what we're currently using).
      index = ui_language_model_->GetIndexFromLocale(
          g_browser_process->GetApplicationLocale());
    }
    DCHECK(-1 != index);
    change_ui_language_combobox_->SetSelectedItem(index);
    starting_ui_language_index_ = index;
  }
  if (!pref_name || *pref_name == prefs::kSpellCheckDictionary) {
    int index = dictionary_language_model_->GetSelectedLanguageIndex(
        prefs::kSpellCheckDictionary);

    // If the index for the current language cannot be found, it is due to
    // the fact that the pref-member value for the last dictionary language
    // set by the user still uses the old format; i.e. language-region, even
    // when region is not necessary. For example, if the user sets the
    // dictionary language to be French, the pref-member value in the user
    // profile is "fr-FR", whereas we now use only "fr". To resolve this issue,
    // if "fr-FR" is read from the pref, the language code ("fr" here) is
    // extracted, and re-written in the pref, so that the pref-member value for
    // dictionary language in the user profile now correctly stores "fr"
    // instead of "fr-FR".
    if (index < 0) {
      const std::string& lang_region = WideToASCII(
          dictionary_language_.GetValue());
      dictionary_language_.SetValue(ASCIIToWide(
          SpellCheckCommon::GetLanguageFromLanguageRegion(lang_region)));
      index = dictionary_language_model_->GetSelectedLanguageIndex(
          prefs::kSpellCheckDictionary);
    }

    change_dictionary_language_combobox_->SetSelectedItem(index);
    spellcheck_language_index_selected_ = -1;
  }
  if (!pref_name || *pref_name == prefs::kEnableSpellCheck) {
    enable_spellchecking_checkbox_->SetChecked(
        enable_spellcheck_.GetValue());
  }
  if (!pref_name || *pref_name == prefs::kEnableAutoSpellCorrect) {
    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    if (command_line.HasSwitch(switches::kExperimentalSpellcheckerFeatures)) {
      enable_autospellcorrect_checkbox_->SetChecked(
          enable_autospellcorrect_.GetValue());
    }
  }
}

void LanguagesPageView::ItemChanged(views::Combobox* sender,
                                    int prev_index,
                                    int new_index) {
  if (prev_index == new_index)
    return;

  if (sender == change_ui_language_combobox_) {
    if (new_index == starting_ui_language_index_)
      ui_language_index_selected_ = -1;
    else
      ui_language_index_selected_ = new_index;

    if (!language_warning_shown_) {
      RestartMessageBox::ShowMessageBox(GetWindow()->GetNativeWindow());
      language_warning_shown_ = true;
    }
  } else if (sender == change_dictionary_language_combobox_) {
    // Set the spellcheck language selected.
    spellcheck_language_index_selected_ = new_index;

    // Remove the previously added spell check language to the accept list.
    if (!spellcheck_language_added_.empty()) {
      int old_index = language_order_table_model_->GetIndex(
          spellcheck_language_added_);
      if (old_index > -1)
        language_order_table_model_->Remove(old_index);
    }

    // Add this new spell check language only if it is not already in the
    // accept language list.
    std::string language =
        dictionary_language_model_->GetLocaleFromIndex(new_index);
    int index = language_order_table_model_->GetIndex(language);
    if (index == -1) {
      // Add the new language.
      OnAddLanguage(language);
      language_table_edited_ = true;
      spellcheck_language_added_ = language;
    } else {
      spellcheck_language_added_ = "";
    }
  }
}

void LanguagesPageView::OnSelectionChanged() {
  move_up_button_->SetEnabled(language_order_table_->FirstSelectedRow() > 0 &&
                              language_order_table_->SelectedRowCount() == 1);
  move_down_button_->SetEnabled(language_order_table_->FirstSelectedRow() <
                                language_order_table_->RowCount() - 1 &&
                                language_order_table_->SelectedRowCount() ==
                                1);
  remove_button_->SetEnabled(language_order_table_->SelectedRowCount() > 0);
}

void LanguagesPageView::OnRemoveLanguage() {
  int item_selected = 0;
  for (views::TableView::iterator i =
       language_order_table_->SelectionBegin();
       i != language_order_table_->SelectionEnd(); ++i) {
    language_order_table_model_->Remove(*i);
    item_selected = *i;
  }

  move_up_button_->SetEnabled(false);
  move_down_button_->SetEnabled(false);
  remove_button_->SetEnabled(false);
  int items_left = language_order_table_model_->RowCount();
  if (items_left <= 0)
    return;
  if (item_selected > items_left - 1)
    item_selected = items_left - 1;
  language_order_table_->Select(item_selected);
  OnSelectionChanged();
}

void LanguagesPageView::OnMoveDownLanguage() {
  int item_selected = language_order_table_->FirstSelectedRow();
  language_order_table_model_->MoveDown(item_selected);
  language_order_table_->Select(item_selected + 1);
  OnSelectionChanged();
}

void LanguagesPageView::OnMoveUpLanguage() {
  int item_selected = language_order_table_->FirstSelectedRow();
  language_order_table_model_->MoveUp(item_selected);
  language_order_table_->Select(item_selected - 1);

  OnSelectionChanged();
}

void LanguagesPageView::SaveChanges() {
  if (language_order_table_model_.get() && language_table_edited_) {
    accept_languages_.SetValue(ASCIIToWide(
        language_order_table_model_->GetLanguageList()));
  }

  if (ui_language_index_selected_ != -1) {
    UserMetricsRecordAction(UserMetricsAction("Options_AppLanguage"),
                            g_browser_process->local_state());
    app_locale_.SetValue(ASCIIToWide(ui_language_model_->
        GetLocaleFromIndex(ui_language_index_selected_)));

    // Remove pref values for spellcheck dictionaries forcefully.
    PrefService* prefs = profile()->GetPrefs();
    if (prefs)
      prefs->ClearPref(prefs::kSpellCheckDictionary);
  }

  if (spellcheck_language_index_selected_ != -1) {
    UserMetricsRecordAction(UserMetricsAction("Options_DictionaryLanguage"),
                            profile()->GetPrefs());
    dictionary_language_.SetValue(ASCIIToWide(dictionary_language_model_->
        GetLocaleFromIndex(spellcheck_language_index_selected_)));
  }

  if (enable_spellcheck_checkbox_clicked_)
    enable_spellcheck_.SetValue(enable_spellchecking_checkbox_->checked());

  if (enable_autospellcorrect_checkbox_clicked_) {
    enable_autospellcorrect_.SetValue(
        enable_autospellcorrect_checkbox_->checked());
  }
}

Generated by  Doxygen 1.6.0   Back to index