browser_actions_container.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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_keybinding_registry_views.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/extensions/extension_popup.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"
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/extension_registry.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/runtime_data.h"
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/feature_switch.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.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 between most items in the container, as well as after the
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// last item or chevron (if visible).
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kItemSpacing = ToolbarView::kStandardSpacing;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Horizontal spacing before the chevron (if visible).
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kChevronSpacing = kItemSpacing - 2;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// The maximum number of icons to show per row when in overflow mode (showing
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// icons in the application menu).
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// TODO(devlin): Compute the right number of icons to show, depending on the
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch//               menu width.
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(OS_LINUX)
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst int kIconsPerMenuRow = 8;  // The menu on Linux is wider.
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#else
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst int kIconsPerMenuRow = 7;
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
6903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Returns the ExtensionAction for the given |extension|.
7003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)ExtensionAction* GetExtensionAction(const Extension& extension,
7103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                    Profile* profile) {
7203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  extensions::ExtensionActionManager* action_manager =
7303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      extensions::ExtensionActionManager::Get(profile);
7403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ExtensionAction* action = action_manager->GetBrowserAction(extension);
7503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return action ? action : action_manager->GetPageAction(extension);
7603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
7703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// A version of MenuButton with almost empty insets to fit properly on the
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// toolbar.
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class ChevronMenuButton : public views::MenuButton {
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public:
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ChevronMenuButton(views::ButtonListener* listener,
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    const base::string16& text,
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    views::MenuButtonListener* menu_button_listener,
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    bool show_menu_marker)
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      : views::MenuButton(listener,
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          text,
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          menu_button_listener,
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          show_menu_marker) {
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual ~ChevronMenuButton() {}
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual scoped_ptr<views::LabelButtonBorder> CreateDefaultBorder() const
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      OVERRIDE {
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // The chevron resource was designed to not have any insets.
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    scoped_ptr<views::LabelButtonBorder> border =
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        views::MenuButton::CreateDefaultBorder();
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    border->set_insets(gfx::Insets());
100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return border.Pass();
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private:
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ChevronMenuButton);
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// BrowserActionsContainer::DropPosition
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)struct BrowserActionsContainer::DropPosition {
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DropPosition(size_t row, size_t icon_in_row);
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // The (0-indexed) row into which the action will be dropped.
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  size_t row;
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // The (0-indexed) icon in the row before the action will be dropped.
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  size_t icon_in_row;
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)BrowserActionsContainer::DropPosition::DropPosition(
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    size_t row, size_t icon_in_row)
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : row(row), icon_in_row(icon_in_row) {
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BrowserActionsContainer
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// static
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BrowserActionsContainer::disable_animations_during_testing_ = false;
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
133116680a4aac90f2aa7413d9095a592090648e557Ben MurdochBrowserActionsContainer::BrowserActionsContainer(
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Browser* browser,
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    View* owner_view,
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BrowserActionsContainer* main_container)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : profile_(browser->profile()),
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser_(browser),
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      owner_view_(owner_view),
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      main_container_(main_container),
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      popup_owner_(NULL),
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_(NULL),
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      container_width_(0),
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      resize_area_(NULL),
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chevron_(NULL),
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      overflow_menu_(NULL),
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      suppress_chevron_(false),
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resize_amount_(0),
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      animation_target_size_(0),
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      task_factory_(this),
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      show_menu_task_factory_(this) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_id(VIEW_ID_BROWSER_ACTION_TOOLBAR);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  model_ = extensions::ExtensionToolbarModel::Get(browser->profile());
155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (model_)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->AddObserver(this);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool overflow_experiment =
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extensions::FeatureSwitch::extension_action_redesign()->IsEnabled();
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!in_overflow_mode() || overflow_experiment);
161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!in_overflow_mode()) {
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryViews(
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        browser->profile(),
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        owner_view->GetFocusManager(),
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        extensions::ExtensionKeybindingRegistry::ALL_EXTENSIONS,
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this));
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    resize_animation_.reset(new gfx::SlideAnimation(this));
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    resize_area_ = new views::ResizeArea(this);
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    AddChildView(resize_area_);
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // 'Main' mode doesn't need a chevron overflow when overflow is shown inside
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // the Chrome menu.
175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!overflow_experiment) {
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chevron_ = new ChevronMenuButton(NULL, base::string16(), this, false);
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chevron_->SetBorder(views::Border::NullBorder());
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chevron_->EnableCanvasFlippingForRTLUI(true);
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chevron_->SetAccessibleName(
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          l10n_util::GetStringUTF16(IDS_ACCNAME_EXTENSIONS_CHEVRON));
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chevron_->SetVisible(false);
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      AddChildView(chevron_);
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BrowserActionsContainer::~BrowserActionsContainer() {
188effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  FOR_EACH_OBSERVER(BrowserActionsContainerObserver,
189effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    observers_,
190effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    OnBrowserActionsContainerDestroyed());
191effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (overflow_menu_)
1937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    overflow_menu_->set_observer(NULL);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->RemoveObserver(this);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopShowFolderDropMenuTimer();
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  HideActivePopup();
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteBrowserActionViews();
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::Init() {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadImages();
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We wait to set the container width until now so that the chevron images
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be loaded.  The width calculation needs to know the chevron size.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_ && model_->extensions_initialized())
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetContainerWidth();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BrowserActionView* BrowserActionsContainer::GetBrowserActionView(
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExtensionAction* action) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (BrowserActionViews::iterator i(browser_action_views_.begin());
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != browser_action_views_.end(); ++i) {
2146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if ((*i)->extension_action() == action)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return *i;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::RefreshBrowserActionViews() {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i)
2226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    browser_action_views_[i]->UpdateState();
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::CreateBrowserActionViews() {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(browser_action_views_.empty());
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!model_)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const extensions::ExtensionList& toolbar_items = model_->toolbar_items();
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (extensions::ExtensionList::const_iterator i(toolbar_items.begin());
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != toolbar_items.end(); ++i) {
2337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!ShouldDisplayBrowserAction(i->get()))
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    BrowserActionView* view =
23703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        new BrowserActionView(i->get(),
23803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                              GetExtensionAction(*i->get(), profile_),
23903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                              browser_,
24003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                              this);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_action_views_.push_back(view);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddChildView(view);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::DeleteBrowserActionViews() {
2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  HideActivePopup();
248116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (overflow_menu_)
249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    overflow_menu_->NotifyBrowserActionViewsDeleting();
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&browser_action_views_);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t BrowserActionsContainer::VisibleBrowserActions() const {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t visible_actions = 0;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (browser_action_views_[i]->visible())
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++visible_actions;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return visible_actions;
26046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
26146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
26246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)size_t BrowserActionsContainer::VisibleBrowserActionsAfterAnimation() const {
26346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!animating())
26446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return VisibleBrowserActions();
26546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return WidthToIconCount(animation_target_size_);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BrowserActionsContainer::ExecuteExtensionCommand(
270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const extensions::Extension* extension,
271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const extensions::Command& command) {
272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Global commands are handled by the ExtensionCommandsGlobalRegistry
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // instance.
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!command.global());
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  extension_keybinding_registry_->ExecuteCommand(extension->id(),
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                 command.accelerator());
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
279116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool BrowserActionsContainer::ShownInsideMenu() const {
280116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return in_overflow_mode();
281116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BrowserActionsContainer::OnBrowserActionViewDragDone() {
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // We notify here as well as in OnPerformDrop because the dragged view is
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // removed in OnPerformDrop, so it will never get its OnDragDone() call.
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(devlin): we should see about fixing that.
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(BrowserActionsContainerObserver,
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    observers_,
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    OnBrowserActionDragDone());
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)views::View* BrowserActionsContainer::GetOverflowReferenceView() {
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // We should only need an overflow reference when using the traditional
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // chevron overflow.
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(chevron_);
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return chevron_;
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void BrowserActionsContainer::SetPopupOwner(BrowserActionView* popup_owner) {
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // We should never be setting a popup owner when one already exists.
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(!popup_owner_ || !popup_owner);
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  popup_owner_ = popup_owner;
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BrowserActionsContainer::HideActivePopup() {
3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (popup_owner_)
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    popup_owner_->view_controller()->HidePopup();
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
310effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BrowserActionsContainer::AddObserver(
311effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    BrowserActionsContainerObserver* observer) {
312effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  observers_.AddObserver(observer);
313effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
314effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
315effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BrowserActionsContainer::RemoveObserver(
316effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    BrowserActionsContainerObserver* observer) {
317effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  observers_.RemoveObserver(observer);
318effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
319effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size BrowserActionsContainer::GetPreferredSize() const {
32103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  size_t icon_count = GetIconCount();
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // If there are no actions to show, or we are in overflow mode and the main
324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // container is already showing them all, then no further work is required.
325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (icon_count == 0)
326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return gfx::Size();
327116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
328116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (in_overflow_mode()) {
329116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // When in overflow, y is multiline, so the pixel count is IconHeight()
330116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // times the number of rows needed.
331116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return gfx::Size(
332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        IconCountToWidth(kIconsPerMenuRow, false),
333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        (((icon_count - 1) / kIconsPerMenuRow) + 1) * IconHeight());
334116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
335116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We calculate the size of the view by taking the current width and
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // subtracting resize_amount_ (the latter represents how far the user is
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // resizing the view or, if animating the snapping, how far to animate it).
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // But we also clamp it to a minimum size and the maximum size, so that the
340116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // container can never shrink too far or take up more space than it needs.
341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // In other words: MinimumNonemptyWidth() < width() - resize < ClampTo(MAX).
342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int preferred_width = std::min(
343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      std::max(MinimumNonemptyWidth(), container_width_ - resize_amount_),
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IconCountToWidth(-1, false));
345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return gfx::Size(preferred_width, IconHeight());
346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size BrowserActionsContainer::GetMinimumSize() const {
349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int min_width = std::min(MinimumNonemptyWidth(), IconCountToWidth(-1, false));
350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return gfx::Size(min_width, IconHeight());
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::Layout() {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (browser_action_views_.empty()) {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetVisible(false);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVisible(true);
360116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (resize_area_)
361116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    resize_area_->SetBounds(0, 0, kItemSpacing, height());
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the icons don't all fit, show the chevron (unless suppressed).
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_x = GetPreferredSize().width();
365116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if ((IconCountToWidth(-1, false) > max_x) && !suppress_chevron_ && chevron_) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chevron_->SetVisible(true);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Size chevron_size(chevron_->GetPreferredSize());
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    max_x -=
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ToolbarView::kStandardSpacing + chevron_size.width() + kChevronSpacing;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chevron_->SetBounds(
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        width() - ToolbarView::kStandardSpacing - chevron_size.width(),
372effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        0,
373effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        chevron_size.width(),
374effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        chevron_size.height());
375116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else if (chevron_) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chevron_->SetVisible(false);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now draw the icons for the browser actions in the available space.
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int icon_width = IconWidth(false);
381116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (in_overflow_mode()) {
382116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (size_t i = 0;
383116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         i < main_container_->VisibleBrowserActionsAfterAnimation(); ++i) {
384116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // Ensure that any browser actions shown in the main view are hidden in
385116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // the overflow view.
386116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      browser_action_views_[i]->SetVisible(false);
387116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
388116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
389116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (size_t i = main_container_->VisibleBrowserActionsAfterAnimation();
390116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         i < browser_action_views_.size(); ++i) {
391116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      BrowserActionView* view = browser_action_views_[i];
392116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      size_t index = i - main_container_->VisibleBrowserActionsAfterAnimation();
393116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      int row_index = static_cast<int>(index) / kIconsPerMenuRow;
3945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      int x = kItemSpacing + (index * IconWidth(true)) -
395116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          (row_index * IconWidth(true) * kIconsPerMenuRow);
396116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      gfx::Rect rect_bounds(
397116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          x, IconHeight() * row_index, icon_width, IconHeight());
398116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      view->SetBoundsRect(rect_bounds);
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view->SetVisible(true);
400116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
401116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
402116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (BrowserActionViews::const_iterator it = browser_action_views_.begin();
403116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         it < browser_action_views_.end(); ++it) {
404116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      BrowserActionView* view = *it;
405116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      int x = ToolbarView::kStandardSpacing +
406116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          ((it - browser_action_views_.begin()) * IconWidth(true));
407116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      view->SetVisible(x + icon_width <= max_x);
408116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (view->visible())
409116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        view->SetBounds(x, 0, icon_width, IconHeight());
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::GetDropFormats(
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int* formats,
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::set<OSExchangeData::CustomFormat>* custom_formats) {
4175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return BrowserActionDragData::GetDropFormats(custom_formats);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::AreDropTypesRequired() {
4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return BrowserActionDragData::AreDropTypesRequired();
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::CanDrop(const OSExchangeData& data) {
4255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return BrowserActionDragData::CanDrop(data, profile_);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnDragEntered(
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::DropTargetEvent& event) {
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::OnDragUpdated(
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::DropTargetEvent& event) {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First check if we are above the chevron (overflow) menu.
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetEventHandlerForPoint(event.location()) == chevron_) {
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!show_menu_task_factory_.HasWeakPtrs() && !overflow_menu_)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StartShowFolderDropMenuTimer();
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ui::DragDropTypes::DRAG_MOVE;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopShowFolderDropMenuTimer();
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Figure out where to display the indicator.  This is a complex calculation:
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First, we figure out how much space is to the left of the icon area, so we
4455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // can calculate the true offset into the icon area. The easiest way to do
4465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // this is to just find where the first icon starts.
4475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int width_before_icons =
4485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      browser_action_views_[GetFirstVisibleIconIndex()]->x();
4495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // If we're right-to-left, we flip the mirror the event.x() so that our
4515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // calculations are consistent with left-to-right.
4525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int offset_into_icon_area =
4535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      GetMirroredXInView(event.x()) - width_before_icons;
4545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Next, figure out what row we're on. This only matters for overflow mode,
4565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // but the calculation is the same for both.
4575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  size_t row_index = event.y() / IconHeight();
4585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Sanity check - we should never be on a different row in the main container.
4605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(in_overflow_mode() || row_index == 0);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Next, we determine which icon to place the indicator in front of.  We want
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to place the indicator in front of icon n when the cursor is between the
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // midpoints of icons (n - 1) and n.  To do this we take the offset into the
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon area and transform it as follows:
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Real icon area:
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   0   a     *  b        c
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   |   |        |        |
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   |[IC|ON]  [IC|ON]  [IC|ON]
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We want to be before icon 0 for 0 < x <= a, icon 1 for a < x <= b, etc.
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Here the "*" represents the offset into the icon area, and since it's
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // between a and b, we want to return "1".
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Transformed "icon area":
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   0        a     *  b        c
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   |        |        |        |
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   |[ICON]  |[ICON]  |[ICON]  |
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we shift both our offset and our divider points later by half an icon
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // plus one spacing unit, then it becomes very easy to calculate how many
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // divider points we've passed, because they're the multiples of "one icon
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // plus padding".
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int before_icon_unclamped = (offset_into_icon_area + (IconWidth(false) / 2) +
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kItemSpacing) / IconWidth(true);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // We need to figure out how many icons are visible on the relevant row.
4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // In the main container, this will just be the visible actions.
4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int visible_icons_on_row = VisibleBrowserActionsAfterAnimation();
4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (in_overflow_mode()) {
4905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // If this is the final row of the overflow, then this is the remainder of
4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // visible icons. Otherwise, it's a full row (kIconsPerRow).
4925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    visible_icons_on_row =
4935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        row_index ==
4945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            static_cast<size_t>(visible_icons_on_row / kIconsPerMenuRow) ?
4955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                visible_icons_on_row % kIconsPerMenuRow :
4965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                kIconsPerMenuRow;
4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Because the user can drag outside the container bounds, we need to clamp to
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the valid range.  Note that the maximum allowable value is (num icons), not
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (num icons - 1), because we represent the indicator being past the last
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon as being "before the (last + 1) icon".
5035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  size_t before_icon_in_row =
5045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      std::min(std::max(before_icon_unclamped, 0), visible_icons_on_row);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!drop_position_.get() ||
5075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      !(drop_position_->row == row_index &&
5085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        drop_position_->icon_in_row == before_icon_in_row)) {
5095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    drop_position_.reset(new DropPosition(row_index, before_icon_in_row));
5105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SchedulePaint();
5115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::DragDropTypes::DRAG_MOVE;
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnDragExited() {
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopShowFolderDropMenuTimer();
5185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  drop_position_.reset();
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::OnPerformDrop(
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::DropTargetEvent& event) {
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserActionDragData data;
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!data.Read(event.data()))
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ui::DragDropTypes::DRAG_NONE;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we have the same view as we started with.
5296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DCHECK_EQ(browser_action_views_[data.index()]->extension()->id(),
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            data.id());
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(model_);
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  size_t i =
5345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      drop_position_->row * kIconsPerMenuRow + drop_position_->icon_in_row;
5355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (in_overflow_mode())
5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    i += GetFirstVisibleIconIndex();
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |i| now points to the item to the right of the drop indicator*, which is
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // correct when dragging an icon to the left. When dragging to the right,
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // however, we want the icon being dragged to get the index of the item to
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the left of the drop indicator, so we subtract one.
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // * Well, it can also point to the end, but not when dragging to the left. :)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i > data.index())
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    --i;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->IsOffTheRecord())
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    i = model_->IncognitoIndexToOriginal(i);
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  model_->MoveExtensionIcon(
5496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      browser_action_views_[data.index()]->extension(), i);
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnDragExited();  // Perform clean up after dragging.
5525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(BrowserActionsContainerObserver,
5535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    observers_,
5545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    OnBrowserActionDragDone());
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::DragDropTypes::DRAG_MOVE;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::GetAccessibleState(
559a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ui::AXViewState* state) {
560a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  state->role = ui::AX_ROLE_GROUP;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_EXTENSIONS);
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnMenuButtonClicked(views::View* source,
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const gfx::Point& point) {
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (source == chevron_) {
567116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    overflow_menu_ =
568116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        new BrowserActionOverflowMenuController(this,
569116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                browser_,
570116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                chevron_,
571116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                browser_action_views_,
572116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                VisibleBrowserActions(),
573116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                false);
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_menu_->set_observer(this);
575116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    overflow_menu_->RunMenu(GetWidget());
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::WriteDragDataForView(View* sender,
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   const gfx::Point& press_pt,
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   OSExchangeData* data) {
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(data);
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
5856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    BrowserActionView* view = browser_action_views_[i];
5866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (view == sender) {
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Set the dragging image for the icon.
5886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      gfx::ImageSkia badge(view->GetIconWithBadge());
589f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      drag_utils::SetDragImageOnDataObject(badge,
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           press_pt.OffsetFromOrigin(),
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           data);
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Fill in the remaining info.
5946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      BrowserActionDragData drag_data(view->extension()->id(), i);
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_data.Write(profile_, data);
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::GetDragOperationsForView(View* sender,
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      const gfx::Point& p) {
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::DragDropTypes::DRAG_MOVE;
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::CanStartDragForView(View* sender,
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const gfx::Point& press_pt,
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const gfx::Point& p) {
609effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // We don't allow dragging while we're highlighting.
610effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return !model_->is_highlighting();
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnResize(int resize_amount, bool done_resizing) {
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!done_resizing) {
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_amount_ = resize_amount;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnBrowserActionVisibilityChanged();
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Up until now we've only been modifying the resize_amount, but now it is
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // time to set the container size to the size we have resized to, and then
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // animate to the nearest icon count size if necessary (which may be 0).
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_width = IconCountToWidth(-1, false);
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_width_ =
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::min(std::max(0, container_width_ - resize_amount), max_width);
62603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
62703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Save off the desired number of visible icons.  We do this now instead of at
62803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // the end of the animation so that even if the browser is shut down while
62903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // animating, the right value will be restored on next run.
63003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // NOTE: Don't save the icon count in incognito because there may be fewer
63103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // icons in that mode. The result is that the container in a normal window is
63203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // always at least as wide as in an incognito window.
63303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int visible_icons = WidthToIconCount(container_width_);
63403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!profile_->IsOffTheRecord())
63503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    model_->SetVisibleIconCount(visible_icons);
63603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
63703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  Animate(gfx::Tween::EASE_OUT, visible_icons);
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::AnimationProgressed(
641d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const gfx::Animation* animation) {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(resize_animation_.get(), animation);
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_amount_ = static_cast<int>(resize_animation_->GetCurrentValue() *
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (container_width_ - animation_target_size_));
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnBrowserActionVisibilityChanged();
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
648d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void BrowserActionsContainer::AnimationEnded(const gfx::Animation* animation) {
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_width_ = animation_target_size_;
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  animation_target_size_ = 0;
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_amount_ = 0;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  suppress_chevron_ = false;
653a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  OnBrowserActionVisibilityChanged();
654effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
655effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  FOR_EACH_OBSERVER(BrowserActionsContainerObserver,
656effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    observers_,
657effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    OnBrowserActionsContainerAnimationEnded());
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::NotifyMenuDeleted(
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserActionOverflowMenuController* controller) {
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(overflow_menu_, controller);
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_ = NULL;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)content::WebContents* BrowserActionsContainer::GetCurrentWebContents() {
6675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return browser_->tab_strip_model()->GetActiveWebContents();
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extensions::ActiveTabPermissionGranter*
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserActionsContainer::GetActiveTabPermissionGranter() {
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::WebContents* web_contents =
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      browser_->tab_strip_model()->GetActiveWebContents();
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!web_contents)
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return extensions::TabHelper::FromWebContents(web_contents)->
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      active_tab_permission_granter();
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::MoveBrowserAction(const std::string& extension_id,
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                size_t new_index) {
6825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const Extension* extension = extensions::ExtensionRegistry::Get(profile_)->
6835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      enabled_extensions().GetByID(extension_id);
68403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  model_->MoveExtensionIcon(extension, new_index);
6855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  SchedulePaint();
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)size_t BrowserActionsContainer::GetFirstVisibleIconIndex() const {
6895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return in_overflow_mode() ? model_->GetVisibleIconCount() : 0;
690a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
691a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
6925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ExtensionPopup* BrowserActionsContainer::TestGetPopup() {
6935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return popup_owner_ ? popup_owner_->view_controller()->popup() : NULL;
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) {
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->SetVisibleIconCount(icons);
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chevron_->SetVisible(icons < browser_action_views_.size());
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_width_ = IconCountToWidth(icons, chevron_->visible());
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnPaint(gfx::Canvas* canvas) {
705effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // If the views haven't been initialized yet, wait for the next call to
706effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // paint (one will be triggered by entering highlight mode).
707effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (model_->is_highlighting() && !browser_action_views_.empty()) {
708effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    views::Painter::PaintPainterAt(
709effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        canvas, highlight_painter_.get(), GetLocalBounds());
710effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
711effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sky/glen): Instead of using a drop indicator, animate the icons while
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dragging (like we do for tab dragging).
7145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (drop_position_.get()) {
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The two-pixel width drop indicator.
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const int kDropIndicatorWidth = 2;
7175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Convert back to a pixel offset into the container.  First find the X
7195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // coordinate of the drop icon.
7205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int drop_icon_x = browser_action_views_[GetFirstVisibleIconIndex()]->x() +
7215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        (drop_position_->icon_in_row * IconWidth(true));
7225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Next, find the space before the drop icon. This will either be
7235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // kItemSpacing or ToolbarView::kStandardSpacing, depending on whether this
7245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // is the first icon.
7255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // NOTE: Right now, these are the same. But let's do this right for if they
7265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // ever aren't.
7275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int space_before_drop_icon = drop_position_->icon_in_row == 0 ?
7285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ToolbarView::kStandardSpacing : kItemSpacing;
7295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Now place the drop indicator halfway between this and the end of the
7305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // previous icon.  If there is an odd amount of available space between the
7315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // two icons (or the icon and the address bar) after subtracting the drop
7325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // indicator width, this calculation puts the extra pixel on the left side
7335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // of the indicator, since when the indicator is between the address bar and
7345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // the first icon, it looks better closer to the icon.
7355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int drop_indicator_x = drop_icon_x -
7365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ((space_before_drop_icon + kDropIndicatorWidth) / 2);
7375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int row_height = IconHeight();
7385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int drop_indicator_y = row_height * drop_position_->row;
7395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    gfx::Rect indicator_bounds(drop_indicator_x,
7405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               drop_indicator_y,
7415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               kDropIndicatorWidth,
7425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               row_height);
7435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    indicator_bounds.set_x(GetMirroredXForRect(indicator_bounds));
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Color of the drop indicator.
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const SkColor kDropIndicatorColor = SK_ColorBLACK;
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canvas->FillRect(indicator_bounds, kDropIndicatorColor);
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnThemeChanged() {
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadImages();
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void BrowserActionsContainer::ViewHierarchyChanged(
756a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const ViewHierarchyChangedDetails& details) {
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No extensions (e.g., incognito).
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!model_)
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
761a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (details.is_add && details.child == this) {
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Initial toolbar button creation and placement in the widget hierarchy.
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We do this here instead of in the constructor because AddBrowserAction
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // calls Layout on the Toolbar, which needs this object to be constructed
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // before its Layout function is called.
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CreateBrowserActionViews();
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::IconWidth(bool include_padding) {
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool initialized = false;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int icon_width = 0;
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized) {
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    initialized = true;
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_width = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDR_BROWSER_ACTION)->width();
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return icon_width + (include_padding ? kItemSpacing : 0);
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::IconHeight() {
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool initialized = false;
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int icon_height = 0;
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized) {
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    initialized = true;
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_height = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDR_BROWSER_ACTION)->height();
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return icon_height;
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
79403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::ToolbarExtensionAdded(const Extension* extension,
79503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                                    int index) {
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(DEBUG)
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
7986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DCHECK(browser_action_views_[i]->extension() != extension) <<
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           "Asked to add a browser action view for an extension that already "
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           "exists.";
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseOverflowMenu();
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!ShouldDisplayBrowserAction(extension))
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the new browser action to the vector and the view hierarchy.
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->IsOffTheRecord())
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = model_->OriginalIndexToIncognito(index);
81103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserActionView* view =
81203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      new BrowserActionView(extension,
81303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            GetExtensionAction(*extension, profile_),
81403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            browser_,
81503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            this);
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  browser_action_views_.insert(browser_action_views_.begin() + index, view);
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildViewAt(view, index);
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we are still initializing the container, don't bother animating.
820f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!model_->extensions_initialized())
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Enlarge the container if it was already at maximum size and we're not in
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the middle of upgrading.
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((model_->GetVisibleIconCount() < 0) &&
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !extensions::ExtensionSystem::Get(profile_)->runtime_data()->
8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          IsBeingUpgraded(extension)) {
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    suppress_chevron_ = true;
82903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    Animate(gfx::Tween::LINEAR, browser_action_views_.size());
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Just redraw the (possibly modified) visible icon set.
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnBrowserActionVisibilityChanged();
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
83603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::ToolbarExtensionRemoved(
83703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const Extension* extension) {
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseOverflowMenu();
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
84046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  size_t visible_actions = VisibleBrowserActionsAfterAnimation();
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (BrowserActionViews::iterator i(browser_action_views_.begin());
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != browser_action_views_.end(); ++i) {
8436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if ((*i)->extension() == extension) {
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete *i;
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser_action_views_.erase(i);
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the extension is being upgraded we don't want the bar to shrink
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // because the icon is just going to get re-added to the same location.
8495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (extensions::ExtensionSystem::Get(profile_)->runtime_data()->
8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              IsBeingUpgraded(extension))
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (browser_action_views_.size() > visible_actions) {
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If we have more icons than we can show, then we must not be changing
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // the container size (since we either removed an icon from the main
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // area and one from the overflow list will have shifted in, or we
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // removed an entry directly from the overflow list).
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnBrowserActionVisibilityChanged();
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Either we went from overflow to no-overflow, or we shrunk the no-
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // overflow container by 1.  Either way the size changed, so animate.
862116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (chevron_)
863116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          chevron_->SetVisible(false);
86403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        Animate(gfx::Tween::EASE_OUT, browser_action_views_.size());
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
866116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return;  // We have found the action to remove, bail out.
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
87103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::ToolbarExtensionMoved(const Extension* extension,
87203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                                    int index) {
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShouldDisplayBrowserAction(extension))
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->IsOffTheRecord())
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = model_->OriginalIndexToIncognito(index);
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(index >= 0 && index < static_cast<int>(browser_action_views_.size()));
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
88103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserActionViews::iterator iter = browser_action_views_.begin();
88203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int old_index = 0;
88303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  while (iter != browser_action_views_.end() &&
88403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)         (*iter)->extension() != extension) {
88503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ++iter;
88603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ++old_index;
88703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
88803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
88903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(iter != browser_action_views_.end());
89003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (old_index == index)
89103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return;  // Already in place.
89203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
89303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserActionView* moved_view = *iter;
89403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  browser_action_views_.erase(iter);
89503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  browser_action_views_.insert(
89603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      browser_action_views_.begin() + index, moved_view);
89703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
90203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::ToolbarExtensionUpdated(
90303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const Extension* extension) {
90403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserActionView* view = GetViewForExtension(extension);
90503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (view)
90603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    view->UpdateState();
90703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
90803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
90903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool BrowserActionsContainer::ShowExtensionActionPopup(
9105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const Extension* extension) {
9115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return ShowPopupForExtension(extension, false, false);
9128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
9138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
91403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::ToolbarVisibleCountChanged() {
91503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int old_container_width = container_width_;
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetContainerWidth();
91703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (old_container_width != container_width_)
91803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    Animate(gfx::Tween::EASE_OUT, GetIconCount());
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::ToolbarHighlightModeChanged(
92203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    bool is_highlighting) {
923effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // The visual highlighting is done in OnPaint(). It's a bit of a pain that
92403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // we delete and recreate everything here, but given everything else going on
92503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // (the lack of highlight, n more extensions appearing, etc), it's not worth
92603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // the extra complexity to create and insert only the new extensions.
927effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DeleteBrowserActionViews();
928effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CreateBrowserActionViews();
92903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  Animate(gfx::Tween::LINEAR, browser_action_views_.size());
930effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
931effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::LoadImages() {
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::ThemeProvider* tp = GetThemeProvider();
934116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!tp || !chevron_)
935116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
936116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
937f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  chevron_->SetImage(views::Button::STATE_NORMAL,
938f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     *tp->GetImageSkiaNamed(IDR_BROWSER_ACTIONS_OVERFLOW));
939effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
940effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const int kImages[] = IMAGE_GRID(IDR_DEVELOPER_MODE_HIGHLIGHT);
941effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  highlight_painter_.reset(views::Painter::CreateImageGridPainter(kImages));
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
94403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::OnBrowserActionVisibilityChanged() {
94503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  SetVisible(!browser_action_views_.empty());
94603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (owner_view_) {
94703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    owner_view_->Layout();
94803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    owner_view_->SchedulePaint();
94903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
95003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
95103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::SetContainerWidth() {
95303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int visible_actions = GetIconCount();
954116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (chevron_) {
955116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    chevron_->SetVisible(
956116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      static_cast<size_t>(visible_actions) < model_->toolbar_items().size());
957116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
958116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  container_width_ =
959116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      IconCountToWidth(visible_actions, chevron_ && chevron_->visible());
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::CloseOverflowMenu() {
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (overflow_menu_)
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_menu_->CancelMenu();
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::StopShowFolderDropMenuTimer() {
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  show_menu_task_factory_.InvalidateWeakPtrs();
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::StartShowFolderDropMenuTimer() {
972b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&BrowserActionsContainer::ShowDropFolder,
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 show_menu_task_factory_.GetWeakPtr()),
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(views::GetMenuShowDelay()));
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::ShowDropFolder() {
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!overflow_menu_);
9815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  drop_position_.reset();
982116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  overflow_menu_ =
983116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new BrowserActionOverflowMenuController(this,
984116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              browser_,
985116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              chevron_,
986116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              browser_action_views_,
987116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              VisibleBrowserActions(),
988116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              true);
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_->set_observer(this);
990116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  overflow_menu_->RunMenu(GetWidget());
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::IconCountToWidth(int icons,
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              bool display_chevron) const {
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (icons < 0)
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icons = browser_action_views_.size();
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((icons == 0) && !display_chevron)
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ToolbarView::kStandardSpacing;
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int icons_size =
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (icons == 0) ? 0 : ((icons * IconWidth(true)) - kItemSpacing);
1001116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int chevron_size = chevron_ && display_chevron ?
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (kChevronSpacing + chevron_->GetPreferredSize().width()) : 0;
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ToolbarView::kStandardSpacing + icons_size + chevron_size +
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ToolbarView::kStandardSpacing;
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t BrowserActionsContainer::WidthToIconCount(int pixels) const {
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for widths large enough to show the entire icon set.
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pixels >= IconCountToWidth(-1, false))
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return browser_action_views_.size();
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to reserve space for the resize area, chevron, and the spacing on
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // either side of the chevron.
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int available_space = pixels - ToolbarView::kStandardSpacing -
1015116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      (chevron_ ? chevron_->GetPreferredSize().width() : 0) -
1016116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      kChevronSpacing - ToolbarView::kStandardSpacing;
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now we add an extra between-item padding value so the space can be divided
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // evenly by (size of icon with padding).
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<size_t>(
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::max(0, available_space + kItemSpacing) / IconWidth(true));
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1023cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int BrowserActionsContainer::MinimumNonemptyWidth() const {
1024116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!chevron_)
1025116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return ToolbarView::kStandardSpacing;
1026116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return (ToolbarView::kStandardSpacing * 2) + kChevronSpacing +
1027116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chevron_->GetPreferredSize().width();
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
103003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void BrowserActionsContainer::Animate(gfx::Tween::Type tween_type,
103103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                      size_t num_visible_icons) {
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int target_size = IconCountToWidth(num_visible_icons,
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      num_visible_icons < browser_action_views_.size());
1034116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (resize_animation_ && !disable_animations_during_testing_) {
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Animate! We have to set the animation_target_size_ after calling Reset(),
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // because that could end up calling AnimationEnded which clears the value.
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_animation_->Reset();
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_animation_->SetTweenType(tween_type);
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    animation_target_size_ = target_size;
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_animation_->Show();
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    animation_target_size_ = target_size;
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AnimationEnded(resize_animation_.get());
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::ShouldDisplayBrowserAction(
104803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const Extension* extension) const {
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only display incognito-enabled extensions while in incognito mode.
10505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return !profile_->IsOffTheRecord() ||
10515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      extensions::util::IsIncognitoEnabled(extension->id(), profile_);
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BrowserActionsContainer::ShowPopupForExtension(
10555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const extensions::Extension* extension,
10565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool grant_tab_permissions,
10575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool can_override) {
10585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // If the popup cannot override other views, then no other popups can be
10595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // showing, and it must be shown in the active widow with a visible toolbar.
10605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(justinlin): Remove toolbar check when http://crbug.com/308645 is
10615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // fixed.
10625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!can_override &&
10635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      (popup_owner_ ||
10645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       !browser_->window()->IsActive() ||
10655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       !browser_->window()->IsToolbarVisible())) {
10668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
106903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserActionView* view = GetViewForExtension(extension);
107003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return view ? view->view_controller()->ExecuteAction(
107103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                    ExtensionPopup::SHOW, grant_tab_permissions) : false;
107203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
107303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
107403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)BrowserActionView* BrowserActionsContainer::GetViewForExtension(
107503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const Extension* extension) {
107603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (BrowserActionViews::iterator view = browser_action_views_.begin();
107703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       view != browser_action_views_.end(); ++view) {
107803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if ((*view)->extension() == extension)
107903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return *view;
108003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
108103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
108203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return NULL;
108303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
108403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
108503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)size_t BrowserActionsContainer::GetIconCount() const {
108603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!model_)
108703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return 0u;
108803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Find the number of icons which could be displayed.
108903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  size_t displayable_icon_count = 0u;
109003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const extensions::ExtensionList& extensions = model_->toolbar_items();
109103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (extensions::ExtensionList::const_iterator iter = extensions.begin();
109203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       iter != extensions.end(); ++iter) {
109303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    displayable_icon_count += ShouldDisplayBrowserAction(*iter) ? 1u : 0u;
10945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
109503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Find the absolute value for the model's visible count.
109603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int model_size = model_->GetVisibleIconCount();
109703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  size_t absolute_model_size =
109803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      model_size == -1 ? extensions.size() : model_size;
109903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
110003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // The main container will try to show |model_size| icons, but reduce if there
110103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // aren't enough displayable icons to do so.
110203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  size_t main_displayed = std::min(displayable_icon_count, absolute_model_size);
110303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // The overflow will display the extras, if any.
110403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return in_overflow_mode() ?
110503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      displayable_icon_count - main_displayed : main_displayed;
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1107