OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/tab_contents/spelling_menu_observer.h" | 5 #include "chrome/browser/tab_contents/spelling_menu_observer.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
10 #include "base/json/string_escape.h" | 10 #include "base/json/string_escape.h" |
11 #include "base/stringprintf.h" | 11 #include "base/stringprintf.h" |
12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
13 #include "base/values.h" | 13 #include "base/values.h" |
14 #include "chrome/app/chrome_command_ids.h" | 14 #include "chrome/app/chrome_command_ids.h" |
15 #include "chrome/browser/prefs/pref_service.h" | 15 #include "chrome/browser/prefs/pref_service.h" |
16 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
17 #include "chrome/browser/spellchecker/spellcheck_host.h" | |
18 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h" | |
17 #include "chrome/browser/tab_contents/render_view_context_menu.h" | 19 #include "chrome/browser/tab_contents/render_view_context_menu.h" |
18 #include "chrome/common/pref_names.h" | 20 #include "chrome/common/pref_names.h" |
19 #include "content/browser/renderer_host/render_view_host.h" | 21 #include "content/browser/renderer_host/render_view_host.h" |
20 #include "content/public/common/url_fetcher.h" | 22 #include "content/public/common/url_fetcher.h" |
21 #include "googleurl/src/gurl.h" | 23 #include "googleurl/src/gurl.h" |
22 #include "grit/generated_resources.h" | 24 #include "grit/generated_resources.h" |
23 #include "ui/base/l10n/l10n_util.h" | 25 #include "ui/base/l10n/l10n_util.h" |
24 #include "unicode/uloc.h" | 26 #include "unicode/uloc.h" |
25 #include "webkit/glue/context_menu.h" | 27 #include "webkit/glue/context_menu.h" |
26 | 28 |
(...skipping 21 matching lines...) Expand all Loading... | |
48 | 50 |
49 // Exit if we are not in an editable element because we add a menu item only | 51 // Exit if we are not in an editable element because we add a menu item only |
50 // for editable elements. | 52 // for editable elements. |
51 if (!params.is_editable) | 53 if (!params.is_editable) |
52 return; | 54 return; |
53 | 55 |
54 Profile* profile = proxy_->GetProfile(); | 56 Profile* profile = proxy_->GetProfile(); |
55 if (!profile || !profile->GetRequestContext()) | 57 if (!profile || !profile->GetRequestContext()) |
56 return; | 58 return; |
57 | 59 |
58 // Retrieve the misspelled word to be sent to the Spelling service. | 60 PrefService* pref = profile->GetPrefs(); |
59 string16 text = params.misspelled_word; | 61 if (pref->GetBoolean(prefs::kEnableSpellCheck) && |
60 if (text.empty()) | 62 pref->GetBoolean(prefs::kSpellCheckUseSpellingService)) { |
61 return; | 63 // Retrieve the misspelled word to be sent to the Spelling service. |
64 string16 text = params.misspelled_word; | |
65 if (text.empty()) | |
66 return; | |
62 | 67 |
63 // Initialize variables used in OnURLFetchComplete(). We copy the input text | 68 // Initialize variables used in OnURLFetchComplete(). We copy the input text |
64 // to the result text so we can replace its misspelled regions with | 69 // to the result text so we can replace its misspelled regions with |
65 // suggestions. | 70 // suggestions. |
66 loading_frame_ = 0; | 71 loading_frame_ = 0; |
67 succeeded_ = false; | 72 succeeded_ = false; |
68 result_ = text; | 73 result_ = text; |
69 | 74 |
70 // Add a placeholder item. This item will be updated when we receive a | 75 // Add a placeholder item. This item will be updated when we receive a |
71 // response from the Spelling service. (We do not have to disable this item | 76 // response from the Spelling service. (We do not have to disable this item |
72 // now since Chrome will call IsCommandIdEnabled() and disable it.) | 77 // now since Chrome will call IsCommandIdEnabled() and disable it.) |
73 loading_message_ = | 78 loading_message_ = |
74 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLING_CHECKING); | 79 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLING_CHECKING); |
75 proxy_->AddMenuItem(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, | 80 proxy_->AddMenuItem(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, |
76 loading_message_); | 81 loading_message_); |
77 | 82 |
78 // Invoke a JSON-RPC call to the Spelling service in the background so we can | 83 // Invoke a JSON-RPC call to the Spelling service in the background so we |
79 // update the placeholder item when we receive its response. It also starts | 84 // can update the placeholder item when we receive its response. It also |
80 // the animation timer so we can show animation until we receive it. | 85 // starts the animation timer so we can show animation until we receive it. |
81 const PrefService* pref = profile->GetPrefs(); | 86 const PrefService* pref = profile->GetPrefs(); |
82 std::string language = | 87 std::string language = |
83 pref ? pref->GetString(prefs::kSpellCheckDictionary) : "en-US"; | 88 pref ? pref->GetString(prefs::kSpellCheckDictionary) : "en-US"; |
84 Invoke(text, language, profile->GetRequestContext()); | 89 Invoke(text, language, profile->GetRequestContext()); |
90 } | |
91 | |
92 // Append Dictionary spell check suggestions. | |
93 suggestions_ = params.dictionary_suggestions; | |
94 for (size_t i = 0; i < params.dictionary_suggestions.size() && | |
95 IDC_SPELLCHECK_SUGGESTION_0 + i <= IDC_SPELLCHECK_SUGGESTION_LAST; | |
96 ++i) { | |
97 proxy_->AddMenuItem(IDC_SPELLCHECK_SUGGESTION_0 + static_cast<int>(i), | |
98 params.dictionary_suggestions[i]); | |
99 } | |
85 } | 100 } |
86 | 101 |
87 bool SpellingMenuObserver::IsCommandIdSupported(int command_id) { | 102 bool SpellingMenuObserver::IsCommandIdSupported(int command_id) { |
88 return command_id == IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION; | 103 if (command_id >= IDC_SPELLCHECK_SUGGESTION_0 && |
104 command_id <= IDC_SPELLCHECK_SUGGESTION_4) | |
105 return true; | |
106 | |
107 if (command_id == IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION) | |
Miranda Callahan
2011/10/31 13:33:46
Maybe change the last three lines to:
return (com
| |
108 return true; | |
109 return false; | |
89 } | 110 } |
90 | 111 |
91 bool SpellingMenuObserver::IsCommandIdEnabled(int command_id) { | 112 bool SpellingMenuObserver::IsCommandIdEnabled(int command_id) { |
92 return command_id == IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION && succeeded_; | 113 DCHECK(IsCommandIdSupported(command_id)); |
114 | |
115 if (command_id >= IDC_SPELLCHECK_SUGGESTION_0 && | |
116 command_id <= IDC_SPELLCHECK_SUGGESTION_4) | |
117 return true; | |
118 | |
119 if (command_id == IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION) | |
120 return succeeded_; | |
121 return false; | |
93 } | 122 } |
94 | 123 |
95 void SpellingMenuObserver::ExecuteCommand(int command_id) { | 124 void SpellingMenuObserver::ExecuteCommand(int command_id) { |
96 if (IsCommandIdEnabled(command_id)) | 125 DCHECK(IsCommandIdSupported(command_id)); |
126 | |
127 if (command_id >= IDC_SPELLCHECK_SUGGESTION_0 && | |
128 command_id <= IDC_SPELLCHECK_SUGGESTION_4) { | |
129 proxy_->GetRenderViewHost()->Replace( | |
130 suggestions_[command_id - IDC_SPELLCHECK_SUGGESTION_0]); | |
131 // GetSpellCheckHost() can return null when the suggested word is | |
132 // provided by Web SpellCheck API. | |
133 Profile* profile = proxy_->GetProfile(); | |
134 if (profile) { | |
135 SpellCheckHost* spellcheck_host = profile->GetSpellCheckHost(); | |
136 if (spellcheck_host && spellcheck_host->GetMetrics()) | |
137 spellcheck_host->GetMetrics()->RecordReplacedWordStats(1); | |
138 } | |
139 return; | |
140 } | |
141 | |
142 if (command_id == IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION) | |
97 proxy_->GetRenderViewHost()->Replace(result_); | 143 proxy_->GetRenderViewHost()->Replace(result_); |
98 } | 144 } |
99 | 145 |
100 bool SpellingMenuObserver::Invoke(const string16& text, | 146 bool SpellingMenuObserver::Invoke(const string16& text, |
101 const std::string& locale, | 147 const std::string& locale, |
102 net::URLRequestContextGetter* context) { | 148 net::URLRequestContextGetter* context) { |
103 // Create the parameters needed by Spelling API. Spelling API needs three | 149 // Create the parameters needed by Spelling API. Spelling API needs three |
104 // parameters: ISO language code, ISO3 country code, and text to be checked by | 150 // parameters: ISO language code, ISO3 country code, and text to be checked by |
105 // the service. On the other hand, Chrome uses an ISO locale ID and it may | 151 // the service. On the other hand, Chrome uses an ISO locale ID and it may |
106 // not include a country ID, e.g. "fr", "de", etc. To create the input | 152 // not include a country ID, e.g. "fr", "de", etc. To create the input |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
157 | 203 |
158 scoped_ptr<content::URLFetcher> clean_up_fetcher(fetcher_.release()); | 204 scoped_ptr<content::URLFetcher> clean_up_fetcher(fetcher_.release()); |
159 animation_timer_.Stop(); | 205 animation_timer_.Stop(); |
160 | 206 |
161 // Parse the response JSON and replace misspelled words in the |result_| text | 207 // Parse the response JSON and replace misspelled words in the |result_| text |
162 // with their suggestions. | 208 // with their suggestions. |
163 std::string data; | 209 std::string data; |
164 source->GetResponseAsString(&data); | 210 source->GetResponseAsString(&data); |
165 succeeded_ = ParseResponse(source->GetResponseCode(), data); | 211 succeeded_ = ParseResponse(source->GetResponseCode(), data); |
166 if (!succeeded_) | |
167 result_ = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLING_CORRECT); | |
168 | 212 |
169 // Update the menu item with the result text. We enable this item only when | 213 // Update the menu item with the result text. We disable this item and hide it |
170 // the request text has misspelled words. (We disable this item not only when | 214 // when the spelling service does not provide valid suggestions. |
171 // we receive a server error but also when the input text consists only of | |
172 // well-spelled words. For either case, we do not need to replace the input | |
173 // text.) | |
174 proxy_->UpdateMenuItem(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, succeeded_, | 215 proxy_->UpdateMenuItem(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, succeeded_, |
175 false, result_); | 216 !succeeded_, result_); |
176 } | 217 } |
177 | 218 |
178 bool SpellingMenuObserver::ParseResponse(int response, | 219 bool SpellingMenuObserver::ParseResponse(int response, |
179 const std::string& data) { | 220 const std::string& data) { |
180 // When this JSON-RPC call finishes successfully, the Spelling service returns | 221 // When this JSON-RPC call finishes successfully, the Spelling service returns |
181 // an JSON object listed below. | 222 // an JSON object listed below. |
182 // * result - an envelope object representing the result from the APIARY | 223 // * result - an envelope object representing the result from the APIARY |
183 // server, which is the JSON-API front-end for the Spelling service. This | 224 // server, which is the JSON-API front-end for the Spelling service. This |
184 // object consists of the following variable: | 225 // object consists of the following variable: |
185 // - spellingCheckResponse (SpellingCheckResponse). | 226 // - spellingCheckResponse (SpellingCheckResponse). |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
248 // alternative. | 289 // alternative. |
249 DictionaryValue* suggestion = NULL; | 290 DictionaryValue* suggestion = NULL; |
250 string16 text; | 291 string16 text; |
251 if (!suggestions->GetDictionary(0, &suggestion) || | 292 if (!suggestions->GetDictionary(0, &suggestion) || |
252 !suggestion->GetString("suggestion", &text)) { | 293 !suggestion->GetString("suggestion", &text)) { |
253 return false; | 294 return false; |
254 } | 295 } |
255 result_.replace(start, length, text); | 296 result_.replace(start, length, text); |
256 } | 297 } |
257 | 298 |
299 // If the above result text is included in the suggestion list provided by the | |
300 // local spellchecker, we return false to hide this item. | |
301 for (std::vector<string16>::const_iterator it = suggestions_.begin(); | |
302 it != suggestions_.end(); ++it) { | |
303 if (result_ == *it) | |
304 return false; | |
305 } | |
306 | |
258 return true; | 307 return true; |
259 } | 308 } |
260 | 309 |
261 void SpellingMenuObserver::OnAnimationTimerExpired() { | 310 void SpellingMenuObserver::OnAnimationTimerExpired() { |
262 if (!fetcher_.get()) | 311 if (!fetcher_.get()) |
263 return; | 312 return; |
264 | 313 |
265 // Append '.' characters to the end of "Checking". | 314 // Append '.' characters to the end of "Checking". |
266 loading_frame_ = (loading_frame_ + 1) & 3; | 315 loading_frame_ = (loading_frame_ + 1) & 3; |
267 string16 loading_message = loading_message_; | 316 string16 loading_message = loading_message_; |
268 for (int i = 0; i < loading_frame_; ++i) | 317 for (int i = 0; i < loading_frame_; ++i) |
269 loading_message.push_back('.'); | 318 loading_message.push_back('.'); |
270 | 319 |
271 // Update the menu item with the text. We disable this item to prevent users | 320 // Update the menu item with the text. We disable this item to prevent users |
272 // from selecting it. | 321 // from selecting it. |
273 proxy_->UpdateMenuItem(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, false, false, | 322 proxy_->UpdateMenuItem(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, false, false, |
274 loading_message); | 323 loading_message); |
275 } | 324 } |
OLD | NEW |