1 // Copyright (c) 2012 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.
5 #import "chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "chrome/browser/devtools/devtools_window.h"
12 #include "chrome/browser/profiles/profile.h"
13 #import "chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.h"
14 #include "chrome/browser/spellchecker/spellcheck_platform_mac.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_commands.h"
17 #include "chrome/browser/ui/browser_finder.h"
18 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
19 #include "chrome/common/pref_names.h"
20 #include "chrome/common/spellcheck_messages.h"
21 #include "chrome/common/url_constants.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/render_view_host.h"
24 #include "content/public/browser/render_widget_host.h"
25 #include "content/public/browser/render_widget_host_view.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/browser/web_contents_observer.h"
29 using content::RenderViewHost;
31 @interface ChromeRenderWidgetHostViewMacDelegate () <HistorySwiperDelegate>
32 - (void)spellCheckEnabled:(BOOL)enabled checked:(BOOL)checked;
35 namespace ChromeRenderWidgetHostViewMacDelegateInternal {
37 // Filters the message sent by the renderer to know if spellchecking is enabled
38 // or not for the currently focused element.
39 class SpellCheckObserver : public content::WebContentsObserver {
43 ChromeRenderWidgetHostViewMacDelegate* view_delegate)
44 : content::WebContentsObserver(
45 content::WebContents::FromRenderViewHost(host)),
46 view_delegate_(view_delegate) {
49 virtual ~SpellCheckObserver() {
53 virtual bool OnMessageReceived(const IPC::Message& message) override {
55 IPC_BEGIN_MESSAGE_MAP(SpellCheckObserver, message)
56 IPC_MESSAGE_HANDLER(SpellCheckHostMsg_ToggleSpellCheck,
58 IPC_MESSAGE_UNHANDLED(handled = false)
63 void OnToggleSpellCheck(bool enabled, bool checked) {
64 [view_delegate_ spellCheckEnabled:enabled checked:checked];
67 ChromeRenderWidgetHostViewMacDelegate* view_delegate_;
70 } // namespace ChromeRenderWidgetHostViewMacDelegateInternal
72 @implementation ChromeRenderWidgetHostViewMacDelegate
74 - (id)initWithRenderWidgetHost:(content::RenderWidgetHost*)renderWidgetHost {
77 renderWidgetHost_ = renderWidgetHost;
78 if (renderWidgetHost_->IsRenderView()) {
79 spellingObserver_.reset(
80 new ChromeRenderWidgetHostViewMacDelegateInternal::SpellCheckObserver(
81 RenderViewHost::From(renderWidgetHost_), self));
84 historySwiper_.reset([[HistorySwiper alloc] initWithDelegate:self]);
90 [historySwiper_ setDelegate:nil];
94 // Handle an event. All incoming key and mouse events flow through this
95 // delegate method if implemented. Return YES if the event is fully handled, or
96 // NO if normal processing should take place.
97 - (BOOL)handleEvent:(NSEvent*)event {
98 return [historySwiper_ handleEvent:event];
103 - (void)beginGestureWithEvent:(NSEvent*)event {
104 [historySwiper_ beginGestureWithEvent:event];
107 - (void)endGestureWithEvent:(NSEvent*)event {
108 [historySwiper_ endGestureWithEvent:event];
111 // This is a low level API which provides touches associated with an event.
112 // It is used in conjunction with gestures to determine finger placement
114 - (void)touchesMovedWithEvent:(NSEvent*)event {
115 [historySwiper_ touchesMovedWithEvent:event];
118 - (void)touchesBeganWithEvent:(NSEvent*)event {
119 [historySwiper_ touchesBeganWithEvent:event];
122 - (void)touchesCancelledWithEvent:(NSEvent*)event {
123 [historySwiper_ touchesCancelledWithEvent:event];
126 - (void)touchesEndedWithEvent:(NSEvent*)event {
127 [historySwiper_ touchesEndedWithEvent:event];
130 - (BOOL)canRubberbandLeft:(NSView*)view {
131 return [historySwiper_ canRubberbandLeft:view];
134 - (BOOL)canRubberbandRight:(NSView*)view {
135 return [historySwiper_ canRubberbandRight:view];
138 // HistorySwiperDelegate methods
140 - (BOOL)shouldAllowHistorySwiping {
141 if (!renderWidgetHost_ || !renderWidgetHost_->IsRenderView())
143 content::WebContents* webContents = content::WebContents::FromRenderViewHost(
144 RenderViewHost::From(renderWidgetHost_));
145 if (webContents && DevToolsWindow::IsDevToolsWindow(webContents)) {
152 - (NSView*)viewThatWantsHistoryOverlay {
153 return renderWidgetHost_->GetView()->GetNativeView();
156 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item
157 isValidItem:(BOOL*)valid {
158 SEL action = [item action];
160 // For now, this action is always enabled for render view;
161 // this is sub-optimal.
162 // TODO(suzhe): Plumb the "can*" methods up from WebCore.
163 if (action == @selector(checkSpelling:)) {
164 *valid = renderWidgetHost_->IsRenderView();
168 // TODO(groby): Clarify who sends this and if toggleContinuousSpellChecking:
169 // is still necessary.
170 if (action == @selector(toggleContinuousSpellChecking:)) {
171 if ([(id)item respondsToSelector:@selector(setState:)]) {
172 content::RenderProcessHost* host = renderWidgetHost_->GetProcess();
173 Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
176 profile->GetPrefs()->GetBoolean(prefs::kEnableContinuousSpellcheck);
177 NSCellStateValue checkedState =
178 spellcheckChecked_ ? NSOnState : NSOffState;
179 [(id)item setState:checkedState];
181 *valid = spellcheckEnabled_;
188 - (void)rendererHandledWheelEvent:(const blink::WebMouseWheelEvent&)event
189 consumed:(BOOL)consumed {
190 [historySwiper_ rendererHandledWheelEvent:event consumed:consumed];
193 // Spellchecking methods
194 // The next five methods are implemented here since this class is the first
195 // responder for anything in the browser.
197 // This message is sent whenever the user specifies that a word should be
198 // changed from the spellChecker.
199 - (void)changeSpelling:(id)sender {
200 // Grab the currently selected word from the spell panel, as this is the word
201 // that we want to replace the selected word in the text with.
202 NSString* newWord = [[sender selectedCell] stringValue];
203 if (newWord != nil) {
204 content::WebContents* webContents =
205 content::WebContents::FromRenderViewHost(
206 RenderViewHost::From(renderWidgetHost_));
207 webContents->Replace(base::SysNSStringToUTF16(newWord));
211 // This message is sent by NSSpellChecker whenever the next word should be
212 // advanced to, either after a correction or clicking the "Find Next" button.
213 // This isn't documented anywhere useful, like in NSSpellProtocol.h with the
214 // other spelling panel methods. This is probably because Apple assumes that the
215 // the spelling panel will be used with an NSText, which will automatically
216 // catch this and advance to the next word for you. Thanks Apple.
217 // This is also called from the Edit -> Spelling -> Check Spelling menu item.
218 - (void)checkSpelling:(id)sender {
219 renderWidgetHost_->Send(new SpellCheckMsg_AdvanceToNextMisspelling(
220 renderWidgetHost_->GetRoutingID()));
223 // This message is sent by the spelling panel whenever a word is ignored.
224 - (void)ignoreSpelling:(id)sender {
225 // Ideally, we would ask the current RenderView for its tag, but that would
226 // mean making a blocking IPC call from the browser. Instead,
227 // spellcheck_mac::CheckSpelling remembers the last tag and
228 // spellcheck_mac::IgnoreWord assumes that is the correct tag.
229 NSString* wordToIgnore = [sender stringValue];
230 if (wordToIgnore != nil)
231 spellcheck_mac::IgnoreWord(base::SysNSStringToUTF16(wordToIgnore));
234 - (void)showGuessPanel:(id)sender {
235 renderWidgetHost_->Send(new SpellCheckMsg_ToggleSpellPanel(
236 renderWidgetHost_->GetRoutingID(),
237 spellcheck_mac::SpellingPanelVisible()));
240 - (void)toggleContinuousSpellChecking:(id)sender {
241 content::RenderProcessHost* host = renderWidgetHost_->GetProcess();
242 Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
244 PrefService* pref = profile->GetPrefs();
245 pref->SetBoolean(prefs::kEnableContinuousSpellcheck,
246 !pref->GetBoolean(prefs::kEnableContinuousSpellcheck));
249 - (void)spellCheckEnabled:(BOOL)enabled checked:(BOOL)checked {
250 spellcheckEnabled_ = enabled;
251 spellcheckChecked_ = checked;
254 // END Spellchecking methods