OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h" | 5 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h" |
6 | 6 |
7 #include "base/strings/utf_string_conversions.h" | 7 #include "base/strings/utf_string_conversions.h" |
8 #include "chrome/browser/extensions/api/commands/command_service.h" | |
9 #include "chrome/browser/extensions/extension_action.h" | 8 #include "chrome/browser/extensions/extension_action.h" |
10 #include "chrome/browser/extensions/extension_action_icon_factory.h" | |
11 #include "chrome/browser/extensions/extension_action_manager.h" | |
12 #include "chrome/browser/extensions/extension_context_menu_model.h" | |
13 #include "chrome/browser/extensions/extension_tab_util.h" | |
14 #include "chrome/browser/extensions/location_bar_controller.h" | |
15 #include "chrome/browser/extensions/tab_helper.h" | |
16 #include "chrome/browser/platform_util.h" | 9 #include "chrome/browser/platform_util.h" |
17 #include "chrome/browser/profiles/profile.h" | 10 #include "chrome/browser/profiles/profile.h" |
18 #include "chrome/browser/sessions/session_id.h" | 11 #include "chrome/browser/ui/browser.h" |
19 #include "chrome/browser/ui/browser_list.h" | |
20 #include "chrome/browser/ui/extensions/accelerator_priority.h" | |
21 #include "chrome/browser/ui/views/frame/browser_view.h" | |
22 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" | 12 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" |
23 #include "chrome/browser/ui/webui/extensions/extension_info_ui.h" | |
24 #include "extensions/browser/extension_registry.h" | 13 #include "extensions/browser/extension_registry.h" |
25 #include "extensions/common/extension.h" | |
26 #include "ui/accessibility/ax_view_state.h" | 14 #include "ui/accessibility/ax_view_state.h" |
27 #include "ui/events/event.h" | 15 #include "ui/events/event.h" |
28 #include "ui/gfx/canvas.h" | 16 #include "ui/gfx/canvas.h" |
29 #include "ui/gfx/image/image.h" | 17 #include "ui/gfx/image/image.h" |
30 #include "ui/views/controls/menu/menu_runner.h" | |
31 | |
32 using content::WebContents; | |
33 using extensions::LocationBarController; | |
34 using extensions::Extension; | |
35 | 18 |
36 // static | 19 // static |
37 const char PageActionImageView::kViewClassName[] = "PageActionImageView"; | 20 const char PageActionImageView::kViewClassName[] = "PageActionImageView"; |
38 | 21 |
39 PageActionImageView::PageActionImageView(LocationBarView* owner, | 22 PageActionImageView::PageActionImageView(LocationBarView* owner, |
40 ExtensionAction* page_action, | 23 ExtensionAction* page_action, |
41 Browser* browser) | 24 Browser* browser) |
42 : owner_(owner), | 25 : view_controller_(new ExtensionActionViewController( |
43 page_action_(page_action), | 26 extensions::ExtensionRegistry::Get(browser->profile())-> |
44 browser_(browser), | 27 enabled_extensions().GetByID(page_action->extension_id()), |
45 current_tab_id_(-1), | 28 browser, |
46 preview_enabled_(false), | 29 page_action, |
47 popup_(NULL) { | 30 this)), |
48 const Extension* extension = extensions::ExtensionRegistry::Get( | 31 owner_(owner), |
49 owner_->profile())->enabled_extensions().GetByID( | 32 preview_enabled_(false) { |
50 page_action->extension_id()); | 33 // There should be an associated focus manager so that we can safely register |
51 DCHECK(extension); | 34 // accelerators for commands. |
52 | 35 DCHECK(GetFocusManagerForAccelerator()); |
53 icon_factory_.reset( | |
54 new ExtensionActionIconFactory( | |
55 owner_->profile(), extension, page_action, this)); | |
56 | |
57 SetAccessibilityFocusable(true); | 36 SetAccessibilityFocusable(true); |
58 set_context_menu_controller(this); | 37 view_controller_->RegisterCommand(); |
59 | 38 set_context_menu_controller(view_controller_.get()); |
60 extensions::CommandService* command_service = | |
61 extensions::CommandService::Get(browser_->profile()); | |
62 extensions::Command page_action_command; | |
63 if (command_service->GetPageActionCommand( | |
64 extension->id(), | |
65 extensions::CommandService::ACTIVE_ONLY, | |
66 &page_action_command, | |
67 NULL)) { | |
68 page_action_keybinding_.reset( | |
69 new ui::Accelerator(page_action_command.accelerator())); | |
70 owner_->GetFocusManager()->RegisterAccelerator( | |
71 *page_action_keybinding_.get(), | |
72 GetAcceleratorPriority(page_action_command.accelerator(), extension), | |
73 this); | |
74 } | |
75 } | 39 } |
76 | 40 |
77 PageActionImageView::~PageActionImageView() { | 41 PageActionImageView::~PageActionImageView() { |
78 if (owner_->GetFocusManager()) { | |
79 if (page_action_keybinding_.get()) { | |
80 owner_->GetFocusManager()->UnregisterAccelerator( | |
81 *page_action_keybinding_.get(), this); | |
82 } | |
83 } | |
84 | |
85 if (popup_) | |
86 popup_->GetWidget()->RemoveObserver(this); | |
87 HidePopup(); | |
88 } | |
89 | |
90 void PageActionImageView::ExecuteAction( | |
91 ExtensionPopup::ShowAction show_action) { | |
92 WebContents* web_contents = owner_->GetWebContents(); | |
93 if (!web_contents) | |
94 return; | |
95 | |
96 extensions::TabHelper* extensions_tab_helper = | |
97 extensions::TabHelper::FromWebContents(web_contents); | |
98 LocationBarController* controller = | |
99 extensions_tab_helper->location_bar_controller(); | |
100 | |
101 switch (controller->OnClicked(page_action_)) { | |
102 case LocationBarController::ACTION_NONE: | |
103 break; | |
104 | |
105 case LocationBarController::ACTION_SHOW_POPUP: | |
106 ShowPopupWithURL(page_action_->GetPopupUrl(current_tab_id_), show_action); | |
107 break; | |
108 | |
109 case LocationBarController::ACTION_SHOW_CONTEXT_MENU: | |
110 // We are never passing OnClicked a right-click button, so assume that | |
111 // we're never going to be asked to show a context menu. | |
112 // TODO(kalman): if this changes, update this class to pass the real | |
113 // mouse button through to the LocationBarController. | |
114 NOTREACHED(); | |
115 break; | |
116 } | |
117 } | 42 } |
118 | 43 |
119 const char* PageActionImageView::GetClassName() const { | 44 const char* PageActionImageView::GetClassName() const { |
120 return kViewClassName; | 45 return kViewClassName; |
121 } | 46 } |
122 | 47 |
123 void PageActionImageView::GetAccessibleState(ui::AXViewState* state) { | 48 void PageActionImageView::GetAccessibleState(ui::AXViewState* state) { |
124 state->role = ui::AX_ROLE_BUTTON; | 49 state->role = ui::AX_ROLE_BUTTON; |
125 state->name = base::UTF8ToUTF16(tooltip_); | 50 state->name = base::UTF8ToUTF16(tooltip_); |
126 } | 51 } |
127 | 52 |
128 bool PageActionImageView::OnMousePressed(const ui::MouseEvent& event) { | 53 bool PageActionImageView::OnMousePressed(const ui::MouseEvent& event) { |
129 // We want to show the bubble on mouse release; that is the standard behavior | 54 // We want to show the bubble on mouse release; that is the standard behavior |
130 // for buttons. (Also, triggering on mouse press causes bugs like | 55 // for buttons. (Also, triggering on mouse press causes bugs like |
131 // http://crbug.com/33155.) | 56 // http://crbug.com/33155.) |
132 return true; | 57 return true; |
133 } | 58 } |
134 | 59 |
135 void PageActionImageView::OnMouseReleased(const ui::MouseEvent& event) { | 60 void PageActionImageView::OnMouseReleased(const ui::MouseEvent& event) { |
136 if (!HitTestPoint(event.location())) | 61 if (!HitTestPoint(event.location())) |
137 return; | 62 return; |
138 | 63 |
139 if (event.IsRightMouseButton()) { | 64 if (event.IsRightMouseButton()) { |
140 // Don't show a menu here, its handled in View::ProcessMouseReleased. We | 65 // Don't show a menu here, its handled in View::ProcessMouseReleased. We |
141 // show the context menu by way of being the ContextMenuController. | 66 // show the context menu by way of being the ContextMenuController. |
142 return; | 67 return; |
143 } | 68 } |
144 | 69 |
145 ExecuteAction(ExtensionPopup::SHOW); | 70 view_controller_->ExecuteActionByUser(); |
146 } | 71 } |
147 | 72 |
148 bool PageActionImageView::OnKeyPressed(const ui::KeyEvent& event) { | 73 bool PageActionImageView::OnKeyPressed(const ui::KeyEvent& event) { |
149 if (event.key_code() == ui::VKEY_SPACE || | 74 if (event.key_code() == ui::VKEY_SPACE || |
150 event.key_code() == ui::VKEY_RETURN) { | 75 event.key_code() == ui::VKEY_RETURN) { |
151 ExecuteAction(ExtensionPopup::SHOW); | 76 view_controller_->ExecuteActionByUser(); |
152 return true; | 77 return true; |
153 } | 78 } |
154 return false; | 79 return false; |
155 } | 80 } |
156 | 81 |
157 void PageActionImageView::OnGestureEvent(ui::GestureEvent* event) { | 82 void PageActionImageView::OnGestureEvent(ui::GestureEvent* event) { |
158 if (event->type() == ui::ET_GESTURE_TAP) { | 83 if (event->type() == ui::ET_GESTURE_TAP) { |
159 ExecuteAction(ExtensionPopup::SHOW); | 84 view_controller_->ExecuteActionByUser(); |
160 event->SetHandled(); | 85 event->SetHandled(); |
161 } | 86 } |
162 } | 87 } |
163 | 88 |
164 void PageActionImageView::ShowContextMenuForView( | 89 void PageActionImageView::UpdateVisibility(content::WebContents* contents) { |
165 View* source, | 90 int tab_id = view_controller_->GetCurrentTabId(); |
166 const gfx::Point& point, | |
167 ui::MenuSourceType source_type) { | |
168 const Extension* extension = extensions::ExtensionRegistry::Get( | |
169 owner_->profile())->enabled_extensions().GetByID( | |
170 page_action()->extension_id()); | |
171 if (!extension->ShowConfigureContextMenus()) | |
172 return; | |
173 | |
174 scoped_refptr<ExtensionContextMenuModel> context_menu_model( | |
175 new ExtensionContextMenuModel(extension, browser_, this)); | |
176 menu_runner_.reset(new views::MenuRunner( | |
177 context_menu_model.get(), | |
178 views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU)); | |
179 gfx::Point screen_loc; | |
180 views::View::ConvertPointToScreen(this, &screen_loc); | |
181 if (menu_runner_->RunMenuAt(GetWidget(), | |
182 NULL, | |
183 gfx::Rect(screen_loc, size()), | |
184 views::MENU_ANCHOR_TOPLEFT, | |
185 source_type) == views::MenuRunner::MENU_DELETED) { | |
186 return; | |
187 } | |
188 } | |
189 | |
190 bool PageActionImageView::AcceleratorPressed( | |
191 const ui::Accelerator& accelerator) { | |
192 DCHECK(visible()); // Should not have happened due to CanHandleAccelerator. | |
193 | |
194 const std::string extension_id = page_action()->extension_id(); | |
195 const ui::AcceleratorManager::HandlerPriority priority = | |
196 GetAcceleratorPriorityById(accelerator, extension_id, owner_->profile()); | |
197 // Normal priority shortcuts must be handled via standard browser commands | |
198 // to be processed at the proper time. | |
199 if (priority == ui::AcceleratorManager::kHighPriority) | |
200 ExecuteAction(ExtensionPopup::SHOW); | |
201 return priority == ui::AcceleratorManager::kHighPriority; | |
202 } | |
203 | |
204 bool PageActionImageView::CanHandleAccelerators() const { | |
205 // While visible, we don't handle accelerators and while so we also don't | |
206 // count as a priority accelerator handler. | |
207 return visible(); | |
208 } | |
209 | |
210 void PageActionImageView::UpdateVisibility(WebContents* contents, | |
211 const GURL& url) { | |
212 // Save this off so we can pass it back to the extension when the action gets | |
213 // executed. See PageActionImageView::OnMousePressed. | |
214 current_tab_id_ = | |
215 contents ? extensions::ExtensionTabUtil::GetTabId(contents) : -1; | |
216 current_url_ = url; | |
217 | 91 |
218 if (!contents || | 92 if (!contents || |
219 (!preview_enabled_ && !page_action_->GetIsVisible(current_tab_id_))) { | 93 tab_id == -1 || |
| 94 (!preview_enabled_ && !extension_action()->GetIsVisible(tab_id))) { |
220 SetVisible(false); | 95 SetVisible(false); |
221 return; | 96 return; |
222 } | 97 } |
223 | 98 |
224 // Set the tooltip. | 99 // Set the tooltip. |
225 tooltip_ = page_action_->GetTitle(current_tab_id_); | 100 tooltip_ = extension_action()->GetTitle(tab_id); |
226 SetTooltipText(base::UTF8ToUTF16(tooltip_)); | 101 SetTooltipText(base::UTF8ToUTF16(tooltip_)); |
227 | 102 |
228 // Set the image. | 103 // Set the image. |
229 gfx::Image icon = icon_factory_->GetIcon(current_tab_id_); | 104 gfx::Image icon = view_controller_->GetIcon(tab_id); |
230 if (!icon.IsEmpty()) | 105 if (!icon.IsEmpty()) |
231 SetImage(*icon.ToImageSkia()); | 106 SetImage(*icon.ToImageSkia()); |
232 | 107 |
233 SetVisible(true); | 108 SetVisible(true); |
234 } | 109 } |
235 | 110 |
236 void PageActionImageView::InspectPopup() { | 111 void PageActionImageView::PaintChildren(gfx::Canvas* canvas, |
237 ExecuteAction(ExtensionPopup::SHOW_AND_INSPECT); | 112 const views::CullSet& cull_set) { |
238 } | 113 View::PaintChildren(canvas, cull_set); |
239 | 114 int tab_id = view_controller_->GetCurrentTabId(); |
240 void PageActionImageView::OnWidgetDestroying(views::Widget* widget) { | 115 if (tab_id >= 0) { |
241 DCHECK_EQ(popup_->GetWidget(), widget); | 116 view_controller_->extension_action()->PaintBadge( |
242 popup_->GetWidget()->RemoveObserver(this); | 117 canvas, GetLocalBounds(), tab_id); |
243 popup_ = NULL; | 118 } |
244 } | 119 } |
245 | 120 |
246 void PageActionImageView::OnIconUpdated() { | 121 void PageActionImageView::OnIconUpdated() { |
247 WebContents* web_contents = owner_->GetWebContents(); | 122 UpdateVisibility(GetCurrentWebContents()); |
248 if (web_contents) | |
249 UpdateVisibility(web_contents, current_url_); | |
250 } | 123 } |
251 | 124 |
252 void PageActionImageView::PaintChildren(gfx::Canvas* canvas, | 125 views::View* PageActionImageView::GetAsView() { |
253 const views::CullSet& cull_set) { | 126 return this; |
254 View::PaintChildren(canvas, cull_set); | |
255 if (current_tab_id_ >= 0) | |
256 page_action_->PaintBadge(canvas, GetLocalBounds(), current_tab_id_); | |
257 } | 127 } |
258 | 128 |
259 void PageActionImageView::ShowPopupWithURL( | 129 bool PageActionImageView::IsShownInMenu() { |
260 const GURL& popup_url, | 130 return false; |
261 ExtensionPopup::ShowAction show_action) { | |
262 bool popup_showing = popup_ != NULL; | |
263 | |
264 // Always hide the current popup. Only one popup at a time. | |
265 HidePopup(); | |
266 | |
267 // If we were already showing, then treat this click as a dismiss. | |
268 if (popup_showing) | |
269 return; | |
270 | |
271 views::BubbleBorder::Arrow arrow = base::i18n::IsRTL() ? | |
272 views::BubbleBorder::TOP_LEFT : views::BubbleBorder::TOP_RIGHT; | |
273 | |
274 popup_ = ExtensionPopup::ShowPopup(popup_url, browser_, this, arrow, | |
275 show_action); | |
276 popup_->GetWidget()->AddObserver(this); | |
277 } | 131 } |
278 | 132 |
279 void PageActionImageView::HidePopup() { | 133 views::FocusManager* PageActionImageView::GetFocusManagerForAccelerator() { |
280 if (popup_) | 134 return owner_->GetFocusManager(); |
281 popup_->GetWidget()->Close(); | |
282 } | 135 } |
| 136 |
| 137 views::Widget* PageActionImageView::GetParentForContextMenu() { |
| 138 return GetWidget(); |
| 139 } |
| 140 |
| 141 views::View* PageActionImageView::GetReferenceViewForPopup() { |
| 142 return this; |
| 143 } |
| 144 |
| 145 content::WebContents* PageActionImageView::GetCurrentWebContents() { |
| 146 return owner_->GetWebContents(); |
| 147 } |
| 148 |
| 149 void PageActionImageView::HideActivePopup() { |
| 150 // The only popup that will be active is this popup. |
| 151 view_controller_->HidePopup(); |
| 152 } |
OLD | NEW |