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_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" 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 delegate_(delegate), 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)); 57} 58 59WebDialogView::~WebDialogView() { 60} 61 62content::WebContents* WebDialogView::web_contents() { 63 return web_view_->web_contents(); 64} 65 66//////////////////////////////////////////////////////////////////////////////// 67// WebDialogView, views::View implementation: 68 69gfx::Size WebDialogView::GetPreferredSize() const { 70 gfx::Size out; 71 if (delegate_) 72 delegate_->GetDialogSize(&out); 73 return out; 74} 75 76gfx::Size WebDialogView::GetMinimumSize() const { 77 gfx::Size out; 78 if (delegate_) 79 delegate_->GetMinimumDialogSize(&out); 80 return out; 81} 82 83bool WebDialogView::AcceleratorPressed(const ui::Accelerator& accelerator) { 84 // Pressing ESC closes the dialog. 85 DCHECK_EQ(ui::VKEY_ESCAPE, accelerator.key_code()); 86 if (GetWidget()) 87 GetWidget()->Close(); 88 return true; 89} 90 91void WebDialogView::ViewHierarchyChanged( 92 const ViewHierarchyChangedDetails& details) { 93 if (details.is_add && GetWidget()) 94 InitDialog(); 95} 96 97bool 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_) 101 return false; 102 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; 110 return true; 111 } 112 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); 117 } 118 return false; 119} 120 121//////////////////////////////////////////////////////////////////////////////// 122// WebDialogView, views::WidgetDelegate implementation: 123 124bool WebDialogView::CanResize() const { 125 if (delegate_) 126 return delegate_->CanResizeDialog(); 127 return true; 128} 129 130ui::ModalType WebDialogView::GetModalType() const { 131 return GetDialogModalType(); 132} 133 134base::string16 WebDialogView::GetWindowTitle() const { 135 if (delegate_) 136 return delegate_->GetDialogTitle(); 137 return base::string16(); 138} 139 140std::string WebDialogView::GetWindowName() const { 141 if (delegate_) 142 return delegate_->GetDialogName(); 143 return std::string(); 144} 145 146void 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 149 // dialog. 150 if (delegate_) 151 OnDialogClosed(""); 152} 153 154views::View* WebDialogView::GetContentsView() { 155 return this; 156} 157 158views::ClientView* WebDialogView::CreateClientView(views::Widget* widget) { 159 return this; 160} 161 162views::View* WebDialogView::GetInitiallyFocusedView() { 163 return web_view_; 164} 165 166bool WebDialogView::ShouldShowWindowTitle() const { 167 return ShouldShowDialogTitle(); 168} 169 170views::Widget* WebDialogView::GetWidget() { 171 return View::GetWidget(); 172} 173 174const views::Widget* WebDialogView::GetWidget() const { 175 return View::GetWidget(); 176} 177 178//////////////////////////////////////////////////////////////////////////////// 179// WebDialogDelegate implementation: 180 181ui::ModalType WebDialogView::GetDialogModalType() const { 182 if (delegate_) 183 return delegate_->GetDialogModalType(); 184 return ui::MODAL_TYPE_NONE; 185} 186 187base::string16 WebDialogView::GetDialogTitle() const { 188 return GetWindowTitle(); 189} 190 191GURL WebDialogView::GetDialogContentURL() const { 192 if (delegate_) 193 return delegate_->GetDialogContentURL(); 194 return GURL(); 195} 196 197void WebDialogView::GetWebUIMessageHandlers( 198 std::vector<WebUIMessageHandler*>* handlers) const { 199 if (delegate_) 200 delegate_->GetWebUIMessageHandlers(handlers); 201} 202 203void WebDialogView::GetDialogSize(gfx::Size* size) const { 204 if (delegate_) 205 delegate_->GetDialogSize(size); 206} 207 208void WebDialogView::GetMinimumDialogSize(gfx::Size* size) const { 209 if (delegate_) 210 delegate_->GetMinimumDialogSize(size); 211} 212 213std::string WebDialogView::GetDialogArgs() const { 214 if (delegate_) 215 return delegate_->GetDialogArgs(); 216 return std::string(); 217} 218 219void WebDialogView::OnDialogShown(content::WebUI* webui, 220 content::RenderViewHost* render_view_host) { 221 if (delegate_) 222 delegate_->OnDialogShown(webui, render_view_host); 223} 224 225void WebDialogView::OnDialogClosed(const std::string& json_retval) { 226 Detach(); 227 if (delegate_) { 228 // Store the dialog content area size. 229 delegate_->StoreDialogSize(GetContentsBounds().size()); 230 } 231 232 if (GetWidget()) 233 GetWidget()->Close(); 234 235 if (delegate_) { 236 delegate_->OnDialogClosed(json_retval); 237 delegate_ = NULL; // We will not communicate further with the delegate. 238 } 239} 240 241void WebDialogView::OnDialogCloseFromWebUI(const std::string& json_retval) { 242 closed_via_webui_ = true; 243 dialog_close_retval_ = json_retval; 244 if (GetWidget()) 245 GetWidget()->Close(); 246} 247 248void WebDialogView::OnCloseContents(WebContents* source, 249 bool* out_close_dialog) { 250 if (delegate_) 251 delegate_->OnCloseContents(source, out_close_dialog); 252} 253 254bool WebDialogView::ShouldShowDialogTitle() const { 255 if (delegate_) 256 return delegate_->ShouldShowDialogTitle(); 257 return true; 258} 259 260bool WebDialogView::HandleContextMenu( 261 const content::ContextMenuParams& params) { 262 if (delegate_) 263 return delegate_->HandleContextMenu(params); 264 return WebDialogWebContentsDelegate::HandleContextMenu(params); 265} 266 267//////////////////////////////////////////////////////////////////////////////// 268// content::WebContentsDelegate implementation: 269 270void WebDialogView::MoveContents(WebContents* source, const gfx::Rect& pos) { 271 // The contained web page wishes to resize itself. We let it do this because 272 // if it's a dialog we know about, we trust it not to be mean to the user. 273 GetWidget()->SetBounds(pos); 274} 275 276// A simplified version of BrowserView::HandleKeyboardEvent(). 277// We don't handle global keyboard shortcuts here, but that's fine since 278// they're all browser-specific. (This may change in the future.) 279void WebDialogView::HandleKeyboardEvent(content::WebContents* source, 280 const NativeWebKeyboardEvent& event) { 281 if (!event.os_event) 282 return; 283 284 GetWidget()->native_widget_private()->RepostNativeEvent(event.os_event); 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 bool to_different_document) { 323 if (delegate_) 324 delegate_->OnLoadingStateChanged(source); 325} 326 327void WebDialogView::BeforeUnloadFired(content::WebContents* tab, 328 bool proceed, 329 bool* proceed_to_fire_unload) { 330 before_unload_fired_ = true; 331 *proceed_to_fire_unload = proceed; 332} 333 334//////////////////////////////////////////////////////////////////////////////// 335// WebDialogView, private: 336 337void WebDialogView::InitDialog() { 338 content::WebContents* web_contents = web_view_->GetWebContents(); 339 if (web_contents->GetDelegate() == this) 340 return; 341 342 web_contents->SetDelegate(this); 343 344 // Set the delegate. This must be done before loading the page. See 345 // the comment above WebDialogUI in its header file for why. 346 WebDialogUI::SetDelegate(web_contents, this); 347 348 web_view_->LoadInitialURL(GetDialogContentURL()); 349} 350 351} // namespace views 352