This source file includes following definitions.
- client_
- InitMenu
- IsCommandIdSupported
- IsCommandIdChecked
- IsCommandIdEnabled
- ExecuteCommand
- OnMenuCancel
- OnTextCheckComplete
- OnAnimationTimerExpired
#include "chrome/browser/renderer_context_menu/spelling_menu_observer.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/i18n/case_conversion.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
#include "chrome/browser/renderer_context_menu/spelling_bubble_model.h"
#include "chrome/browser/spellchecker/spellcheck_factory.h"
#include "chrome/browser/spellchecker/spellcheck_host_metrics.h"
#include "chrome/browser/spellchecker/spellcheck_platform_mac.h"
#include "chrome/browser/spellchecker/spellcheck_service.h"
#include "chrome/browser/spellchecker/spelling_service_client.h"
#include "chrome/browser/ui/confirm_bubble.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/spellcheck_result.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/common/context_menu_params.h"
#include "extensions/browser/view_type_utils.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/rect.h"
using content::BrowserThread;
SpellingMenuObserver::SpellingMenuObserver(RenderViewContextMenuProxy* proxy)
: proxy_(proxy),
loading_frame_(0),
succeeded_(false),
misspelling_hash_(0),
client_(new SpellingServiceClient) {
if (proxy && proxy->GetProfile()) {
integrate_spelling_service_.Init(prefs::kSpellCheckUseSpellingService,
proxy->GetProfile()->GetPrefs());
autocorrect_spelling_.Init(prefs::kEnableAutoSpellCorrect,
proxy->GetProfile()->GetPrefs());
}
}
SpellingMenuObserver::~SpellingMenuObserver() {
}
void SpellingMenuObserver::InitMenu(const content::ContextMenuParams& params) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!params.misspelled_word.empty() ||
params.dictionary_suggestions.empty());
Profile* profile = proxy_->GetProfile();
if (!params.is_editable || !profile)
return;
if (params.misspelled_word.empty())
return;
suggestions_ = params.dictionary_suggestions;
misspelled_word_ = params.misspelled_word;
misspelling_hash_ = params.misspelling_hash;
bool use_suggestions = SpellingServiceClient::IsAvailable(
profile, SpellingServiceClient::SUGGEST);
if (!suggestions_.empty() || use_suggestions)
proxy_->AddSeparator();
for (size_t i = 0; i < params.dictionary_suggestions.size() &&
IDC_SPELLCHECK_SUGGESTION_0 + i <= IDC_SPELLCHECK_SUGGESTION_LAST;
++i) {
proxy_->AddMenuItem(IDC_SPELLCHECK_SUGGESTION_0 + static_cast<int>(i),
params.dictionary_suggestions[i]);
}
if (use_suggestions) {
succeeded_ = false;
result_ = params.misspelled_word;
loading_message_ =
l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLING_CHECKING);
proxy_->AddMenuItem(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION,
loading_message_);
bool result = client_->RequestTextCheck(
profile, SpellingServiceClient::SUGGEST, params.misspelled_word,
base::Bind(&SpellingMenuObserver::OnTextCheckComplete,
base::Unretained(this), SpellingServiceClient::SUGGEST));
if (result) {
loading_frame_ = 0;
animation_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1),
this, &SpellingMenuObserver::OnAnimationTimerExpired);
}
}
if (params.dictionary_suggestions.empty()) {
proxy_->AddMenuItem(
IDC_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS,
l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS));
bool use_spelling_service = SpellingServiceClient::IsAvailable(
profile, SpellingServiceClient::SPELLCHECK);
if (use_suggestions || use_spelling_service)
proxy_->AddSeparator();
} else {
proxy_->AddSeparator();
SpellcheckService* spellcheck_service =
SpellcheckServiceFactory::GetForContext(profile);
if (spellcheck_service && spellcheck_service->GetMetrics())
spellcheck_service->GetMetrics()->RecordSuggestionStats(1);
}
proxy_->AddMenuItem(IDC_SPELLCHECK_ADD_TO_DICTIONARY,
l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_ADD_TO_DICTIONARY));
#if defined(TOOLKIT_GTK)
extensions::ViewType view_type =
extensions::GetViewType(proxy_->GetWebContents());
if (view_type != extensions::VIEW_TYPE_PANEL) {
#endif
proxy_->AddCheckItem(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE,
l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLING_ASK_GOOGLE));
#if defined(TOOLKIT_GTK)
}
#endif
const CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kEnableSpellingAutoCorrect)) {
proxy_->AddCheckItem(IDC_CONTENT_CONTEXT_AUTOCORRECT_SPELLING_TOGGLE,
l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLING_AUTOCORRECT));
}
proxy_->AddSeparator();
}
bool SpellingMenuObserver::IsCommandIdSupported(int command_id) {
if (command_id >= IDC_SPELLCHECK_SUGGESTION_0 &&
command_id <= IDC_SPELLCHECK_SUGGESTION_LAST)
return true;
switch (command_id) {
case IDC_SPELLCHECK_ADD_TO_DICTIONARY:
case IDC_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS:
case IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION:
case IDC_CONTENT_CONTEXT_SPELLING_TOGGLE:
case IDC_CONTENT_CONTEXT_AUTOCORRECT_SPELLING_TOGGLE:
return true;
default:
return false;
}
}
bool SpellingMenuObserver::IsCommandIdChecked(int command_id) {
DCHECK(IsCommandIdSupported(command_id));
if (command_id == IDC_CONTENT_CONTEXT_SPELLING_TOGGLE)
return integrate_spelling_service_.GetValue() &&
!proxy_->GetProfile()->IsOffTheRecord();
if (command_id == IDC_CONTENT_CONTEXT_AUTOCORRECT_SPELLING_TOGGLE)
return autocorrect_spelling_.GetValue() &&
!proxy_->GetProfile()->IsOffTheRecord();
return false;
}
bool SpellingMenuObserver::IsCommandIdEnabled(int command_id) {
DCHECK(IsCommandIdSupported(command_id));
if (command_id >= IDC_SPELLCHECK_SUGGESTION_0 &&
command_id <= IDC_SPELLCHECK_SUGGESTION_LAST)
return true;
switch (command_id) {
case IDC_SPELLCHECK_ADD_TO_DICTIONARY:
return !misspelled_word_.empty();
case IDC_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS:
return false;
case IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION:
return succeeded_;
case IDC_CONTENT_CONTEXT_SPELLING_TOGGLE:
return integrate_spelling_service_.IsUserModifiable() &&
!proxy_->GetProfile()->IsOffTheRecord();
case IDC_CONTENT_CONTEXT_AUTOCORRECT_SPELLING_TOGGLE:
return integrate_spelling_service_.IsUserModifiable() &&
!proxy_->GetProfile()->IsOffTheRecord();
default:
return false;
}
}
void SpellingMenuObserver::ExecuteCommand(int command_id) {
DCHECK(IsCommandIdSupported(command_id));
if (command_id >= IDC_SPELLCHECK_SUGGESTION_0 &&
command_id <= IDC_SPELLCHECK_SUGGESTION_LAST) {
int suggestion_index = command_id - IDC_SPELLCHECK_SUGGESTION_0;
proxy_->GetWebContents()->ReplaceMisspelling(
suggestions_[suggestion_index]);
Profile* profile = proxy_->GetProfile();
if (profile) {
SpellcheckService* spellcheck =
SpellcheckServiceFactory::GetForContext(profile);
if (spellcheck) {
if (spellcheck->GetMetrics())
spellcheck->GetMetrics()->RecordReplacedWordStats(1);
spellcheck->GetFeedbackSender()->SelectedSuggestion(
misspelling_hash_, suggestion_index);
}
}
return;
}
if (command_id == IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION) {
proxy_->GetWebContents()->ReplaceMisspelling(result_);
misspelled_word_ = result_;
}
if (command_id == IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION ||
command_id == IDC_SPELLCHECK_ADD_TO_DICTIONARY) {
Profile* profile = proxy_->GetProfile();
if (profile) {
SpellcheckService* spellcheck =
SpellcheckServiceFactory::GetForContext(profile);
if (spellcheck) {
spellcheck->GetCustomDictionary()->AddWord(base::UTF16ToUTF8(
misspelled_word_));
spellcheck->GetFeedbackSender()->AddedToDictionary(misspelling_hash_);
}
}
#if defined(OS_MACOSX)
spellcheck_mac::AddWord(misspelled_word_);
#endif
}
if (command_id == IDC_CONTENT_CONTEXT_SPELLING_TOGGLE &&
integrate_spelling_service_.IsUserModifiable()) {
if (!integrate_spelling_service_.GetValue()) {
content::RenderViewHost* rvh = proxy_->GetRenderViewHost();
gfx::Rect rect = rvh->GetView()->GetViewBounds();
chrome::ShowConfirmBubble(
#if defined(TOOLKIT_VIEWS)
proxy_->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
#else
rvh->GetView()->GetNativeView(),
#endif
gfx::Point(rect.CenterPoint().x(), rect.y()),
new SpellingBubbleModel(proxy_->GetProfile(),
proxy_->GetWebContents(),
false));
} else {
Profile* profile = proxy_->GetProfile();
if (profile)
profile->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService,
false);
profile->GetPrefs()->SetBoolean(prefs::kEnableAutoSpellCorrect,
false);
}
}
if (command_id == IDC_CONTENT_CONTEXT_AUTOCORRECT_SPELLING_TOGGLE &&
integrate_spelling_service_.IsUserModifiable()) {
if (!integrate_spelling_service_.GetValue()) {
content::RenderViewHost* rvh = proxy_->GetRenderViewHost();
gfx::Rect rect = rvh->GetView()->GetViewBounds();
chrome::ShowConfirmBubble(rvh->GetView()->GetNativeView(),
gfx::Point(rect.CenterPoint().x(), rect.y()),
new SpellingBubbleModel(
proxy_->GetProfile(),
proxy_->GetWebContents(),
true));
} else {
Profile* profile = proxy_->GetProfile();
if (profile) {
bool current_value = autocorrect_spelling_.GetValue();
profile->GetPrefs()->SetBoolean(prefs::kEnableAutoSpellCorrect,
!current_value);
}
}
}
}
void SpellingMenuObserver::OnMenuCancel() {
Profile* profile = proxy_->GetProfile();
if (!profile)
return;
SpellcheckService* spellcheck =
SpellcheckServiceFactory::GetForContext(profile);
if (!spellcheck)
return;
spellcheck->GetFeedbackSender()->IgnoredSuggestions(misspelling_hash_);
}
void SpellingMenuObserver::OnTextCheckComplete(
SpellingServiceClient::ServiceType type,
bool success,
const base::string16& text,
const std::vector<SpellCheckResult>& results) {
animation_timer_.Stop();
succeeded_ = success;
if (results.empty()) {
succeeded_ = false;
} else {
typedef std::vector<SpellCheckResult> SpellCheckResults;
for (SpellCheckResults::const_iterator it = results.begin();
it != results.end(); ++it) {
result_.replace(it->location, it->length, it->replacement);
}
base::string16 result = base::i18n::ToLower(result_);
for (std::vector<base::string16>::const_iterator it = suggestions_.begin();
it != suggestions_.end(); ++it) {
if (result == base::i18n::ToLower(*it)) {
succeeded_ = false;
break;
}
}
}
if (type != SpellingServiceClient::SPELLCHECK) {
if (!succeeded_) {
result_ = l10n_util::GetStringUTF16(
IDS_CONTENT_CONTEXT_SPELLING_NO_SUGGESTIONS_FROM_GOOGLE);
}
proxy_->UpdateMenuItem(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, succeeded_,
false, result_);
}
}
void SpellingMenuObserver::OnAnimationTimerExpired() {
loading_frame_ = (loading_frame_ + 1) & 3;
base::string16 loading_message =
loading_message_ + base::string16(loading_frame_,'.');
proxy_->UpdateMenuItem(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, false, false,
loading_message);
}