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