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_actions_container.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/extensions/extension_action_manager.h"
108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/extensions/extension_util.h"
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/extensions/extension_view_host.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/tab_helper.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/view_ids.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/extensions/browser_action_drag_data.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/extensions/extension_popup.h"
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/ui/views/frame/browser_view.h"
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/ui/views/toolbar/browser_actions_container_observer.h"
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/common/extensions/command.h"
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/generated_resources.h"
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/extension_registry.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/runtime_data.h"
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/feature_switch.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h"
30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "third_party/skia/include/core/SkColor.h"
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/accessibility/ax_view_state.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/dragdrop/drag_utils.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ui/base/nine_image_painter_factory.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/theme_provider.h"
37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/slide_animation.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ui/gfx/geometry/rect.h"
4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "ui/resources/grit/ui_resources.h"
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/views/controls/button/label_button_border.h"
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/views/controls/button/menu_button.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/resize_area.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/metrics.h"
45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ui/views/painter.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Horizontal spacing before the chevron (if visible).
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int kChevronSpacing = ToolbarView::kStandardSpacing - 2;
5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// A version of MenuButton with almost empty insets to fit properly on the
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// toolbar.
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class ChevronMenuButton : public views::MenuButton {
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public:
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ChevronMenuButton(views::ButtonListener* listener,
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    const base::string16& text,
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    views::MenuButtonListener* menu_button_listener,
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    bool show_menu_marker)
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      : views::MenuButton(listener,
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          text,
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          menu_button_listener,
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          show_menu_marker) {
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual ~ChevronMenuButton() {}
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual scoped_ptr<views::LabelButtonBorder> CreateDefaultBorder() const
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      OVERRIDE {
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // The chevron resource was designed to not have any insets.
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    scoped_ptr<views::LabelButtonBorder> border =
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        views::MenuButton::CreateDefaultBorder();
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    border->set_insets(gfx::Insets());
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return border.Pass();
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private:
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ChevronMenuButton);
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// BrowserActionsContainer::DropPosition
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)struct BrowserActionsContainer::DropPosition {
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DropPosition(size_t row, size_t icon_in_row);
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // The (0-indexed) row into which the action will be dropped.
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  size_t row;
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // The (0-indexed) icon in the row before the action will be dropped.
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  size_t icon_in_row;
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)BrowserActionsContainer::DropPosition::DropPosition(
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    size_t row, size_t icon_in_row)
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : row(row), icon_in_row(icon_in_row) {
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BrowserActionsContainer
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// static
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint BrowserActionsContainer::icons_per_overflow_menu_row_ = 1;
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int BrowserActionsContainer::kItemSpacing = ToolbarView::kStandardSpacing;
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BrowserActionsContainer::disable_animations_during_testing_ = false;
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
116116680a4aac90f2aa7413d9095a592090648e557Ben MurdochBrowserActionsContainer::BrowserActionsContainer(
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Browser* browser,
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    View* owner_view,
119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BrowserActionsContainer* main_container)
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : initialized_(false),
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      profile_(browser->profile()),
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser_(browser),
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      owner_view_(owner_view),
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      main_container_(main_container),
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      popup_owner_(NULL),
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_(NULL),
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      container_width_(0),
128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      resize_area_(NULL),
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chevron_(NULL),
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      overflow_menu_(NULL),
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      suppress_chevron_(false),
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resize_amount_(0),
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      animation_target_size_(0),
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      show_menu_task_factory_(this) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_id(VIEW_ID_BROWSER_ACTION_TOOLBAR);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  model_ = extensions::ExtensionToolbarModel::Get(browser->profile());
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (model_)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->AddObserver(this);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool overflow_experiment =
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extensions::FeatureSwitch::extension_action_redesign()->IsEnabled();
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!in_overflow_mode() || overflow_experiment);
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!in_overflow_mode()) {
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryViews(
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        browser->profile(),
148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        owner_view->GetFocusManager(),
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        extensions::ExtensionKeybindingRegistry::ALL_EXTENSIONS,
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this));
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    resize_animation_.reset(new gfx::SlideAnimation(this));
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    resize_area_ = new views::ResizeArea(this);
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    AddChildView(resize_area_);
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // 'Main' mode doesn't need a chevron overflow when overflow is shown inside
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // the Chrome menu.
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!overflow_experiment) {
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chevron_ = new ChevronMenuButton(NULL, base::string16(), this, false);
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chevron_->EnableCanvasFlippingForRTLUI(true);
161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chevron_->SetAccessibleName(
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          l10n_util::GetStringUTF16(IDS_ACCNAME_EXTENSIONS_CHEVRON));
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chevron_->SetVisible(false);
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      AddChildView(chevron_);
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BrowserActionsContainer::~BrowserActionsContainer() {
170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  FOR_EACH_OBSERVER(BrowserActionsContainerObserver,
171effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    observers_,
172effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    OnBrowserActionsContainerDestroyed());
173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (overflow_menu_)
1757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    overflow_menu_->set_observer(NULL);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->RemoveObserver(this);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopShowFolderDropMenuTimer();
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  HideActivePopup();
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteBrowserActionViews();
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::Init() {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadImages();
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We wait to set the container width until now so that the chevron images
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be loaded.  The width calculation needs to know the chevron size.
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (model_ && model_->extensions_initialized()) {
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    container_width_ = GetPreferredWidth();
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    SetChevronVisibility();
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  initialized_ = true;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciBrowserActionView* BrowserActionsContainer::GetViewForExtension(
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const Extension* extension) {
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (BrowserActionViews::iterator view = browser_action_views_.begin();
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       view != browser_action_views_.end(); ++view) {
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if ((*view)->extension() == extension)
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return *view;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::RefreshBrowserActionViews() {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i)
2086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    browser_action_views_[i]->UpdateState();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::CreateBrowserActionViews() {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(browser_action_views_.empty());
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!model_)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extensions::ExtensionActionManager* action_manager =
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      extensions::ExtensionActionManager::Get(profile_);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const extensions::ExtensionList& toolbar_items = model_->toolbar_items();
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (extensions::ExtensionList::const_iterator i(toolbar_items.begin());
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != toolbar_items.end(); ++i) {
2217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!ShouldDisplayBrowserAction(i->get()))
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    BrowserActionView* view =
22503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        new BrowserActionView(i->get(),
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              action_manager->GetExtensionAction(**i),
22703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                              browser_,
22803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                              this);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_action_views_.push_back(view);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddChildView(view);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::DeleteBrowserActionViews() {
2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  HideActivePopup();
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (overflow_menu_)
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    overflow_menu_->NotifyBrowserActionViewsDeleting();
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&browser_action_views_);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t BrowserActionsContainer::VisibleBrowserActions() const {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t visible_actions = 0;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (browser_action_views_[i]->visible())
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++visible_actions;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return visible_actions;
24846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
24946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
25046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)size_t BrowserActionsContainer::VisibleBrowserActionsAfterAnimation() const {
25146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!animating())
25246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return VisibleBrowserActions();
25346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return WidthToIconCount(animation_target_size_);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BrowserActionsContainer::ExecuteExtensionCommand(
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const extensions::Extension* extension,
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const extensions::Command& command) {
260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Global commands are handled by the ExtensionCommandsGlobalRegistry
261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // instance.
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!command.global());
263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  extension_keybinding_registry_->ExecuteCommand(extension->id(),
264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                 command.accelerator());
265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BrowserActionsContainer::NotifyActionMovedToOverflow() {
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // When an action is moved to overflow, we shrink the size of the container
2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // by 1.
2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!profile_->IsOffTheRecord()) {
2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int icon_count = model_->GetVisibleIconCount();
2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Since this happens when an icon moves from the main bar to overflow, we
2731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // can't possibly have had no visible icons on the main bar.
2741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK_NE(0, icon_count);
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (icon_count == -1)
2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      icon_count = browser_action_views_.size();
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    model_->SetVisibleIconCount(icon_count - 1);
2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Animate(gfx::Tween::EASE_OUT,
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          VisibleBrowserActionsAfterAnimation() - 1);
2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
283116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool BrowserActionsContainer::ShownInsideMenu() const {
284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return in_overflow_mode();
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BrowserActionsContainer::OnBrowserActionViewDragDone() {
2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ToolbarVisibleCountChanged();
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(BrowserActionsContainerObserver,
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    observers_,
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    OnBrowserActionDragDone());
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciviews::MenuButton* BrowserActionsContainer::GetOverflowReferenceView() {
2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // With traditional overflow, the reference is the chevron. With the
2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // redesign, we use the wrench menu instead.
2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return chevron_ ?
2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      chevron_ :
2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      BrowserView::GetBrowserViewForBrowser(browser_)->toolbar()->app_menu();
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionsContainer::SetPopupOwner(BrowserActionView* popup_owner) {
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // We should never be setting a popup owner when one already exists, and
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // never unsetting one when one wasn't set.
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK((!popup_owner_ && popup_owner) ||
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         (popup_owner_ && !popup_owner));
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  popup_owner_ = popup_owner;
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BrowserActionsContainer::HideActivePopup() {
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (popup_owner_)
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    popup_owner_->view_controller()->HidePopup();
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciBrowserActionView* BrowserActionsContainer::GetMainViewForExtension(
3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const Extension* extension) {
3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return in_overflow_mode() ?
3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      main_container_->GetViewForExtension(extension) :
3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      GetViewForExtension(extension);
3201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
322effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BrowserActionsContainer::AddObserver(
323effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    BrowserActionsContainerObserver* observer) {
324effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  observers_.AddObserver(observer);
325effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
326effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
327effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BrowserActionsContainer::RemoveObserver(
328effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    BrowserActionsContainerObserver* observer) {
329effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  observers_.RemoveObserver(observer);
330effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
331effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size BrowserActionsContainer::GetPreferredSize() const {
333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (in_overflow_mode()) {
3341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int icon_count = GetIconCount();
3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // In overflow, we always have a preferred size of a full row (even if we
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // don't use it), and always of at least one row. The parent may decide to
3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // show us even when empty, e.g. as a drag target for dragging in icons from
3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // the main container.
3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int row_count =
3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ((std::max(0, icon_count - 1)) / icons_per_overflow_menu_row_) + 1;
341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return gfx::Size(
3421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        IconCountToWidth(icons_per_overflow_menu_row_, false),
3431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        row_count * IconHeight());
344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
3461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If there are no actions to show, then don't show the container at all.
3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (browser_action_views_.empty())
3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return gfx::Size();
3491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We calculate the size of the view by taking the current width and
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // subtracting resize_amount_ (the latter represents how far the user is
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // resizing the view or, if animating the snapping, how far to animate it).
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // But we also clamp it to a minimum size and the maximum size, so that the
354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // container can never shrink too far or take up more space than it needs.
355116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // In other words: MinimumNonemptyWidth() < width() - resize < ClampTo(MAX).
356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int preferred_width = std::min(
357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      std::max(MinimumNonemptyWidth(), container_width_ - resize_amount_),
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IconCountToWidth(-1, false));
359116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return gfx::Size(preferred_width, IconHeight());
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint BrowserActionsContainer::GetHeightForWidth(int width) const {
3631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (in_overflow_mode())
3641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    icons_per_overflow_menu_row_ = (width - kItemSpacing) / IconWidth(true);
3651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return GetPreferredSize().height();
3661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size BrowserActionsContainer::GetMinimumSize() const {
369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int min_width = std::min(MinimumNonemptyWidth(), IconCountToWidth(-1, false));
370116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return gfx::Size(min_width, IconHeight());
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::Layout() {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (browser_action_views_.empty()) {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetVisible(false);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVisible(true);
380116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (resize_area_)
381116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    resize_area_->SetBounds(0, 0, kItemSpacing, height());
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the icons don't all fit, show the chevron (unless suppressed).
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_x = GetPreferredSize().width();
385116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if ((IconCountToWidth(-1, false) > max_x) && !suppress_chevron_ && chevron_) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chevron_->SetVisible(true);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Size chevron_size(chevron_->GetPreferredSize());
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    max_x -=
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ToolbarView::kStandardSpacing + chevron_size.width() + kChevronSpacing;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chevron_->SetBounds(
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        width() - ToolbarView::kStandardSpacing - chevron_size.width(),
392effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        0,
393effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        chevron_size.width(),
394effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        chevron_size.height());
395116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else if (chevron_) {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chevron_->SetVisible(false);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now draw the icons for the browser actions in the available space.
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int icon_width = IconWidth(false);
401116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (in_overflow_mode()) {
402116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (size_t i = 0;
403116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         i < main_container_->VisibleBrowserActionsAfterAnimation(); ++i) {
404116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // Ensure that any browser actions shown in the main view are hidden in
405116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // the overflow view.
406116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      browser_action_views_[i]->SetVisible(false);
407116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
408116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
409116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (size_t i = main_container_->VisibleBrowserActionsAfterAnimation();
410116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         i < browser_action_views_.size(); ++i) {
411116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      BrowserActionView* view = browser_action_views_[i];
412116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      size_t index = i - main_container_->VisibleBrowserActionsAfterAnimation();
4131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      int row_index = static_cast<int>(index) / icons_per_overflow_menu_row_;
4145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      int x = kItemSpacing + (index * IconWidth(true)) -
4151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          (row_index * IconWidth(true) * icons_per_overflow_menu_row_);
416116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      gfx::Rect rect_bounds(
417116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          x, IconHeight() * row_index, icon_width, IconHeight());
418116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      view->SetBoundsRect(rect_bounds);
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view->SetVisible(true);
420116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
421116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
422116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (BrowserActionViews::const_iterator it = browser_action_views_.begin();
423116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         it < browser_action_views_.end(); ++it) {
424116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      BrowserActionView* view = *it;
425116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      int x = ToolbarView::kStandardSpacing +
426116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          ((it - browser_action_views_.begin()) * IconWidth(true));
427116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      view->SetVisible(x + icon_width <= max_x);
428116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (view->visible())
429116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        view->SetBounds(x, 0, icon_width, IconHeight());
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::GetDropFormats(
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int* formats,
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::set<OSExchangeData::CustomFormat>* custom_formats) {
4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return BrowserActionDragData::GetDropFormats(custom_formats);
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::AreDropTypesRequired() {
4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return BrowserActionDragData::AreDropTypesRequired();
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::CanDrop(const OSExchangeData& data) {
4455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return BrowserActionDragData::CanDrop(data, profile_);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::OnDragUpdated(
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::DropTargetEvent& event) {
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First check if we are above the chevron (overflow) menu.
4511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (chevron_ && GetEventHandlerForPoint(event.location()) == chevron_) {
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!show_menu_task_factory_.HasWeakPtrs() && !overflow_menu_)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StartShowFolderDropMenuTimer();
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ui::DragDropTypes::DRAG_MOVE;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopShowFolderDropMenuTimer();
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t row_index = 0;
4591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t before_icon_in_row = 0;
4601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If there are no visible browser actions (such as when dragging an icon to
4611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // an empty overflow/main container), then 0, 0 for row, column is correct.
4621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (VisibleBrowserActions() != 0) {
4631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Figure out where to display the indicator. This is a complex calculation:
4641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // First, we subtract out the padding to the left of the icon area, which is
4661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // ToolbarView::kStandardSpacing. If we're right-to-left, we also mirror the
4671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // event.x() so that our calculations are consistent with left-to-right.
4681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int offset_into_icon_area =
4691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        GetMirroredXInView(event.x()) - ToolbarView::kStandardSpacing;
4701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Next, figure out what row we're on. This only matters for overflow mode,
4721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // but the calculation is the same for both.
4731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    row_index = event.y() / IconHeight();
4741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Sanity check - we should never be on a different row in the main
4761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // container.
4771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(in_overflow_mode() || row_index == 0);
4781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Next, we determine which icon to place the indicator in front of. We want
4801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // to place the indicator in front of icon n when the cursor is between the
4811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // midpoints of icons (n - 1) and n.  To do this we take the offset into the
4821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // icon area and transform it as follows:
4831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    //
4841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Real icon area:
4851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    //   0   a     *  b        c
4861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    //   |   |        |        |
4871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    //   |[IC|ON]  [IC|ON]  [IC|ON]
4881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // We want to be before icon 0 for 0 < x <= a, icon 1 for a < x <= b, etc.
4891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Here the "*" represents the offset into the icon area, and since it's
4901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // between a and b, we want to return "1".
4911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    //
4921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Transformed "icon area":
4931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    //   0        a     *  b        c
4941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    //   |        |        |        |
4951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    //   |[ICON]  |[ICON]  |[ICON]  |
4961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // If we shift both our offset and our divider points later by half an icon
4971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // plus one spacing unit, then it becomes very easy to calculate how many
4981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // divider points we've passed, because they're the multiples of "one icon
4991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // plus padding".
5001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int before_icon_unclamped =
5011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        (offset_into_icon_area + (IconWidth(false) / 2) +
5021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        kItemSpacing) / IconWidth(true);
5031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // We need to figure out how many icons are visible on the relevant row.
5051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // In the main container, this will just be the visible actions.
5061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int visible_icons_on_row = VisibleBrowserActionsAfterAnimation();
5071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (in_overflow_mode()) {
5081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // If this is the final row of the overflow, then this is the remainder of
5091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // visible icons. Otherwise, it's a full row (kIconsPerRow).
5101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      visible_icons_on_row =
5111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          row_index ==
5121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              static_cast<size_t>(visible_icons_on_row /
5131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  icons_per_overflow_menu_row_) ?
5141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  visible_icons_on_row % icons_per_overflow_menu_row_ :
5151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  icons_per_overflow_menu_row_;
5161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
5175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Because the user can drag outside the container bounds, we need to clamp
5191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // to the valid range. Note that the maximum allowable value is (num icons),
5201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // not (num icons - 1), because we represent the indicator being past the
5211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // last icon as being "before the (last + 1) icon".
5221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    before_icon_in_row =
5231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        std::min(std::max(before_icon_unclamped, 0), visible_icons_on_row);
5241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!drop_position_.get() ||
5275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      !(drop_position_->row == row_index &&
5285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        drop_position_->icon_in_row == before_icon_in_row)) {
5295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    drop_position_.reset(new DropPosition(row_index, before_icon_in_row));
5305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SchedulePaint();
5315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::DragDropTypes::DRAG_MOVE;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnDragExited() {
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopShowFolderDropMenuTimer();
5385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  drop_position_.reset();
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::OnPerformDrop(
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::DropTargetEvent& event) {
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserActionDragData data;
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!data.Read(event.data()))
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ui::DragDropTypes::DRAG_NONE;
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we have the same view as we started with.
5496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DCHECK_EQ(browser_action_views_[data.index()]->extension()->id(),
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            data.id());
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(model_);
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t i = drop_position_->row * icons_per_overflow_menu_row_ +
5541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci             drop_position_->icon_in_row;
5555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (in_overflow_mode())
5561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    i += main_container_->VisibleBrowserActionsAfterAnimation();
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |i| now points to the item to the right of the drop indicator*, which is
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // correct when dragging an icon to the left. When dragging to the right,
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // however, we want the icon being dragged to get the index of the item to
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the left of the drop indicator, so we subtract one.
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // * Well, it can also point to the end, but not when dragging to the left. :)
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i > data.index())
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    --i;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->IsOffTheRecord())
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    i = model_->IncognitoIndexToOriginal(i);
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If this was a drag between containers, we will have to adjust the number of
5691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // visible icons.
5701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool drag_between_containers =
5711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      !browser_action_views_[data.index()]->visible();
57203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  model_->MoveExtensionIcon(
5736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      browser_action_views_[data.index()]->extension(), i);
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (drag_between_containers) {
5761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Add one for the dropped icon.
5771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size_t new_icon_count = VisibleBrowserActionsAfterAnimation() + 1;
5781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Let the main container update the model.
5801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (in_overflow_mode())
5811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      main_container_->NotifyActionMovedToOverflow();
5821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    else if (!profile_->IsOffTheRecord())  // This is the main container.
5831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      model_->SetVisibleIconCount(model_->GetVisibleIconCount() + 1);
5841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // The size changed, so we need to animate.
5861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Animate(gfx::Tween::EASE_OUT, new_icon_count);
5871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
5881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnDragExited();  // Perform clean up after dragging.
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::DragDropTypes::DRAG_MOVE;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::GetAccessibleState(
594a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ui::AXViewState* state) {
595a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  state->role = ui::AX_ROLE_GROUP;
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_EXTENSIONS);
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnMenuButtonClicked(views::View* source,
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const gfx::Point& point) {
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (source == chevron_) {
602116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    overflow_menu_ =
603116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        new BrowserActionOverflowMenuController(this,
604116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                browser_,
605116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                chevron_,
606116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                browser_action_views_,
607116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                VisibleBrowserActions(),
608116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                false);
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_menu_->set_observer(this);
610116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    overflow_menu_->RunMenu(GetWidget());
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::WriteDragDataForView(View* sender,
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   const gfx::Point& press_pt,
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   OSExchangeData* data) {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(data);
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
6206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    BrowserActionView* view = browser_action_views_[i];
6216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (view == sender) {
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Set the dragging image for the icon.
6236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      gfx::ImageSkia badge(view->GetIconWithBadge());
624f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      drag_utils::SetDragImageOnDataObject(badge,
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           press_pt.OffsetFromOrigin(),
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           data);
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Fill in the remaining info.
6296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      BrowserActionDragData drag_data(view->extension()->id(), i);
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_data.Write(profile_, data);
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::GetDragOperationsForView(View* sender,
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      const gfx::Point& p) {
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::DragDropTypes::DRAG_MOVE;
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::CanStartDragForView(View* sender,
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const gfx::Point& press_pt,
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const gfx::Point& p) {
644effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // We don't allow dragging while we're highlighting.
645effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return !model_->is_highlighting();
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnResize(int resize_amount, bool done_resizing) {
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!done_resizing) {
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_amount_ = resize_amount;
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnBrowserActionVisibilityChanged();
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Up until now we've only been modifying the resize_amount, but now it is
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // time to set the container size to the size we have resized to, and then
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // animate to the nearest icon count size if necessary (which may be 0).
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_width = IconCountToWidth(-1, false);
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_width_ =
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::min(std::max(0, container_width_ - resize_amount), max_width);
66103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
66203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Save off the desired number of visible icons.  We do this now instead of at
66303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // the end of the animation so that even if the browser is shut down while
66403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // animating, the right value will be restored on next run.
66503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // NOTE: Don't save the icon count in incognito because there may be fewer
66603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // icons in that mode. The result is that the container in a normal window is
66703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // always at least as wide as in an incognito window.
66803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int visible_icons = WidthToIconCount(container_width_);
66903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!profile_->IsOffTheRecord())
67003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    model_->SetVisibleIconCount(visible_icons);
67103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  Animate(gfx::Tween::EASE_OUT, visible_icons);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::AnimationProgressed(
675d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const gfx::Animation* animation) {
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(resize_animation_.get(), animation);
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_amount_ = static_cast<int>(resize_animation_->GetCurrentValue() *
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (container_width_ - animation_target_size_));
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnBrowserActionVisibilityChanged();
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
682d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void BrowserActionsContainer::AnimationEnded(const gfx::Animation* animation) {
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_width_ = animation_target_size_;
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  animation_target_size_ = 0;
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_amount_ = 0;
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  suppress_chevron_ = false;
6871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SetChevronVisibility();
688a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  OnBrowserActionVisibilityChanged();
689effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
690effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  FOR_EACH_OBSERVER(BrowserActionsContainerObserver,
691effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    observers_,
692effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    OnBrowserActionsContainerAnimationEnded());
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::NotifyMenuDeleted(
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserActionOverflowMenuController* controller) {
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(overflow_menu_, controller);
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_ = NULL;
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)content::WebContents* BrowserActionsContainer::GetCurrentWebContents() {
7025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return browser_->tab_strip_model()->GetActiveWebContents();
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extensions::ActiveTabPermissionGranter*
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserActionsContainer::GetActiveTabPermissionGranter() {
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::WebContents* web_contents =
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      browser_->tab_strip_model()->GetActiveWebContents();
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!web_contents)
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return extensions::TabHelper::FromWebContents(web_contents)->
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      active_tab_permission_granter();
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ExtensionPopup* BrowserActionsContainer::TestGetPopup() {
7165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return popup_owner_ ? popup_owner_->view_controller()->popup() : NULL;
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) {
7201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  model_->SetVisibleIconCountForTest(icons);
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnPaint(gfx::Canvas* canvas) {
724effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // If the views haven't been initialized yet, wait for the next call to
725effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // paint (one will be triggered by entering highlight mode).
726effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (model_->is_highlighting() && !browser_action_views_.empty()) {
727effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    views::Painter::PaintPainterAt(
728effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        canvas, highlight_painter_.get(), GetLocalBounds());
729effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
730effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sky/glen): Instead of using a drop indicator, animate the icons while
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dragging (like we do for tab dragging).
7335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (drop_position_.get()) {
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The two-pixel width drop indicator.
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const int kDropIndicatorWidth = 2;
7365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Convert back to a pixel offset into the container.  First find the X
7385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // coordinate of the drop icon.
7391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int drop_icon_x = ToolbarView::kStandardSpacing +
7405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        (drop_position_->icon_in_row * IconWidth(true));
7415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Next, find the space before the drop icon. This will either be
7425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // kItemSpacing or ToolbarView::kStandardSpacing, depending on whether this
7435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // is the first icon.
7445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // NOTE: Right now, these are the same. But let's do this right for if they
7455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // ever aren't.
7465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int space_before_drop_icon = drop_position_->icon_in_row == 0 ?
7475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ToolbarView::kStandardSpacing : kItemSpacing;
7485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Now place the drop indicator halfway between this and the end of the
7495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // previous icon.  If there is an odd amount of available space between the
7505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // two icons (or the icon and the address bar) after subtracting the drop
7515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // indicator width, this calculation puts the extra pixel on the left side
7525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // of the indicator, since when the indicator is between the address bar and
7535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // the first icon, it looks better closer to the icon.
7545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int drop_indicator_x = drop_icon_x -
7555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ((space_before_drop_icon + kDropIndicatorWidth) / 2);
7565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int row_height = IconHeight();
7575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int drop_indicator_y = row_height * drop_position_->row;
7585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    gfx::Rect indicator_bounds(drop_indicator_x,
7595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               drop_indicator_y,
7605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               kDropIndicatorWidth,
7615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               row_height);
7625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    indicator_bounds.set_x(GetMirroredXForRect(indicator_bounds));
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Color of the drop indicator.
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const SkColor kDropIndicatorColor = SK_ColorBLACK;
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canvas->FillRect(indicator_bounds, kDropIndicatorColor);
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnThemeChanged() {
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadImages();
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
774a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void BrowserActionsContainer::ViewHierarchyChanged(
775a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const ViewHierarchyChangedDetails& details) {
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No extensions (e.g., incognito).
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!model_)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
780a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (details.is_add && details.child == this) {
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Initial toolbar button creation and placement in the widget hierarchy.
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We do this here instead of in the constructor because AddBrowserAction
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // calls Layout on the Toolbar, which needs this object to be constructed
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // before its Layout function is called.
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CreateBrowserActionViews();
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::IconWidth(bool include_padding) {
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool initialized = false;
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int icon_width = 0;
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized) {
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    initialized = true;
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_width = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDR_BROWSER_ACTION)->width();
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return icon_width + (include_padding ? kItemSpacing : 0);
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::IconHeight() {
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool initialized = false;
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int icon_height = 0;
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized) {
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    initialized = true;
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_height = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDR_BROWSER_ACTION)->height();
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return icon_height;
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
81303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::ToolbarExtensionAdded(const Extension* extension,
81403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                                    int index) {
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(DEBUG)
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
8176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DCHECK(browser_action_views_[i]->extension() != extension) <<
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           "Asked to add a browser action view for an extension that already "
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           "exists.";
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseOverflowMenu();
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
824f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!ShouldDisplayBrowserAction(extension))
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the new browser action to the vector and the view hierarchy.
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->IsOffTheRecord())
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = model_->OriginalIndexToIncognito(index);
83003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserActionView* view =
83103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      new BrowserActionView(extension,
8321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            extensions::ExtensionActionManager::Get(profile_)->
8331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                GetExtensionAction(*extension),
83403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            browser_,
83503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            this);
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  browser_action_views_.insert(browser_action_views_.begin() + index, view);
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildViewAt(view, index);
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we are still initializing the container, don't bother animating.
840f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!model_->extensions_initialized())
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If this is just an upgrade, then don't worry about resizing.
8441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!extensions::ExtensionSystem::Get(profile_)->runtime_data()->
8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          IsBeingUpgraded(extension)) {
8461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // We need to resize if either:
8471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // - The container is set to display all icons (visible count = -1), or
8481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // - The container will need to expand to include the chevron. This can
8491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    //   happen when the container is set to display <n> icons, where <n> is
8501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    //   the number of icons before the new icon. With the new icon, the chevron
8511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    //   will need to be displayed.
8521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int model_icon_count = model_->GetVisibleIconCount();
8531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (model_icon_count == -1 ||
8541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        (static_cast<size_t>(model_icon_count) < browser_action_views_.size() &&
8551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         (chevron_ && !chevron_->visible()))) {
8561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      suppress_chevron_ = true;
8571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      Animate(gfx::Tween::LINEAR, GetIconCount());
8581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
8591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
8621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Otherwise, we don't have to resize, so just redraw the (possibly modified)
8631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // visible icon set.
8641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  OnBrowserActionVisibilityChanged();
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
86703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::ToolbarExtensionRemoved(
86803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const Extension* extension) {
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseOverflowMenu();
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
87146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  size_t visible_actions = VisibleBrowserActionsAfterAnimation();
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (BrowserActionViews::iterator i(browser_action_views_.begin());
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != browser_action_views_.end(); ++i) {
8746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if ((*i)->extension() == extension) {
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete *i;
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser_action_views_.erase(i);
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the extension is being upgraded we don't want the bar to shrink
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // because the icon is just going to get re-added to the same location.
8805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (extensions::ExtensionSystem::Get(profile_)->runtime_data()->
8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              IsBeingUpgraded(extension))
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (browser_action_views_.size() > visible_actions) {
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If we have more icons than we can show, then we must not be changing
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // the container size (since we either removed an icon from the main
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // area and one from the overflow list will have shifted in, or we
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // removed an entry directly from the overflow list).
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnBrowserActionVisibilityChanged();
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Either we went from overflow to no-overflow, or we shrunk the no-
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // overflow container by 1.  Either way the size changed, so animate.
893116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (chevron_)
894116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          chevron_->SetVisible(false);
89503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        Animate(gfx::Tween::EASE_OUT, browser_action_views_.size());
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
897116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return;  // We have found the action to remove, bail out.
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
90203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::ToolbarExtensionMoved(const Extension* extension,
90303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                                    int index) {
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShouldDisplayBrowserAction(extension))
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->IsOffTheRecord())
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = model_->OriginalIndexToIncognito(index);
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(index >= 0 && index < static_cast<int>(browser_action_views_.size()));
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
91203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserActionViews::iterator iter = browser_action_views_.begin();
91303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int old_index = 0;
91403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  while (iter != browser_action_views_.end() &&
91503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)         (*iter)->extension() != extension) {
91603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ++iter;
91703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ++old_index;
91803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
91903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
92003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(iter != browser_action_views_.end());
92103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (old_index == index)
92203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return;  // Already in place.
92303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
92403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserActionView* moved_view = *iter;
92503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  browser_action_views_.erase(iter);
92603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  browser_action_views_.insert(
92703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      browser_action_views_.begin() + index, moved_view);
92803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
93303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::ToolbarExtensionUpdated(
93403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const Extension* extension) {
93503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserActionView* view = GetViewForExtension(extension);
93603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (view)
93703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    view->UpdateState();
93803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
93903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
94003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool BrowserActionsContainer::ShowExtensionActionPopup(
9411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const Extension* extension,
9421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bool grant_active_tab) {
9431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Don't override another popup, and only show in the active window.
9441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (popup_owner_ || !browser_->window()->IsActive())
9451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return false;
9461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
9471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  BrowserActionView* view = GetViewForExtension(extension);
9481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return view && view->view_controller()->ExecuteAction(ExtensionPopup::SHOW,
9491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                        grant_active_tab);
9508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
9518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
95203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::ToolbarVisibleCountChanged() {
9531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (GetPreferredWidth() != container_width_)
95403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    Animate(gfx::Tween::EASE_OUT, GetIconCount());
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::ToolbarHighlightModeChanged(
95803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    bool is_highlighting) {
959effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // The visual highlighting is done in OnPaint(). It's a bit of a pain that
96003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // we delete and recreate everything here, but given everything else going on
96103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // (the lack of highlight, n more extensions appearing, etc), it's not worth
96203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // the extra complexity to create and insert only the new extensions.
963effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DeleteBrowserActionViews();
964effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CreateBrowserActionViews();
9651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Animate(gfx::Tween::LINEAR, GetIconCount());
9661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
9671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
9681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciBrowser* BrowserActionsContainer::GetBrowser() {
9691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return browser_;
970effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
971effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::LoadImages() {
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::ThemeProvider* tp = GetThemeProvider();
974116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!tp || !chevron_)
975116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
976116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
977f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  chevron_->SetImage(views::Button::STATE_NORMAL,
978f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     *tp->GetImageSkiaNamed(IDR_BROWSER_ACTIONS_OVERFLOW));
979effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
980effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const int kImages[] = IMAGE_GRID(IDR_DEVELOPER_MODE_HIGHLIGHT);
981effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  highlight_painter_.reset(views::Painter::CreateImageGridPainter(kImages));
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
98403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::OnBrowserActionVisibilityChanged() {
98503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  SetVisible(!browser_action_views_.empty());
98603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (owner_view_) {
98703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    owner_view_->Layout();
98803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    owner_view_->SchedulePaint();
9891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
9901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // In overflow mode, we don't have an owner view, but we still have to
9911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // update ourselves.
9921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Layout();
9931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    SchedulePaint();
99403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
99503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
99603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
9971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint BrowserActionsContainer::GetPreferredWidth() {
9981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t visible_actions = GetIconCount();
9991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return IconCountToWidth(
10001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      visible_actions,
10011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      chevron_ && visible_actions < browser_action_views_.size());
10021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
10031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
10041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BrowserActionsContainer::SetChevronVisibility() {
1005116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (chevron_) {
1006116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    chevron_->SetVisible(
10071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        VisibleBrowserActionsAfterAnimation() < browser_action_views_.size());
1008116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::CloseOverflowMenu() {
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (overflow_menu_)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_menu_->CancelMenu();
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::StopShowFolderDropMenuTimer() {
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  show_menu_task_factory_.InvalidateWeakPtrs();
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::StartShowFolderDropMenuTimer() {
1021b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&BrowserActionsContainer::ShowDropFolder,
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 show_menu_task_factory_.GetWeakPtr()),
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(views::GetMenuShowDelay()));
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::ShowDropFolder() {
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!overflow_menu_);
1030116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  overflow_menu_ =
1031116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new BrowserActionOverflowMenuController(this,
1032116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              browser_,
1033116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              chevron_,
1034116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              browser_action_views_,
1035116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              VisibleBrowserActions(),
1036116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              true);
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_->set_observer(this);
1038116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  overflow_menu_->RunMenu(GetWidget());
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::IconCountToWidth(int icons,
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              bool display_chevron) const {
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (icons < 0)
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icons = browser_action_views_.size();
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((icons == 0) && !display_chevron)
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ToolbarView::kStandardSpacing;
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int icons_size =
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (icons == 0) ? 0 : ((icons * IconWidth(true)) - kItemSpacing);
1049116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int chevron_size = chevron_ && display_chevron ?
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (kChevronSpacing + chevron_->GetPreferredSize().width()) : 0;
10511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // In overflow mode, our padding is to use item spacing on either end (just so
10521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // we can see the drop indicator). Otherwise we use the standard toolbar
10531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // spacing.
10541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Note: These are actually the same thing, but, on the offchance one
10551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // changes, let's get it right.
10561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int padding =
10571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      2 * (in_overflow_mode() ? kItemSpacing : ToolbarView::kStandardSpacing);
10581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return icons_size + chevron_size + padding;
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t BrowserActionsContainer::WidthToIconCount(int pixels) const {
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for widths large enough to show the entire icon set.
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pixels >= IconCountToWidth(-1, false))
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return browser_action_views_.size();
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // We reserve space for the padding on either side of the toolbar...
10671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int available_space = pixels - (ToolbarView::kStandardSpacing * 2);
10681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // ... and, if the chevron is enabled, the chevron.
10691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (chevron_)
10701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    available_space -= (chevron_->GetPreferredSize().width() + kChevronSpacing);
10711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now we add an extra between-item padding value so the space can be divided
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // evenly by (size of icon with padding).
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<size_t>(
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::max(0, available_space + kItemSpacing) / IconWidth(true));
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1078cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int BrowserActionsContainer::MinimumNonemptyWidth() const {
1079116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!chevron_)
1080116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return ToolbarView::kStandardSpacing;
1081116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return (ToolbarView::kStandardSpacing * 2) + kChevronSpacing +
1082116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chevron_->GetPreferredSize().width();
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
108503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::Animate(gfx::Tween::Type tween_type,
108603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                      size_t num_visible_icons) {
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int target_size = IconCountToWidth(num_visible_icons,
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      num_visible_icons < browser_action_views_.size());
1089116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (resize_animation_ && !disable_animations_during_testing_) {
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Animate! We have to set the animation_target_size_ after calling Reset(),
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // because that could end up calling AnimationEnded which clears the value.
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_animation_->Reset();
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_animation_->SetTweenType(tween_type);
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    animation_target_size_ = target_size;
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_animation_->Show();
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    animation_target_size_ = target_size;
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AnimationEnded(resize_animation_.get());
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::ShouldDisplayBrowserAction(
110303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const Extension* extension) const {
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only display incognito-enabled extensions while in incognito mode.
11055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return !profile_->IsOffTheRecord() ||
11065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      extensions::util::IsIncognitoEnabled(extension->id(), profile_);
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
110903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)size_t BrowserActionsContainer::GetIconCount() const {
111003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!model_)
111103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return 0u;
11121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const extensions::ExtensionList& extensions = model_->toolbar_items();
11141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Find the absolute value for the model's visible count.
11161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int model_visible_size = model_->GetVisibleIconCount();
11171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t absolute_model_visible_size =
11181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      model_visible_size == -1 ? extensions.size() : model_visible_size;
11191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
112003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Find the number of icons which could be displayed.
112103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  size_t displayable_icon_count = 0u;
11221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t main_displayed = 0u;
11231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < extensions.size(); ++i) {
11241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Should there be an icon for this extension at all?
11251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (ShouldDisplayBrowserAction(extensions[i].get())) {
11261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ++displayable_icon_count;
11271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // Should we display it on the main bar? If this is an incognito window,
11281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // icons have the same overflow status they do in a regular window.
11291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      main_displayed += i < absolute_model_visible_size ? 1u : 0u;
11301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
11315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
11321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If this is an existing (initialized) container from an incognito profile,
11341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // we can't trust the model (because the incognito bars don't adjust model
11351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // settings). Instead, we go off what we currently have displayed.
11361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (initialized_ && profile_->IsOffTheRecord()) {
11371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    main_displayed = in_overflow_mode() ?
11381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        main_container_->VisibleBrowserActionsAfterAnimation() :
11391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        VisibleBrowserActionsAfterAnimation();
11401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
11411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The overflow displays any (displayable) icons not shown by the main bar.
114303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return in_overflow_mode() ?
114403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      displayable_icon_count - main_displayed : main_displayed;
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1146