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.
4
5#include "chrome/browser/ui/webui/constrained_web_dialog_delegate_base.h"
6
7#include "base/strings/utf_string_conversions.h"
8#include "chrome/browser/ui/browser_finder.h"
9#include "chrome/browser/ui/browser_window.h"
10#include "chrome/browser/ui/views/constrained_window_views.h"
11#include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
12#include "content/public/browser/native_web_keyboard_event.h"
13#include "content/public/browser/web_contents.h"
14#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
15#include "ui/views/controls/webview/webview.h"
16#include "ui/views/widget/widget.h"
17#include "ui/views/window/dialog_delegate.h"
18#include "ui/web_dialogs/web_dialog_delegate.h"
19#include "ui/web_dialogs/web_dialog_ui.h"
20
21namespace {
22
23class WebDialogWebContentsDelegateViews
24    : public ui::WebDialogWebContentsDelegate {
25 public:
26  WebDialogWebContentsDelegateViews(content::BrowserContext* browser_context,
27                                    content::WebContents* initiator,
28                                    views::WebView* web_view)
29      : ui::WebDialogWebContentsDelegate(browser_context,
30                                         new ChromeWebContentsHandler()),
31        initiator_(initiator),
32        web_view_(web_view) {
33  }
34  virtual ~WebDialogWebContentsDelegateViews() {}
35
36  // ui::WebDialogWebContentsDelegate:
37  virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE {
38    // Ensure the WebView is focused when its WebContents is focused.
39    web_view_->RequestFocus();
40  }
41  virtual void HandleKeyboardEvent(
42      content::WebContents* source,
43      const content::NativeWebKeyboardEvent& event) OVERRIDE {
44    // Forward shortcut keys in dialog to the browser. http://crbug.com/104586
45    // Disabled on Mac due to http://crbug.com/112173
46#if !defined(OS_MACOSX)
47    Browser* current_browser = chrome::FindBrowserWithWebContents(initiator_);
48    if (!current_browser)
49      return;
50    current_browser->window()->HandleKeyboardEvent(event);
51#endif
52  }
53
54 private:
55  content::WebContents* initiator_;
56  views::WebView* web_view_;
57
58  DISALLOW_COPY_AND_ASSIGN(WebDialogWebContentsDelegateViews);
59};
60
61class ConstrainedWebDialogDelegateViews
62    : public ConstrainedWebDialogDelegateBase {
63 public:
64  ConstrainedWebDialogDelegateViews(content::BrowserContext* context,
65                                    ui::WebDialogDelegate* delegate,
66                                    content::WebContents* web_contents,
67                                    views::WebView* view)
68      : ConstrainedWebDialogDelegateBase(context, delegate,
69            new WebDialogWebContentsDelegateViews(context, web_contents, view)),
70        view_(view) {}
71
72  virtual ~ConstrainedWebDialogDelegateViews() {}
73
74  // ui::WebDialogWebContentsDelegate:
75  virtual void CloseContents(content::WebContents* source) OVERRIDE {
76    view_->GetWidget()->Close();
77  }
78
79  // contents::WebContentsDelegate:
80  virtual void HandleKeyboardEvent(
81      content::WebContents* source,
82      const content::NativeWebKeyboardEvent& event) OVERRIDE {
83    unhandled_keyboard_event_handler_.HandleKeyboardEvent(
84        event, view_->GetFocusManager());
85  }
86
87  // ConstrainedWebDialogDelegate:
88  virtual web_modal::NativeWebContentsModalDialog GetNativeDialog() OVERRIDE {
89    return view_->GetWidget()->GetNativeView();
90  }
91
92 private:
93  // Converts keyboard events on the WebContents to accelerators.
94  views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
95
96  views::WebView* view_;
97
98  DISALLOW_COPY_AND_ASSIGN(ConstrainedWebDialogDelegateViews);
99};
100
101class ConstrainedWebDialogDelegateViewViews
102    : public views::WebView,
103      public ConstrainedWebDialogDelegate,
104      public views::WidgetDelegate {
105 public:
106  ConstrainedWebDialogDelegateViewViews(
107      content::BrowserContext* browser_context,
108      ui::WebDialogDelegate* delegate,
109      content::WebContents* web_contents)
110      : views::WebView(browser_context),
111        impl_(new ConstrainedWebDialogDelegateViews(browser_context, delegate,
112                                                    web_contents, this)) {
113    SetWebContents(GetWebContents());
114    AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
115  }
116  virtual ~ConstrainedWebDialogDelegateViewViews() {}
117
118  // ConstrainedWebDialogDelegate:
119  virtual const ui::WebDialogDelegate* GetWebDialogDelegate() const OVERRIDE {
120    return impl_->GetWebDialogDelegate();
121  }
122  virtual ui::WebDialogDelegate* GetWebDialogDelegate() OVERRIDE {
123    return impl_->GetWebDialogDelegate();
124  }
125  virtual void OnDialogCloseFromWebUI() OVERRIDE {
126    return impl_->OnDialogCloseFromWebUI();
127  }
128  virtual void ReleaseWebContentsOnDialogClose() OVERRIDE {
129    return impl_->ReleaseWebContentsOnDialogClose();
130  }
131  virtual web_modal::NativeWebContentsModalDialog GetNativeDialog() OVERRIDE {
132    return impl_->GetNativeDialog();
133  }
134  virtual content::WebContents* GetWebContents() OVERRIDE {
135    return impl_->GetWebContents();
136  }
137
138  // views::WidgetDelegate:
139  virtual views::View* GetInitiallyFocusedView() OVERRIDE {
140    return this;
141  }
142  virtual void WindowClosing() OVERRIDE {
143    if (!impl_->closed_via_webui())
144      GetWebDialogDelegate()->OnDialogClosed(std::string());
145  }
146  virtual views::Widget* GetWidget() OVERRIDE {
147    return View::GetWidget();
148  }
149  virtual const views::Widget* GetWidget() const OVERRIDE {
150    return View::GetWidget();
151  }
152  virtual base::string16 GetWindowTitle() const OVERRIDE {
153    return impl_->closed_via_webui() ? base::string16() :
154        GetWebDialogDelegate()->GetDialogTitle();
155  }
156  virtual views::View* GetContentsView() OVERRIDE {
157    return this;
158  }
159  virtual views::NonClientFrameView* CreateNonClientFrameView(
160      views::Widget* widget) OVERRIDE {
161    return views::DialogDelegate::CreateDialogFrameView(widget);
162  }
163  virtual bool ShouldShowCloseButton() const OVERRIDE {
164    // No close button if the dialog doesn't want a title bar.
165    return impl_->GetWebDialogDelegate()->ShouldShowDialogTitle();
166  }
167  virtual ui::ModalType GetModalType() const OVERRIDE {
168    return ui::MODAL_TYPE_CHILD;
169  }
170
171  // views::WebView:
172  virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE {
173    // Pressing ESC closes the dialog.
174    DCHECK_EQ(ui::VKEY_ESCAPE, accelerator.key_code());
175    GetWidget()->Close();
176    return true;
177  }
178  virtual gfx::Size GetPreferredSize() const OVERRIDE {
179    gfx::Size size;
180    if (!impl_->closed_via_webui())
181      GetWebDialogDelegate()->GetDialogSize(&size);
182    return size;
183  }
184  virtual gfx::Size GetMinimumSize() const OVERRIDE {
185    // Return an empty size so that we can be made smaller.
186    return gfx::Size();
187  }
188
189 private:
190  scoped_ptr<ConstrainedWebDialogDelegateViews> impl_;
191
192  DISALLOW_COPY_AND_ASSIGN(ConstrainedWebDialogDelegateViewViews);
193};
194
195}  // namespace
196
197ConstrainedWebDialogDelegate* CreateConstrainedWebDialog(
198    content::BrowserContext* browser_context,
199    ui::WebDialogDelegate* delegate,
200    content::WebContents* web_contents) {
201  ConstrainedWebDialogDelegateViewViews* dialog =
202      new ConstrainedWebDialogDelegateViewViews(
203          browser_context, delegate, web_contents);
204  ShowWebModalDialogViews(dialog, web_contents);
205  return dialog;
206}
207