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/spelling_options_submenu_observer.h"
6
7 #include "base/check_op.h"
8 #include "base/command_line.h"
9 #include "chrome/app/chrome_command_ids.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
13 #include "chrome/browser/spellchecker/spellcheck_service.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/grit/generated_resources.h"
16 #include "components/prefs/pref_member.h"
17 #include "components/prefs/pref_service.h"
18 #include "components/renderer_context_menu/render_view_context_menu_proxy.h"
19 #include "components/spellcheck/browser/pref_names.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "ui/base/l10n/l10n_util.h"
23 #include "ui/base/models/menu_separator_types.h"
24
25 using content::BrowserThread;
26
SpellingOptionsSubMenuObserver(RenderViewContextMenuProxy * proxy,ui::SimpleMenuModel::Delegate * delegate,int group_id)27 SpellingOptionsSubMenuObserver::SpellingOptionsSubMenuObserver(
28 RenderViewContextMenuProxy* proxy,
29 ui::SimpleMenuModel::Delegate* delegate,
30 int group_id)
31 : proxy_(proxy),
32 submenu_model_(delegate),
33 language_group_id_(group_id),
34 num_selected_dictionaries_(0) {
35 if (proxy_ && proxy_->GetBrowserContext()) {
36 Profile* profile = Profile::FromBrowserContext(proxy_->GetBrowserContext());
37 use_spelling_service_.Init(spellcheck::prefs::kSpellCheckUseSpellingService,
38 profile->GetPrefs());
39 }
40 DCHECK(proxy_);
41 }
42
~SpellingOptionsSubMenuObserver()43 SpellingOptionsSubMenuObserver::~SpellingOptionsSubMenuObserver() {}
44
InitMenu(const content::ContextMenuParams & params)45 void SpellingOptionsSubMenuObserver::InitMenu(
46 const content::ContextMenuParams& params) {
47 DCHECK_CURRENTLY_ON(BrowserThread::UI);
48
49 // Add available spell-checker languages to the sub menu.
50 content::BrowserContext* browser_context = proxy_->GetBrowserContext();
51 DCHECK(browser_context);
52 SpellcheckService::GetDictionaries(browser_context, &dictionaries_);
53 DCHECK(dictionaries_.size() <
54 IDC_SPELLCHECK_LANGUAGES_LAST - IDC_SPELLCHECK_LANGUAGES_FIRST);
55 const std::string app_locale = g_browser_process->GetApplicationLocale();
56
57 if (dictionaries_.size() > 1) {
58 submenu_model_.AddRadioItemWithStringId(
59 IDC_SPELLCHECK_MULTI_LINGUAL,
60 IDS_CONTENT_CONTEXT_SPELLCHECK_MULTI_LINGUAL, language_group_id_);
61 }
62
63 const size_t kMaxLanguages = static_cast<size_t>(
64 IDC_SPELLCHECK_LANGUAGES_FIRST - IDC_SPELLCHECK_LANGUAGES_LAST);
65 for (size_t i = 0; i < dictionaries_.size() && i < kMaxLanguages; ++i) {
66 submenu_model_.AddRadioItem(
67 IDC_SPELLCHECK_LANGUAGES_FIRST + i,
68 l10n_util::GetDisplayNameForLocale(dictionaries_[i].language,
69 app_locale, true),
70 language_group_id_);
71 if (dictionaries_[i].used_for_spellcheck)
72 ++num_selected_dictionaries_;
73 }
74
75 // Add an item that opens the 'Settings - Languages' page. This item is
76 // handled in RenderViewContextMenu.
77 submenu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS,
78 IDS_CONTENT_CONTEXT_LANGUAGE_SETTINGS);
79 submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
80
81 if (dictionaries_.size() > 0) {
82 // Add a 'Use basic spell check' item in the sub menu.
83 submenu_model_.AddCheckItem(
84 IDC_CHECK_SPELLING_WHILE_TYPING,
85 l10n_util::GetStringUTF16(
86 IDS_CONTENT_CONTEXT_CHECK_SPELLING_WHILE_TYPING));
87
88 // Add a check item 'Use enhanced spell check'. This item is handled in
89 // SpellingMenuObserver.
90 Profile* profile = Profile::FromBrowserContext(proxy_->GetBrowserContext());
91 RenderViewContextMenu::AddSpellCheckServiceItem(
92 &submenu_model_,
93 profile->GetPrefs()->GetBoolean(spellcheck::prefs::kSpellCheckEnable) &&
94 use_spelling_service_.GetValue());
95 }
96
97 proxy_->AddSubMenu(
98 IDC_SPELLCHECK_MENU,
99 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLCHECK_MENU),
100 &submenu_model_);
101 }
102
IsCommandIdSupported(int command_id)103 bool SpellingOptionsSubMenuObserver::IsCommandIdSupported(int command_id) {
104 // Allow Spell Check language items on sub menu for text area context menu.
105 if (command_id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
106 command_id < IDC_SPELLCHECK_LANGUAGES_LAST) {
107 DCHECK_GT(IDC_SPELLCHECK_LANGUAGES_FIRST + dictionaries_.size(),
108 static_cast<size_t>(command_id));
109 return true;
110 }
111
112 switch (command_id) {
113 case IDC_CHECK_SPELLING_WHILE_TYPING:
114 case IDC_SPELLCHECK_MENU:
115 case IDC_SPELLCHECK_MULTI_LINGUAL:
116 return true;
117 }
118
119 return false;
120 }
121
IsCommandIdChecked(int command_id)122 bool SpellingOptionsSubMenuObserver::IsCommandIdChecked(int command_id) {
123 DCHECK(IsCommandIdSupported(command_id));
124
125 if (command_id == IDC_SPELLCHECK_MULTI_LINGUAL)
126 return num_selected_dictionaries_ == dictionaries_.size();
127
128 if (command_id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
129 command_id < IDC_SPELLCHECK_LANGUAGES_LAST) {
130 if (num_selected_dictionaries_ == dictionaries_.size())
131 return dictionaries_.size() == 1;
132
133 size_t dictionary_index =
134 static_cast<size_t>(command_id - IDC_SPELLCHECK_LANGUAGES_FIRST);
135 return dictionaries_[dictionary_index].used_for_spellcheck;
136 }
137
138 // Check box for 'Use basic spell check'.
139 if (command_id == IDC_CHECK_SPELLING_WHILE_TYPING) {
140 Profile* profile = Profile::FromBrowserContext(proxy_->GetBrowserContext());
141 return profile->GetPrefs()->GetBoolean(
142 spellcheck::prefs::kSpellCheckEnable) &&
143 !profile->GetPrefs()->GetBoolean(
144 spellcheck::prefs::kSpellCheckUseSpellingService);
145 }
146
147 return false;
148 }
149
IsCommandIdEnabled(int command_id)150 bool SpellingOptionsSubMenuObserver::IsCommandIdEnabled(int command_id) {
151 DCHECK(IsCommandIdSupported(command_id));
152
153 Profile* profile = Profile::FromBrowserContext(proxy_->GetBrowserContext());
154 DCHECK(profile);
155 const PrefService* pref = profile->GetPrefs();
156 if ((command_id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
157 command_id < IDC_SPELLCHECK_LANGUAGES_LAST) ||
158 command_id == IDC_SPELLCHECK_MULTI_LINGUAL) {
159 return pref->GetBoolean(spellcheck::prefs::kSpellCheckEnable);
160 }
161
162 switch (command_id) {
163 case IDC_CHECK_SPELLING_WHILE_TYPING:
164 return !pref->FindPreference(spellcheck::prefs::kSpellCheckEnable)
165 ->IsManaged();
166
167 case IDC_SPELLCHECK_MENU:
168 return true;
169 }
170
171 return false;
172 }
173
ExecuteCommand(int command_id)174 void SpellingOptionsSubMenuObserver::ExecuteCommand(int command_id) {
175 DCHECK(IsCommandIdSupported(command_id));
176
177 // Check to see if one of the spell check language ids have been clicked.
178 Profile* profile = Profile::FromBrowserContext(proxy_->GetBrowserContext());
179 DCHECK(profile);
180
181 if (command_id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
182 static_cast<size_t>(command_id) <
183 IDC_SPELLCHECK_LANGUAGES_FIRST + dictionaries_.size()) {
184 size_t dictionary_index =
185 static_cast<size_t>(command_id - IDC_SPELLCHECK_LANGUAGES_FIRST);
186 StringListPrefMember dictionaries_pref;
187 dictionaries_pref.Init(spellcheck::prefs::kSpellCheckDictionaries,
188 profile->GetPrefs());
189 dictionaries_pref.SetValue({dictionaries_[dictionary_index].language});
190 return;
191 }
192
193 switch (command_id) {
194 case IDC_CHECK_SPELLING_WHILE_TYPING: {
195 bool spellCheckEnabled =
196 profile->GetPrefs()->GetBoolean(spellcheck::prefs::kSpellCheckEnable);
197 bool enhancedSpellCheckEnabled = profile->GetPrefs()->GetBoolean(
198 spellcheck::prefs::kSpellCheckUseSpellingService);
199
200 if (spellCheckEnabled && !enhancedSpellCheckEnabled) {
201 // User is turning off spell check
202 profile->GetPrefs()->SetBoolean(spellcheck::prefs::kSpellCheckEnable,
203 false);
204 } else if (enhancedSpellCheckEnabled) {
205 // Use is choosing 'basic' over 'enhanced'
206 profile->GetPrefs()->SetBoolean(spellcheck::prefs::kSpellCheckEnable,
207 true);
208 profile->GetPrefs()->SetBoolean(
209 spellcheck::prefs::kSpellCheckUseSpellingService, false);
210 } else {
211 // User is turning on spell check
212 profile->GetPrefs()->SetBoolean(spellcheck::prefs::kSpellCheckEnable,
213 true);
214 }
215 break;
216 }
217
218 case IDC_SPELLCHECK_MULTI_LINGUAL: {
219 StringListPrefMember dictionaries_pref;
220 dictionaries_pref.Init(spellcheck::prefs::kSpellCheckDictionaries,
221 profile->GetPrefs());
222 std::vector<std::string> all_languages;
223 for (const auto& dictionary : dictionaries_)
224 all_languages.push_back(dictionary.language);
225 dictionaries_pref.SetValue(all_languages);
226 break;
227 }
228 }
229 }
230