Chromium Code Reviews| 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 |