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

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

Issue 419023002: Move ShowPopup logic from BrowserActionsContainer to BrowserActionView (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>
8
7 #include "base/strings/utf_string_conversions.h" 9 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/chrome_notification_types.h" 10 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/extensions/api/commands/command_service.h" 11 #include "chrome/browser/extensions/api/commands/command_service.h"
10 #include "chrome/browser/extensions/extension_action.h" 12 #include "chrome/browser/extensions/extension_action.h"
11 #include "chrome/browser/extensions/extension_action_manager.h" 13 #include "chrome/browser/extensions/extension_action_manager.h"
12 #include "chrome/browser/extensions/extension_context_menu_model.h" 14 #include "chrome/browser/extensions/extension_context_menu_model.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/themes/theme_service.h" 16 #include "chrome/browser/themes/theme_service.h"
16 #include "chrome/browser/themes/theme_service_factory.h" 17 #include "chrome/browser/themes/theme_service_factory.h"
17 #include "chrome/browser/ui/browser.h" 18 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/extensions/accelerator_priority.h" 19 #include "chrome/browser/ui/extensions/accelerator_priority.h"
19 #include "chrome/browser/ui/view_ids.h" 20 #include "chrome/browser/ui/view_ids.h"
20 #include "chrome/browser/ui/views/frame/browser_view.h" 21 #include "chrome/browser/ui/views/frame/browser_view.h"
21 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h" 22 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
22 #include "chrome/browser/ui/views/toolbar/toolbar_view.h" 23 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
23 #include "extensions/common/extension.h" 24 #include "extensions/common/extension.h"
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 BrowserActionView::Delegate* delegate) 105 BrowserActionView::Delegate* delegate)
105 : MenuButton(this, base::string16(), NULL, false), 106 : MenuButton(this, base::string16(), NULL, false),
106 browser_(browser), 107 browser_(browser),
107 browser_action_( 108 browser_action_(
108 extensions::ExtensionActionManager::Get(browser->profile())-> 109 extensions::ExtensionActionManager::Get(browser->profile())->
109 GetBrowserAction(*extension)), 110 GetBrowserAction(*extension)),
110 extension_(extension), 111 extension_(extension),
111 icon_factory_(browser->profile(), extension, browser_action_, this), 112 icon_factory_(browser->profile(), extension, browser_action_, this),
112 delegate_(delegate), 113 delegate_(delegate),
113 called_registered_extension_command_(false), 114 called_registered_extension_command_(false),
115 popup_(NULL),
114 icon_observer_(NULL) { 116 icon_observer_(NULL) {
115 SetHorizontalAlignment(gfx::ALIGN_CENTER); 117 SetHorizontalAlignment(gfx::ALIGN_CENTER);
116 set_context_menu_controller(this); 118 set_context_menu_controller(this);
117 119
118 // No UpdateState() here because View hierarchy not setup yet. Our parent 120 // No UpdateState() here because View hierarchy not setup yet. Our parent
119 // should call UpdateState() after creation. 121 // should call UpdateState() after creation.
120 122
121 content::NotificationSource notification_source = 123 content::NotificationSource notification_source =
122 content::Source<Profile>(browser_->profile()->GetOriginalProfile()); 124 content::Source<Profile>(browser_->profile()->GetOriginalProfile());
123 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED, 125 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
124 content::Source<ExtensionAction>(browser_action_)); 126 content::Source<ExtensionAction>(browser_action_));
125 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED, 127 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED,
126 notification_source); 128 notification_source);
127 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED, 129 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED,
128 notification_source); 130 notification_source);
129 131
130 // We also listen for browser theme changes on linux because a switch from or 132 // We also listen for browser theme changes on linux because a switch from or
131 // to GTK requires that we regrab our browser action images. 133 // to GTK requires that we regrab our browser action images.
132 registrar_.Add( 134 registrar_.Add(
133 this, 135 this,
134 chrome::NOTIFICATION_BROWSER_THEME_CHANGED, 136 chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
135 content::Source<ThemeService>( 137 content::Source<ThemeService>(
136 ThemeServiceFactory::GetForProfile(browser->profile()))); 138 ThemeServiceFactory::GetForProfile(browser->profile())));
137 } 139 }
138 140
139 void BrowserActionButton::Destroy() { 141 void BrowserActionButton::Destroy() {
140 MaybeUnregisterExtensionCommand(false); 142 MaybeUnregisterExtensionCommand(false);
141 143 HidePopup();
142 if (menu_runner_) { 144 if (menu_runner_) {
143 menu_runner_->Cancel(); 145 menu_runner_->Cancel();
144 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 146 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
145 } else { 147 } else {
146 delete this; 148 delete this;
147 } 149 }
148 } 150 }
149 151
150 void BrowserActionButton::ViewHierarchyChanged( 152 void BrowserActionButton::ViewHierarchyChanged(
151 const ViewHierarchyChangedDetails& details) { 153 const ViewHierarchyChangedDetails& details) {
(...skipping 17 matching lines...) Expand all
169 return true; 171 return true;
170 } 172 }
171 173
172 void BrowserActionButton::GetAccessibleState(ui::AXViewState* state) { 174 void BrowserActionButton::GetAccessibleState(ui::AXViewState* state) {
173 views::MenuButton::GetAccessibleState(state); 175 views::MenuButton::GetAccessibleState(state);
174 state->role = ui::AX_ROLE_BUTTON; 176 state->role = ui::AX_ROLE_BUTTON;
175 } 177 }
176 178
177 void BrowserActionButton::ButtonPressed(views::Button* sender, 179 void BrowserActionButton::ButtonPressed(views::Button* sender,
178 const ui::Event& event) { 180 const ui::Event& event) {
179 delegate_->OnBrowserActionExecuted(this); 181 ExecuteBrowserAction();
180 } 182 }
181 183
182 void BrowserActionButton::ShowContextMenuForView( 184 void BrowserActionButton::ShowContextMenuForView(
183 View* source, 185 View* source,
184 const gfx::Point& point, 186 const gfx::Point& point,
185 ui::MenuSourceType source_type) { 187 ui::MenuSourceType source_type) {
186 if (!extension()->ShowConfigureContextMenus()) 188 if (!extension()->ShowConfigureContextMenus())
187 return; 189 return;
188 190
189 SetButtonPushed(); 191 SetButtonPushed();
190 192
191 // Reconstructs the menu every time because the menu's contents are dynamic. 193 // Reconstructs the menu every time because the menu's contents are dynamic.
192 scoped_refptr<ExtensionContextMenuModel> context_menu_contents( 194 scoped_refptr<ExtensionContextMenuModel> context_menu_contents(
193 new ExtensionContextMenuModel(extension(), browser_, delegate_)); 195 new ExtensionContextMenuModel(extension(), browser_, this));
194 gfx::Point screen_loc; 196 gfx::Point screen_loc;
195 views::View::ConvertPointToScreen(this, &screen_loc); 197 views::View::ConvertPointToScreen(this, &screen_loc);
196 198
197 views::Widget* parent = NULL; 199 views::Widget* parent = NULL;
198 int run_types = views::MenuRunner::HAS_MNEMONICS | 200 int run_types = views::MenuRunner::HAS_MNEMONICS |
199 views::MenuRunner::CONTEXT_MENU; 201 views::MenuRunner::CONTEXT_MENU;
200 if (delegate_->ShownInsideMenu()) { 202 if (delegate_->ShownInsideMenu()) {
201 run_types |= views::MenuRunner::IS_NESTED; 203 run_types |= views::MenuRunner::IS_NESTED;
202 // RunMenuAt expects a nested menu to be parented by the same widget as the 204 // RunMenuAt expects a nested menu to be parented by the same widget as the
203 // already visible menu, in this case the Chrome menu. 205 // already visible menu, in this case the Chrome menu.
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 bool BrowserActionButton::IsPopup() { 266 bool BrowserActionButton::IsPopup() {
265 int tab_id = delegate_->GetCurrentTabId(); 267 int tab_id = delegate_->GetCurrentTabId();
266 return (tab_id < 0) ? false : browser_action_->HasPopup(tab_id); 268 return (tab_id < 0) ? false : browser_action_->HasPopup(tab_id);
267 } 269 }
268 270
269 GURL BrowserActionButton::GetPopupUrl() { 271 GURL BrowserActionButton::GetPopupUrl() {
270 int tab_id = delegate_->GetCurrentTabId(); 272 int tab_id = delegate_->GetCurrentTabId();
271 return (tab_id < 0) ? GURL() : browser_action_->GetPopupUrl(tab_id); 273 return (tab_id < 0) ? GURL() : browser_action_->GetPopupUrl(tab_id);
272 } 274 }
273 275
276 bool BrowserActionButton::ShowPopup(
277 ExtensionPopup::ShowAction show_action,
278 bool grant_tab_permissions) {
279 GURL popup_url;
280 if (delegate_->GetModel()->ExecuteBrowserAction(
281 extension_, browser_, &popup_url, grant_tab_permissions) ==
282 extensions::ExtensionToolbarModel::ACTION_NONE) {
283 return false;
284 }
285
286 // If we're already showing the popup for this browser action, just hide it
287 // and return.
288 bool already_showing = popup_ != NULL;
289
290 // Always hide the current popup, even if it's not the same.
291 // Only one popup should be visible at a time.
292 delegate_->HideActivePopup();
293 if (already_showing)
294 return false;
295
296 // Browser actions in the overflow menu can still show popups, so we may need
297 // a reference view other than this button's parent. If so, use the overflow
298 // view.
299 views::View* reference_view =
300 parent()->visible() ? this : delegate_->GetOverflowReferenceView();
301
302 popup_ = ExtensionPopup::ShowPopup(popup_url,
303 browser_,
304 reference_view,
305 views::BubbleBorder::TOP_RIGHT,
306 show_action);
307 popup_->GetWidget()->AddObserver(this);
308 delegate_->SetPopupOwner(this);
309
310 // Only set button as pushed if it was triggered by a user click.
311 if (grant_tab_permissions)
312 SetButtonPushed();
313 return true;
314 }
315
316 void BrowserActionButton::HidePopup() {
317 if (popup_)
318 CleanupPopup(true);
319 }
320
321 void BrowserActionButton::ExecuteBrowserAction() {
322 ShowPopup(ExtensionPopup::SHOW, true);
323 }
324
274 void BrowserActionButton::Observe(int type, 325 void BrowserActionButton::Observe(int type,
275 const content::NotificationSource& source, 326 const content::NotificationSource& source,
276 const content::NotificationDetails& details) { 327 const content::NotificationDetails& details) {
277 switch (type) { 328 switch (type) {
278 case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED: 329 case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED:
279 UpdateState(); 330 UpdateState();
280 // The browser action may have become visible/hidden so we need to make 331 // The browser action may have become visible/hidden so we need to make
281 // sure the state gets updated. 332 // sure the state gets updated.
282 delegate_->OnBrowserActionVisibilityChanged(); 333 delegate_->OnBrowserActionVisibilityChanged();
283 break; 334 break;
(...skipping 24 matching lines...) Expand all
308 void BrowserActionButton::OnIconUpdated() { 359 void BrowserActionButton::OnIconUpdated() {
309 UpdateState(); 360 UpdateState();
310 if (icon_observer_) 361 if (icon_observer_)
311 icon_observer_->OnIconUpdated(GetIconWithBadge()); 362 icon_observer_->OnIconUpdated(GetIconWithBadge());
312 } 363 }
313 364
314 bool BrowserActionButton::Activate() { 365 bool BrowserActionButton::Activate() {
315 if (!IsPopup()) 366 if (!IsPopup())
316 return true; 367 return true;
317 368
318 delegate_->OnBrowserActionExecuted(this); 369 ExecuteBrowserAction();
319 370
320 // TODO(erikkay): Run a nested modal loop while the mouse is down to 371 // TODO(erikkay): Run a nested modal loop while the mouse is down to
321 // enable menu-like drag-select behavior. 372 // enable menu-like drag-select behavior.
322 373
323 // The return value of this method is returned via OnMousePressed. 374 // The return value of this method is returned via OnMousePressed.
324 // We need to return false here since we're handing off focus to another 375 // We need to return false here since we're handing off focus to another
325 // widget/view, and true will grab it right back and try to send events 376 // widget/view, and true will grab it right back and try to send events
326 // to us. 377 // to us.
327 return false; 378 return false;
328 } 379 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 } 430 }
380 431
381 bool BrowserActionButton::AcceleratorPressed( 432 bool BrowserActionButton::AcceleratorPressed(
382 const ui::Accelerator& accelerator) { 433 const ui::Accelerator& accelerator) {
383 // Normal priority shortcuts must be handled via standard browser commands to 434 // Normal priority shortcuts must be handled via standard browser commands to
384 // be processed at the proper time. 435 // be processed at the proper time.
385 if (GetAcceleratorPriority(accelerator, extension_) == 436 if (GetAcceleratorPriority(accelerator, extension_) ==
386 ui::AcceleratorManager::kNormalPriority) 437 ui::AcceleratorManager::kNormalPriority)
387 return false; 438 return false;
388 439
389 delegate_->OnBrowserActionExecuted(this); 440 ExecuteBrowserAction();
390 return true; 441 return true;
391 } 442 }
392 443
393 void BrowserActionButton::SetButtonPushed() { 444 void BrowserActionButton::SetButtonPushed() {
394 SetState(views::CustomButton::STATE_PRESSED); 445 SetState(views::CustomButton::STATE_PRESSED);
395 menu_visible_ = true; 446 menu_visible_ = true;
396 } 447 }
397 448
398 void BrowserActionButton::SetButtonNotPushed() { 449 void BrowserActionButton::SetButtonNotPushed() {
399 SetState(views::CustomButton::STATE_NORMAL); 450 SetState(views::CustomButton::STATE_NORMAL);
(...skipping 13 matching lines...) Expand all
413 return browser_action_->GetIconWithBadge(icon, tab_id, spacing); 464 return browser_action_->GetIconWithBadge(icon, tab_id, spacing);
414 } 465 }
415 466
416 gfx::ImageSkia BrowserActionButton::GetIconForTest() { 467 gfx::ImageSkia BrowserActionButton::GetIconForTest() {
417 return GetImage(views::Button::STATE_NORMAL); 468 return GetImage(views::Button::STATE_NORMAL);
418 } 469 }
419 470
420 BrowserActionButton::~BrowserActionButton() { 471 BrowserActionButton::~BrowserActionButton() {
421 } 472 }
422 473
474 void BrowserActionButton::InspectPopup() {
475 ShowPopup(ExtensionPopup::SHOW_AND_INSPECT, true);
476 }
477
478 void BrowserActionButton::OnWidgetDestroying(views::Widget* widget) {
479 DCHECK(popup_);
480 DCHECK_EQ(popup_->GetWidget(), widget);
481 CleanupPopup(false);
482 }
483
423 void BrowserActionButton::MaybeRegisterExtensionCommand() { 484 void BrowserActionButton::MaybeRegisterExtensionCommand() {
424 extensions::CommandService* command_service = 485 extensions::CommandService* command_service =
425 extensions::CommandService::Get(browser_->profile()); 486 extensions::CommandService::Get(browser_->profile());
426 extensions::Command browser_action_command; 487 extensions::Command browser_action_command;
427 if (command_service->GetBrowserActionCommand( 488 if (command_service->GetBrowserActionCommand(
428 extension_->id(), 489 extension_->id(),
429 extensions::CommandService::ACTIVE_ONLY, 490 extensions::CommandService::ACTIVE_ONLY,
430 &browser_action_command, 491 &browser_action_command,
431 NULL)) { 492 NULL)) {
432 keybinding_.reset(new ui::Accelerator( 493 keybinding_.reset(new ui::Accelerator(
(...skipping 16 matching lines...) Expand all
449 extensions::Command browser_action_command; 510 extensions::Command browser_action_command;
450 if (!only_if_active || !command_service->GetBrowserActionCommand( 511 if (!only_if_active || !command_service->GetBrowserActionCommand(
451 extension_->id(), 512 extension_->id(),
452 extensions::CommandService::ACTIVE_ONLY, 513 extensions::CommandService::ACTIVE_ONLY,
453 &browser_action_command, 514 &browser_action_command,
454 NULL)) { 515 NULL)) {
455 GetFocusManager()->UnregisterAccelerator(*keybinding_.get(), this); 516 GetFocusManager()->UnregisterAccelerator(*keybinding_.get(), this);
456 keybinding_.reset(NULL); 517 keybinding_.reset(NULL);
457 } 518 }
458 } 519 }
520
521 void BrowserActionButton::CleanupPopup(bool close_widget) {
522 DCHECK(popup_);
523 // We need to do these actions synchronously (instead of closing and then
524 // performing the rest of the cleanup in OnWidgetDestroyed()) because
525 // OnWidgetDestroyed() can be called asynchronously from Close(), and we need
526 // to keep the delegate's popup owner up-to-date.
527 popup_->GetWidget()->RemoveObserver(this);
528 if (close_widget)
529 popup_->GetWidget()->Close();
530 popup_ = NULL;
531 SetButtonNotPushed();
532 delegate_->SetPopupOwner(NULL);
533 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/toolbar/browser_action_view.h ('k') | chrome/browser/ui/views/toolbar/browser_actions_container.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698