OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/toolbar/browser_action_view.h" | 5 #include "chrome/browser/ui/views/toolbar/browser_action_view.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
10 #include "chrome/browser/chrome_notification_types.h" | 10 #include "chrome/browser/chrome_notification_types.h" |
11 #include "chrome/browser/extensions/api/commands/command_service.h" | |
12 #include "chrome/browser/extensions/extension_action.h" | 11 #include "chrome/browser/extensions/extension_action.h" |
13 #include "chrome/browser/extensions/extension_action_manager.h" | 12 #include "chrome/browser/extensions/extension_action_manager.h" |
14 #include "chrome/browser/extensions/extension_context_menu_model.h" | |
15 #include "chrome/browser/profiles/profile.h" | 13 #include "chrome/browser/profiles/profile.h" |
16 #include "chrome/browser/themes/theme_service.h" | 14 #include "chrome/browser/themes/theme_service.h" |
17 #include "chrome/browser/themes/theme_service_factory.h" | 15 #include "chrome/browser/themes/theme_service_factory.h" |
18 #include "chrome/browser/ui/browser.h" | 16 #include "chrome/browser/ui/browser.h" |
19 #include "chrome/browser/ui/extensions/accelerator_priority.h" | |
20 #include "chrome/browser/ui/view_ids.h" | 17 #include "chrome/browser/ui/view_ids.h" |
21 #include "chrome/browser/ui/views/frame/browser_view.h" | 18 #include "chrome/browser/ui/views/frame/browser_view.h" |
22 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h" | 19 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h" |
23 #include "chrome/browser/ui/views/toolbar/toolbar_view.h" | 20 #include "chrome/browser/ui/views/toolbar/toolbar_view.h" |
24 #include "extensions/common/extension.h" | 21 #include "extensions/common/extension.h" |
25 #include "extensions/common/manifest_constants.h" | 22 #include "extensions/common/manifest_constants.h" |
26 #include "grit/generated_resources.h" | 23 #include "grit/generated_resources.h" |
27 #include "grit/theme_resources.h" | 24 #include "grit/theme_resources.h" |
28 #include "ui/accessibility/ax_view_state.h" | 25 #include "ui/accessibility/ax_view_state.h" |
29 #include "ui/base/l10n/l10n_util.h" | 26 #include "ui/base/l10n/l10n_util.h" |
30 #include "ui/base/resource/resource_bundle.h" | 27 #include "ui/base/resource/resource_bundle.h" |
31 #include "ui/events/event.h" | 28 #include "ui/events/event.h" |
32 #include "ui/gfx/image/image_skia.h" | 29 #include "ui/gfx/image/image_skia.h" |
33 #include "ui/gfx/image/image_skia_operations.h" | 30 #include "ui/gfx/image/image_skia_operations.h" |
34 #include "ui/gfx/image/image_skia_source.h" | 31 #include "ui/gfx/image/image_skia_source.h" |
35 #include "ui/views/controls/button/label_button_border.h" | 32 #include "ui/views/controls/button/label_button_border.h" |
36 #include "ui/views/controls/menu/menu_item_view.h" | |
37 #include "ui/views/controls/menu/menu_runner.h" | |
38 | 33 |
39 using extensions::Extension; | 34 using extensions::Extension; |
40 using views::LabelButtonBorder; | 35 using views::LabelButtonBorder; |
41 | 36 |
42 namespace { | 37 namespace { |
43 | 38 |
44 // We have smaller insets than normal STYLE_TEXTBUTTON buttons so that we can | 39 // We have smaller insets than normal STYLE_TEXTBUTTON buttons so that we can |
45 // fit user supplied icons in without clipping them. | 40 // fit user supplied icons in without clipping them. |
46 const int kBorderInset = 4; | 41 const int kBorderInset = 4; |
47 | 42 |
48 } // namespace | 43 } // namespace |
49 | 44 |
50 //////////////////////////////////////////////////////////////////////////////// | 45 //////////////////////////////////////////////////////////////////////////////// |
51 // BrowserActionView | 46 // BrowserActionView |
52 | 47 |
53 BrowserActionView::BrowserActionView(const Extension* extension, | 48 BrowserActionView::BrowserActionView(const Extension* extension, |
54 Browser* browser, | 49 Browser* browser, |
55 BrowserActionView::Delegate* delegate) | 50 BrowserActionView::Delegate* delegate) |
56 : browser_(browser), | 51 : delegate_(delegate), |
57 delegate_(delegate), | 52 button_(NULL) { |
58 button_(NULL), | |
59 extension_(extension) { | |
60 set_id(VIEW_ID_BROWSER_ACTION); | 53 set_id(VIEW_ID_BROWSER_ACTION); |
61 button_ = new BrowserActionButton(extension_, browser_, delegate_); | 54 button_ = new BrowserActionButton(extension, browser, delegate_); |
62 button_->set_drag_controller(delegate_); | 55 button_->set_drag_controller(delegate_); |
63 button_->set_owned_by_client(); | 56 button_->set_owned_by_client(); |
64 AddChildView(button_); | 57 AddChildView(button_); |
65 button_->UpdateState(); | 58 button_->UpdateState(); |
66 } | 59 } |
67 | 60 |
68 BrowserActionView::~BrowserActionView() { | 61 BrowserActionView::~BrowserActionView() { |
69 button_->Destroy(); | 62 delete button_; |
70 } | 63 } |
71 | 64 |
72 gfx::ImageSkia BrowserActionView::GetIconWithBadge() { | 65 gfx::ImageSkia BrowserActionView::GetIconWithBadge() { |
73 return button_->GetIconWithBadge(); | 66 return button_->GetIconWithBadge(); |
74 } | 67 } |
75 | 68 |
76 void BrowserActionView::Layout() { | 69 void BrowserActionView::Layout() { |
77 button_->SetBounds(0, 0, width(), height()); | 70 button_->SetBounds(0, 0, width(), height()); |
78 } | 71 } |
79 | 72 |
80 void BrowserActionView::GetAccessibleState(ui::AXViewState* state) { | 73 void BrowserActionView::GetAccessibleState(ui::AXViewState* state) { |
81 state->name = l10n_util::GetStringUTF16( | 74 state->name = l10n_util::GetStringUTF16( |
82 IDS_ACCNAME_EXTENSIONS_BROWSER_ACTION); | 75 IDS_ACCNAME_EXTENSIONS_BROWSER_ACTION); |
83 state->role = ui::AX_ROLE_GROUP; | 76 state->role = ui::AX_ROLE_GROUP; |
84 } | 77 } |
85 | 78 |
86 gfx::Size BrowserActionView::GetPreferredSize() const { | 79 gfx::Size BrowserActionView::GetPreferredSize() const { |
87 return gfx::Size(BrowserActionsContainer::IconWidth(false), | 80 return gfx::Size(BrowserActionsContainer::IconWidth(false), |
88 BrowserActionsContainer::IconHeight()); | 81 BrowserActionsContainer::IconHeight()); |
89 } | 82 } |
90 | 83 |
91 void BrowserActionView::PaintChildren(gfx::Canvas* canvas, | 84 void BrowserActionView::PaintChildren(gfx::Canvas* canvas, |
92 const views::CullSet& cull_set) { | 85 const views::CullSet& cull_set) { |
93 View::PaintChildren(canvas, cull_set); | 86 View::PaintChildren(canvas, cull_set); |
94 ExtensionAction* action = button()->browser_action(); | 87 ExtensionAction* action = button_->extension_action(); |
95 int tab_id = delegate_->GetCurrentTabId(); | 88 int tab_id = button_->extension_action_view()->GetCurrentTabId(); |
96 if (tab_id >= 0) | 89 if (tab_id >= 0) |
97 action->PaintBadge(canvas, GetLocalBounds(), tab_id); | 90 action->PaintBadge(canvas, GetLocalBounds(), tab_id); |
98 } | 91 } |
99 | 92 |
100 //////////////////////////////////////////////////////////////////////////////// | 93 //////////////////////////////////////////////////////////////////////////////// |
101 // BrowserActionButton | 94 // BrowserActionButton |
102 | 95 |
103 BrowserActionButton::BrowserActionButton(const Extension* extension, | 96 BrowserActionButton::BrowserActionButton(const Extension* extension, |
104 Browser* browser, | 97 Browser* browser, |
105 BrowserActionView::Delegate* delegate) | 98 BrowserActionView::Delegate* delegate) |
106 : MenuButton(this, base::string16(), NULL, false), | 99 : MenuButton(this, base::string16(), NULL, false), |
107 browser_(browser), | 100 extension_action_view_(new ExtensionActionView( |
108 browser_action_( | 101 extension, |
102 browser, | |
109 extensions::ExtensionActionManager::Get(browser->profile())-> | 103 extensions::ExtensionActionManager::Get(browser->profile())-> |
110 GetBrowserAction(*extension)), | 104 GetBrowserAction(*extension), |
111 extension_(extension), | 105 this)), |
112 icon_factory_(browser->profile(), extension, browser_action_, this), | |
113 delegate_(delegate), | 106 delegate_(delegate), |
114 called_registered_extension_command_(false), | 107 called_registered_extension_command_(false), |
115 popup_(NULL), | |
116 icon_observer_(NULL) { | 108 icon_observer_(NULL) { |
117 SetHorizontalAlignment(gfx::ALIGN_CENTER); | 109 SetHorizontalAlignment(gfx::ALIGN_CENTER); |
118 set_context_menu_controller(this); | 110 set_context_menu_controller(extension_action_view_.get()); |
119 | 111 |
120 // No UpdateState() here because View hierarchy not setup yet. Our parent | 112 // No UpdateState() here because View hierarchy not setup yet. Our parent |
121 // should call UpdateState() after creation. | 113 // should call UpdateState() after creation. |
122 | 114 |
123 content::NotificationSource notification_source = | 115 content::NotificationSource notification_source = |
124 content::Source<Profile>(browser_->profile()->GetOriginalProfile()); | 116 content::Source<Profile>(browser->profile()->GetOriginalProfile()); |
125 registrar_.Add(this, | 117 registrar_.Add(this, |
126 extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED, | 118 extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED, |
127 content::Source<ExtensionAction>(browser_action_)); | 119 content::Source<ExtensionAction>(extension_action())); |
128 registrar_.Add(this, | 120 registrar_.Add(this, |
129 extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED, | 121 extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED, |
130 notification_source); | 122 notification_source); |
131 registrar_.Add(this, | 123 registrar_.Add(this, |
132 extensions::NOTIFICATION_EXTENSION_COMMAND_REMOVED, | 124 extensions::NOTIFICATION_EXTENSION_COMMAND_REMOVED, |
133 notification_source); | 125 notification_source); |
134 | 126 |
135 // We also listen for browser theme changes on linux because a switch from or | 127 // We also listen for browser theme changes on linux because a switch from or |
136 // to GTK requires that we regrab our browser action images. | 128 // to GTK requires that we regrab our browser action images. |
137 registrar_.Add( | 129 registrar_.Add( |
138 this, | 130 this, |
139 chrome::NOTIFICATION_BROWSER_THEME_CHANGED, | 131 chrome::NOTIFICATION_BROWSER_THEME_CHANGED, |
140 content::Source<ThemeService>( | 132 content::Source<ThemeService>( |
141 ThemeServiceFactory::GetForProfile(browser->profile()))); | 133 ThemeServiceFactory::GetForProfile(browser->profile()))); |
142 } | 134 } |
143 | 135 |
144 void BrowserActionButton::Destroy() { | |
Devlin
2014/08/05 20:08:57
Pretty sure we don't need this - when menu_runner_
| |
145 MaybeUnregisterExtensionCommand(false); | |
146 HidePopup(); | |
147 if (menu_runner_) { | |
148 menu_runner_->Cancel(); | |
149 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
150 } else { | |
151 delete this; | |
152 } | |
153 } | |
154 | |
155 void BrowserActionButton::ViewHierarchyChanged( | 136 void BrowserActionButton::ViewHierarchyChanged( |
156 const ViewHierarchyChangedDetails& details) { | 137 const ViewHierarchyChangedDetails& details) { |
157 if (details.is_add && !called_registered_extension_command_ && | 138 if (details.is_add && !called_registered_extension_command_ && |
158 GetFocusManager()) { | 139 GetFocusManager()) { |
159 MaybeRegisterExtensionCommand(); | 140 extension_action_view_->RegisterCommand(); |
160 called_registered_extension_command_ = true; | 141 called_registered_extension_command_ = true; |
161 } | 142 } |
162 | 143 |
163 MenuButton::ViewHierarchyChanged(details); | 144 MenuButton::ViewHierarchyChanged(details); |
164 } | 145 } |
165 | 146 |
166 void BrowserActionButton::OnDragDone() { | 147 void BrowserActionButton::OnDragDone() { |
167 delegate_->OnBrowserActionViewDragDone(); | 148 delegate_->OnBrowserActionViewDragDone(); |
168 } | 149 } |
169 | 150 |
170 bool BrowserActionButton::CanHandleAccelerators() const { | 151 bool BrowserActionButton::CanHandleAccelerators() const { |
171 // View::CanHandleAccelerators() checks to see if the view is visible before | 152 // View::CanHandleAccelerators() checks to see if the view is visible before |
172 // allowing it to process accelerators. This is not appropriate for browser | 153 // allowing it to process accelerators. This is not appropriate for browser |
173 // actions buttons, which can be hidden inside the overflow area. | 154 // actions buttons, which can be hidden inside the overflow area. |
174 return true; | 155 return true; |
175 } | 156 } |
176 | 157 |
177 void BrowserActionButton::GetAccessibleState(ui::AXViewState* state) { | 158 void BrowserActionButton::GetAccessibleState(ui::AXViewState* state) { |
178 views::MenuButton::GetAccessibleState(state); | 159 views::MenuButton::GetAccessibleState(state); |
179 state->role = ui::AX_ROLE_BUTTON; | 160 state->role = ui::AX_ROLE_BUTTON; |
180 } | 161 } |
181 | 162 |
182 void BrowserActionButton::ButtonPressed(views::Button* sender, | 163 void BrowserActionButton::ButtonPressed(views::Button* sender, |
183 const ui::Event& event) { | 164 const ui::Event& event) { |
184 ExecuteBrowserAction(); | 165 extension_action_view_->ExecuteActionByUser(); |
185 } | |
186 | |
187 void BrowserActionButton::ShowContextMenuForView( | |
188 View* source, | |
189 const gfx::Point& point, | |
190 ui::MenuSourceType source_type) { | |
191 if (!extension()->ShowConfigureContextMenus()) | |
192 return; | |
193 | |
194 SetButtonPushed(); | |
195 | |
196 // Reconstructs the menu every time because the menu's contents are dynamic. | |
197 scoped_refptr<ExtensionContextMenuModel> context_menu_contents( | |
198 new ExtensionContextMenuModel(extension(), browser_, this)); | |
199 gfx::Point screen_loc; | |
200 views::View::ConvertPointToScreen(this, &screen_loc); | |
201 | |
202 views::Widget* parent = NULL; | |
203 int run_types = views::MenuRunner::HAS_MNEMONICS | | |
204 views::MenuRunner::CONTEXT_MENU; | |
205 if (delegate_->ShownInsideMenu()) { | |
206 run_types |= views::MenuRunner::IS_NESTED; | |
207 // RunMenuAt expects a nested menu to be parented by the same widget as the | |
208 // already visible menu, in this case the Chrome menu. | |
209 parent = BrowserView::GetBrowserViewForBrowser(browser_)->toolbar() | |
210 ->app_menu() | |
211 ->GetWidget(); | |
212 } else { | |
213 parent = GetWidget(); | |
214 } | |
215 | |
216 menu_runner_.reset( | |
217 new views::MenuRunner(context_menu_contents.get(), run_types)); | |
218 | |
219 if (menu_runner_->RunMenuAt(parent, | |
220 NULL, | |
221 gfx::Rect(screen_loc, size()), | |
222 views::MENU_ANCHOR_TOPLEFT, | |
223 source_type) == | |
224 views::MenuRunner::MENU_DELETED) { | |
225 return; | |
226 } | |
227 | |
228 menu_runner_.reset(); | |
229 SetButtonNotPushed(); | |
230 } | 166 } |
231 | 167 |
232 void BrowserActionButton::UpdateState() { | 168 void BrowserActionButton::UpdateState() { |
233 int tab_id = delegate_->GetCurrentTabId(); | 169 int tab_id = extension_action_view_->GetCurrentTabId(); |
234 if (tab_id < 0) | 170 if (tab_id < 0) |
235 return; | 171 return; |
236 | 172 |
237 if (!IsEnabled(tab_id)) { | 173 if (!IsEnabled(tab_id)) { |
238 SetState(views::CustomButton::STATE_DISABLED); | 174 SetState(views::CustomButton::STATE_DISABLED); |
239 } else { | 175 } else { |
240 SetState(menu_visible_ ? | 176 SetState(menu_visible_ ? |
241 views::CustomButton::STATE_PRESSED : | 177 views::CustomButton::STATE_PRESSED : |
242 views::CustomButton::STATE_NORMAL); | 178 views::CustomButton::STATE_NORMAL); |
243 } | 179 } |
244 | 180 |
245 gfx::ImageSkia icon = *icon_factory_.GetIcon(tab_id).ToImageSkia(); | 181 gfx::ImageSkia icon = *extension_action_view_->GetIcon(tab_id).ToImageSkia(); |
246 | 182 |
247 if (!icon.isNull()) { | 183 if (!icon.isNull()) { |
248 if (!browser_action()->GetIsVisible(tab_id)) | 184 if (!extension_action()->GetIsVisible(tab_id)) |
249 icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25); | 185 icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25); |
250 | 186 |
251 ThemeService* theme = | 187 ThemeService* theme = |
252 ThemeServiceFactory::GetForProfile(browser_->profile()); | 188 ThemeServiceFactory::GetForProfile( |
189 extension_action_view_->browser()->profile()); | |
253 | 190 |
254 gfx::ImageSkia bg = *theme->GetImageSkiaNamed(IDR_BROWSER_ACTION); | 191 gfx::ImageSkia bg = *theme->GetImageSkiaNamed(IDR_BROWSER_ACTION); |
255 SetImage(views::Button::STATE_NORMAL, | 192 SetImage(views::Button::STATE_NORMAL, |
256 gfx::ImageSkiaOperations::CreateSuperimposedImage(bg, icon)); | 193 gfx::ImageSkiaOperations::CreateSuperimposedImage(bg, icon)); |
257 } | 194 } |
258 | 195 |
259 // If the browser action name is empty, show the extension name instead. | 196 // If the browser action name is empty, show the extension name instead. |
260 std::string title = browser_action()->GetTitle(tab_id); | 197 std::string title = extension_action()->GetTitle(tab_id); |
261 base::string16 name = | 198 base::string16 name = |
262 base::UTF8ToUTF16(title.empty() ? extension()->name() : title); | 199 base::UTF8ToUTF16(title.empty() ? extension()->name() : title); |
263 SetTooltipText(name); | 200 SetTooltipText(name); |
264 SetAccessibleName(name); | 201 SetAccessibleName(name); |
265 | 202 |
266 parent()->SchedulePaint(); | 203 parent()->SchedulePaint(); |
267 } | 204 } |
268 | 205 |
269 bool BrowserActionButton::IsPopup() { | 206 bool BrowserActionButton::IsPopup() { |
270 int tab_id = delegate_->GetCurrentTabId(); | 207 int tab_id = extension_action_view_->GetCurrentTabId(); |
271 return (tab_id < 0) ? false : browser_action_->HasPopup(tab_id); | 208 return (tab_id < 0) ? false : extension_action()->HasPopup(tab_id); |
272 } | |
273 | |
274 GURL BrowserActionButton::GetPopupUrl() { | |
275 int tab_id = delegate_->GetCurrentTabId(); | |
276 return (tab_id < 0) ? GURL() : browser_action_->GetPopupUrl(tab_id); | |
277 } | |
278 | |
279 bool BrowserActionButton::ShowPopup( | |
280 ExtensionPopup::ShowAction show_action, | |
281 bool grant_tab_permissions) { | |
282 GURL popup_url; | |
283 if (delegate_->GetModel()->ExecuteBrowserAction( | |
284 extension_, browser_, &popup_url, grant_tab_permissions) == | |
285 extensions::ExtensionToolbarModel::ACTION_NONE) { | |
286 return false; | |
287 } | |
288 | |
289 // If we're already showing the popup for this browser action, just hide it | |
290 // and return. | |
291 bool already_showing = popup_ != NULL; | |
292 | |
293 // Always hide the current popup, even if it's not the same. | |
294 // Only one popup should be visible at a time. | |
295 delegate_->HideActivePopup(); | |
296 if (already_showing) | |
297 return false; | |
298 | |
299 // Browser actions in the overflow menu can still show popups, so we may need | |
300 // a reference view other than this button's parent. If so, use the overflow | |
301 // view. | |
302 views::View* reference_view = | |
303 parent()->visible() ? this : delegate_->GetOverflowReferenceView(); | |
304 | |
305 popup_ = ExtensionPopup::ShowPopup(popup_url, | |
306 browser_, | |
307 reference_view, | |
308 views::BubbleBorder::TOP_RIGHT, | |
309 show_action); | |
310 popup_->GetWidget()->AddObserver(this); | |
311 delegate_->SetPopupOwner(this); | |
312 | |
313 // Only set button as pushed if it was triggered by a user click. | |
314 if (grant_tab_permissions) | |
315 SetButtonPushed(); | |
316 return true; | |
317 } | |
318 | |
319 void BrowserActionButton::HidePopup() { | |
320 if (popup_) | |
321 CleanupPopup(true); | |
322 } | |
323 | |
324 void BrowserActionButton::ExecuteBrowserAction() { | |
325 ShowPopup(ExtensionPopup::SHOW, true); | |
326 } | 209 } |
327 | 210 |
328 void BrowserActionButton::Observe(int type, | 211 void BrowserActionButton::Observe(int type, |
329 const content::NotificationSource& source, | 212 const content::NotificationSource& source, |
330 const content::NotificationDetails& details) { | 213 const content::NotificationDetails& details) { |
331 switch (type) { | 214 switch (type) { |
332 case extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED: | 215 case extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED: |
333 UpdateState(); | 216 UpdateState(); |
334 // The browser action may have become visible/hidden so we need to make | 217 // The browser action may have become visible/hidden so we need to make |
335 // sure the state gets updated. | 218 // sure the state gets updated. |
336 delegate_->OnBrowserActionVisibilityChanged(); | 219 delegate_->OnBrowserActionVisibilityChanged(); |
337 break; | 220 break; |
338 case extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED: | 221 case extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED: |
339 case extensions::NOTIFICATION_EXTENSION_COMMAND_REMOVED: { | 222 case extensions::NOTIFICATION_EXTENSION_COMMAND_REMOVED: { |
340 std::pair<const std::string, const std::string>* payload = | 223 std::pair<const std::string, const std::string>* payload = |
341 content::Details<std::pair<const std::string, const std::string> >( | 224 content::Details<std::pair<const std::string, const std::string> >( |
342 details).ptr(); | 225 details).ptr(); |
343 if (extension_->id() == payload->first && | 226 if (extension()->id() == payload->first && |
344 payload->second == | 227 payload->second == |
345 extensions::manifest_values::kBrowserActionCommandEvent) { | 228 extensions::manifest_values::kBrowserActionCommandEvent) { |
346 if (type == extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED) | 229 if (type == extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED) |
347 MaybeRegisterExtensionCommand(); | 230 extension_action_view_->RegisterCommand(); |
348 else | 231 else |
349 MaybeUnregisterExtensionCommand(true); | 232 extension_action_view_->UnregisterCommand(true); |
350 } | 233 } |
351 break; | 234 break; |
352 } | 235 } |
353 case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: | 236 case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: |
354 UpdateState(); | 237 UpdateState(); |
355 break; | 238 break; |
356 default: | 239 default: |
357 NOTREACHED(); | 240 NOTREACHED(); |
358 break; | 241 break; |
359 } | 242 } |
360 } | 243 } |
361 | 244 |
362 void BrowserActionButton::OnIconUpdated() { | |
363 UpdateState(); | |
364 if (icon_observer_) | |
365 icon_observer_->OnIconUpdated(GetIconWithBadge()); | |
366 } | |
367 | |
368 bool BrowserActionButton::Activate() { | 245 bool BrowserActionButton::Activate() { |
369 if (!IsPopup()) | 246 if (!IsPopup()) |
370 return true; | 247 return true; |
371 | 248 |
372 ExecuteBrowserAction(); | 249 extension_action_view_->ExecuteActionByUser(); |
373 | 250 |
374 // TODO(erikkay): Run a nested modal loop while the mouse is down to | 251 // TODO(erikkay): Run a nested modal loop while the mouse is down to |
375 // enable menu-like drag-select behavior. | 252 // enable menu-like drag-select behavior. |
376 | 253 |
377 // The return value of this method is returned via OnMousePressed. | 254 // The return value of this method is returned via OnMousePressed. |
378 // We need to return false here since we're handing off focus to another | 255 // We need to return false here since we're handing off focus to another |
379 // widget/view, and true will grab it right back and try to send events | 256 // widget/view, and true will grab it right back and try to send events |
380 // to us. | 257 // to us. |
381 return false; | 258 return false; |
382 } | 259 } |
383 | 260 |
384 bool BrowserActionButton::OnMousePressed(const ui::MouseEvent& event) { | 261 bool BrowserActionButton::OnMousePressed(const ui::MouseEvent& event) { |
385 if (!event.IsRightMouseButton()) { | 262 if (!event.IsRightMouseButton()) { |
386 return IsPopup() ? MenuButton::OnMousePressed(event) : | 263 return IsPopup() ? MenuButton::OnMousePressed(event) : |
387 LabelButton::OnMousePressed(event); | 264 LabelButton::OnMousePressed(event); |
388 } | 265 } |
389 | 266 |
390 if (!views::View::ShouldShowContextMenuOnMousePress()) { | 267 if (!views::View::ShouldShowContextMenuOnMousePress()) { |
391 // See comments in MenuButton::Activate() as to why this is needed. | 268 // See comments in MenuButton::Activate() as to why this is needed. |
392 SetMouseHandler(NULL); | 269 SetMouseHandler(NULL); |
393 | 270 |
394 ShowContextMenu(gfx::Point(), ui::MENU_SOURCE_MOUSE); | 271 ShowContextMenu(gfx::Point(), ui::MENU_SOURCE_MOUSE); |
395 } | 272 } |
396 return false; | 273 return false; |
397 } | 274 } |
398 | 275 |
399 void BrowserActionButton::OnMouseReleased(const ui::MouseEvent& event) { | 276 void BrowserActionButton::OnMouseReleased(const ui::MouseEvent& event) { |
400 if (IsPopup() || menu_runner_) { | 277 if (IsPopup() || extension_action_view_->is_menu_running()) { |
401 // TODO(erikkay) this never actually gets called (probably because of the | 278 // TODO(erikkay) this never actually gets called (probably because of the |
402 // loss of focus). | 279 // loss of focus). |
403 MenuButton::OnMouseReleased(event); | 280 MenuButton::OnMouseReleased(event); |
404 } else { | 281 } else { |
405 LabelButton::OnMouseReleased(event); | 282 LabelButton::OnMouseReleased(event); |
406 } | 283 } |
407 } | 284 } |
408 | 285 |
409 void BrowserActionButton::OnMouseExited(const ui::MouseEvent& event) { | 286 void BrowserActionButton::OnMouseExited(const ui::MouseEvent& event) { |
410 if (IsPopup() || menu_runner_) | 287 if (IsPopup() || extension_action_view_->is_menu_running()) |
411 MenuButton::OnMouseExited(event); | 288 MenuButton::OnMouseExited(event); |
412 else | 289 else |
413 LabelButton::OnMouseExited(event); | 290 LabelButton::OnMouseExited(event); |
414 } | 291 } |
415 | 292 |
416 bool BrowserActionButton::OnKeyReleased(const ui::KeyEvent& event) { | 293 bool BrowserActionButton::OnKeyReleased(const ui::KeyEvent& event) { |
417 return IsPopup() ? MenuButton::OnKeyReleased(event) : | 294 return IsPopup() ? MenuButton::OnKeyReleased(event) : |
418 LabelButton::OnKeyReleased(event); | 295 LabelButton::OnKeyReleased(event); |
419 } | 296 } |
420 | 297 |
421 void BrowserActionButton::OnGestureEvent(ui::GestureEvent* event) { | 298 void BrowserActionButton::OnGestureEvent(ui::GestureEvent* event) { |
422 if (IsPopup()) | 299 if (IsPopup()) |
423 MenuButton::OnGestureEvent(event); | 300 MenuButton::OnGestureEvent(event); |
424 else | 301 else |
425 LabelButton::OnGestureEvent(event); | 302 LabelButton::OnGestureEvent(event); |
426 } | 303 } |
427 | 304 |
428 scoped_ptr<LabelButtonBorder> BrowserActionButton::CreateDefaultBorder() const { | 305 scoped_ptr<LabelButtonBorder> BrowserActionButton::CreateDefaultBorder() const { |
429 scoped_ptr<LabelButtonBorder> border = LabelButton::CreateDefaultBorder(); | 306 scoped_ptr<LabelButtonBorder> border = LabelButton::CreateDefaultBorder(); |
430 border->set_insets(gfx::Insets(kBorderInset, kBorderInset, | 307 border->set_insets(gfx::Insets(kBorderInset, kBorderInset, |
431 kBorderInset, kBorderInset)); | 308 kBorderInset, kBorderInset)); |
432 return border.Pass(); | 309 return border.Pass(); |
433 } | 310 } |
434 | 311 |
435 bool BrowserActionButton::AcceleratorPressed( | 312 bool BrowserActionButton::AcceleratorPressed( |
436 const ui::Accelerator& accelerator) { | 313 const ui::Accelerator& accelerator) { |
437 // Normal priority shortcuts must be handled via standard browser commands to | 314 return extension_action_view_->AcceleratorPressed(accelerator); |
438 // be processed at the proper time. | |
439 if (GetAcceleratorPriority(accelerator, extension_) == | |
440 ui::AcceleratorManager::kNormalPriority) | |
441 return false; | |
442 | |
443 ExecuteBrowserAction(); | |
444 return true; | |
445 } | 315 } |
446 | 316 |
447 void BrowserActionButton::SetButtonPushed() { | 317 void BrowserActionButton::SetButtonPushed() { |
448 SetState(views::CustomButton::STATE_PRESSED); | 318 SetState(views::CustomButton::STATE_PRESSED); |
449 menu_visible_ = true; | 319 menu_visible_ = true; |
450 } | 320 } |
451 | 321 |
452 void BrowserActionButton::SetButtonNotPushed() { | 322 void BrowserActionButton::SetButtonNotPushed() { |
453 SetState(views::CustomButton::STATE_NORMAL); | 323 SetState(views::CustomButton::STATE_NORMAL); |
454 menu_visible_ = false; | 324 menu_visible_ = false; |
455 } | 325 } |
456 | 326 |
457 bool BrowserActionButton::IsEnabled(int tab_id) const { | 327 bool BrowserActionButton::IsEnabled(int tab_id) const { |
458 return browser_action_->GetIsVisible(tab_id); | 328 return extension_action_view_->extension_action()->GetIsVisible(tab_id); |
459 } | 329 } |
460 | 330 |
461 gfx::ImageSkia BrowserActionButton::GetIconWithBadge() { | 331 gfx::ImageSkia BrowserActionButton::GetIconWithBadge() { |
462 int tab_id = delegate_->GetCurrentTabId(); | 332 int tab_id = extension_action_view_->GetCurrentTabId(); |
463 gfx::Size spacing(0, ToolbarView::kVertSpacing); | 333 gfx::Size spacing(0, ToolbarView::kVertSpacing); |
464 gfx::ImageSkia icon = *icon_factory_.GetIcon(tab_id).ToImageSkia(); | 334 gfx::ImageSkia icon = *extension_action_view_->GetIcon(tab_id).ToImageSkia(); |
465 if (!IsEnabled(tab_id)) | 335 if (!IsEnabled(tab_id)) |
466 icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25); | 336 icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25); |
467 return browser_action_->GetIconWithBadge(icon, tab_id, spacing); | 337 return extension_action()->GetIconWithBadge(icon, tab_id, spacing); |
468 } | 338 } |
469 | 339 |
470 gfx::ImageSkia BrowserActionButton::GetIconForTest() { | 340 gfx::ImageSkia BrowserActionButton::GetIconForTest() { |
471 return GetImage(views::Button::STATE_NORMAL); | 341 return GetImage(views::Button::STATE_NORMAL); |
472 } | 342 } |
473 | 343 |
474 BrowserActionButton::~BrowserActionButton() { | 344 BrowserActionButton::~BrowserActionButton() { |
475 } | 345 } |
476 | 346 |
477 void BrowserActionButton::InspectPopup() { | 347 void BrowserActionButton::OnIconUpdated() { |
478 ShowPopup(ExtensionPopup::SHOW_AND_INSPECT, true); | 348 UpdateState(); |
349 if (icon_observer_) | |
350 icon_observer_->OnIconUpdated(GetIconWithBadge()); | |
479 } | 351 } |
480 | 352 |
481 void BrowserActionButton::OnWidgetDestroying(views::Widget* widget) { | 353 views::View* BrowserActionButton::GetAsView() { |
482 DCHECK(popup_); | 354 return this; |
483 DCHECK_EQ(popup_->GetWidget(), widget); | |
484 CleanupPopup(false); | |
485 } | 355 } |
486 | 356 |
487 void BrowserActionButton::MaybeRegisterExtensionCommand() { | 357 bool BrowserActionButton::IsNestedView() { |
488 extensions::CommandService* command_service = | 358 return delegate_->ShownInsideMenu(); |
489 extensions::CommandService::Get(browser_->profile()); | |
490 extensions::Command browser_action_command; | |
491 if (command_service->GetBrowserActionCommand( | |
492 extension_->id(), | |
493 extensions::CommandService::ACTIVE_ONLY, | |
494 &browser_action_command, | |
495 NULL)) { | |
496 keybinding_.reset(new ui::Accelerator( | |
497 browser_action_command.accelerator())); | |
498 GetFocusManager()->RegisterAccelerator( | |
499 *keybinding_.get(), | |
500 GetAcceleratorPriority(browser_action_command.accelerator(), | |
501 extension_), | |
502 this); | |
503 } | |
504 } | 359 } |
505 | 360 |
506 void BrowserActionButton::MaybeUnregisterExtensionCommand(bool only_if_active) { | 361 views::FocusManager* BrowserActionButton::GetFocusManagerForAccelerator() { |
507 if (!keybinding_.get() || !GetFocusManager()) | 362 return GetFocusManager(); |
508 return; | |
509 | |
510 extensions::CommandService* command_service = | |
511 extensions::CommandService::Get(browser_->profile()); | |
512 | |
513 extensions::Command browser_action_command; | |
514 if (!only_if_active || !command_service->GetBrowserActionCommand( | |
515 extension_->id(), | |
516 extensions::CommandService::ACTIVE_ONLY, | |
517 &browser_action_command, | |
518 NULL)) { | |
519 GetFocusManager()->UnregisterAccelerator(*keybinding_.get(), this); | |
520 keybinding_.reset(NULL); | |
521 } | |
522 } | 363 } |
523 | 364 |
524 void BrowserActionButton::CleanupPopup(bool close_widget) { | 365 views::Widget* BrowserActionButton::GetParentForContextMenu() { |
525 DCHECK(popup_); | 366 // RunMenuAt expects a nested menu to be parented by the same widget as the |
367 // already visible menu, in this case the Chrome menu. | |
368 return delegate_->ShownInsideMenu() ? | |
369 BrowserView::GetBrowserViewForBrowser( | |
370 extension_action_view_->browser()) | |
371 ->toolbar()->app_menu()->GetWidget() : | |
372 GetWidget(); | |
373 } | |
374 | |
375 views::View* BrowserActionButton::GetReferenceViewForPopup() { | |
376 // Browser actions in the overflow menu can still show popups, so we may need | |
377 // a reference view other than this button's parent. If so, use the overflow | |
378 // view. | |
379 return parent()->visible() ? this : delegate_->GetOverflowReferenceView(); | |
380 } | |
381 | |
382 content::WebContents* BrowserActionButton::GetCurrentWebContents() { | |
383 return delegate_->GetCurrentWebContents(); | |
384 } | |
385 | |
386 void BrowserActionButton::HideActivePopup() { | |
387 delegate_->HideActivePopup(); | |
388 } | |
389 | |
390 void BrowserActionButton::OnPopupShown(bool grant_tab_permissions) { | |
391 delegate_->SetPopupOwner(this); | |
392 if (grant_tab_permissions) | |
393 SetButtonPushed(); | |
394 } | |
395 | |
396 void BrowserActionButton::CleanupPopup() { | |
526 // We need to do these actions synchronously (instead of closing and then | 397 // We need to do these actions synchronously (instead of closing and then |
527 // performing the rest of the cleanup in OnWidgetDestroyed()) because | 398 // performing the rest of the cleanup in OnWidgetDestroyed()) because |
528 // OnWidgetDestroyed() can be called asynchronously from Close(), and we need | 399 // OnWidgetDestroyed() can be called asynchronously from Close(), and we need |
529 // to keep the delegate's popup owner up-to-date. | 400 // to keep the delegate's popup owner up-to-date. |
530 popup_->GetWidget()->RemoveObserver(this); | |
531 if (close_widget) | |
532 popup_->GetWidget()->Close(); | |
533 popup_ = NULL; | |
534 SetButtonNotPushed(); | 401 SetButtonNotPushed(); |
535 delegate_->SetPopupOwner(NULL); | 402 delegate_->SetPopupOwner(NULL); |
536 } | 403 } |
404 | |
405 void BrowserActionButton::OnWillShowContextMenus() { | |
406 SetButtonPushed(); | |
407 } | |
408 | |
409 void BrowserActionButton::OnContextMenuDone() { | |
410 SetButtonNotPushed(); | |
411 } | |
OLD | NEW |