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) { |
| 103 if (command_id >= IDC_SPELLCHECK_SUGGESTION_0 && |
| 104 command_id <= IDC_SPELLCHECK_SUGGESTION_4) |
| 105 return true; |
| 106 |
88 return command_id == IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION; | 107 return command_id == IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION; |
89 } | 108 } |
90 | 109 |
91 bool SpellingMenuObserver::IsCommandIdEnabled(int command_id) { | 110 bool SpellingMenuObserver::IsCommandIdEnabled(int command_id) { |
92 return command_id == IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION && succeeded_; | 111 DCHECK(IsCommandIdSupported(command_id)); |
| 112 |
| 113 if (command_id >= IDC_SPELLCHECK_SUGGESTION_0 && |
| 114 command_id <= IDC_SPELLCHECK_SUGGESTION_4) |
| 115 return true; |
| 116 |
| 117 if (command_id == IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION) |
| 118 return succeeded_; |
| 119 return false; |
93 } | 120 } |
94 | 121 |
95 void SpellingMenuObserver::ExecuteCommand(int command_id) { | 122 void SpellingMenuObserver::ExecuteCommand(int command_id) { |
96 if (IsCommandIdEnabled(command_id)) | 123 DCHECK(IsCommandIdSupported(command_id)); |
| 124 |
| 125 if (command_id >= IDC_SPELLCHECK_SUGGESTION_0 && |
| 126 command_id <= IDC_SPELLCHECK_SUGGESTION_4) { |
| 127 proxy_->GetRenderViewHost()->Replace( |
| 128 suggestions_[command_id - IDC_SPELLCHECK_SUGGESTION_0]); |
| 129 // GetSpellCheckHost() can return null when the suggested word is |
| 130 // provided by Web SpellCheck API. |
| 131 Profile* profile = proxy_->GetProfile(); |
| 132 if (profile) { |
| 133 SpellCheckHost* spellcheck_host = profile->GetSpellCheckHost(); |
| 134 if (spellcheck_host && spellcheck_host->GetMetrics()) |
| 135 spellcheck_host->GetMetrics()->RecordReplacedWordStats(1); |
| 136 } |
| 137 return; |
| 138 } |
| 139 |
| 140 if (command_id == IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION) |
97 proxy_->GetRenderViewHost()->Replace(result_); | 141 proxy_->GetRenderViewHost()->Replace(result_); |
98 } | 142 } |
99 | 143 |
100 bool SpellingMenuObserver::Invoke(const string16& text, | 144 bool SpellingMenuObserver::Invoke(const string16& text, |
101 const std::string& locale, | 145 const std::string& locale, |
102 net::URLRequestContextGetter* context) { | 146 net::URLRequestContextGetter* context) { |
103 // Create the parameters needed by Spelling API. Spelling API needs three | 147 // 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 | 148 // 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 | 149 // 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 | 150 // 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)); | 200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
157 | 201 |
158 scoped_ptr<content::URLFetcher> clean_up_fetcher(fetcher_.release()); | 202 scoped_ptr<content::URLFetcher> clean_up_fetcher(fetcher_.release()); |
159 animation_timer_.Stop(); | 203 animation_timer_.Stop(); |
160 | 204 |
161 // Parse the response JSON and replace misspelled words in the |result_| text | 205 // Parse the response JSON and replace misspelled words in the |result_| text |
162 // with their suggestions. | 206 // with their suggestions. |
163 std::string data; | 207 std::string data; |
164 source->GetResponseAsString(&data); | 208 source->GetResponseAsString(&data); |
165 succeeded_ = ParseResponse(source->GetResponseCode(), data); | 209 succeeded_ = ParseResponse(source->GetResponseCode(), data); |
166 if (!succeeded_) | |
167 result_ = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLING_CORRECT); | |
168 | 210 |
169 // Update the menu item with the result text. We enable this item only when | 211 // 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 | 212 // 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_, | 213 proxy_->UpdateMenuItem(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, succeeded_, |
175 false, result_); | 214 !succeeded_, result_); |
176 } | 215 } |
177 | 216 |
178 bool SpellingMenuObserver::ParseResponse(int response, | 217 bool SpellingMenuObserver::ParseResponse(int response, |
179 const std::string& data) { | 218 const std::string& data) { |
180 // When this JSON-RPC call finishes successfully, the Spelling service returns | 219 // When this JSON-RPC call finishes successfully, the Spelling service returns |
181 // an JSON object listed below. | 220 // an JSON object listed below. |
182 // * result - an envelope object representing the result from the APIARY | 221 // * result - an envelope object representing the result from the APIARY |
183 // server, which is the JSON-API front-end for the Spelling service. This | 222 // server, which is the JSON-API front-end for the Spelling service. This |
184 // object consists of the following variable: | 223 // object consists of the following variable: |
185 // - spellingCheckResponse (SpellingCheckResponse). | 224 // - spellingCheckResponse (SpellingCheckResponse). |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 // alternative. | 287 // alternative. |
249 DictionaryValue* suggestion = NULL; | 288 DictionaryValue* suggestion = NULL; |
250 string16 text; | 289 string16 text; |
251 if (!suggestions->GetDictionary(0, &suggestion) || | 290 if (!suggestions->GetDictionary(0, &suggestion) || |
252 !suggestion->GetString("suggestion", &text)) { | 291 !suggestion->GetString("suggestion", &text)) { |
253 return false; | 292 return false; |
254 } | 293 } |
255 result_.replace(start, length, text); | 294 result_.replace(start, length, text); |
256 } | 295 } |
257 | 296 |
| 297 // If the above result text is included in the suggestion list provided by the |
| 298 // local spellchecker, we return false to hide this item. |
| 299 for (std::vector<string16>::const_iterator it = suggestions_.begin(); |
| 300 it != suggestions_.end(); ++it) { |
| 301 if (result_ == *it) |
| 302 return false; |
| 303 } |
| 304 |
258 return true; | 305 return true; |
259 } | 306 } |
260 | 307 |
261 void SpellingMenuObserver::OnAnimationTimerExpired() { | 308 void SpellingMenuObserver::OnAnimationTimerExpired() { |
262 if (!fetcher_.get()) | 309 if (!fetcher_.get()) |
263 return; | 310 return; |
264 | 311 |
265 // Append '.' characters to the end of "Checking". | 312 // Append '.' characters to the end of "Checking". |
266 loading_frame_ = (loading_frame_ + 1) & 3; | 313 loading_frame_ = (loading_frame_ + 1) & 3; |
267 string16 loading_message = loading_message_; | 314 string16 loading_message = loading_message_; |
268 for (int i = 0; i < loading_frame_; ++i) | 315 for (int i = 0; i < loading_frame_; ++i) |
269 loading_message.push_back('.'); | 316 loading_message.push_back('.'); |
270 | 317 |
271 // Update the menu item with the text. We disable this item to prevent users | 318 // Update the menu item with the text. We disable this item to prevent users |
272 // from selecting it. | 319 // from selecting it. |
273 proxy_->UpdateMenuItem(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, false, false, | 320 proxy_->UpdateMenuItem(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, false, false, |
274 loading_message); | 321 loading_message); |
275 } | 322 } |
OLD | NEW |