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