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