Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(897)

Side by Side Diff: chrome/browser/ui/views/toolbar/browser_action_view.cc

Issue 431173002: Create ExtensionActionView class (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698