Home | History | Annotate | Download | only in webview
      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