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 #include "ui/views/controls/webview/web_dialog_view.h"
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_private.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"
27 using content::NativeWebKeyboardEvent
;
28 using content::WebContents
;
29 using content::WebUIMessageHandler
;
30 using ui::WebDialogDelegate
;
31 using ui::WebDialogUI
;
32 using ui::WebDialogWebContentsDelegate
;
36 ////////////////////////////////////////////////////////////////////////////////
37 // WebDialogView, public:
39 WebDialogView::WebDialogView(
40 content::BrowserContext
* context
,
41 WebDialogDelegate
* delegate
,
42 WebContentsHandler
* handler
)
43 : ClientView(NULL
, NULL
),
44 WebDialogWebContentsDelegate(context
, handler
),
46 web_view_(new views::WebView(context
)),
47 is_attempting_close_dialog_(false),
48 before_unload_fired_(false),
49 closed_via_webui_(false),
50 close_contents_called_(false) {
51 web_view_
->set_allow_accelerators(true);
52 AddChildView(web_view_
);
53 set_contents_view(web_view_
);
54 SetLayoutManager(new views::FillLayout
);
55 // Pressing the ESC key will close the dialog.
56 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE
, ui::EF_NONE
));
59 WebDialogView::~WebDialogView() {
62 content::WebContents
* WebDialogView::web_contents() {
63 return web_view_
->web_contents();
66 ////////////////////////////////////////////////////////////////////////////////
67 // WebDialogView, views::View implementation:
69 gfx::Size
WebDialogView::GetPreferredSize() const {
72 delegate_
->GetDialogSize(&out
);
76 gfx::Size
WebDialogView::GetMinimumSize() const {
79 delegate_
->GetMinimumDialogSize(&out
);
83 bool WebDialogView::AcceleratorPressed(const ui::Accelerator
& accelerator
) {
84 // Pressing ESC closes the dialog.
85 DCHECK_EQ(ui::VKEY_ESCAPE
, accelerator
.key_code());
91 void WebDialogView::ViewHierarchyChanged(
92 const ViewHierarchyChangedDetails
& details
) {
93 if (details
.is_add
&& GetWidget())
97 bool WebDialogView::CanClose() {
98 // Don't close UI if |delegate_| does not allow users to close it by
99 // clicking on "x" button or pressing Esc shortcut key on hosting dialog.
100 if (!delegate_
->CanCloseDialog() && !close_contents_called_
)
103 // If CloseContents() is called before CanClose(), which is called by
104 // RenderViewHostImpl::ClosePageIgnoringUnloadEvents, it indicates
105 // beforeunload event should not be fired during closing.
106 if ((is_attempting_close_dialog_
&& before_unload_fired_
) ||
107 close_contents_called_
) {
108 is_attempting_close_dialog_
= false;
109 before_unload_fired_
= false;
113 if (!is_attempting_close_dialog_
) {
114 // Fire beforeunload event when user attempts to close the dialog.
115 is_attempting_close_dialog_
= true;
116 web_view_
->web_contents()->DispatchBeforeUnload(false);
121 ////////////////////////////////////////////////////////////////////////////////
122 // WebDialogView, views::WidgetDelegate implementation:
124 bool WebDialogView::CanResize() const {
126 return delegate_
->CanResizeDialog();
130 ui::ModalType
WebDialogView::GetModalType() const {
131 return GetDialogModalType();
134 base::string16
WebDialogView::GetWindowTitle() const {
136 return delegate_
->GetDialogTitle();
137 return base::string16();
140 std::string
WebDialogView::GetWindowName() const {
142 return delegate_
->GetDialogName();
143 return std::string();
146 void WebDialogView::WindowClosing() {
147 // If we still have a delegate that means we haven't notified it of the
148 // dialog closing. This happens if the user clicks the Close button on the
154 views::View
* WebDialogView::GetContentsView() {
158 views::ClientView
* WebDialogView::CreateClientView(views::Widget
* widget
) {
162 views::View
* WebDialogView::GetInitiallyFocusedView() {
166 bool WebDialogView::ShouldShowWindowTitle() const {
167 return ShouldShowDialogTitle();
170 views::Widget
* WebDialogView::GetWidget() {
171 return View::GetWidget();
174 const views::Widget
* WebDialogView::GetWidget() const {
175 return View::GetWidget();
178 ////////////////////////////////////////////////////////////////////////////////
179 // WebDialogDelegate implementation:
181 ui::ModalType
WebDialogView::GetDialogModalType() const {
183 return delegate_
->GetDialogModalType();
184 return ui::MODAL_TYPE_NONE
;
187 base::string16
WebDialogView::GetDialogTitle() const {
188 return GetWindowTitle();
191 GURL
WebDialogView::GetDialogContentURL() const {
193 return delegate_
->GetDialogContentURL();
197 void WebDialogView::GetWebUIMessageHandlers(
198 std::vector
<WebUIMessageHandler
*>* handlers
) const {
200 delegate_
->GetWebUIMessageHandlers(handlers
);
203 void WebDialogView::GetDialogSize(gfx::Size
* size
) const {
205 delegate_
->GetDialogSize(size
);
208 void WebDialogView::GetMinimumDialogSize(gfx::Size
* size
) const {
210 delegate_
->GetMinimumDialogSize(size
);
213 std::string
WebDialogView::GetDialogArgs() const {
215 return delegate_
->GetDialogArgs();
216 return std::string();
219 void WebDialogView::OnDialogShown(content::WebUI
* webui
,
220 content::RenderViewHost
* render_view_host
) {
222 delegate_
->OnDialogShown(webui
, render_view_host
);
225 void WebDialogView::OnDialogClosed(const std::string
& json_retval
) {
228 // Store the dialog content area size.
229 delegate_
->StoreDialogSize(GetContentsBounds().size());
233 GetWidget()->Close();
236 delegate_
->OnDialogClosed(json_retval
);
237 delegate_
= NULL
; // We will not communicate further with the delegate.
241 void WebDialogView::OnDialogCloseFromWebUI(const std::string
& json_retval
) {
242 closed_via_webui_
= true;
243 dialog_close_retval_
= json_retval
;
245 GetWidget()->Close();
248 void WebDialogView::OnCloseContents(WebContents
* source
,
249 bool* out_close_dialog
) {
250 DCHECK(out_close_dialog
);
252 delegate_
->OnCloseContents(source
, out_close_dialog
);
255 bool WebDialogView::ShouldShowDialogTitle() const {
257 return delegate_
->ShouldShowDialogTitle();
261 bool WebDialogView::HandleContextMenu(
262 const content::ContextMenuParams
& params
) {
264 return delegate_
->HandleContextMenu(params
);
265 return WebDialogWebContentsDelegate::HandleContextMenu(params
);
268 ////////////////////////////////////////////////////////////////////////////////
269 // content::WebContentsDelegate implementation:
271 void WebDialogView::MoveContents(WebContents
* source
, const gfx::Rect
& pos
) {
272 // The contained web page wishes to resize itself. We let it do this because
273 // if it's a dialog we know about, we trust it not to be mean to the user.
274 GetWidget()->SetBounds(pos
);
277 // A simplified version of BrowserView::HandleKeyboardEvent().
278 // We don't handle global keyboard shortcuts here, but that's fine since
279 // they're all browser-specific. (This may change in the future.)
280 void WebDialogView::HandleKeyboardEvent(content::WebContents
* source
,
281 const NativeWebKeyboardEvent
& event
) {
285 GetWidget()->native_widget_private()->RepostNativeEvent(event
.os_event
);
288 void WebDialogView::CloseContents(WebContents
* source
) {
289 close_contents_called_
= true;
290 bool close_dialog
= false;
291 OnCloseContents(source
, &close_dialog
);
293 OnDialogClosed(closed_via_webui_
? dialog_close_retval_
: std::string());
296 content::WebContents
* WebDialogView::OpenURLFromTab(
297 content::WebContents
* source
,
298 const content::OpenURLParams
& params
) {
299 content::WebContents
* new_contents
= NULL
;
301 delegate_
->HandleOpenURLFromTab(source
, params
, &new_contents
)) {
304 return WebDialogWebContentsDelegate::OpenURLFromTab(source
, params
);
307 void WebDialogView::AddNewContents(content::WebContents
* source
,
308 content::WebContents
* new_contents
,
309 WindowOpenDisposition disposition
,
310 const gfx::Rect
& initial_rect
,
313 if (delegate_
&& delegate_
->HandleAddNewContents(
314 source
, new_contents
, disposition
, initial_rect
, user_gesture
)) {
317 WebDialogWebContentsDelegate::AddNewContents(
318 source
, new_contents
, disposition
, initial_rect
, user_gesture
,
322 void WebDialogView::LoadingStateChanged(content::WebContents
* source
,
323 bool to_different_document
) {
325 delegate_
->OnLoadingStateChanged(source
);
328 void WebDialogView::BeforeUnloadFired(content::WebContents
* tab
,
330 bool* proceed_to_fire_unload
) {
331 before_unload_fired_
= true;
332 *proceed_to_fire_unload
= proceed
;
335 bool WebDialogView::ShouldCreateWebContents(
336 content::WebContents
* web_contents
,
338 int main_frame_route_id
,
339 WindowContainerType window_container_type
,
340 const std::string
& frame_name
,
341 const GURL
& target_url
,
342 const std::string
& partition_id
,
343 content::SessionStorageNamespace
* session_storage_namespace
) {
345 return delegate_
->HandleShouldCreateWebContents();
349 ////////////////////////////////////////////////////////////////////////////////
350 // WebDialogView, private:
352 void WebDialogView::InitDialog() {
353 content::WebContents
* web_contents
= web_view_
->GetWebContents();
354 if (web_contents
->GetDelegate() == this)
357 web_contents
->SetDelegate(this);
359 // Set the delegate. This must be done before loading the page. See
360 // the comment above WebDialogUI in its header file for why.
361 WebDialogUI::SetDelegate(web_contents
, this);
363 web_view_
->LoadInitialURL(GetDialogContentURL());