1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/views/toolbar/browser_action_view.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <string>
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_action.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
13558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "chrome/browser/themes/theme_service.h"
14558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "chrome/browser/themes/theme_service_factory.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "chrome/browser/ui/view_ids.h"
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/ui/views/frame/browser_view.h"
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/generated_resources.h"
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "extensions/common/manifest_constants.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h"
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/accessibility/ax_view_state.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
27d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/event.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia_operations.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia_source.h"
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/controls/button/label_button_border.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension;
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing views::LabelButtonBorder;
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace {
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// We have smaller insets than normal STYLE_TEXTBUTTON buttons so that we can
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// fit user supplied icons in without clipping them.
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst int kBorderInset = 4;
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BrowserActionView
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BrowserActionView::BrowserActionView(const Extension* extension,
4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                     ExtensionAction* extension_action,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     Browser* browser,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     BrowserActionView::Delegate* delegate)
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : MenuButton(this, base::string16(), NULL, false),
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      view_controller_(new ExtensionActionViewController(
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          extension,
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          browser,
5503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          extension_action,
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this)),
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_(delegate),
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      called_registered_extension_command_(false),
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      icon_observer_(NULL) {
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  set_id(VIEW_ID_BROWSER_ACTION);
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  SetHorizontalAlignment(gfx::ALIGN_CENTER);
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  set_context_menu_controller(view_controller_.get());
636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  set_drag_controller(delegate_);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationSource notification_source =
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      content::Source<Profile>(browser->profile()->GetOriginalProfile());
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  registrar_.Add(this,
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 notification_source);
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  registrar_.Add(this,
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 extensions::NOTIFICATION_EXTENSION_COMMAND_REMOVED,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 notification_source);
73558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
74558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // We also listen for browser theme changes on linux because a switch from or
75558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // to GTK requires that we regrab our browser action images.
76558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  registrar_.Add(
77558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      this,
78558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
79558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      content::Source<ThemeService>(
80558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          ThemeServiceFactory::GetForProfile(browser->profile())));
816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  UpdateState();
836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)BrowserActionView::~BrowserActionView() {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::ViewHierarchyChanged(
89a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const ViewHierarchyChangedDetails& details) {
90a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (details.is_add && !called_registered_extension_command_ &&
91a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      GetFocusManager()) {
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    view_controller_->RegisterCommand();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_registered_extension_command_ = true;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
96a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  MenuButton::ViewHierarchyChanged(details);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::OnDragDone() {
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  delegate_->OnBrowserActionViewDragDone();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)gfx::Size BrowserActionView::GetPreferredSize() const {
1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return gfx::Size(BrowserActionsContainer::IconWidth(false),
1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                   BrowserActionsContainer::IconHeight());
1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::PaintChildren(gfx::Canvas* canvas,
1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                      const views::CullSet& cull_set) {
1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  View::PaintChildren(canvas, cull_set);
1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  int tab_id = view_controller_->GetCurrentTabId();
1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (tab_id >= 0)
1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    extension_action()->PaintBadge(canvas, GetLocalBounds(), tab_id);
1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::GetAccessibleState(ui::AXViewState* state) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::MenuButton::GetAccessibleState(state);
1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  state->name = l10n_util::GetStringUTF16(
1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      IDS_ACCNAME_EXTENSIONS_BROWSER_ACTION);
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  state->role = ui::AX_ROLE_BUTTON;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::ButtonPressed(views::Button* sender,
1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                      const ui::Event& event) {
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  view_controller_->ExecuteActionByUser();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::UpdateState() {
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int tab_id = view_controller_->GetCurrentTabId();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tab_id < 0)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!IsEnabled(tab_id))
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetState(views::CustomButton::STATE_DISABLED);
135e4256316f8b5e8d1ec0df1f7762771622a53fa63Ben Murdoch  else if (state() == views::CustomButton::STATE_DISABLED)
136e4256316f8b5e8d1ec0df1f7762771622a53fa63Ben Murdoch    SetState(views::CustomButton::STATE_NORMAL);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  gfx::ImageSkia icon = *view_controller_->GetIcon(tab_id).ToImageSkia();
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!icon.isNull()) {
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!extension_action()->GetIsVisible(tab_id))
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ThemeService* theme = ThemeServiceFactory::GetForProfile(
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        view_controller_->browser()->profile());
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    gfx::ImageSkia bg = *theme->GetImageSkiaNamed(IDR_BROWSER_ACTION);
148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    SetImage(views::Button::STATE_NORMAL,
149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             gfx::ImageSkiaOperations::CreateSuperimposedImage(bg, icon));
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the browser action name is empty, show the extension name instead.
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string title = extension_action()->GetTitle(tab_id);
154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 name =
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::UTF8ToUTF16(title.empty() ? extension()->name() : title);
156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  SetTooltipText(name);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetAccessibleName(name);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
159e4256316f8b5e8d1ec0df1f7762771622a53fa63Ben Murdoch  Layout();  // We need to layout since we may have added an icon as a result.
1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  SchedulePaint();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool BrowserActionView::IsPopup() {
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int tab_id = view_controller_->GetCurrentTabId();
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return (tab_id < 0) ? false : extension_action()->HasPopup(tab_id);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::Observe(int type,
1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                const content::NotificationSource& source,
1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                const content::NotificationDetails& details) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED:
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case extensions::NOTIFICATION_EXTENSION_COMMAND_REMOVED: {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::pair<const std::string, const std::string>* payload =
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Details<std::pair<const std::string, const std::string> >(
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              details).ptr();
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (extension()->id() == payload->first &&
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          payload->second ==
179d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              extensions::manifest_values::kBrowserActionCommandEvent) {
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (type == extensions::NOTIFICATION_EXTENSION_COMMAND_ADDED)
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          view_controller_->RegisterCommand();
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          view_controller_->UnregisterCommand(true);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
187558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    case chrome::NOTIFICATION_BROWSER_THEME_CHANGED:
188558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      UpdateState();
189558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      break;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool BrowserActionView::Activate() {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsPopup())
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  view_controller_->ExecuteActionByUser();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(erikkay): Run a nested modal loop while the mouse is down to
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // enable menu-like drag-select behavior.
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The return value of this method is returned via OnMousePressed.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to return false here since we're handing off focus to another
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // widget/view, and true will grab it right back and try to send events
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to us.
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool BrowserActionView::OnMousePressed(const ui::MouseEvent& event) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!event.IsRightMouseButton()) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return IsPopup() ? MenuButton::OnMousePressed(event) :
215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       LabelButton::OnMousePressed(event);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::OnMouseReleased(const ui::MouseEvent& event) {
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (IsPopup() || view_controller_->is_menu_running()) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(erikkay) this never actually gets called (probably because of the
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // loss of focus).
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MenuButton::OnMouseReleased(event);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    LabelButton::OnMouseReleased(event);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::OnMouseExited(const ui::MouseEvent& event) {
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (IsPopup() || view_controller_->is_menu_running())
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MenuButton::OnMouseExited(event);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    LabelButton::OnMouseExited(event);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool BrowserActionView::OnKeyReleased(const ui::KeyEvent& event) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IsPopup() ? MenuButton::OnKeyReleased(event) :
239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     LabelButton::OnKeyReleased(event);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::OnGestureEvent(ui::GestureEvent* event) {
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsPopup())
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MenuButton::OnGestureEvent(event);
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    LabelButton::OnGestureEvent(event);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)scoped_ptr<LabelButtonBorder> BrowserActionView::CreateDefaultBorder() const {
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<LabelButtonBorder> border = LabelButton::CreateDefaultBorder();
251116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  border->set_insets(gfx::Insets(kBorderInset, kBorderInset,
252116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                 kBorderInset, kBorderInset));
253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return border.Pass();
254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
255116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool BrowserActionView::IsEnabled(int tab_id) const {
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return view_controller_->extension_action()->GetIsVisible(tab_id);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)gfx::ImageSkia BrowserActionView::GetIconWithBadge() {
2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int tab_id = view_controller_->GetCurrentTabId();
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  gfx::Size spacing(0, ToolbarView::kVertSpacing);
2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  gfx::ImageSkia icon = *view_controller_->GetIcon(tab_id).ToImageSkia();
264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!IsEnabled(tab_id))
265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    icon = gfx::ImageSkiaOperations::CreateTransparentImage(icon, .25);
2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return extension_action()->GetIconWithBadge(icon, tab_id, spacing);
267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)gfx::ImageSkia BrowserActionView::GetIconForTest() {
270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return GetImage(views::Button::STATE_NORMAL);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::OnIconUpdated() {
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  UpdateState();
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (icon_observer_)
2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    icon_observer_->OnIconUpdated(GetIconWithBadge());
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)views::View* BrowserActionView::GetAsView() {
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return this;
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool BrowserActionView::IsShownInMenu() {
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return delegate_->ShownInsideMenu();
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)views::FocusManager* BrowserActionView::GetFocusManagerForAccelerator() {
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return GetFocusManager();
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)views::Widget* BrowserActionView::GetParentForContextMenu() {
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // RunMenuAt expects a nested menu to be parented by the same widget as the
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // already visible menu, in this case the Chrome menu.
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return delegate_->ShownInsideMenu() ?
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      BrowserView::GetBrowserViewForBrowser(view_controller_->browser())
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          ->toolbar()->app_menu()->GetWidget() :
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      GetWidget();
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciExtensionActionViewController*
3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciBrowserActionView::GetPreferredPopupViewController() {
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return delegate_->ShownInsideMenu() ?
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      delegate_->GetMainViewForExtension(extension())->view_controller() :
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      view_controller();
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)views::View* BrowserActionView::GetReferenceViewForPopup() {
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Browser actions in the overflow menu can still show popups, so we may need
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // a reference view other than this button's parent. If so, use the overflow
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // view.
3116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return visible() ? this : delegate_->GetOverflowReferenceView();
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciviews::MenuButton* BrowserActionView::GetContextMenuButton() {
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(visible());  // We should never show a context menu for a hidden item.
3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return this;
3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)content::WebContents* BrowserActionView::GetCurrentWebContents() {
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return delegate_->GetCurrentWebContents();
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::HideActivePopup() {
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  delegate_->HideActivePopup();
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::OnPopupShown(bool grant_tab_permissions) {
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  delegate_->SetPopupOwner(this);
3291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If this was through direct user action, we press the menu button.
3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (grant_tab_permissions) {
3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // We set the state of the menu button we're using as a reference view,
3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // which is either this or the overflow reference view.
3331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // This cast is safe because GetReferenceViewForPopup returns either |this|
3341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // or delegate_->GetOverflowReferenceView(), which returns a MenuButton.
3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    views::MenuButton* reference_view =
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        static_cast<views::MenuButton*>(GetReferenceViewForPopup());
3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pressed_lock_.reset(new views::MenuButton::PressedLock(reference_view));
3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionView::CleanupPopup() {
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // We need to do these actions synchronously (instead of closing and then
3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // performing the rest of the cleanup in OnWidgetDestroyed()) because
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // OnWidgetDestroyed() can be called asynchronously from Close(), and we need
3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // to keep the delegate's popup owner up-to-date.
3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  delegate_->SetPopupOwner(NULL);
3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  pressed_lock_.reset();  // Unpress the menu button if it was pressed.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
349