web_dialog_view.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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 "ui/views/controls/webview/web_dialog_view.h"
6
7#include <vector>
8
9#include "base/strings/utf_string_conversions.h"
10#include "content/public/browser/browser_context.h"
11#include "content/public/browser/native_web_keyboard_event.h"
12#include "content/public/browser/notification_details.h"
13#include "content/public/browser/notification_source.h"
14#include "content/public/browser/notification_types.h"
15#include "content/public/browser/render_frame_host.h"
16#include "content/public/browser/web_contents.h"
17#include "ui/events/event.h"
18#include "ui/events/keycodes/keyboard_codes.h"
19#include "ui/views/controls/webview/webview.h"
20#include "ui/views/layout/fill_layout.h"
21#include "ui/views/widget/native_widget_aura.h"
22#include "ui/views/widget/root_view.h"
23#include "ui/views/widget/widget.h"
24#include "ui/web_dialogs/web_dialog_delegate.h"
25#include "ui/web_dialogs/web_dialog_ui.h"
26
27using content::NativeWebKeyboardEvent;
28using content::WebContents;
29using content::WebUIMessageHandler;
30using ui::WebDialogDelegate;
31using ui::WebDialogUI;
32using ui::WebDialogWebContentsDelegate;
33
34namespace views {
35
36////////////////////////////////////////////////////////////////////////////////
37// WebDialogView, public:
38
39WebDialogView::WebDialogView(
40    content::BrowserContext* context,
41    WebDialogDelegate* delegate,
42    WebContentsHandler* handler)
43    : ClientView(NULL, NULL),
44      WebDialogWebContentsDelegate(context, handler),
45      initialized_(false),
46      delegate_(delegate),
47      web_view_(new views::WebView(context)),
48      is_attempting_close_dialog_(false),
49      before_unload_fired_(false),
50      closed_via_webui_(false),
51      close_contents_called_(false) {
52  web_view_->set_allow_accelerators(true);
53  AddChildView(web_view_);
54  set_contents_view(web_view_);
55  SetLayoutManager(new views::FillLayout);
56  // Pressing the ESC key will close the dialog.
57  AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
58}
59
60WebDialogView::~WebDialogView() {
61}
62
63content::WebContents* WebDialogView::web_contents() {
64  return web_view_->web_contents();
65}
66
67////////////////////////////////////////////////////////////////////////////////
68// WebDialogView, views::View implementation:
69
70gfx::Size WebDialogView::GetPreferredSize() {
71  gfx::Size out;
72  if (delegate_)
73    delegate_->GetDialogSize(&out);
74  return out;
75}
76
77gfx::Size WebDialogView::GetMinimumSize() {
78  gfx::Size out;
79  if (delegate_)
80    delegate_->GetMinimumDialogSize(&out);
81  return out;
82}
83
84bool WebDialogView::AcceleratorPressed(const ui::Accelerator& accelerator) {
85  // Pressing ESC closes the dialog.
86  DCHECK_EQ(ui::VKEY_ESCAPE, accelerator.key_code());
87  if (GetWidget())
88    GetWidget()->Close();
89  return true;
90}
91
92void WebDialogView::ViewHierarchyChanged(
93    const ViewHierarchyChangedDetails& details) {
94  if (details.is_add && GetWidget())
95    InitDialog();
96}
97
98bool WebDialogView::CanClose() {
99  // Don't close UI if |delegate_| does not allow users to close it by
100  // clicking on "x" button or pressing Esc shortcut key on hosting dialog.
101  if (!delegate_->CanCloseDialog() && !close_contents_called_)
102    return false;
103
104  // If CloseContents() is called before CanClose(), which is called by
105  // RenderViewHostImpl::ClosePageIgnoringUnloadEvents, it indicates
106  // beforeunload event should not be fired during closing.
107  if ((is_attempting_close_dialog_ && before_unload_fired_) ||
108      close_contents_called_) {
109    is_attempting_close_dialog_ = false;
110    before_unload_fired_ = false;
111    return true;
112  }
113
114  if (!is_attempting_close_dialog_) {
115    // Fire beforeunload event when user attempts to close the dialog.
116    is_attempting_close_dialog_ = true;
117    web_view_->web_contents()->DispatchBeforeUnload(false);
118  }
119  return false;
120}
121
122////////////////////////////////////////////////////////////////////////////////
123// WebDialogView, views::WidgetDelegate implementation:
124
125bool WebDialogView::CanResize() const {
126  return true;
127}
128
129ui::ModalType WebDialogView::GetModalType() const {
130  return GetDialogModalType();
131}
132
133base::string16 WebDialogView::GetWindowTitle() const {
134  if (delegate_)
135    return delegate_->GetDialogTitle();
136  return base::string16();
137}
138
139std::string WebDialogView::GetWindowName() const {
140  if (delegate_)
141    return delegate_->GetDialogName();
142  return std::string();
143}
144
145void WebDialogView::WindowClosing() {
146  // If we still have a delegate that means we haven't notified it of the
147  // dialog closing. This happens if the user clicks the Close button on the
148  // dialog.
149  if (delegate_)
150    OnDialogClosed("");
151}
152
153views::View* WebDialogView::GetContentsView() {
154  return this;
155}
156
157views::ClientView* WebDialogView::CreateClientView(views::Widget* widget) {
158  return this;
159}
160
161views::View* WebDialogView::GetInitiallyFocusedView() {
162  return web_view_;
163}
164
165bool WebDialogView::ShouldShowWindowTitle() const {
166  return ShouldShowDialogTitle();
167}
168
169views::Widget* WebDialogView::GetWidget() {
170  return View::GetWidget();
171}
172
173const views::Widget* WebDialogView::GetWidget() const {
174  return View::GetWidget();
175}
176
177////////////////////////////////////////////////////////////////////////////////
178// WebDialogDelegate implementation:
179
180ui::ModalType WebDialogView::GetDialogModalType() const {
181  if (delegate_)
182    return delegate_->GetDialogModalType();
183  return ui::MODAL_TYPE_NONE;
184}
185
186base::string16 WebDialogView::GetDialogTitle() const {
187  return GetWindowTitle();
188}
189
190GURL WebDialogView::GetDialogContentURL() const {
191  if (delegate_)
192    return delegate_->GetDialogContentURL();
193  return GURL();
194}
195
196void WebDialogView::GetWebUIMessageHandlers(
197    std::vector<WebUIMessageHandler*>* handlers) const {
198  if (delegate_)
199    delegate_->GetWebUIMessageHandlers(handlers);
200}
201
202void WebDialogView::GetDialogSize(gfx::Size* size) const {
203  if (delegate_)
204    delegate_->GetDialogSize(size);
205}
206
207void WebDialogView::GetMinimumDialogSize(gfx::Size* size) const {
208  if (delegate_)
209    delegate_->GetMinimumDialogSize(size);
210}
211
212std::string WebDialogView::GetDialogArgs() const {
213  if (delegate_)
214    return delegate_->GetDialogArgs();
215  return std::string();
216}
217
218void WebDialogView::OnDialogShown(content::WebUI* webui,
219                                  content::RenderViewHost* render_view_host) {
220  if (delegate_)
221    delegate_->OnDialogShown(webui, render_view_host);
222}
223
224void WebDialogView::OnDialogClosed(const std::string& json_retval) {
225  Detach();
226  if (delegate_) {
227    // Store the dialog content area size.
228    delegate_->StoreDialogSize(GetContentsBounds().size());
229  }
230
231  if (GetWidget())
232    GetWidget()->Close();
233
234  if (delegate_) {
235    delegate_->OnDialogClosed(json_retval);
236    delegate_ = NULL;  // We will not communicate further with the delegate.
237  }
238}
239
240void WebDialogView::OnDialogCloseFromWebUI(const std::string& json_retval) {
241  closed_via_webui_ = true;
242  dialog_close_retval_ = json_retval;
243  if (GetWidget())
244    GetWidget()->Close();
245}
246
247void WebDialogView::OnCloseContents(WebContents* source,
248                                    bool* out_close_dialog) {
249  if (delegate_)
250    delegate_->OnCloseContents(source, out_close_dialog);
251}
252
253bool WebDialogView::ShouldShowDialogTitle() const {
254  if (delegate_)
255    return delegate_->ShouldShowDialogTitle();
256  return true;
257}
258
259bool WebDialogView::HandleContextMenu(
260    const content::ContextMenuParams& params) {
261  if (delegate_)
262    return delegate_->HandleContextMenu(params);
263  return WebDialogWebContentsDelegate::HandleContextMenu(params);
264}
265
266////////////////////////////////////////////////////////////////////////////////
267// content::WebContentsDelegate implementation:
268
269void WebDialogView::MoveContents(WebContents* source, const gfx::Rect& pos) {
270  // The contained web page wishes to resize itself. We let it do this because
271  // if it's a dialog we know about, we trust it not to be mean to the user.
272  GetWidget()->SetBounds(pos);
273}
274
275// A simplified version of BrowserView::HandleKeyboardEvent().
276// We don't handle global keyboard shortcuts here, but that's fine since
277// they're all browser-specific. (This may change in the future.)
278void WebDialogView::HandleKeyboardEvent(content::WebContents* source,
279                                        const NativeWebKeyboardEvent& event) {
280  if (!event.os_event)
281    return;
282  ui::KeyEvent aura_event(event.os_event->native_event(), false);
283  ui::EventHandler* event_handler =
284      GetWidget()->native_widget()->GetEventHandler();
285
286  DCHECK(event_handler);
287  if (event_handler)
288    event_handler->OnKeyEvent(&aura_event);
289
290}
291
292void WebDialogView::CloseContents(WebContents* source) {
293  close_contents_called_ = true;
294  bool close_dialog = false;
295  OnCloseContents(source, &close_dialog);
296  if (close_dialog)
297    OnDialogClosed(closed_via_webui_ ? dialog_close_retval_ : std::string());
298}
299
300content::WebContents* WebDialogView::OpenURLFromTab(
301    content::WebContents* source,
302    const content::OpenURLParams& params) {
303  content::WebContents* new_contents = NULL;
304  if (delegate_ &&
305      delegate_->HandleOpenURLFromTab(source, params, &new_contents)) {
306    return new_contents;
307  }
308  return WebDialogWebContentsDelegate::OpenURLFromTab(source, params);
309}
310
311void WebDialogView::AddNewContents(content::WebContents* source,
312                                   content::WebContents* new_contents,
313                                   WindowOpenDisposition disposition,
314                                   const gfx::Rect& initial_pos,
315                                   bool user_gesture,
316                                   bool* was_blocked) {
317  if (delegate_ && delegate_->HandleAddNewContents(
318          source, new_contents, disposition, initial_pos, user_gesture)) {
319    return;
320  }
321  WebDialogWebContentsDelegate::AddNewContents(
322      source, new_contents, disposition, initial_pos, user_gesture,
323      was_blocked);
324}
325
326void WebDialogView::LoadingStateChanged(content::WebContents* source,
327    bool to_different_document) {
328  if (delegate_)
329    delegate_->OnLoadingStateChanged(source);
330}
331
332void WebDialogView::BeforeUnloadFired(content::WebContents* tab,
333                                      bool proceed,
334                                      bool* proceed_to_fire_unload) {
335  before_unload_fired_ = true;
336  *proceed_to_fire_unload = proceed;
337}
338
339////////////////////////////////////////////////////////////////////////////////
340// WebDialogView, private:
341
342void WebDialogView::InitDialog() {
343  content::WebContents* web_contents = web_view_->GetWebContents();
344  if (web_contents->GetDelegate() == this)
345    return;
346
347  web_contents->SetDelegate(this);
348
349  // Set the delegate. This must be done before loading the page. See
350  // the comment above WebDialogUI in its header file for why.
351  WebDialogUI::SetDelegate(web_contents, this);
352
353  web_view_->LoadInitialURL(GetDialogContentURL());
354}
355
356}  // namespace views
357