browser_action_view.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
1902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com// Copyright 2013 The Chromium Authors. All rights reserved.
2902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com// Use of this source code is governed by a BSD-style license that can be
3902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com// found in the LICENSE file.
4902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
5902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "chrome/browser/ui/views/toolbar/browser_action_view.h"
6902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
7902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "base/strings/utf_string_conversions.h"
8902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "chrome/browser/chrome_notification_types.h"
9902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "chrome/browser/extensions/api/commands/command_service.h"
10902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "chrome/browser/extensions/extension_action.h"
11902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "chrome/browser/extensions/extension_action_manager.h"
12902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "chrome/browser/extensions/extension_context_menu_model.h"
13902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "chrome/browser/extensions/extension_service.h"
14902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "chrome/browser/profiles/profile.h"
152a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org#include "chrome/browser/themes/theme_service.h"
16902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "chrome/browser/themes/theme_service_factory.h"
178a1cdaece7e1d009befb84f21bb82370025bf4d6robertphillips@google.com#include "chrome/browser/ui/browser.h"
1897cee9735350cb472249ce1a827ba1aa6b2a5f59chudy@google.com#include "chrome/browser/ui/view_ids.h"
19902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
2032bbcf828d66ad244fa25b468bc3a229e531491frobertphillips@google.com#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
2132bbcf828d66ad244fa25b468bc3a229e531491frobertphillips@google.com#include "extensions/common/extension.h"
2286681b37bd20204e47a492119b345c01d00bc939fmalita@google.com#include "extensions/common/manifest_constants.h"
23902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "grit/generated_resources.h"
2480a4a60f96c33ccd850f9b0eb4b69ab08c198196chudy@google.com#include "grit/theme_resources.h"
25f4741c1322944e194ca34a8f5cf8188fe2c0efe2robertphillips@google.com#include "ui/accessibility/ax_view_state.h"
26902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "ui/base/l10n/l10n_util.h"
27768ac85655017d4106444bf3ad044680a575ccaacommit-bot@chromium.org#include "ui/base/resource/resource_bundle.h"
28768ac85655017d4106444bf3ad044680a575ccaacommit-bot@chromium.org#include "ui/events/event.h"
29768ac85655017d4106444bf3ad044680a575ccaacommit-bot@chromium.org#include "ui/gfx/image/image_skia.h"
3057f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org#include "ui/gfx/image/image_skia_operations.h"
31902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "ui/gfx/image/image_skia_source.h"
32902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com#include "ui/views/controls/menu/menu_item_view.h"
33f4741c1322944e194ca34a8f5cf8188fe2c0efe2robertphillips@google.com#include "ui/views/controls/menu/menu_runner.h"
34f4741c1322944e194ca34a8f5cf8188fe2c0efe2robertphillips@google.com
35f4741c1322944e194ca34a8f5cf8188fe2c0efe2robertphillips@google.comusing extensions::Extension;
3657f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org
3757f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org////////////////////////////////////////////////////////////////////////////////
3857f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org// BrowserActionView
3957f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org
4057f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.orgbool BrowserActionView::Delegate::NeedToShowMultipleIconStates() const {
412a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org  return true;
422a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org}
4357f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org
44f4741c1322944e194ca34a8f5cf8188fe2c0efe2robertphillips@google.combool BrowserActionView::Delegate::NeedToShowTooltip() const {
45f4741c1322944e194ca34a8f5cf8188fe2c0efe2robertphillips@google.com  return true;
4632bbcf828d66ad244fa25b468bc3a229e531491frobertphillips@google.com}
4732bbcf828d66ad244fa25b468bc3a229e531491frobertphillips@google.com
48f84ad8f7fc0194389a8099da2c5e8fff9f092890skia.committer@gmail.comBrowserActionView::BrowserActionView(const Extension* extension,
4932bbcf828d66ad244fa25b468bc3a229e531491frobertphillips@google.com                                     Browser* browser,
5032bbcf828d66ad244fa25b468bc3a229e531491frobertphillips@google.com                                     BrowserActionView::Delegate* delegate)
51902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com    : browser_(browser),
52902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com      delegate_(delegate),
53902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com      button_(NULL),
54902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com      extension_(extension) {
55902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  set_id(VIEW_ID_BROWSER_ACTION);
56902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  button_ = new BrowserActionButton(extension_, browser_, delegate_);
57902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  button_->set_drag_controller(delegate_);
58902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  button_->set_owned_by_client();
59902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  AddChildView(button_);
60902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  button_->UpdateState();
610b5bbb0f82e022c8acfbcb6312f0ed18e1ab90cechudy@google.com}
620b5bbb0f82e022c8acfbcb6312f0ed18e1ab90cechudy@google.com
630b5bbb0f82e022c8acfbcb6312f0ed18e1ab90cechudy@google.comBrowserActionView::~BrowserActionView() {
64a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com  button_->Destroy();
65a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com}
66a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com
67a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.comgfx::ImageSkia BrowserActionView::GetIconWithBadge() {
68a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com  return button_->GetIconWithBadge();
69a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com}
70a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com
71a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.comvoid BrowserActionView::Layout() {
72a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com  button_->SetBounds(0, y(), width(), height());
73a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com}
74a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com
75a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.comvoid BrowserActionView::GetAccessibleState(ui::AXViewState* state) {
76a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com  state->name = l10n_util::GetStringUTF16(
77a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com      IDS_ACCNAME_EXTENSIONS_BROWSER_ACTION);
780b5bbb0f82e022c8acfbcb6312f0ed18e1ab90cechudy@google.com  state->role = ui::AX_ROLE_GROUP;
790b5bbb0f82e022c8acfbcb6312f0ed18e1ab90cechudy@google.com}
80830b8793bb1646bb76817bdc228dd8e2a92bef7dchudy@google.com
81902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.comgfx::Size BrowserActionView::GetPreferredSize() const {
82902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  return gfx::Size(BrowserActionsContainer::IconWidth(false),
8350c84da68b17647371a81593402e897d639989e4robertphillips@google.com                   BrowserActionsContainer::IconHeight());
8450c84da68b17647371a81593402e897d639989e4robertphillips@google.com}
8550c84da68b17647371a81593402e897d639989e4robertphillips@google.com
8650c84da68b17647371a81593402e897d639989e4robertphillips@google.comvoid BrowserActionView::PaintChildren(gfx::Canvas* canvas,
8750c84da68b17647371a81593402e897d639989e4robertphillips@google.com                                      const views::CullSet& cull_set) {
8850c84da68b17647371a81593402e897d639989e4robertphillips@google.com  View::PaintChildren(canvas, cull_set);
89902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  ExtensionAction* action = button()->browser_action();
90902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  int tab_id = delegate_->GetCurrentTabId();
91902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  if (tab_id >= 0)
92902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com    action->PaintBadge(canvas, GetLocalBounds(), tab_id);
93902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com}
94902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
9550c84da68b17647371a81593402e897d639989e4robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
9650c84da68b17647371a81593402e897d639989e4robertphillips@google.com// BrowserActionButton
9750c84da68b17647371a81593402e897d639989e4robertphillips@google.com
9850c84da68b17647371a81593402e897d639989e4robertphillips@google.comBrowserActionButton::BrowserActionButton(const Extension* extension,
9950c84da68b17647371a81593402e897d639989e4robertphillips@google.com                                         Browser* browser,
10050c84da68b17647371a81593402e897d639989e4robertphillips@google.com                                         BrowserActionView::Delegate* delegate)
10150c84da68b17647371a81593402e897d639989e4robertphillips@google.com    : MenuButton(this, base::string16(), NULL, false),
102902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com      browser_(browser),
103902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com      browser_action_(
104902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com          extensions::ExtensionActionManager::Get(browser->profile())->
10597cee9735350cb472249ce1a827ba1aa6b2a5f59chudy@google.com          GetBrowserAction(*extension)),
106902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com      extension_(extension),
107902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com      icon_factory_(browser->profile(), extension, browser_action_, this),
1087e4cfbf144af7d530d552946cee2a21d30b9b50fchudy@google.com      delegate_(delegate),
1097e4cfbf144af7d530d552946cee2a21d30b9b50fchudy@google.com      context_menu_(NULL),
1107e4cfbf144af7d530d552946cee2a21d30b9b50fchudy@google.com      called_registered_extension_command_(false),
1117e4cfbf144af7d530d552946cee2a21d30b9b50fchudy@google.com      icon_observer_(NULL) {
1127e4cfbf144af7d530d552946cee2a21d30b9b50fchudy@google.com  SetBorder(views::Border::NullBorder());
1137e4cfbf144af7d530d552946cee2a21d30b9b50fchudy@google.com  set_alignment(TextButton::ALIGN_CENTER);
114902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  set_context_menu_controller(this);
115902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
1164469938e92d779dff05e745559e67907bbf21e78reed@google.com  // No UpdateState() here because View hierarchy not setup yet. Our parent
1178a1cdaece7e1d009befb84f21bb82370025bf4d6robertphillips@google.com  // should call UpdateState() after creation.
1182e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
119febc0ec41b4cff6ea69f2b89d72c0d330d198283robertphillips@google.com  content::NotificationSource notification_source =
120febc0ec41b4cff6ea69f2b89d72c0d330d198283robertphillips@google.com      content::Source<Profile>(browser_->profile()->GetOriginalProfile());
121febc0ec41b4cff6ea69f2b89d72c0d330d198283robertphillips@google.com  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
122febc0ec41b4cff6ea69f2b89d72c0d330d198283robertphillips@google.com                 content::Source<ExtensionAction>(browser_action_));
123febc0ec41b4cff6ea69f2b89d72c0d330d198283robertphillips@google.com  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED,
124902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com                 notification_source);
125902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED,
126902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com                 notification_source);
127902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
1288a1cdaece7e1d009befb84f21bb82370025bf4d6robertphillips@google.com  // We also listen for browser theme changes on linux because a switch from or
129902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  // to GTK requires that we regrab our browser action images.
130902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  registrar_.Add(
13157f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org      this,
13257f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org      chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
13357f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org      content::Source<ThemeService>(
13457f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org          ThemeServiceFactory::GetForProfile(browser->profile())));
13557f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org}
136f14143226acf209615c4dd841aa6632aff112ab3chudy@google.com
137f14143226acf209615c4dd841aa6632aff112ab3chudy@google.comvoid BrowserActionButton::Destroy() {
1380d4fe14a41bd04535310f8b2edee9e30191fdd79commit-bot@chromium.org  MaybeUnregisterExtensionCommand(false);
13967baba4892649fdb6fb0827c7d54e5adb7538443robertphillips@google.com
140f14143226acf209615c4dd841aa6632aff112ab3chudy@google.com  if (context_menu_) {
141f14143226acf209615c4dd841aa6632aff112ab3chudy@google.com    context_menu_->Cancel();
142902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com    base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
143902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  } else {
144902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com    delete this;
145902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  }
146902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com}
147902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
148b9ddd4e9f184f4a4545eca69c55ec1ad1ce59170chudy@google.comvoid BrowserActionButton::ViewHierarchyChanged(
149b9ddd4e9f184f4a4545eca69c55ec1ad1ce59170chudy@google.com    const ViewHierarchyChangedDetails& details) {
150b9ddd4e9f184f4a4545eca69c55ec1ad1ce59170chudy@google.com  if (details.is_add && !called_registered_extension_command_ &&
151b9ddd4e9f184f4a4545eca69c55ec1ad1ce59170chudy@google.com      GetFocusManager()) {
152b9ddd4e9f184f4a4545eca69c55ec1ad1ce59170chudy@google.com    MaybeRegisterExtensionCommand();
153e8cc6e8071935339a06548b13a0668b56a7540f5bungeman@google.com    called_registered_extension_command_ = true;
154e8cc6e8071935339a06548b13a0668b56a7540f5bungeman@google.com  }
155830b8793bb1646bb76817bdc228dd8e2a92bef7dchudy@google.com
156830b8793bb1646bb76817bdc228dd8e2a92bef7dchudy@google.com  MenuButton::ViewHierarchyChanged(details);
1572a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org}
1582a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org
159902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.combool BrowserActionButton::CanHandleAccelerators() const {
160902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  // View::CanHandleAccelerators() checks to see if the view is visible before
161902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  // allowing it to process accelerators. This is not appropriate for browser
162902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  // actions buttons, which can be hidden inside the overflow area.
163902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  return true;
164902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com}
165902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
166902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.comvoid BrowserActionButton::GetAccessibleState(ui::AXViewState* state) {
167902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  views::MenuButton::GetAccessibleState(state);
1687112173c3c4cd1b1e7da8cdf971d71f01dd91299reed@google.com  state->role = ui::AX_ROLE_BUTTON;
169eed779d866e1e239bfb9ebc6a225b7345a41adf9commit-bot@chromium.org}
170eed779d866e1e239bfb9ebc6a225b7345a41adf9commit-bot@chromium.org
171902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.comvoid BrowserActionButton::ButtonPressed(views::Button* sender,
172902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com                                        const ui::Event& event) {
173902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  delegate_->OnBrowserActionExecuted(this);
174902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com}
175902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
176902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.comvoid BrowserActionButton::ShowContextMenuForView(
177902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com    View* source,
178902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com    const gfx::Point& point,
179902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com    ui::MenuSourceType source_type) {
1800a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com  if (!extension()->ShowConfigureContextMenus())
1810a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com    return;
1820a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com
1830a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com  SetButtonPushed();
1840a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com
1850a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com  // Reconstructs the menu every time because the menu's contents are dynamic.
18667baba4892649fdb6fb0827c7d54e5adb7538443robertphillips@google.com  scoped_refptr<ExtensionContextMenuModel> context_menu_contents_(
18767baba4892649fdb6fb0827c7d54e5adb7538443robertphillips@google.com      new ExtensionContextMenuModel(extension(), browser_, delegate_));
188902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  menu_runner_.reset(new views::MenuRunner(context_menu_contents_.get()));
189902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
1907ce564cccb246ec56427085872b2e1458fe74bd1bsalomon@google.com  context_menu_ = menu_runner_->GetMenu();
1917ce564cccb246ec56427085872b2e1458fe74bd1bsalomon@google.com  gfx::Point screen_loc;
192902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  views::View::ConvertPointToScreen(this, &screen_loc);
193902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  if (menu_runner_->RunMenuAt(
194902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com          GetWidget(),
195902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com          NULL,
196902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com          gfx::Rect(screen_loc, size()),
1977ce564cccb246ec56427085872b2e1458fe74bd1bsalomon@google.com          views::MENU_ANCHOR_TOPLEFT,
1987ce564cccb246ec56427085872b2e1458fe74bd1bsalomon@google.com          source_type,
19967baba4892649fdb6fb0827c7d54e5adb7538443robertphillips@google.com          views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) ==
20067baba4892649fdb6fb0827c7d54e5adb7538443robertphillips@google.com      views::MenuRunner::MENU_DELETED) {
201902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com    return;
202902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  }
203902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
204902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  menu_runner_.reset();
20567baba4892649fdb6fb0827c7d54e5adb7538443robertphillips@google.com  SetButtonNotPushed();
20667baba4892649fdb6fb0827c7d54e5adb7538443robertphillips@google.com  context_menu_ = NULL;
20767baba4892649fdb6fb0827c7d54e5adb7538443robertphillips@google.com}
208902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
209902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.comvoid BrowserActionButton::UpdateState() {
2103b0a9fe5672e7339ec3e5e6d3986b15f57ae24e7robertphillips@google.com  int tab_id = delegate_->GetCurrentTabId();
2113b0a9fe5672e7339ec3e5e6d3986b15f57ae24e7robertphillips@google.com  if (tab_id < 0)
2123b0a9fe5672e7339ec3e5e6d3986b15f57ae24e7robertphillips@google.com    return;
2138f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com
2145c70cdca5efe541b70d010e91607bf8626ea49cacommit-bot@chromium.org  SetShowMultipleIconStates(delegate_->NeedToShowMultipleIconStates());
2155c70cdca5efe541b70d010e91607bf8626ea49cacommit-bot@chromium.org
216370a89980b2d38a6d01903b484bf404d6c48b496skia.committer@gmail.com  if (!IsEnabled(tab_id)) {
217370a89980b2d38a6d01903b484bf404d6c48b496skia.committer@gmail.com    SetState(views::CustomButton::STATE_DISABLED);
2188f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com  } else {
2195c70cdca5efe541b70d010e91607bf8626ea49cacommit-bot@chromium.org    SetState(menu_visible_ ?
2208f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com             views::CustomButton::STATE_PRESSED :
2218f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com             views::CustomButton::STATE_NORMAL);
222370a89980b2d38a6d01903b484bf404d6c48b496skia.committer@gmail.com  }
223370a89980b2d38a6d01903b484bf404d6c48b496skia.committer@gmail.com
2248f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com  gfx::ImageSkia icon = *icon_factory_.GetIcon(tab_id).ToImageSkia();
2258f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com
2268f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com  if (!icon.isNull()) {
2278f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com    if (!browser_action()->GetIsVisible(tab_id))
2288f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com      icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25);
2298f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com
2308f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com    ThemeService* theme =
2318f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com        ThemeServiceFactory::GetForProfile(browser_->profile());
2328f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com
2338f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com    gfx::ImageSkia bg = *theme->GetImageSkiaNamed(IDR_BROWSER_ACTION);
2348f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com    SetIcon(gfx::ImageSkiaOperations::CreateSuperimposedImage(bg, icon));
235ab5827354e2c23624acc3fc1fe4a83788bc99e96commit-bot@chromium.org
236e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org    gfx::ImageSkia bg_h = *theme->GetImageSkiaNamed(IDR_BROWSER_ACTION_H);
237e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org    SetHoverIcon(gfx::ImageSkiaOperations::CreateSuperimposedImage(bg_h, icon));
238e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org
239e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org    gfx::ImageSkia bg_p = *theme->GetImageSkiaNamed(IDR_BROWSER_ACTION_P);
24044c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.org    SetPushedIcon(
24144c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.org        gfx::ImageSkiaOperations::CreateSuperimposedImage(bg_p, icon));
24244c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.org  }
243ab5827354e2c23624acc3fc1fe4a83788bc99e96commit-bot@chromium.org
244e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com  // If the browser action name is empty, show the extension name instead.
245e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com  std::string title = browser_action()->GetTitle(tab_id);
246e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com  base::string16 name =
247e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com      base::UTF8ToUTF16(title.empty() ? extension()->name() : title);
248e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com  SetTooltipText(delegate_->NeedToShowTooltip() ? name : base::string16());
249e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com  SetAccessibleName(name);
250e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com
251e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com  parent()->SchedulePaint();
252210ae2a42613b9048e8e8c4096c5bf4fe2ddf838commit-bot@chromium.org}
253210ae2a42613b9048e8e8c4096c5bf4fe2ddf838commit-bot@chromium.org
254ab5827354e2c23624acc3fc1fe4a83788bc99e96commit-bot@chromium.orgbool BrowserActionButton::IsPopup() {
2558f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com  int tab_id = delegate_->GetCurrentTabId();
2568f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com  return (tab_id < 0) ? false : browser_action_->HasPopup(tab_id);
2578f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com}
2588f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com
2598f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.comGURL BrowserActionButton::GetPopupUrl() {
2601643b2c9bc5adb4324bb459bb7811f58bc7c2d62commit-bot@chromium.org  int tab_id = delegate_->GetCurrentTabId();
261768ac85655017d4106444bf3ad044680a575ccaacommit-bot@chromium.org  return (tab_id < 0) ? GURL() : browser_action_->GetPopupUrl(tab_id);
262902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com}
26367baba4892649fdb6fb0827c7d54e5adb7538443robertphillips@google.com
26457f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.orgvoid BrowserActionButton::Observe(int type,
265b9ddd4e9f184f4a4545eca69c55ec1ad1ce59170chudy@google.com                                  const content::NotificationSource& source,
2661735d6696e9a941925e6ca352849307d698ef139commit-bot@chromium.org                                  const content::NotificationDetails& details) {
2677e4cfbf144af7d530d552946cee2a21d30b9b50fchudy@google.com  switch (type) {
268768ac85655017d4106444bf3ad044680a575ccaacommit-bot@chromium.org    case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED:
269830b8793bb1646bb76817bdc228dd8e2a92bef7dchudy@google.com      UpdateState();
270e8cc6e8071935339a06548b13a0668b56a7540f5bungeman@google.com      // The browser action may have become visible/hidden so we need to make
271a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com      // sure the state gets updated.
272a9e937c7b712b024de108fa963f92d0e70e4a296chudy@google.com      delegate_->OnBrowserActionVisibilityChanged();
27332bbcf828d66ad244fa25b468bc3a229e531491frobertphillips@google.com      break;
2742a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org    case chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED:
2752a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org    case chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED: {
2762a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org      std::pair<const std::string, const std::string>* payload =
2772a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org          content::Details<std::pair<const std::string, const std::string> >(
278f4741c1322944e194ca34a8f5cf8188fe2c0efe2robertphillips@google.com              details).ptr();
279f4741c1322944e194ca34a8f5cf8188fe2c0efe2robertphillips@google.com      if (extension_->id() == payload->first &&
280902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com          payload->second ==
28132bbcf828d66ad244fa25b468bc3a229e531491frobertphillips@google.com              extensions::manifest_values::kBrowserActionCommandEvent) {
28232bbcf828d66ad244fa25b468bc3a229e531491frobertphillips@google.com        if (type == chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED)
28332bbcf828d66ad244fa25b468bc3a229e531491frobertphillips@google.com          MaybeRegisterExtensionCommand();
284902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com        else
2850699e02101405623ad47f225729ed2521b2a0501tomhudson@google.com          MaybeUnregisterExtensionCommand(true);
2860699e02101405623ad47f225729ed2521b2a0501tomhudson@google.com      }
2870699e02101405623ad47f225729ed2521b2a0501tomhudson@google.com      break;
2880699e02101405623ad47f225729ed2521b2a0501tomhudson@google.com    }
2890699e02101405623ad47f225729ed2521b2a0501tomhudson@google.com    case chrome::NOTIFICATION_BROWSER_THEME_CHANGED:
2900699e02101405623ad47f225729ed2521b2a0501tomhudson@google.com      UpdateState();
2910699e02101405623ad47f225729ed2521b2a0501tomhudson@google.com      break;
292ade9a3485e78d471f5f0902e9e50a2ec74c88e76skia.committer@gmail.com    default:
2931643b2c9bc5adb4324bb459bb7811f58bc7c2d62commit-bot@chromium.org      NOTREACHED();
2941643b2c9bc5adb4324bb459bb7811f58bc7c2d62commit-bot@chromium.org      break;
2951643b2c9bc5adb4324bb459bb7811f58bc7c2d62commit-bot@chromium.org  }
2961643b2c9bc5adb4324bb459bb7811f58bc7c2d62commit-bot@chromium.org}
2971643b2c9bc5adb4324bb459bb7811f58bc7c2d62commit-bot@chromium.org
298ade9a3485e78d471f5f0902e9e50a2ec74c88e76skia.committer@gmail.comvoid BrowserActionButton::OnIconUpdated() {
2991643b2c9bc5adb4324bb459bb7811f58bc7c2d62commit-bot@chromium.org  UpdateState();
3001643b2c9bc5adb4324bb459bb7811f58bc7c2d62commit-bot@chromium.org  if (icon_observer_)
3011643b2c9bc5adb4324bb459bb7811f58bc7c2d62commit-bot@chromium.org    icon_observer_->OnIconUpdated(GetIconWithBadge());
3021643b2c9bc5adb4324bb459bb7811f58bc7c2d62commit-bot@chromium.org}
3031643b2c9bc5adb4324bb459bb7811f58bc7c2d62commit-bot@chromium.org
3040699e02101405623ad47f225729ed2521b2a0501tomhudson@google.combool BrowserActionButton::Activate() {
305902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  if (!IsPopup())
306902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com    return true;
307902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
308902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  delegate_->OnBrowserActionExecuted(this);
309830b8793bb1646bb76817bdc228dd8e2a92bef7dchudy@google.com
310830b8793bb1646bb76817bdc228dd8e2a92bef7dchudy@google.com  // TODO(erikkay): Run a nested modal loop while the mouse is down to
311830b8793bb1646bb76817bdc228dd8e2a92bef7dchudy@google.com  // enable menu-like drag-select behavior.
312830b8793bb1646bb76817bdc228dd8e2a92bef7dchudy@google.com
313830b8793bb1646bb76817bdc228dd8e2a92bef7dchudy@google.com  // The return value of this method is returned via OnMousePressed.
314830b8793bb1646bb76817bdc228dd8e2a92bef7dchudy@google.com  // We need to return false here since we're handing off focus to another
3153b0a9fe5672e7339ec3e5e6d3986b15f57ae24e7robertphillips@google.com  // widget/view, and true will grab it right back and try to send events
31657f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org  // to us.
31757f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org  return false;
31857f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org}
31957f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org
32057f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.orgbool BrowserActionButton::OnMousePressed(const ui::MouseEvent& event) {
32157f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org  if (!event.IsRightMouseButton()) {
32257f74e0aa931e7784d47cba3ecc83020aa8e72b2commit-bot@chromium.org    return IsPopup() ? MenuButton::OnMousePressed(event) :
3232a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org                       TextButton::OnMousePressed(event);
3242a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org  }
3252a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org
3262a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org  if (!views::View::ShouldShowContextMenuOnMousePress()) {
3272a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org    // See comments in MenuButton::Activate() as to why this is needed.
3282a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org    SetMouseHandler(NULL);
3292a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org
3302a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org    ShowContextMenu(gfx::Point(), ui::MENU_SOURCE_MOUSE);
3312a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org  }
3322a67e123a3e559774a16a58cbe5106bc0fb86740commit-bot@chromium.org  return false;
3333b0a9fe5672e7339ec3e5e6d3986b15f57ae24e7robertphillips@google.com}
334902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com
335902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.comvoid BrowserActionButton::OnMouseReleased(const ui::MouseEvent& event) {
336902ebe5eb41a350b766238b3b103c22fe9fc0fb5chudy@google.com  if (IsPopup() || context_menu_) {
337    // TODO(erikkay) this never actually gets called (probably because of the
338    // loss of focus).
339    MenuButton::OnMouseReleased(event);
340  } else {
341    TextButton::OnMouseReleased(event);
342  }
343}
344
345void BrowserActionButton::OnMouseExited(const ui::MouseEvent& event) {
346  if (IsPopup() || context_menu_)
347    MenuButton::OnMouseExited(event);
348  else
349    TextButton::OnMouseExited(event);
350}
351
352bool BrowserActionButton::OnKeyReleased(const ui::KeyEvent& event) {
353  return IsPopup() ? MenuButton::OnKeyReleased(event) :
354                     TextButton::OnKeyReleased(event);
355}
356
357void BrowserActionButton::OnGestureEvent(ui::GestureEvent* event) {
358  if (IsPopup())
359    MenuButton::OnGestureEvent(event);
360  else
361    TextButton::OnGestureEvent(event);
362}
363
364bool BrowserActionButton::AcceleratorPressed(
365    const ui::Accelerator& accelerator) {
366  delegate_->OnBrowserActionExecuted(this);
367  return true;
368}
369
370void BrowserActionButton::SetButtonPushed() {
371  SetState(views::CustomButton::STATE_PRESSED);
372  menu_visible_ = true;
373}
374
375void BrowserActionButton::SetButtonNotPushed() {
376  SetState(views::CustomButton::STATE_NORMAL);
377  menu_visible_ = false;
378}
379
380bool BrowserActionButton::IsEnabled(int tab_id) const {
381  return browser_action_->GetIsVisible(tab_id);
382}
383
384gfx::ImageSkia BrowserActionButton::GetIconWithBadge() {
385  int tab_id = delegate_->GetCurrentTabId();
386  gfx::Size spacing(0, ToolbarView::kVertSpacing);
387  gfx::ImageSkia icon = *icon_factory_.GetIcon(tab_id).ToImageSkia();
388  if (!IsEnabled(tab_id))
389    icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25);
390  return browser_action_->GetIconWithBadge(icon, tab_id, spacing);
391}
392
393gfx::ImageSkia BrowserActionButton::GetIconForTest() {
394  return icon();
395}
396
397BrowserActionButton::~BrowserActionButton() {
398}
399
400void BrowserActionButton::MaybeRegisterExtensionCommand() {
401  extensions::CommandService* command_service =
402      extensions::CommandService::Get(browser_->profile());
403  extensions::Command browser_action_command;
404  if (command_service->GetBrowserActionCommand(
405          extension_->id(),
406          extensions::CommandService::ACTIVE_ONLY,
407          &browser_action_command,
408          NULL)) {
409    keybinding_.reset(new ui::Accelerator(
410        browser_action_command.accelerator()));
411    GetFocusManager()->RegisterAccelerator(
412        *keybinding_.get(), ui::AcceleratorManager::kHighPriority, this);
413  }
414}
415
416void BrowserActionButton::MaybeUnregisterExtensionCommand(bool only_if_active) {
417  if (!keybinding_.get() || !GetFocusManager())
418    return;
419
420  extensions::CommandService* command_service =
421      extensions::CommandService::Get(browser_->profile());
422
423  extensions::Command browser_action_command;
424  if (!only_if_active || !command_service->GetBrowserActionCommand(
425          extension_->id(),
426          extensions::CommandService::ACTIVE_ONLY,
427          &browser_action_command,
428          NULL)) {
429    GetFocusManager()->UnregisterAccelerator(*keybinding_.get(), this);
430    keybinding_.reset(NULL);
431  }
432}
433