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), | |
58 button_(NULL), | |
59 extension_(extension) { | |
60 set_id(VIEW_ID_BROWSER_ACTION); | 52 set_id(VIEW_ID_BROWSER_ACTION); |
61 button_ = new BrowserActionButton(extension_, browser_, delegate_); | 53 button_.reset(new BrowserActionButton(extension, browser, delegate_)); |
62 button_->set_drag_controller(delegate_); | 54 button_->set_drag_controller(delegate_); |
63 button_->set_owned_by_client(); | 55 button_->set_owned_by_client(); |
64 AddChildView(button_); | 56 AddChildView(button_.get()); |
65 button_->UpdateState(); | 57 button_->UpdateState(); |
66 } | 58 } |
67 | 59 |
68 BrowserActionView::~BrowserActionView() { | 60 BrowserActionView::~BrowserActionView() { |
69 button_->Destroy(); | |
70 } | 61 } |
71 | 62 |
72 gfx::ImageSkia BrowserActionView::GetIconWithBadge() { | 63 gfx::ImageSkia BrowserActionView::GetIconWithBadge() { |
73 return button_->GetIconWithBadge(); | 64 return button_->GetIconWithBadge(); |
74 } | 65 } |
75 | 66 |
76 void BrowserActionView::Layout() { | 67 void BrowserActionView::Layout() { |
77 button_->SetBounds(0, 0, width(), height()); | 68 button_->SetBounds(0, 0, width(), height()); |
78 } | 69 } |
79 | 70 |
80 void BrowserActionView::GetAccessibleState(ui::AXViewState* state) { | 71 void BrowserActionView::GetAccessibleState(ui::AXViewState* state) { |
81 state->name = l10n_util::GetStringUTF16( | 72 state->name = l10n_util::GetStringUTF16( |
82 IDS_ACCNAME_EXTENSIONS_BROWSER_ACTION); | 73 IDS_ACCNAME_EXTENSIONS_BROWSER_ACTION); |
83 state->role = ui::AX_ROLE_GROUP; | 74 state->role = ui::AX_ROLE_GROUP; |
84 } | 75 } |
85 | 76 |
86 gfx::Size BrowserActionView::GetPreferredSize() const { | 77 gfx::Size BrowserActionView::GetPreferredSize() const { |
87 return gfx::Size(BrowserActionsContainer::IconWidth(false), | 78 return gfx::Size(BrowserActionsContainer::IconWidth(false), |
88 BrowserActionsContainer::IconHeight()); | 79 BrowserActionsContainer::IconHeight()); |
89 } | 80 } |
90 | 81 |
91 void BrowserActionView::PaintChildren(gfx::Canvas* canvas, | 82 void BrowserActionView::PaintChildren(gfx::Canvas* canvas, |
92 const views::CullSet& cull_set) { | 83 const views::CullSet& cull_set) { |
93 View::PaintChildren(canvas, cull_set); | 84 View::PaintChildren(canvas, cull_set); |
94 ExtensionAction* action = button()->browser_action(); | 85 ExtensionAction* action = button_->extension_action(); |
95 int tab_id = delegate_->GetCurrentTabId(); | 86 int tab_id = button_->view_controller()->GetCurrentTabId(); |
96 if (tab_id >= 0) | 87 if (tab_id >= 0) |
97 action->PaintBadge(canvas, GetLocalBounds(), tab_id); | 88 action->PaintBadge(canvas, GetLocalBounds(), tab_id); |
98 } | 89 } |
99 | 90 |
100 //////////////////////////////////////////////////////////////////////////////// | 91 //////////////////////////////////////////////////////////////////////////////// |
101 // BrowserActionButton | 92 // BrowserActionButton |
102 | 93 |
103 BrowserActionButton::BrowserActionButton(const Extension* extension, | 94 BrowserActionButton::BrowserActionButton(const Extension* extension, |
104 Browser* browser, | 95 Browser* browser, |
105 BrowserActionView::Delegate* delegate) | 96 BrowserActionView::Delegate* delegate) |
106 : MenuButton(this, base::string16(), NULL, false), | 97 : MenuButton(this, base::string16(), NULL, false), |
107 browser_(browser), | 98 view_controller_(new ExtensionActionViewController( |
108 browser_action_( | 99 extension, |
| 100 browser, |
109 extensions::ExtensionActionManager::Get(browser->profile())-> | 101 extensions::ExtensionActionManager::Get(browser->profile())-> |
110 GetBrowserAction(*extension)), | 102 GetBrowserAction(*extension), |
111 extension_(extension), | 103 this)), |
112 icon_factory_(browser->profile(), extension, browser_action_, this), | |
113 delegate_(delegate), | 104 delegate_(delegate), |
114 called_registered_extension_command_(false), | 105 called_registered_extension_command_(false), |
115 popup_(NULL), | |
116 icon_observer_(NULL) { | 106 icon_observer_(NULL) { |
117 SetHorizontalAlignment(gfx::ALIGN_CENTER); | 107 SetHorizontalAlignment(gfx::ALIGN_CENTER); |
118 set_context_menu_controller(this); | 108 set_context_menu_controller(view_controller_.get()); |
119 | 109 |
120 // No UpdateState() here because View hierarchy not setup yet. Our parent | 110 // No UpdateState() here because View hierarchy not setup yet. Our parent |
121 // should call UpdateState() after creation. | 111 // should call UpdateState() after creation. |
122 | 112 |
123 content::NotificationSource notification_source = | 113 content::NotificationSource notification_source = |
124 content::Source<Profile>(browser_->profile()->GetOriginalProfile()); | 114 content::Source<Profile>(browser->profile()->GetOriginalProfile()); |
125 registrar_.Add(this, | 115 registrar_.Add(this, |
126 extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED, | 116 extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED, |
127 content::Source<ExtensionAction>(browser_action_)); | 117 content::Source<ExtensionAction>(extension_action())); |
128 registrar_.Add(this, | 118 registrar_.Add(this, |
129 extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED, | 119 extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED, |
130 notification_source); | 120 notification_source); |
131 registrar_.Add(this, | 121 registrar_.Add(this, |
132 extensions::NOTIFICATION_EXTENSION_COMMAND_REMOVED, | 122 extensions::NOTIFICATION_EXTENSION_COMMAND_REMOVED, |
133 notification_source); | 123 notification_source); |
134 | 124 |
135 // We also listen for browser theme changes on linux because a switch from or | 125 // 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. | 126 // to GTK requires that we regrab our browser action images. |
137 registrar_.Add( | 127 registrar_.Add( |
138 this, | 128 this, |
139 chrome::NOTIFICATION_BROWSER_THEME_CHANGED, | 129 chrome::NOTIFICATION_BROWSER_THEME_CHANGED, |
140 content::Source<ThemeService>( | 130 content::Source<ThemeService>( |
141 ThemeServiceFactory::GetForProfile(browser->profile()))); | 131 ThemeServiceFactory::GetForProfile(browser->profile()))); |
142 } | 132 } |
143 | 133 |
144 void BrowserActionButton::Destroy() { | |
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( | 134 void BrowserActionButton::ViewHierarchyChanged( |
156 const ViewHierarchyChangedDetails& details) { | 135 const ViewHierarchyChangedDetails& details) { |
157 if (details.is_add && !called_registered_extension_command_ && | 136 if (details.is_add && !called_registered_extension_command_ && |
158 GetFocusManager()) { | 137 GetFocusManager()) { |
159 MaybeRegisterExtensionCommand(); | 138 view_controller_->RegisterCommand(); |
160 called_registered_extension_command_ = true; | 139 called_registered_extension_command_ = true; |
161 } | 140 } |
162 | 141 |
163 MenuButton::ViewHierarchyChanged(details); | 142 MenuButton::ViewHierarchyChanged(details); |
164 } | 143 } |
165 | 144 |
166 void BrowserActionButton::OnDragDone() { | 145 void BrowserActionButton::OnDragDone() { |
167 delegate_->OnBrowserActionViewDragDone(); | 146 delegate_->OnBrowserActionViewDragDone(); |
168 } | 147 } |
169 | 148 |
170 bool BrowserActionButton::CanHandleAccelerators() const { | |
171 // View::CanHandleAccelerators() checks to see if the view is visible before | |
172 // allowing it to process accelerators. This is not appropriate for browser | |
173 // actions buttons, which can be hidden inside the overflow area. | |
174 return true; | |
175 } | |
176 | |
177 void BrowserActionButton::GetAccessibleState(ui::AXViewState* state) { | 149 void BrowserActionButton::GetAccessibleState(ui::AXViewState* state) { |
178 views::MenuButton::GetAccessibleState(state); | 150 views::MenuButton::GetAccessibleState(state); |
179 state->role = ui::AX_ROLE_BUTTON; | 151 state->role = ui::AX_ROLE_BUTTON; |
180 } | 152 } |
181 | 153 |
182 void BrowserActionButton::ButtonPressed(views::Button* sender, | 154 void BrowserActionButton::ButtonPressed(views::Button* sender, |
183 const ui::Event& event) { | 155 const ui::Event& event) { |
184 ExecuteBrowserAction(); | 156 view_controller_->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 } | 157 } |
231 | 158 |
232 void BrowserActionButton::UpdateState() { | 159 void BrowserActionButton::UpdateState() { |
233 int tab_id = delegate_->GetCurrentTabId(); | 160 int tab_id = view_controller_->GetCurrentTabId(); |
234 if (tab_id < 0) | 161 if (tab_id < 0) |
235 return; | 162 return; |
236 | 163 |
237 if (!IsEnabled(tab_id)) { | 164 if (!IsEnabled(tab_id)) { |
238 SetState(views::CustomButton::STATE_DISABLED); | 165 SetState(views::CustomButton::STATE_DISABLED); |
239 } else { | 166 } else { |
240 SetState(menu_visible_ ? | 167 SetState(menu_visible_ ? |
241 views::CustomButton::STATE_PRESSED : | 168 views::CustomButton::STATE_PRESSED : |
242 views::CustomButton::STATE_NORMAL); | 169 views::CustomButton::STATE_NORMAL); |
243 } | 170 } |
244 | 171 |
245 gfx::ImageSkia icon = *icon_factory_.GetIcon(tab_id).ToImageSkia(); | 172 gfx::ImageSkia icon = *view_controller_->GetIcon(tab_id).ToImageSkia(); |
246 | 173 |
247 if (!icon.isNull()) { | 174 if (!icon.isNull()) { |
248 if (!browser_action()->GetIsVisible(tab_id)) | 175 if (!extension_action()->GetIsVisible(tab_id)) |
249 icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25); | 176 icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25); |
250 | 177 |
251 ThemeService* theme = | 178 ThemeService* theme = ThemeServiceFactory::GetForProfile( |
252 ThemeServiceFactory::GetForProfile(browser_->profile()); | 179 view_controller_->browser()->profile()); |
253 | 180 |
254 gfx::ImageSkia bg = *theme->GetImageSkiaNamed(IDR_BROWSER_ACTION); | 181 gfx::ImageSkia bg = *theme->GetImageSkiaNamed(IDR_BROWSER_ACTION); |
255 SetImage(views::Button::STATE_NORMAL, | 182 SetImage(views::Button::STATE_NORMAL, |
256 gfx::ImageSkiaOperations::CreateSuperimposedImage(bg, icon)); | 183 gfx::ImageSkiaOperations::CreateSuperimposedImage(bg, icon)); |
257 } | 184 } |
258 | 185 |
259 // If the browser action name is empty, show the extension name instead. | 186 // If the browser action name is empty, show the extension name instead. |
260 std::string title = browser_action()->GetTitle(tab_id); | 187 std::string title = extension_action()->GetTitle(tab_id); |
261 base::string16 name = | 188 base::string16 name = |
262 base::UTF8ToUTF16(title.empty() ? extension()->name() : title); | 189 base::UTF8ToUTF16(title.empty() ? extension()->name() : title); |
263 SetTooltipText(name); | 190 SetTooltipText(name); |
264 SetAccessibleName(name); | 191 SetAccessibleName(name); |
265 | 192 |
266 parent()->SchedulePaint(); | 193 parent()->SchedulePaint(); |
267 } | 194 } |
268 | 195 |
269 bool BrowserActionButton::IsPopup() { | 196 bool BrowserActionButton::IsPopup() { |
270 int tab_id = delegate_->GetCurrentTabId(); | 197 int tab_id = view_controller_->GetCurrentTabId(); |
271 return (tab_id < 0) ? false : browser_action_->HasPopup(tab_id); | 198 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 } | 199 } |
327 | 200 |
328 void BrowserActionButton::Observe(int type, | 201 void BrowserActionButton::Observe(int type, |
329 const content::NotificationSource& source, | 202 const content::NotificationSource& source, |
330 const content::NotificationDetails& details) { | 203 const content::NotificationDetails& details) { |
331 switch (type) { | 204 switch (type) { |
332 case extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED: | 205 case extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED: |
333 UpdateState(); | 206 UpdateState(); |
334 // The browser action may have become visible/hidden so we need to make | 207 // The browser action may have become visible/hidden so we need to make |
335 // sure the state gets updated. | 208 // sure the state gets updated. |
336 delegate_->OnBrowserActionVisibilityChanged(); | 209 delegate_->OnBrowserActionVisibilityChanged(); |
337 break; | 210 break; |
338 case extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED: | 211 case extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED: |
339 case extensions::NOTIFICATION_EXTENSION_COMMAND_REMOVED: { | 212 case extensions::NOTIFICATION_EXTENSION_COMMAND_REMOVED: { |
340 std::pair<const std::string, const std::string>* payload = | 213 std::pair<const std::string, const std::string>* payload = |
341 content::Details<std::pair<const std::string, const std::string> >( | 214 content::Details<std::pair<const std::string, const std::string> >( |
342 details).ptr(); | 215 details).ptr(); |
343 if (extension_->id() == payload->first && | 216 if (extension()->id() == payload->first && |
344 payload->second == | 217 payload->second == |
345 extensions::manifest_values::kBrowserActionCommandEvent) { | 218 extensions::manifest_values::kBrowserActionCommandEvent) { |
346 if (type == extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED) | 219 if (type == extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED) |
347 MaybeRegisterExtensionCommand(); | 220 view_controller_->RegisterCommand(); |
348 else | 221 else |
349 MaybeUnregisterExtensionCommand(true); | 222 view_controller_->UnregisterCommand(true); |
350 } | 223 } |
351 break; | 224 break; |
352 } | 225 } |
353 case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: | 226 case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: |
354 UpdateState(); | 227 UpdateState(); |
355 break; | 228 break; |
356 default: | 229 default: |
357 NOTREACHED(); | 230 NOTREACHED(); |
358 break; | 231 break; |
359 } | 232 } |
360 } | 233 } |
361 | 234 |
362 void BrowserActionButton::OnIconUpdated() { | |
363 UpdateState(); | |
364 if (icon_observer_) | |
365 icon_observer_->OnIconUpdated(GetIconWithBadge()); | |
366 } | |
367 | |
368 bool BrowserActionButton::Activate() { | 235 bool BrowserActionButton::Activate() { |
369 if (!IsPopup()) | 236 if (!IsPopup()) |
370 return true; | 237 return true; |
371 | 238 |
372 ExecuteBrowserAction(); | 239 view_controller_->ExecuteActionByUser(); |
373 | 240 |
374 // TODO(erikkay): Run a nested modal loop while the mouse is down to | 241 // TODO(erikkay): Run a nested modal loop while the mouse is down to |
375 // enable menu-like drag-select behavior. | 242 // enable menu-like drag-select behavior. |
376 | 243 |
377 // The return value of this method is returned via OnMousePressed. | 244 // 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 | 245 // 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 | 246 // widget/view, and true will grab it right back and try to send events |
380 // to us. | 247 // to us. |
381 return false; | 248 return false; |
382 } | 249 } |
383 | 250 |
384 bool BrowserActionButton::OnMousePressed(const ui::MouseEvent& event) { | 251 bool BrowserActionButton::OnMousePressed(const ui::MouseEvent& event) { |
385 if (!event.IsRightMouseButton()) { | 252 if (!event.IsRightMouseButton()) { |
386 return IsPopup() ? MenuButton::OnMousePressed(event) : | 253 return IsPopup() ? MenuButton::OnMousePressed(event) : |
387 LabelButton::OnMousePressed(event); | 254 LabelButton::OnMousePressed(event); |
388 } | 255 } |
389 | 256 |
390 if (!views::View::ShouldShowContextMenuOnMousePress()) { | 257 if (!views::View::ShouldShowContextMenuOnMousePress()) { |
391 // See comments in MenuButton::Activate() as to why this is needed. | 258 // See comments in MenuButton::Activate() as to why this is needed. |
392 SetMouseHandler(NULL); | 259 SetMouseHandler(NULL); |
393 | 260 |
394 ShowContextMenu(gfx::Point(), ui::MENU_SOURCE_MOUSE); | 261 ShowContextMenu(gfx::Point(), ui::MENU_SOURCE_MOUSE); |
395 } | 262 } |
396 return false; | 263 return false; |
397 } | 264 } |
398 | 265 |
399 void BrowserActionButton::OnMouseReleased(const ui::MouseEvent& event) { | 266 void BrowserActionButton::OnMouseReleased(const ui::MouseEvent& event) { |
400 if (IsPopup() || menu_runner_) { | 267 if (IsPopup() || view_controller_->is_menu_running()) { |
401 // TODO(erikkay) this never actually gets called (probably because of the | 268 // TODO(erikkay) this never actually gets called (probably because of the |
402 // loss of focus). | 269 // loss of focus). |
403 MenuButton::OnMouseReleased(event); | 270 MenuButton::OnMouseReleased(event); |
404 } else { | 271 } else { |
405 LabelButton::OnMouseReleased(event); | 272 LabelButton::OnMouseReleased(event); |
406 } | 273 } |
407 } | 274 } |
408 | 275 |
409 void BrowserActionButton::OnMouseExited(const ui::MouseEvent& event) { | 276 void BrowserActionButton::OnMouseExited(const ui::MouseEvent& event) { |
410 if (IsPopup() || menu_runner_) | 277 if (IsPopup() || view_controller_->is_menu_running()) |
411 MenuButton::OnMouseExited(event); | 278 MenuButton::OnMouseExited(event); |
412 else | 279 else |
413 LabelButton::OnMouseExited(event); | 280 LabelButton::OnMouseExited(event); |
414 } | 281 } |
415 | 282 |
416 bool BrowserActionButton::OnKeyReleased(const ui::KeyEvent& event) { | 283 bool BrowserActionButton::OnKeyReleased(const ui::KeyEvent& event) { |
417 return IsPopup() ? MenuButton::OnKeyReleased(event) : | 284 return IsPopup() ? MenuButton::OnKeyReleased(event) : |
418 LabelButton::OnKeyReleased(event); | 285 LabelButton::OnKeyReleased(event); |
419 } | 286 } |
420 | 287 |
421 void BrowserActionButton::OnGestureEvent(ui::GestureEvent* event) { | 288 void BrowserActionButton::OnGestureEvent(ui::GestureEvent* event) { |
422 if (IsPopup()) | 289 if (IsPopup()) |
423 MenuButton::OnGestureEvent(event); | 290 MenuButton::OnGestureEvent(event); |
424 else | 291 else |
425 LabelButton::OnGestureEvent(event); | 292 LabelButton::OnGestureEvent(event); |
426 } | 293 } |
427 | 294 |
428 scoped_ptr<LabelButtonBorder> BrowserActionButton::CreateDefaultBorder() const { | 295 scoped_ptr<LabelButtonBorder> BrowserActionButton::CreateDefaultBorder() const { |
429 scoped_ptr<LabelButtonBorder> border = LabelButton::CreateDefaultBorder(); | 296 scoped_ptr<LabelButtonBorder> border = LabelButton::CreateDefaultBorder(); |
430 border->set_insets(gfx::Insets(kBorderInset, kBorderInset, | 297 border->set_insets(gfx::Insets(kBorderInset, kBorderInset, |
431 kBorderInset, kBorderInset)); | 298 kBorderInset, kBorderInset)); |
432 return border.Pass(); | 299 return border.Pass(); |
433 } | 300 } |
434 | 301 |
435 bool BrowserActionButton::AcceleratorPressed( | |
436 const ui::Accelerator& accelerator) { | |
437 // Normal priority shortcuts must be handled via standard browser commands to | |
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 } | |
446 | |
447 void BrowserActionButton::SetButtonPushed() { | 302 void BrowserActionButton::SetButtonPushed() { |
448 SetState(views::CustomButton::STATE_PRESSED); | 303 SetState(views::CustomButton::STATE_PRESSED); |
449 menu_visible_ = true; | 304 menu_visible_ = true; |
450 } | 305 } |
451 | 306 |
452 void BrowserActionButton::SetButtonNotPushed() { | 307 void BrowserActionButton::SetButtonNotPushed() { |
453 SetState(views::CustomButton::STATE_NORMAL); | 308 SetState(views::CustomButton::STATE_NORMAL); |
454 menu_visible_ = false; | 309 menu_visible_ = false; |
455 } | 310 } |
456 | 311 |
457 bool BrowserActionButton::IsEnabled(int tab_id) const { | 312 bool BrowserActionButton::IsEnabled(int tab_id) const { |
458 return browser_action_->GetIsVisible(tab_id); | 313 return view_controller_->extension_action()->GetIsVisible(tab_id); |
459 } | 314 } |
460 | 315 |
461 gfx::ImageSkia BrowserActionButton::GetIconWithBadge() { | 316 gfx::ImageSkia BrowserActionButton::GetIconWithBadge() { |
462 int tab_id = delegate_->GetCurrentTabId(); | 317 int tab_id = view_controller_->GetCurrentTabId(); |
463 gfx::Size spacing(0, ToolbarView::kVertSpacing); | 318 gfx::Size spacing(0, ToolbarView::kVertSpacing); |
464 gfx::ImageSkia icon = *icon_factory_.GetIcon(tab_id).ToImageSkia(); | 319 gfx::ImageSkia icon = *view_controller_->GetIcon(tab_id).ToImageSkia(); |
465 if (!IsEnabled(tab_id)) | 320 if (!IsEnabled(tab_id)) |
466 icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25); | 321 icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25); |
467 return browser_action_->GetIconWithBadge(icon, tab_id, spacing); | 322 return extension_action()->GetIconWithBadge(icon, tab_id, spacing); |
468 } | 323 } |
469 | 324 |
470 gfx::ImageSkia BrowserActionButton::GetIconForTest() { | 325 gfx::ImageSkia BrowserActionButton::GetIconForTest() { |
471 return GetImage(views::Button::STATE_NORMAL); | 326 return GetImage(views::Button::STATE_NORMAL); |
472 } | 327 } |
473 | 328 |
474 BrowserActionButton::~BrowserActionButton() { | 329 BrowserActionButton::~BrowserActionButton() { |
475 } | 330 } |
476 | 331 |
477 void BrowserActionButton::InspectPopup() { | 332 void BrowserActionButton::OnIconUpdated() { |
478 ShowPopup(ExtensionPopup::SHOW_AND_INSPECT, true); | 333 UpdateState(); |
| 334 if (icon_observer_) |
| 335 icon_observer_->OnIconUpdated(GetIconWithBadge()); |
479 } | 336 } |
480 | 337 |
481 void BrowserActionButton::OnWidgetDestroying(views::Widget* widget) { | 338 views::View* BrowserActionButton::GetAsView() { |
482 DCHECK(popup_); | 339 return this; |
483 DCHECK_EQ(popup_->GetWidget(), widget); | |
484 CleanupPopup(false); | |
485 } | 340 } |
486 | 341 |
487 void BrowserActionButton::MaybeRegisterExtensionCommand() { | 342 bool BrowserActionButton::IsShownInMenu() { |
488 extensions::CommandService* command_service = | 343 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 } | 344 } |
505 | 345 |
506 void BrowserActionButton::MaybeUnregisterExtensionCommand(bool only_if_active) { | 346 views::FocusManager* BrowserActionButton::GetFocusManagerForAccelerator() { |
507 if (!keybinding_.get() || !GetFocusManager()) | 347 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 } | 348 } |
523 | 349 |
524 void BrowserActionButton::CleanupPopup(bool close_widget) { | 350 views::Widget* BrowserActionButton::GetParentForContextMenu() { |
525 DCHECK(popup_); | 351 // RunMenuAt expects a nested menu to be parented by the same widget as the |
| 352 // already visible menu, in this case the Chrome menu. |
| 353 return delegate_->ShownInsideMenu() ? |
| 354 BrowserView::GetBrowserViewForBrowser(view_controller_->browser()) |
| 355 ->toolbar()->app_menu()->GetWidget() : |
| 356 GetWidget(); |
| 357 } |
| 358 |
| 359 views::View* BrowserActionButton::GetReferenceViewForPopup() { |
| 360 // Browser actions in the overflow menu can still show popups, so we may need |
| 361 // a reference view other than this button's parent. If so, use the overflow |
| 362 // view. |
| 363 return parent()->visible() ? this : delegate_->GetOverflowReferenceView(); |
| 364 } |
| 365 |
| 366 content::WebContents* BrowserActionButton::GetCurrentWebContents() { |
| 367 return delegate_->GetCurrentWebContents(); |
| 368 } |
| 369 |
| 370 void BrowserActionButton::HideActivePopup() { |
| 371 delegate_->HideActivePopup(); |
| 372 } |
| 373 |
| 374 void BrowserActionButton::OnPopupShown(bool grant_tab_permissions) { |
| 375 delegate_->SetPopupOwner(this); |
| 376 if (grant_tab_permissions) |
| 377 SetButtonPushed(); |
| 378 } |
| 379 |
| 380 void BrowserActionButton::CleanupPopup() { |
526 // We need to do these actions synchronously (instead of closing and then | 381 // We need to do these actions synchronously (instead of closing and then |
527 // performing the rest of the cleanup in OnWidgetDestroyed()) because | 382 // performing the rest of the cleanup in OnWidgetDestroyed()) because |
528 // OnWidgetDestroyed() can be called asynchronously from Close(), and we need | 383 // OnWidgetDestroyed() can be called asynchronously from Close(), and we need |
529 // to keep the delegate's popup owner up-to-date. | 384 // 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(); | 385 SetButtonNotPushed(); |
535 delegate_->SetPopupOwner(NULL); | 386 delegate_->SetPopupOwner(NULL); |
536 } | 387 } |
| 388 |
| 389 void BrowserActionButton::OnWillShowContextMenus() { |
| 390 SetButtonPushed(); |
| 391 } |
| 392 |
| 393 void BrowserActionButton::OnContextMenuDone() { |
| 394 SetButtonNotPushed(); |
| 395 } |
OLD | NEW |