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