Upstream version 10.38.220.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / tab_contents / chrome_web_contents_view_delegate_views.cc
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 "chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.h"
6
7 #include "chrome/browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.h"
8 #include "chrome/browser/ui/sad_tab_helper.h"
9 #include "chrome/browser/ui/tab_contents/chrome_web_contents_view_delegate.h"
10 #include "chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.h"
11 #include "chrome/browser/ui/views/sad_tab_view.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "components/web_modal/web_contents_modal_dialog_manager.h"
14 #include "content/public/browser/render_process_host.h"
15 #include "content/public/browser/render_view_host.h"
16 #include "content/public/browser/render_widget_host_view.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/browser/web_contents_delegate.h"
19 #include "ui/aura/client/screen_position_client.h"
20 #include "ui/aura/window.h"
21 #include "ui/views/focus/focus_manager.h"
22 #include "ui/views/focus/view_storage.h"
23 #include "ui/views/widget/widget.h"
24
25 using web_modal::WebContentsModalDialogManager;
26
27 ChromeWebContentsViewDelegateViews::ChromeWebContentsViewDelegateViews(
28     content::WebContents* web_contents)
29     : ContextMenuDelegate(web_contents),
30       web_contents_(web_contents) {
31   last_focused_view_storage_id_ =
32       views::ViewStorage::GetInstance()->CreateStorageID();
33 }
34
35 ChromeWebContentsViewDelegateViews::~ChromeWebContentsViewDelegateViews() {
36   // Makes sure to remove any stored view we may still have in the ViewStorage.
37   //
38   // It is possible the view went away before us, so we only do this if the
39   // view is registered.
40   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
41   if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
42     view_storage->RemoveView(last_focused_view_storage_id_);
43 }
44
45 content::WebDragDestDelegate*
46     ChromeWebContentsViewDelegateViews::GetDragDestDelegate() {
47   // We install a chrome specific handler to intercept bookmark drags for the
48   // bookmark manager/extension API.
49   bookmark_handler_.reset(new WebDragBookmarkHandlerAura);
50   return bookmark_handler_.get();
51 }
52
53 bool ChromeWebContentsViewDelegateViews::Focus() {
54   SadTabHelper* sad_tab_helper = SadTabHelper::FromWebContents(web_contents_);
55   if (sad_tab_helper) {
56     SadTabView* sad_tab = static_cast<SadTabView*>(sad_tab_helper->sad_tab());
57     if (sad_tab) {
58       sad_tab->RequestFocus();
59       return true;
60     }
61   }
62
63   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
64       WebContentsModalDialogManager::FromWebContents(web_contents_);
65   if (web_contents_modal_dialog_manager) {
66     // TODO(erg): WebContents used to own web contents modal dialogs, which is
67     // why this is here. Eventually this should be ported to a containing view
68     // specializing in web contents modal dialog management.
69     if (web_contents_modal_dialog_manager->IsDialogActive()) {
70       web_contents_modal_dialog_manager->FocusTopmostDialog();
71       return true;
72     }
73   }
74
75   return false;
76 }
77
78 void ChromeWebContentsViewDelegateViews::TakeFocus(bool reverse) {
79   views::FocusManager* focus_manager = GetFocusManager();
80   if (focus_manager)
81     focus_manager->AdvanceFocus(reverse);
82 }
83
84 void ChromeWebContentsViewDelegateViews::StoreFocus() {
85   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
86
87   if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
88     view_storage->RemoveView(last_focused_view_storage_id_);
89
90   if (!GetFocusManager())
91     return;
92   views::View* focused_view = GetFocusManager()->GetFocusedView();
93   if (focused_view)
94     view_storage->StoreView(last_focused_view_storage_id_, focused_view);
95 }
96
97 void ChromeWebContentsViewDelegateViews::RestoreFocus() {
98   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
99   views::View* last_focused_view =
100       view_storage->RetrieveView(last_focused_view_storage_id_);
101
102   if (!last_focused_view) {
103     SetInitialFocus();
104   } else {
105     if (last_focused_view->IsFocusable() &&
106         GetFocusManager()->ContainsView(last_focused_view)) {
107       last_focused_view->RequestFocus();
108     } else {
109       // The focused view may not belong to the same window hierarchy (e.g.
110       // if the location bar was focused and the tab is dragged out), or it may
111       // no longer be focusable (e.g. if the location bar was focused and then
112       // we switched to fullscreen mode).  In that case we default to the
113       // default focus.
114       SetInitialFocus();
115     }
116     view_storage->RemoveView(last_focused_view_storage_id_);
117   }
118 }
119
120 scoped_ptr<RenderViewContextMenu> ChromeWebContentsViewDelegateViews::BuildMenu(
121     content::WebContents* web_contents,
122     const content::ContextMenuParams& params) {
123   scoped_ptr<RenderViewContextMenu> menu;
124   content::RenderFrameHost* focused_frame = web_contents->GetFocusedFrame();
125   // If the frame tree does not have a focused frame at this point, do not
126   // bother creating RenderViewContextMenuViews.
127   // This happens if the frame has navigated to a different page before
128   // ContextMenu message was received by the current RenderFrameHost.
129   if (focused_frame) {
130     menu.reset(RenderViewContextMenuViews::Create(focused_frame, params));
131     menu->Init();
132   }
133   return menu.Pass();
134 }
135
136 void ChromeWebContentsViewDelegateViews::ShowMenu(
137     scoped_ptr<RenderViewContextMenu> menu) {
138   context_menu_.reset(static_cast<RenderViewContextMenuViews*>(menu.release()));
139   if (!context_menu_.get())
140     return;
141
142   // Menus need a Widget to work. If we're not the active tab we won't
143   // necessarily be in a widget.
144   views::Widget* top_level_widget = GetTopLevelWidget();
145   if (!top_level_widget)
146     return;
147
148   const content::ContextMenuParams& params = context_menu_->params();
149   // Don't show empty menus.
150   if (context_menu_->menu_model().GetItemCount() == 0)
151     return;
152
153   gfx::Point screen_point(params.x, params.y);
154
155   // Convert from target window coordinates to root window coordinates.
156   aura::Window* target_window = GetActiveNativeView();
157   aura::Window* root_window = target_window->GetRootWindow();
158   aura::client::ScreenPositionClient* screen_position_client =
159       aura::client::GetScreenPositionClient(root_window);
160   if (screen_position_client) {
161     screen_position_client->ConvertPointToScreen(target_window,
162                                                  &screen_point);
163   }
164   // Enable recursive tasks on the message loop so we can get updates while
165   // the context menu is being displayed.
166   base::MessageLoop::ScopedNestableTaskAllower allow(
167       base::MessageLoop::current());
168   context_menu_->RunMenuAt(top_level_widget, screen_point, params.source_type);
169 }
170
171 void ChromeWebContentsViewDelegateViews::ShowContextMenu(
172     content::RenderFrameHost* render_frame_host,
173     const content::ContextMenuParams& params) {
174   ShowMenu(
175       BuildMenu(content::WebContents::FromRenderFrameHost(render_frame_host),
176                 params));
177 }
178
179 void ChromeWebContentsViewDelegateViews::SizeChanged(const gfx::Size& size) {
180   SadTabHelper* sad_tab_helper = SadTabHelper::FromWebContents(web_contents_);
181   if (!sad_tab_helper)
182     return;
183   SadTabView* sad_tab = static_cast<SadTabView*>(sad_tab_helper->sad_tab());
184   if (sad_tab)
185     sad_tab->GetWidget()->SetBounds(gfx::Rect(size));
186 }
187
188 aura::Window* ChromeWebContentsViewDelegateViews::GetActiveNativeView() {
189   return web_contents_->GetFullscreenRenderWidgetHostView() ?
190       web_contents_->GetFullscreenRenderWidgetHostView()->GetNativeView() :
191       web_contents_->GetNativeView();
192 }
193
194 views::Widget* ChromeWebContentsViewDelegateViews::GetTopLevelWidget() {
195   return views::Widget::GetTopLevelWidgetForNativeView(GetActiveNativeView());
196 }
197
198 views::FocusManager*
199     ChromeWebContentsViewDelegateViews::GetFocusManager() {
200   views::Widget* toplevel_widget = GetTopLevelWidget();
201   return toplevel_widget ? toplevel_widget->GetFocusManager() : NULL;
202 }
203
204 void ChromeWebContentsViewDelegateViews::SetInitialFocus() {
205   if (web_contents_->FocusLocationBarByDefault()) {
206     if (web_contents_->GetDelegate())
207       web_contents_->GetDelegate()->SetFocusToLocationBar(false);
208   } else {
209     web_contents_->Focus();
210   }
211 }
212
213 namespace chrome {
214
215 content::WebContentsViewDelegate* CreateWebContentsViewDelegate(
216     content::WebContents* web_contents) {
217   return new ChromeWebContentsViewDelegateViews(web_contents);
218 }
219
220 }  // namespace chrome