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