1// Copyright 2014 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.
4
5#include "chrome/browser/renderer_context_menu/spellchecker_submenu_observer.h"
6
7#include "base/command_line.h"
8#include "base/logging.h"
9#include "base/prefs/pref_member.h"
10#include "base/prefs/pref_service.h"
11#include "chrome/app/chrome_command_ids.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
14#include "chrome/browser/spellchecker/spellcheck_service.h"
15#include "chrome/common/chrome_switches.h"
16#include "chrome/common/pref_names.h"
17#include "chrome/common/spellcheck_messages.h"
18#include "chrome/grit/generated_resources.h"
19#include "content/public/browser/render_view_host.h"
20#include "content/public/browser/render_widget_host_view.h"
21#include "extensions/browser/view_type_utils.h"
22#include "ui/base/l10n/l10n_util.h"
23#include "ui/base/models/simple_menu_model.h"
24
25using content::BrowserThread;
26
27SpellCheckerSubMenuObserver::SpellCheckerSubMenuObserver(
28    RenderViewContextMenuProxy* proxy,
29    ui::SimpleMenuModel::Delegate* delegate,
30    int group)
31    : proxy_(proxy),
32      submenu_model_(delegate),
33      language_group_(group),
34      language_selected_(0) {
35  DCHECK(proxy_);
36}
37
38SpellCheckerSubMenuObserver::~SpellCheckerSubMenuObserver() {
39}
40
41void SpellCheckerSubMenuObserver::InitMenu(
42    const content::ContextMenuParams& params) {
43  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
44
45  // Add available spell-checker languages to the sub menu.
46  content::BrowserContext* browser_context = proxy_->GetBrowserContext();
47  DCHECK(browser_context);
48  language_selected_ =
49      SpellcheckService::GetSpellCheckLanguages(browser_context, &languages_);
50  DCHECK(languages_.size() <
51         IDC_SPELLCHECK_LANGUAGES_LAST - IDC_SPELLCHECK_LANGUAGES_FIRST);
52  const std::string app_locale = g_browser_process->GetApplicationLocale();
53  for (size_t i = 0; i < languages_.size(); ++i) {
54    base::string16 display_name(
55        l10n_util::GetDisplayNameForLocale(languages_[i], app_locale, true));
56    submenu_model_.AddRadioItem(IDC_SPELLCHECK_LANGUAGES_FIRST + i,
57                                display_name,
58                                language_group_);
59  }
60
61  // Add an item that opens the 'fonts and languages options' page.
62  submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
63  submenu_model_.AddItemWithStringId(
64      IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS,
65      IDS_CONTENT_CONTEXT_LANGUAGE_SETTINGS);
66
67  // Add a 'Check spelling while typing' item in the sub menu.
68  submenu_model_.AddCheckItem(
69      IDC_CHECK_SPELLING_WHILE_TYPING,
70      l10n_util::GetStringUTF16(
71          IDS_CONTENT_CONTEXT_CHECK_SPELLING_WHILE_TYPING));
72
73  // Add a check item "Ask Google for spelling suggestions" item. (This class
74  // does not handle this item because the SpellingMenuObserver class handles it
75  // on behalf of this class.)
76  submenu_model_.AddCheckItem(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE,
77      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLING_ASK_GOOGLE));
78
79  // Add a check item "Automatically correct spelling".
80  const CommandLine* command_line = CommandLine::ForCurrentProcess();
81  if (command_line->HasSwitch(switches::kEnableSpellingAutoCorrect)) {
82    submenu_model_.AddCheckItem(IDC_CONTENT_CONTEXT_AUTOCORRECT_SPELLING_TOGGLE,
83        l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLING_AUTOCORRECT));
84  }
85
86  proxy_->AddSubMenu(
87      IDC_SPELLCHECK_MENU,
88      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLCHECK_MENU),
89      &submenu_model_);
90}
91
92bool SpellCheckerSubMenuObserver::IsCommandIdSupported(int command_id) {
93  // Allow Spell Check language items on sub menu for text area context menu.
94  if (command_id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
95      command_id < IDC_SPELLCHECK_LANGUAGES_LAST) {
96    return true;
97  }
98
99  switch (command_id) {
100    case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
101      // Return false so RenderViewContextMenu can handle this item because it
102      // is hard for this class to handle it.
103      return false;
104
105    case IDC_CHECK_SPELLING_WHILE_TYPING:
106    case IDC_SPELLPANEL_TOGGLE:
107    case IDC_SPELLCHECK_MENU:
108      return true;
109  }
110
111  return false;
112}
113
114bool SpellCheckerSubMenuObserver::IsCommandIdChecked(int command_id) {
115  DCHECK(IsCommandIdSupported(command_id));
116
117  if (command_id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
118      command_id < IDC_SPELLCHECK_LANGUAGES_LAST) {
119    return language_selected_ == command_id - IDC_SPELLCHECK_LANGUAGES_FIRST;
120  }
121
122  // Check box for 'Check Spelling while typing'.
123  if (command_id == IDC_CHECK_SPELLING_WHILE_TYPING) {
124    Profile* profile = Profile::FromBrowserContext(proxy_->GetBrowserContext());
125    DCHECK(profile);
126    return profile->GetPrefs()->GetBoolean(prefs::kEnableContinuousSpellcheck);
127  }
128
129  return false;
130}
131
132bool SpellCheckerSubMenuObserver::IsCommandIdEnabled(int command_id) {
133  DCHECK(IsCommandIdSupported(command_id));
134
135  Profile* profile = Profile::FromBrowserContext(proxy_->GetBrowserContext());
136  DCHECK(profile);
137  const PrefService* pref = profile->GetPrefs();
138  if (command_id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
139      command_id < IDC_SPELLCHECK_LANGUAGES_LAST) {
140    return pref->GetBoolean(prefs::kEnableContinuousSpellcheck);
141  }
142
143  switch (command_id) {
144    case IDC_CHECK_SPELLING_WHILE_TYPING:
145    case IDC_SPELLPANEL_TOGGLE:
146    case IDC_SPELLCHECK_MENU:
147      return true;
148  }
149
150  return false;
151}
152
153void SpellCheckerSubMenuObserver::ExecuteCommand(int command_id) {
154  DCHECK(IsCommandIdSupported(command_id));
155
156  // Check to see if one of the spell check language ids have been clicked.
157  Profile* profile = Profile::FromBrowserContext(proxy_->GetBrowserContext());
158  DCHECK(profile);
159  if (command_id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
160      command_id < IDC_SPELLCHECK_LANGUAGES_LAST) {
161    const size_t language = command_id - IDC_SPELLCHECK_LANGUAGES_FIRST;
162    if (profile && language < languages_.size()) {
163      StringPrefMember dictionary_language;
164      dictionary_language.Init(prefs::kSpellCheckDictionary,
165                               profile->GetPrefs());
166      dictionary_language.SetValue(languages_[language]);
167    }
168    return;
169  }
170
171  switch (command_id) {
172    case IDC_CHECK_SPELLING_WHILE_TYPING:
173      profile->GetPrefs()->SetBoolean(
174          prefs::kEnableContinuousSpellcheck,
175          !profile->GetPrefs()->GetBoolean(prefs::kEnableContinuousSpellcheck));
176    break;
177  }
178}
179