| 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> |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |