browser_actions_container.cc revision f2477e01787aa58f445919b809d89e252beef54f
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"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/extensions/extension_util.h"
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/extensions/extension_view_host.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/tab_helper.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/session_tab_helper.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/view_ids.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/extensions/browser_action_drag_data.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/extensions/extension_popup.h"
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/views/toolbar/browser_action_view.h"
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ui_resources.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/accessibility/accessible_view_state.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/dragdrop/drag_utils.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/theme_provider.h"
35d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/slide_animation.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/resize_area.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/metrics.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Horizontal spacing between most items in the container, as well as after the
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// last item or chevron (if visible).
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kItemSpacing = ToolbarView::kStandardSpacing;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Horizontal spacing before the chevron (if visible).
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kChevronSpacing = kItemSpacing - 2;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::disable_animations_during_testing_ = false;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BrowserActionsContainer
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BrowserActionsContainer::BrowserActionsContainer(Browser* browser,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 View* owner_view)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : profile_(browser->profile()),
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser_(browser),
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      owner_view_(owner_view),
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      popup_(NULL),
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      popup_button_(NULL),
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_(NULL),
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      container_width_(0),
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chevron_(NULL),
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      overflow_menu_(NULL),
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      suppress_chevron_(false),
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resize_amount_(0),
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      animation_target_size_(0),
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drop_indicator_position_(-1),
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      task_factory_(this),
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      show_menu_task_factory_(this) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_id(VIEW_ID_BROWSER_ACTION_TOOLBAR);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  model_ = ExtensionToolbarModel::Get(browser->profile());
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (model_)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->AddObserver(this);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryViews(
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser->profile(),
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      owner_view->GetFocusManager(),
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extensions::ExtensionKeybindingRegistry::ALL_EXTENSIONS,
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      this));
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
89d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  resize_animation_.reset(new gfx::SlideAnimation(this));
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_area_ = new views::ResizeArea(this);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(resize_area_);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chevron_ = new views::MenuButton(NULL, string16(), this, false);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chevron_->set_border(NULL);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chevron_->EnableCanvasFlippingForRTLUI(true);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chevron_->SetAccessibleName(
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_ACCNAME_EXTENSIONS_CHEVRON));
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chevron_->SetVisible(false);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(chevron_);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BrowserActionsContainer::~BrowserActionsContainer() {
1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (overflow_menu_)
1047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    overflow_menu_->set_observer(NULL);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->RemoveObserver(this);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopShowFolderDropMenuTimer();
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (popup_)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_->GetWidget()->RemoveObserver(this);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HidePopup();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteBrowserActionViews();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::Init() {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadImages();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We wait to set the container width until now so that the chevron images
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be loaded.  The width calculation needs to know the chevron size.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_ &&
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !profile_->GetPrefs()->HasPrefPath(prefs::kExtensionToolbarSize)) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Migration code to the new VisibleIconCount pref.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(mpcomplete): remove this after users are upgraded to 5.0.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int predefined_width =
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (predefined_width != 0)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_->SetVisibleIconCount(WidthToIconCount(predefined_width));
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_ && model_->extensions_initialized())
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetContainerWidth();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BrowserActionView* BrowserActionsContainer::GetBrowserActionView(
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExtensionAction* action) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (BrowserActionViews::iterator i(browser_action_views_.begin());
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != browser_action_views_.end(); ++i) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*i)->button()->browser_action() == action)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return *i;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::RefreshBrowserActionViews() {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_action_views_[i]->button()->UpdateState();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::CreateBrowserActionViews() {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(browser_action_views_.empty());
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!model_)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const extensions::ExtensionList& toolbar_items = model_->toolbar_items();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (extensions::ExtensionList::const_iterator i(toolbar_items.begin());
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != toolbar_items.end(); ++i) {
1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!ShouldDisplayBrowserAction(i->get()))
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BrowserActionView* view = new BrowserActionView(i->get(), browser_, this);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_action_views_.push_back(view);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddChildView(view);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::DeleteBrowserActionViews() {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HidePopup();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&browser_action_views_);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t BrowserActionsContainer::VisibleBrowserActions() const {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t visible_actions = 0;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (browser_action_views_[i]->visible())
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++visible_actions;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return visible_actions;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size BrowserActionsContainer::GetPreferredSize() {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (browser_action_views_.empty())
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return gfx::Size(ToolbarView::kStandardSpacing, 0);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We calculate the size of the view by taking the current width and
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // subtracting resize_amount_ (the latter represents how far the user is
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // resizing the view or, if animating the snapping, how far to animate it).
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // But we also clamp it to a minimum size and the maximum size, so that the
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // container can never shrink too far or take up more space than it needs. In
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // other words: ContainerMinSize() < width() - resize < ClampTo(MAX).
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int clamped_width = std::min(
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::max(ContainerMinSize(), container_width_ - resize_amount_),
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IconCountToWidth(-1, false));
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::Size(clamped_width, 0);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::Layout() {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (browser_action_views_.empty()) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetVisible(false);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVisible(true);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_area_->SetBounds(0, ToolbarView::kVertSpacing, kItemSpacing,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          IconHeight());
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the icons don't all fit, show the chevron (unless suppressed).
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_x = GetPreferredSize().width();
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((IconCountToWidth(-1, false) > max_x) && !suppress_chevron_) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chevron_->SetVisible(true);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Size chevron_size(chevron_->GetPreferredSize());
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    max_x -=
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ToolbarView::kStandardSpacing + chevron_size.width() + kChevronSpacing;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chevron_->SetBounds(
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        width() - ToolbarView::kStandardSpacing - chevron_size.width(),
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ToolbarView::kVertSpacing, chevron_size.width(), chevron_size.height());
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chevron_->SetVisible(false);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now draw the icons for the browser actions in the available space.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int icon_width = IconWidth(false);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserActionView* view = browser_action_views_[i];
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int x = ToolbarView::kStandardSpacing + (i * IconWidth(true));
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (x + icon_width <= max_x) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view->SetBounds(x, 0, icon_width, height());
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view->SetVisible(true);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view->SetVisible(false);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::GetDropFormats(
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int* formats,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::set<OSExchangeData::CustomFormat>* custom_formats) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  custom_formats->insert(BrowserActionDragData::GetBrowserActionCustomFormat());
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::AreDropTypesRequired() {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::CanDrop(const OSExchangeData& data) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserActionDragData drop_data;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return drop_data.Read(data) ? drop_data.IsFromProfile(profile_) : false;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnDragEntered(
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::DropTargetEvent& event) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::OnDragUpdated(
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::DropTargetEvent& event) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First check if we are above the chevron (overflow) menu.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetEventHandlerForPoint(event.location()) == chevron_) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!show_menu_task_factory_.HasWeakPtrs() && !overflow_menu_)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StartShowFolderDropMenuTimer();
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ui::DragDropTypes::DRAG_MOVE;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopShowFolderDropMenuTimer();
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Figure out where to display the indicator.  This is a complex calculation:
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First, we figure out how much space is to the left of the icon area, so we
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // can calculate the true offset into the icon area.
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int width_before_icons = ToolbarView::kStandardSpacing +
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (base::i18n::IsRTL() ?
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (chevron_->GetPreferredSize().width() + kChevronSpacing) : 0);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int offset_into_icon_area = event.x() - width_before_icons;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Next, we determine which icon to place the indicator in front of.  We want
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to place the indicator in front of icon n when the cursor is between the
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // midpoints of icons (n - 1) and n.  To do this we take the offset into the
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon area and transform it as follows:
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Real icon area:
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   0   a     *  b        c
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   |   |        |        |
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   |[IC|ON]  [IC|ON]  [IC|ON]
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We want to be before icon 0 for 0 < x <= a, icon 1 for a < x <= b, etc.
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Here the "*" represents the offset into the icon area, and since it's
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // between a and b, we want to return "1".
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Transformed "icon area":
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   0        a     *  b        c
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   |        |        |        |
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   |[ICON]  |[ICON]  |[ICON]  |
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we shift both our offset and our divider points later by half an icon
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // plus one spacing unit, then it becomes very easy to calculate how many
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // divider points we've passed, because they're the multiples of "one icon
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // plus padding".
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int before_icon_unclamped = (offset_into_icon_area + (IconWidth(false) / 2) +
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kItemSpacing) / IconWidth(true);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Because the user can drag outside the container bounds, we need to clamp to
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the valid range.  Note that the maximum allowable value is (num icons), not
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (num icons - 1), because we represent the indicator being past the last
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon as being "before the (last + 1) icon".
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int before_icon = std::min(std::max(before_icon_unclamped, 0),
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             static_cast<int>(VisibleBrowserActions()));
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now we convert back to a pixel offset into the container.  We want to place
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the center of the drop indicator at the midpoint of the space before our
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // chosen icon.
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetDropIndicator(width_before_icons + (before_icon * IconWidth(true)) -
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (kItemSpacing / 2));
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::DragDropTypes::DRAG_MOVE;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnDragExited() {
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopShowFolderDropMenuTimer();
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drop_indicator_position_ = -1;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::OnPerformDrop(
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::DropTargetEvent& event) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserActionDragData data;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!data.Read(event.data()))
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ui::DragDropTypes::DRAG_NONE;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we have the same view as we started with.
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(browser_action_views_[data.index()]->button()->extension()->id(),
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            data.id());
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(model_);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t i = 0;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (; i < browser_action_views_.size(); ++i) {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int view_x = browser_action_views_[i]->GetMirroredBounds().x();
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!browser_action_views_[i]->visible() ||
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (base::i18n::IsRTL() ? (view_x < drop_indicator_position_) :
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            (view_x >= drop_indicator_position_))) {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We have reached the end of the visible icons or found one that has a
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // higher x position than the drop point.
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |i| now points to the item to the right of the drop indicator*, which is
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // correct when dragging an icon to the left. When dragging to the right,
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // however, we want the icon being dragged to get the index of the item to
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the left of the drop indicator, so we subtract one.
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // * Well, it can also point to the end, but not when dragging to the left. :)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i > data.index())
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    --i;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->IsOffTheRecord())
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    i = model_->IncognitoIndexToOriginal(i);
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->MoveBrowserAction(
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser_action_views_[data.index()]->button()->extension(), i);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnDragExited();  // Perform clean up after dragging.
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::DragDropTypes::DRAG_MOVE;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::GetAccessibleState(
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui::AccessibleViewState* state) {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->role = ui::AccessibilityTypes::ROLE_GROUPING;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_EXTENSIONS);
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnMenuButtonClicked(views::View* source,
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const gfx::Point& point) {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (source == chevron_) {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_menu_ = new BrowserActionOverflowMenuController(
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this, browser_, chevron_, browser_action_views_,
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VisibleBrowserActions());
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_menu_->set_observer(this);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_menu_->RunMenu(GetWidget(), false);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::WriteDragDataForView(View* sender,
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   const gfx::Point& press_pt,
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   OSExchangeData* data) {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(data);
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserActionButton* button = browser_action_views_[i]->button();
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (button == sender) {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Set the dragging image for the icon.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::ImageSkia badge(browser_action_views_[i]->GetIconWithBadge());
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_utils::SetDragImageOnDataObject(badge, button->size(),
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           press_pt.OffsetFromOrigin(),
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           data);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Fill in the remaining info.
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserActionDragData drag_data(
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          browser_action_views_[i]->button()->extension()->id(), i);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_data.Write(profile_, data);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::GetDragOperationsForView(View* sender,
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      const gfx::Point& p) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::DragDropTypes::DRAG_MOVE;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::CanStartDragForView(View* sender,
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const gfx::Point& press_pt,
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const gfx::Point& p) {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnResize(int resize_amount, bool done_resizing) {
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!done_resizing) {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_amount_ = resize_amount;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnBrowserActionVisibilityChanged();
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Up until now we've only been modifying the resize_amount, but now it is
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // time to set the container size to the size we have resized to, and then
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // animate to the nearest icon count size if necessary (which may be 0).
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_width = IconCountToWidth(-1, false);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_width_ =
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::min(std::max(0, container_width_ - resize_amount), max_width);
423d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SaveDesiredSizeAndAnimate(gfx::Tween::EASE_OUT,
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            WidthToIconCount(container_width_));
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::AnimationProgressed(
428d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const gfx::Animation* animation) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(resize_animation_.get(), animation);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_amount_ = static_cast<int>(resize_animation_->GetCurrentValue() *
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (container_width_ - animation_target_size_));
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnBrowserActionVisibilityChanged();
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void BrowserActionsContainer::AnimationEnded(const gfx::Animation* animation) {
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_width_ = animation_target_size_;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  animation_target_size_ = 0;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_amount_ = 0;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnBrowserActionVisibilityChanged();
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  suppress_chevron_ = false;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::NotifyMenuDeleted(
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserActionOverflowMenuController* controller) {
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(overflow_menu_, controller);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_ = NULL;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BrowserActionsContainer::OnWidgetDestroying(views::Widget* widget) {
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(popup_->GetWidget(), widget);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  popup_->GetWidget()->RemoveObserver(this);
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  popup_ = NULL;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |popup_button_| is NULL if the extension has been removed.
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (popup_button_) {
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_button_->SetButtonNotPushed();
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_button_ = NULL;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::InspectPopup(ExtensionAction* action) {
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserActionView* view = GetBrowserActionView(action);
4628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ShowPopup(view->button(), ExtensionPopup::SHOW_AND_INSPECT, true);
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::GetCurrentTabId() const {
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::WebContents* active_tab =
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      browser_->tab_strip_model()->GetActiveWebContents();
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!active_tab)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SessionTabHelper::FromWebContents(active_tab)->session_id().id();
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnBrowserActionExecuted(
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserActionButton* button) {
4768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ShowPopup(button, ExtensionPopup::SHOW, true);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnBrowserActionVisibilityChanged() {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVisible(!browser_action_views_.empty());
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owner_view_->Layout();
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owner_view_->SchedulePaint();
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Point BrowserActionsContainer::GetViewContentOffset() const {
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::Point(0, ToolbarView::kVertSpacing);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extensions::ActiveTabPermissionGranter*
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserActionsContainer::GetActiveTabPermissionGranter() {
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::WebContents* web_contents =
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      browser_->tab_strip_model()->GetActiveWebContents();
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!web_contents)
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return extensions::TabHelper::FromWebContents(web_contents)->
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      active_tab_permission_granter();
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::MoveBrowserAction(const std::string& extension_id,
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                size_t new_index) {
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionService* service =
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::ExtensionSystem::Get(profile_)->extension_service();
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (service) {
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension = service->GetExtensionById(extension_id, false);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->MoveBrowserAction(extension, new_index);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SchedulePaint();
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::HidePopup() {
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove this as an observer and clear |popup_| and |popup_button_| here,
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // since we might change them before OnWidgetDestroying() gets called.
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (popup_) {
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_->GetWidget()->RemoveObserver(this);
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_->GetWidget()->Close();
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_ = NULL;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (popup_button_) {
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_button_->SetButtonNotPushed();
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_button_ = NULL;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::TestExecuteBrowserAction(int index) {
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserActionButton* button = browser_action_views_[index]->button();
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnBrowserActionExecuted(button);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) {
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->SetVisibleIconCount(icons);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chevron_->SetVisible(icons < browser_action_views_.size());
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_width_ = IconCountToWidth(icons, chevron_->visible());
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnPaint(gfx::Canvas* canvas) {
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sky/glen): Instead of using a drop indicator, animate the icons while
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dragging (like we do for tab dragging).
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drop_indicator_position_ > -1) {
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The two-pixel width drop indicator.
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const int kDropIndicatorWidth = 2;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Rect indicator_bounds(
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        drop_indicator_position_ - (kDropIndicatorWidth / 2),
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ToolbarView::kVertSpacing, kDropIndicatorWidth, IconHeight());
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Color of the drop indicator.
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const SkColor kDropIndicatorColor = SK_ColorBLACK;
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canvas->FillRect(indicator_bounds, kDropIndicatorColor);
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::OnThemeChanged() {
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadImages();
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
557a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void BrowserActionsContainer::ViewHierarchyChanged(
558a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const ViewHierarchyChangedDetails& details) {
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No extensions (e.g., incognito).
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!model_)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
563a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (details.is_add && details.child == this) {
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Initial toolbar button creation and placement in the widget hierarchy.
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We do this here instead of in the constructor because AddBrowserAction
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // calls Layout on the Toolbar, which needs this object to be constructed
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // before its Layout function is called.
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CreateBrowserActionViews();
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::IconWidth(bool include_padding) {
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool initialized = false;
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int icon_width = 0;
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized) {
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    initialized = true;
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_width = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDR_BROWSER_ACTION)->width();
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return icon_width + (include_padding ? kItemSpacing : 0);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::IconHeight() {
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool initialized = false;
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int icon_height = 0;
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized) {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    initialized = true;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_height = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDR_BROWSER_ACTION)->height();
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return icon_height;
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::BrowserActionAdded(const Extension* extension,
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 int index) {
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(DEBUG)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < browser_action_views_.size(); ++i) {
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(browser_action_views_[i]->button()->extension() != extension) <<
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           "Asked to add a browser action view for an extension that already "
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           "exists.";
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseOverflowMenu();
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShouldDisplayBrowserAction(extension))
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t visible_actions = VisibleBrowserActions();
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the new browser action to the vector and the view hierarchy.
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->IsOffTheRecord())
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = model_->OriginalIndexToIncognito(index);
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserActionView* view = new BrowserActionView(extension, browser_, this);
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  browser_action_views_.insert(browser_action_views_.begin() + index, view);
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildViewAt(view, index);
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we are still initializing the container, don't bother animating.
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!model_->extensions_initialized())
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Enlarge the container if it was already at maximum size and we're not in
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the middle of upgrading.
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((model_->GetVisibleIconCount() < 0) &&
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !extensions::ExtensionSystem::Get(profile_)->extension_service()->
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          IsBeingUpgraded(extension)) {
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    suppress_chevron_ = true;
629d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    SaveDesiredSizeAndAnimate(gfx::Tween::LINEAR, visible_actions + 1);
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Just redraw the (possibly modified) visible icon set.
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnBrowserActionVisibilityChanged();
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::BrowserActionRemoved(const Extension* extension) {
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseOverflowMenu();
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (popup_ && popup_->host()->extension() == extension)
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HidePopup();
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t visible_actions = VisibleBrowserActions();
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (BrowserActionViews::iterator i(browser_action_views_.begin());
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != browser_action_views_.end(); ++i) {
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*i)->button()->extension() == extension) {
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete *i;
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser_action_views_.erase(i);
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the extension is being upgraded we don't want the bar to shrink
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // because the icon is just going to get re-added to the same location.
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (extensions::ExtensionSystem::Get(profile_)->extension_service()->
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              IsBeingUpgraded(extension))
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (browser_action_views_.size() > visible_actions) {
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If we have more icons than we can show, then we must not be changing
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // the container size (since we either removed an icon from the main
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // area and one from the overflow list will have shifted in, or we
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // removed an entry directly from the overflow list).
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnBrowserActionVisibilityChanged();
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Either we went from overflow to no-overflow, or we shrunk the no-
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // overflow container by 1.  Either way the size changed, so animate.
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        chevron_->SetVisible(false);
665d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        SaveDesiredSizeAndAnimate(gfx::Tween::EASE_OUT,
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  browser_action_views_.size());
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::BrowserActionMoved(const Extension* extension,
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 int index) {
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShouldDisplayBrowserAction(extension))
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->IsOffTheRecord())
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = model_->OriginalIndexToIncognito(index);
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(index >= 0 && index < static_cast<int>(browser_action_views_.size()));
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteBrowserActionViews();
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CreateBrowserActionViews();
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool BrowserActionsContainer::BrowserActionShowPopup(
6908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const extensions::Extension* extension) {
6918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Do not override other popups and only show in active window. The window
6928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // must also have a toolbar, otherwise it should not be showing popups.
6938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // TODO(justinlin): Remove toolbar check when http://crbug.com/308645 is
6948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // fixed.
6958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (popup_ ||
6968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      !browser_->window()->IsActive() ||
6978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      !browser_->window()->IsToolbarVisible()) {
6988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
6998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
7008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
7018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (BrowserActionViews::iterator it = browser_action_views_.begin();
7028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       it != browser_action_views_.end(); ++it) {
7038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    BrowserActionButton* button = (*it)->button();
7048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (button && button->extension() == extension)
7058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return ShowPopup(button, ExtensionPopup::SHOW, false);
7068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
7078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return false;
7088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
7098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::ModelLoaded() {
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetContainerWidth();
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::LoadImages() {
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::ThemeProvider* tp = GetThemeProvider();
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chevron_->SetIcon(*tp->GetImageSkiaNamed(IDR_BROWSER_ACTIONS_OVERFLOW));
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chevron_->SetHoverIcon(*tp->GetImageSkiaNamed(
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IDR_BROWSER_ACTIONS_OVERFLOW_H));
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chevron_->SetPushedIcon(*tp->GetImageSkiaNamed(
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IDR_BROWSER_ACTIONS_OVERFLOW_P));
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::SetContainerWidth() {
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int visible_actions = model_->GetVisibleIconCount();
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visible_actions < 0)  // All icons should be visible.
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visible_actions = model_->toolbar_items().size();
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chevron_->SetVisible(
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<size_t>(visible_actions) < model_->toolbar_items().size());
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_width_ = IconCountToWidth(visible_actions, chevron_->visible());
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::CloseOverflowMenu() {
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (overflow_menu_)
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_menu_->CancelMenu();
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::StopShowFolderDropMenuTimer() {
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  show_menu_task_factory_.InvalidateWeakPtrs();
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::StartShowFolderDropMenuTimer() {
742b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&BrowserActionsContainer::ShowDropFolder,
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 show_menu_task_factory_.GetWeakPtr()),
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(views::GetMenuShowDelay()));
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::ShowDropFolder() {
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!overflow_menu_);
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetDropIndicator(-1);
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_ = new BrowserActionOverflowMenuController(
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this, browser_, chevron_, browser_action_views_, VisibleBrowserActions());
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_->set_observer(this);
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_->RunMenu(GetWidget(), true);
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::SetDropIndicator(int x_pos) {
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drop_indicator_position_ != x_pos) {
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drop_indicator_position_ = x_pos;
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SchedulePaint();
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::IconCountToWidth(int icons,
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              bool display_chevron) const {
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (icons < 0)
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icons = browser_action_views_.size();
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((icons == 0) && !display_chevron)
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ToolbarView::kStandardSpacing;
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int icons_size =
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (icons == 0) ? 0 : ((icons * IconWidth(true)) - kItemSpacing);
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int chevron_size = display_chevron ?
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (kChevronSpacing + chevron_->GetPreferredSize().width()) : 0;
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ToolbarView::kStandardSpacing + icons_size + chevron_size +
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ToolbarView::kStandardSpacing;
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t BrowserActionsContainer::WidthToIconCount(int pixels) const {
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for widths large enough to show the entire icon set.
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pixels >= IconCountToWidth(-1, false))
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return browser_action_views_.size();
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to reserve space for the resize area, chevron, and the spacing on
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // either side of the chevron.
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int available_space = pixels - ToolbarView::kStandardSpacing -
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chevron_->GetPreferredSize().width() - kChevronSpacing -
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ToolbarView::kStandardSpacing;
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now we add an extra between-item padding value so the space can be divided
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // evenly by (size of icon with padding).
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<size_t>(
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::max(0, available_space + kItemSpacing) / IconWidth(true));
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsContainer::ContainerMinSize() const {
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ToolbarView::kStandardSpacing + kChevronSpacing +
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chevron_->GetPreferredSize().width() + ToolbarView::kStandardSpacing;
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsContainer::SaveDesiredSizeAndAnimate(
801d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    gfx::Tween::Type tween_type,
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t num_visible_icons) {
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save off the desired number of visible icons.  We do this now instead of at
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the end of the animation so that even if the browser is shut down while
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // animating, the right value will be restored on next run.
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: Don't save the icon count in incognito because there may be fewer
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icons in that mode. The result is that the container in a normal window is
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // always at least as wide as in an incognito window.
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!profile_->IsOffTheRecord())
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->SetVisibleIconCount(num_visible_icons);
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int target_size = IconCountToWidth(num_visible_icons,
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      num_visible_icons < browser_action_views_.size());
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!disable_animations_during_testing_) {
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Animate! We have to set the animation_target_size_ after calling Reset(),
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // because that could end up calling AnimationEnded which clears the value.
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_animation_->Reset();
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_animation_->SetTweenType(tween_type);
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    animation_target_size_ = target_size;
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_animation_->Show();
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    animation_target_size_ = target_size;
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AnimationEnded(resize_animation_.get());
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsContainer::ShouldDisplayBrowserAction(
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only display incognito-enabled extensions while in incognito mode.
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (!profile_->IsOffTheRecord() ||
8328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       extension_util::IsIncognitoEnabled(
8338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)           extension->id(),
8348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)           extensions::ExtensionSystem::Get(profile_)->extension_service()));
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool BrowserActionsContainer::ShowPopup(
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserActionButton* button,
8398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    ExtensionPopup::ShowAction show_action,
8408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    bool should_grant) {
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension = button->extension();
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL popup_url;
8438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (model_->ExecuteBrowserAction(
8448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          extension, browser_, &popup_url, should_grant) !=
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ExtensionToolbarModel::ACTION_SHOW_POPUP) {
8468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're showing the same popup, just hide it and return.
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool same_showing = popup_ && button == popup_button_;
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Always hide the current popup, even if it's not the same.
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only one popup should be visible at a time.
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HidePopup();
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (same_showing)
8578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can get the execute event for browser actions that are not visible,
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // since buttons can be activated from the overflow menu (chevron). In that
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // case we show the popup as originating from the chevron.
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  View* reference_view = button->parent()->visible() ? button : chevron_;
863c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  views::BubbleBorder::Arrow arrow = base::i18n::IsRTL() ?
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      views::BubbleBorder::TOP_LEFT : views::BubbleBorder::TOP_RIGHT;
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  popup_ = ExtensionPopup::ShowPopup(popup_url,
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     browser_,
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     reference_view,
868c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                     arrow,
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     show_action);
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  popup_->GetWidget()->AddObserver(this);
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  popup_button_ = button;
8728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
8738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Only set button as pushed if it was triggered by a user click.
8748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (should_grant)
8758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    popup_button_->SetButtonPushed();
8768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return true;
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
878