Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / web_dialog_window_controller.mm
blobb66c86ce115954edde1de5c5a4d49a059c488a41
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/ui/cocoa/web_dialog_window_controller.h"
7 #include "base/logging.h"
8 #include "base/mac/scoped_nsobject.h"
9 #include "base/strings/sys_string_conversions.h"
10 #import "chrome/browser/ui/browser_dialogs.h"
11 #import "chrome/browser/ui/cocoa/browser_command_executor.h"
12 #import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
13 #include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
14 #include "content/public/browser/native_web_keyboard_event.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/browser/web_ui_message_handler.h"
17 #include "ui/events/keycodes/keyboard_codes.h"
18 #include "ui/gfx/geometry/size.h"
19 #include "ui/web_dialogs/web_dialog_delegate.h"
20 #include "ui/web_dialogs/web_dialog_web_contents_delegate.h"
22 using content::NativeWebKeyboardEvent;
23 using content::WebContents;
24 using content::WebUIMessageHandler;
25 using ui::WebDialogDelegate;
26 using ui::WebDialogUI;
27 using ui::WebDialogWebContentsDelegate;
29 // Thin bridge that routes notifications to
30 // WebDialogWindowController's member variables.
31 class WebDialogWindowDelegateBridge
32     : public WebDialogDelegate,
33       public WebDialogWebContentsDelegate {
34 public:
35   // All parameters must be non-NULL/non-nil.
36   WebDialogWindowDelegateBridge(WebDialogWindowController* controller,
37                                 content::BrowserContext* context,
38                                 WebDialogDelegate* delegate);
40   ~WebDialogWindowDelegateBridge() override;
42   // Called when the window is directly closed, e.g. from the close
43   // button or from an accelerator.
44   void WindowControllerClosed();
46   // WebDialogDelegate declarations.
47   ui::ModalType GetDialogModalType() const override;
48   base::string16 GetDialogTitle() const override;
49   GURL GetDialogContentURL() const override;
50   void GetWebUIMessageHandlers(
51       std::vector<WebUIMessageHandler*>* handlers) const override;
52   void GetDialogSize(gfx::Size* size) const override;
53   void GetMinimumDialogSize(gfx::Size* size) const override;
54   std::string GetDialogArgs() const override;
55   void OnDialogClosed(const std::string& json_retval) override;
56   void OnCloseContents(WebContents* source, bool* out_close_dialog) override;
57   bool ShouldShowDialogTitle() const override { return true; }
59   // WebDialogWebContentsDelegate declarations.
60   void MoveContents(WebContents* source, const gfx::Rect& pos) override;
61   void HandleKeyboardEvent(content::WebContents* source,
62                            const NativeWebKeyboardEvent& event) override;
63   void CloseContents(WebContents* source) override;
64   content::WebContents* OpenURLFromTab(
65       content::WebContents* source,
66       const content::OpenURLParams& params) override;
67   void AddNewContents(content::WebContents* source,
68                       content::WebContents* new_contents,
69                       WindowOpenDisposition disposition,
70                       const gfx::Rect& initial_rect,
71                       bool user_gesture,
72                       bool* was_blocked) override;
73   void LoadingStateChanged(content::WebContents* source,
74                            bool to_different_document) override;
76 private:
77   WebDialogWindowController* controller_;  // weak
78   WebDialogDelegate* delegate_;  // weak, owned by controller_
80   // Calls delegate_'s OnDialogClosed() exactly once, nulling it out afterwards
81   // so that no other WebDialogDelegate calls are sent to it. Returns whether or
82   // not the OnDialogClosed() was actually called on the delegate.
83   bool DelegateOnDialogClosed(const std::string& json_retval);
85   DISALLOW_COPY_AND_ASSIGN(WebDialogWindowDelegateBridge);
88 // ChromeEventProcessingWindow expects its controller to implement the
89 // BrowserCommandExecutor protocol.
90 @interface WebDialogWindowController (InternalAPI) <BrowserCommandExecutor>
92 // BrowserCommandExecutor methods.
93 - (void)executeCommand:(int)command;
95 @end
97 namespace chrome {
99 gfx::NativeWindow ShowWebDialog(gfx::NativeView parent,
100                                 content::BrowserContext* context,
101                                 WebDialogDelegate* delegate) {
102   return [WebDialogWindowController showWebDialog:delegate
103                                           context:context];
106 }  // namespace chrome
108 WebDialogWindowDelegateBridge::WebDialogWindowDelegateBridge(
109     WebDialogWindowController* controller,
110     content::BrowserContext* context,
111     WebDialogDelegate* delegate)
112     : WebDialogWebContentsDelegate(context, new ChromeWebContentsHandler),
113       controller_(controller),
114       delegate_(delegate) {
115   DCHECK(controller_);
116   DCHECK(delegate_);
119 WebDialogWindowDelegateBridge::~WebDialogWindowDelegateBridge() {}
121 void WebDialogWindowDelegateBridge::WindowControllerClosed() {
122   Detach();
123   controller_ = nil;
124   DelegateOnDialogClosed("");
127 bool WebDialogWindowDelegateBridge::DelegateOnDialogClosed(
128     const std::string& json_retval) {
129   if (delegate_) {
130     WebDialogDelegate* real_delegate = delegate_;
131     delegate_ = NULL;
132     real_delegate->OnDialogClosed(json_retval);
133     return true;
134   }
135   return false;
138 // WebDialogDelegate definitions.
140 // All of these functions check for NULL first since delegate_ is set
141 // to NULL when the window is closed.
143 ui::ModalType WebDialogWindowDelegateBridge::GetDialogModalType() const {
144   // TODO(akalin): Support modal dialog boxes.
145   if (delegate_ && delegate_->GetDialogModalType() != ui::MODAL_TYPE_NONE) {
146     LOG(WARNING) << "Modal Web dialogs are not supported yet";
147   }
148   return ui::MODAL_TYPE_NONE;
151 base::string16 WebDialogWindowDelegateBridge::GetDialogTitle() const {
152   return delegate_ ? delegate_->GetDialogTitle() : base::string16();
155 GURL WebDialogWindowDelegateBridge::GetDialogContentURL() const {
156   return delegate_ ? delegate_->GetDialogContentURL() : GURL();
159 void WebDialogWindowDelegateBridge::GetWebUIMessageHandlers(
160     std::vector<WebUIMessageHandler*>* handlers) const {
161   if (delegate_) {
162     delegate_->GetWebUIMessageHandlers(handlers);
163   } else {
164     // TODO(akalin): Add this clause in the windows version.  Also
165     // make sure that everything expects handlers to be non-NULL and
166     // document it.
167     handlers->clear();
168   }
171 void WebDialogWindowDelegateBridge::GetDialogSize(gfx::Size* size) const {
172   if (delegate_)
173     delegate_->GetDialogSize(size);
174   else
175     *size = gfx::Size();
178 void WebDialogWindowDelegateBridge::GetMinimumDialogSize(
179     gfx::Size* size) const {
180   if (delegate_)
181     delegate_->GetMinimumDialogSize(size);
182   else
183     *size = gfx::Size();
186 std::string WebDialogWindowDelegateBridge::GetDialogArgs() const {
187   return delegate_ ? delegate_->GetDialogArgs() : "";
190 void WebDialogWindowDelegateBridge::OnDialogClosed(
191     const std::string& json_retval) {
192   Detach();
193   // [controller_ close] should be called at most once, too.
194   if (DelegateOnDialogClosed(json_retval)) {
195     [controller_ close];
196   }
197   controller_ = nil;
200 void WebDialogWindowDelegateBridge::OnCloseContents(WebContents* source,
201                                                     bool* out_close_dialog) {
202   if (out_close_dialog)
203     *out_close_dialog = true;
206 void WebDialogWindowDelegateBridge::CloseContents(WebContents* source) {
207   bool close_dialog = false;
208   OnCloseContents(source, &close_dialog);
209   if (close_dialog)
210     OnDialogClosed(std::string());
213 content::WebContents* WebDialogWindowDelegateBridge::OpenURLFromTab(
214     content::WebContents* source,
215     const content::OpenURLParams& params) {
216   content::WebContents* new_contents = NULL;
217   if (delegate_ &&
218       delegate_->HandleOpenURLFromTab(source, params, &new_contents)) {
219     return new_contents;
220   }
221   return WebDialogWebContentsDelegate::OpenURLFromTab(source, params);
224 void WebDialogWindowDelegateBridge::AddNewContents(
225     content::WebContents* source,
226     content::WebContents* new_contents,
227     WindowOpenDisposition disposition,
228     const gfx::Rect& initial_rect,
229     bool user_gesture,
230     bool* was_blocked) {
231   if (delegate_ && delegate_->HandleAddNewContents(
232           source, new_contents, disposition, initial_rect, user_gesture)) {
233     return;
234   }
235   WebDialogWebContentsDelegate::AddNewContents(
236       source, new_contents, disposition, initial_rect, user_gesture,
237       was_blocked);
240 void WebDialogWindowDelegateBridge::LoadingStateChanged(
241     content::WebContents* source, bool to_different_document) {
242   if (delegate_)
243     delegate_->OnLoadingStateChanged(source);
246 void WebDialogWindowDelegateBridge::MoveContents(WebContents* source,
247                                                  const gfx::Rect& pos) {
248   // TODO(akalin): Actually set the window bounds.
251 // A simplified version of BrowserWindowCocoa::HandleKeyboardEvent().
252 // We don't handle global keyboard shortcuts here, but that's fine since
253 // they're all browser-specific. (This may change in the future.)
254 void WebDialogWindowDelegateBridge::HandleKeyboardEvent(
255     content::WebContents* source,
256     const NativeWebKeyboardEvent& event) {
257   if (event.skip_in_browser || event.type == NativeWebKeyboardEvent::Char)
258     return;
260   // Close ourselves if the user hits Esc or Command-. .  The normal
261   // way to do this is to implement (void)cancel:(int)sender, but
262   // since we handle keyboard events ourselves we can't do that.
263   //
264   // According to experiments, hitting Esc works regardless of the
265   // presence of other modifiers (as long as it's not an app-level
266   // shortcut, e.g. Commmand-Esc for Front Row) but no other modifiers
267   // can be present for Command-. to work.
268   //
269   // TODO(thakis): It would be nice to get cancel: to work somehow.
270   // Bug: http://code.google.com/p/chromium/issues/detail?id=32828 .
271   if (event.type == NativeWebKeyboardEvent::RawKeyDown &&
272       ((event.windowsKeyCode == ui::VKEY_ESCAPE) ||
273        (event.windowsKeyCode == ui::VKEY_OEM_PERIOD &&
274         event.modifiers == NativeWebKeyboardEvent::MetaKey))) {
275     [controller_ close];
276     return;
277   }
279   ChromeEventProcessingWindow* event_window =
280       static_cast<ChromeEventProcessingWindow*>([controller_ window]);
281   DCHECK([event_window isKindOfClass:[ChromeEventProcessingWindow class]]);
282   [event_window redispatchKeyEvent:event.os_event];
285 @implementation WebDialogWindowController (InternalAPI)
287 // This gets called whenever a chrome-specific keyboard shortcut is performed
288 // in the Web dialog window.  We simply swallow all those events.
289 - (void)executeCommand:(int)command {}
291 @end
293 @implementation WebDialogWindowController
295 // NOTE(akalin): We'll probably have to add the parentWindow parameter back
296 // in once we implement modal dialogs.
298 + (NSWindow*)showWebDialog:(WebDialogDelegate*)delegate
299                    context:(content::BrowserContext*)context {
300   WebDialogWindowController* webDialogWindowController =
301     [[WebDialogWindowController alloc] initWithDelegate:delegate
302                                                 context:context];
303   [webDialogWindowController loadDialogContents];
304   [webDialogWindowController showWindow:nil];
305   return [webDialogWindowController window];
308 - (id)initWithDelegate:(WebDialogDelegate*)delegate
309                context:(content::BrowserContext*)context {
310   DCHECK(delegate);
311   DCHECK(context);
313   gfx::Size dialogSize;
314   delegate->GetDialogSize(&dialogSize);
315   NSRect dialogRect = NSMakeRect(0, 0, dialogSize.width(), dialogSize.height());
316   NSUInteger style = NSTitledWindowMask | NSClosableWindowMask |
317       NSResizableWindowMask;
318   base::scoped_nsobject<ChromeEventProcessingWindow> window(
319       [[ChromeEventProcessingWindow alloc]
320           initWithContentRect:dialogRect
321                     styleMask:style
322                       backing:NSBackingStoreBuffered
323                         defer:YES]);
324   if (!window.get()) {
325     return nil;
326   }
327   self = [super initWithWindow:window];
328   if (!self) {
329     return nil;
330   }
331   [window setWindowController:self];
332   [window setDelegate:self];
333   [window setTitle:base::SysUTF16ToNSString(delegate->GetDialogTitle())];
334   [window setMinSize:dialogRect.size];
335   [window center];
336   delegate_.reset(
337       new WebDialogWindowDelegateBridge(self, context, delegate));
338   return self;
341 - (void)loadDialogContents {
342   webContents_.reset(WebContents::Create(
343       WebContents::CreateParams(delegate_->browser_context())));
344   [[self window] setContentView:webContents_->GetNativeView()];
345   webContents_->SetDelegate(delegate_.get());
347   // This must be done before loading the page; see the comments in
348   // WebDialogUI.
349   WebDialogUI::SetDelegate(webContents_.get(), delegate_.get());
351   webContents_->GetController().LoadURL(
352       delegate_->GetDialogContentURL(),
353       content::Referrer(),
354       ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
355       std::string());
357   // TODO(akalin): add accelerator for ESC to close the dialog box.
358   //
359   // TODO(akalin): Figure out why implementing (void)cancel:(id)sender
360   // to do the above doesn't work.
363 - (void)windowWillClose:(NSNotification*)notification {
364   delegate_->WindowControllerClosed();
365   [self autorelease];
368 @end