diff options
Diffstat (limited to 'chrome/browser/views/browser_actions_container.cc')
-rw-r--r-- | chrome/browser/views/browser_actions_container.cc | 1100 |
1 files changed, 0 insertions, 1100 deletions
diff --git a/chrome/browser/views/browser_actions_container.cc b/chrome/browser/views/browser_actions_container.cc deleted file mode 100644 index b630806..0000000 --- a/chrome/browser/views/browser_actions_container.cc +++ /dev/null @@ -1,1100 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/views/browser_actions_container.h" - -#include "app/l10n_util.h" -#include "app/resource_bundle.h" -#include "app/slide_animation.h" -#include "base/stl_util-inl.h" -#include "base/string_util.h" -#include "base/utf_string_conversions.h" -#include "chrome/browser/browser.h" -#include "chrome/browser/browser_window.h" -#include "chrome/browser/extensions/extension_browser_event_router.h" -#include "chrome/browser/extensions/extension_host.h" -#include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/renderer_host/render_view_host.h" -#include "chrome/browser/renderer_host/render_widget_host_view.h" -#include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/themes/browser_theme_provider.h" -#include "chrome/browser/view_ids.h" -#include "chrome/browser/views/detachable_toolbar_view.h" -#include "chrome/browser/views/extensions/browser_action_drag_data.h" -#include "chrome/browser/views/extensions/extension_popup.h" -#include "chrome/browser/views/toolbar_view.h" -#include "chrome/common/extensions/extension_action.h" -#include "chrome/common/extensions/extension_resource.h" -#include "chrome/common/notification_source.h" -#include "chrome/common/notification_type.h" -#include "chrome/common/pref_names.h" -#include "gfx/canvas.h" -#include "gfx/canvas_skia.h" -#include "grit/app_resources.h" -#include "grit/generated_resources.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkTypeface.h" -#include "third_party/skia/include/effects/SkGradientShader.h" -#include "views/controls/button/menu_button.h" -#include "views/controls/button/text_button.h" -#include "views/controls/menu/menu_2.h" -#include "views/drag_utils.h" -#include "views/window/window.h" - -#include "grit/theme_resources.h" - -// Horizontal spacing between most items in the container, as well as after the -// last item or chevron (if visible). -static const int kItemSpacing = ToolbarView::kStandardSpacing; -// Horizontal spacing before the chevron (if visible). -static const int kChevronSpacing = kItemSpacing - 2; - -// static -bool BrowserActionsContainer::disable_animations_during_testing_ = false; - -//////////////////////////////////////////////////////////////////////////////// -// BrowserActionButton - -BrowserActionButton::BrowserActionButton(const Extension* extension, - BrowserActionsContainer* panel) - : ALLOW_THIS_IN_INITIALIZER_LIST( - MenuButton(this, std::wstring(), NULL, false)), - browser_action_(extension->browser_action()), - extension_(extension), - ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)), - showing_context_menu_(false), - panel_(panel) { - set_border(NULL); - set_alignment(TextButton::ALIGN_CENTER); - - // No UpdateState() here because View hierarchy not setup yet. Our parent - // should call UpdateState() after creation. - - registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED, - Source<ExtensionAction>(browser_action_)); -} - -void BrowserActionButton::Destroy() { - if (showing_context_menu_) { - context_menu_menu_->CancelMenu(); - MessageLoop::current()->DeleteSoon(FROM_HERE, this); - } else { - delete this; - } -} - -void BrowserActionButton::ViewHierarchyChanged( - bool is_add, View* parent, View* child) { - if (is_add && child == this) { - // The Browser Action API does not allow the default icon path to be - // changed at runtime, so we can load this now and cache it. - std::string relative_path = browser_action_->default_icon_path(); - if (relative_path.empty()) - return; - - // LoadImage is not guaranteed to be synchronous, so we might see the - // callback OnImageLoaded execute immediately. It (through UpdateState) - // expects GetParent() to return the owner for this button, so this - // function is as early as we can start this request. - tracker_.LoadImage(extension_, extension_->GetResource(relative_path), - gfx::Size(Extension::kBrowserActionIconMaxSize, - Extension::kBrowserActionIconMaxSize), - ImageLoadingTracker::DONT_CACHE); - } - - MenuButton::ViewHierarchyChanged(is_add, parent, child); -} - -void BrowserActionButton::ButtonPressed(views::Button* sender, - const views::Event& event) { - panel_->OnBrowserActionExecuted(this, false); -} - -void BrowserActionButton::OnImageLoaded(SkBitmap* image, - ExtensionResource resource, - int index) { - if (image) - default_icon_ = *image; - - // Call back to UpdateState() because a more specific icon might have been set - // while the load was outstanding. - UpdateState(); -} - -void BrowserActionButton::UpdateState() { - int tab_id = panel_->GetCurrentTabId(); - if (tab_id < 0) - return; - - SkBitmap icon(browser_action()->GetIcon(tab_id)); - if (icon.isNull()) - icon = default_icon_; - if (!icon.isNull()) { - SkPaint paint; - paint.setXfermode(SkXfermode::Create(SkXfermode::kSrcOver_Mode)); - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - - SkBitmap bg; - rb.GetBitmapNamed(IDR_BROWSER_ACTION)->copyTo(&bg, - SkBitmap::kARGB_8888_Config); - SkCanvas bg_canvas(bg); - bg_canvas.drawBitmap(icon, SkIntToScalar((bg.width() - icon.width()) / 2), - SkIntToScalar((bg.height() - icon.height()) / 2), &paint); - SetIcon(bg); - - SkBitmap bg_h; - rb.GetBitmapNamed(IDR_BROWSER_ACTION_H)->copyTo(&bg_h, - SkBitmap::kARGB_8888_Config); - SkCanvas bg_h_canvas(bg_h); - bg_h_canvas.drawBitmap(icon, - SkIntToScalar((bg_h.width() - icon.width()) / 2), - SkIntToScalar((bg_h.height() - icon.height()) / 2), &paint); - SetHoverIcon(bg_h); - - SkBitmap bg_p; - rb.GetBitmapNamed(IDR_BROWSER_ACTION_P)->copyTo(&bg_p, - SkBitmap::kARGB_8888_Config); - SkCanvas bg_p_canvas(bg_p); - bg_p_canvas.drawBitmap(icon, - SkIntToScalar((bg_p.width() - icon.width()) / 2), - SkIntToScalar((bg_p.height() - icon.height()) / 2), &paint); - SetPushedIcon(bg_p); - } - - // If the browser action name is empty, show the extension name instead. - std::wstring name = UTF8ToWide(browser_action()->GetTitle(tab_id)); - if (name.empty()) - name = UTF8ToWide(extension()->name()); - SetTooltipText(name); - SetAccessibleName(name); - GetParent()->SchedulePaint(); -} - -void BrowserActionButton::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - DCHECK(type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED); - UpdateState(); - // The browser action may have become visible/hidden so we need to make - // sure the state gets updated. - panel_->OnBrowserActionVisibilityChanged(); -} - -bool BrowserActionButton::IsPopup() { - int tab_id = panel_->GetCurrentTabId(); - return (tab_id < 0) ? false : browser_action_->HasPopup(tab_id); -} - -GURL BrowserActionButton::GetPopupUrl() { - int tab_id = panel_->GetCurrentTabId(); - return (tab_id < 0) ? GURL() : browser_action_->GetPopupUrl(tab_id); -} - -bool BrowserActionButton::Activate() { - if (!IsPopup()) - return true; - - panel_->OnBrowserActionExecuted(this, false); - - // TODO(erikkay): Run a nested modal loop while the mouse is down to - // enable menu-like drag-select behavior. - - // The return value of this method is returned via OnMousePressed. - // We need to return false here since we're handing off focus to another - // widget/view, and true will grab it right back and try to send events - // to us. - return false; -} - -bool BrowserActionButton::OnMousePressed(const views::MouseEvent& e) { - if (!e.IsRightMouseButton()) { - return IsPopup() ? - MenuButton::OnMousePressed(e) : TextButton::OnMousePressed(e); - } - - // Get the top left point of this button in screen coordinates. - gfx::Point point = gfx::Point(0, 0); - ConvertPointToScreen(this, &point); - - // Make the menu appear below the button. - point.Offset(0, height()); - - ShowContextMenu(point, true); - return false; -} - -void BrowserActionButton::OnMouseReleased(const views::MouseEvent& e, - bool canceled) { - if (IsPopup() || showing_context_menu_) { - // TODO(erikkay) this never actually gets called (probably because of the - // loss of focus). - MenuButton::OnMouseReleased(e, canceled); - } else { - TextButton::OnMouseReleased(e, canceled); - } -} - -bool BrowserActionButton::OnKeyReleased(const views::KeyEvent& e) { - return IsPopup() ? - MenuButton::OnKeyReleased(e) : TextButton::OnKeyReleased(e); -} - -void BrowserActionButton::OnMouseExited(const views::MouseEvent& e) { - if (IsPopup() || showing_context_menu_) - MenuButton::OnMouseExited(e); - else - TextButton::OnMouseExited(e); -} - -void BrowserActionButton::ShowContextMenu(const gfx::Point& p, - bool is_mouse_gesture) { - showing_context_menu_ = true; - SetButtonPushed(); - - // Reconstructs the menu every time because the menu's contents are dynamic. - context_menu_contents_ = - new ExtensionContextMenuModel(extension(), panel_->browser(), panel_); - context_menu_menu_.reset(new views::Menu2(context_menu_contents_.get())); - context_menu_menu_->RunContextMenuAt(p); - - SetButtonNotPushed(); - showing_context_menu_ = false; -} - -void BrowserActionButton::SetButtonPushed() { - SetState(views::CustomButton::BS_PUSHED); - menu_visible_ = true; -} - -void BrowserActionButton::SetButtonNotPushed() { - SetState(views::CustomButton::BS_NORMAL); - menu_visible_ = false; -} - -BrowserActionButton::~BrowserActionButton() { -} - - -//////////////////////////////////////////////////////////////////////////////// -// BrowserActionView - -BrowserActionView::BrowserActionView(const Extension* extension, - BrowserActionsContainer* panel) - : panel_(panel) { - button_ = new BrowserActionButton(extension, panel); - button_->SetDragController(panel_); - AddChildView(button_); - button_->UpdateState(); - SetAccessibleName( - l10n_util::GetString(IDS_ACCNAME_EXTENSIONS_BROWSER_ACTION)); -} - -BrowserActionView::~BrowserActionView() { - RemoveChildView(button_); - button_->Destroy(); -} - -gfx::Canvas* BrowserActionView::GetIconWithBadge() { - int tab_id = panel_->GetCurrentTabId(); - - SkBitmap icon = button_->extension()->browser_action()->GetIcon(tab_id); - if (icon.isNull()) - icon = button_->default_icon(); - - gfx::Canvas* canvas = new gfx::CanvasSkia(icon.width(), icon.height(), false); - canvas->DrawBitmapInt(icon, 0, 0); - - if (tab_id >= 0) { - gfx::Rect bounds(icon.width(), icon.height() + ToolbarView::kVertSpacing); - button_->extension()->browser_action()->PaintBadge(canvas, bounds, tab_id); - } - - return canvas; -} - -AccessibilityTypes::Role BrowserActionView::GetAccessibleRole() { - return AccessibilityTypes::ROLE_GROUPING; -} - -void BrowserActionView::Layout() { - // We can't rely on button_->GetPreferredSize() here because that's not set - // correctly until the first call to - // BrowserActionsContainer::RefreshBrowserActionViews(), whereas this can be - // called before that when the initial bounds are set (and then not after, - // since the bounds don't change). So instead of setting the height from the - // button's preferred size, we use IconHeight(), since that's how big the - // button should be regardless of what it's displaying. - button_->SetBounds(0, ToolbarView::kVertSpacing, width(), - BrowserActionsContainer::IconHeight()); -} - -void BrowserActionView::PaintChildren(gfx::Canvas* canvas) { - View::PaintChildren(canvas); - ExtensionAction* action = button()->browser_action(); - int tab_id = panel_->GetCurrentTabId(); - if (tab_id >= 0) - action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id); -} - -//////////////////////////////////////////////////////////////////////////////// -// BrowserActionsContainer - -BrowserActionsContainer::BrowserActionsContainer(Browser* browser, - View* owner_view) - : profile_(browser->profile()), - browser_(browser), - owner_view_(owner_view), - popup_(NULL), - popup_button_(NULL), - model_(NULL), - container_width_(0), - chevron_(NULL), - overflow_menu_(NULL), - suppress_chevron_(false), - resize_amount_(0), - animation_target_size_(0), - drop_indicator_position_(-1), - ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), - ALLOW_THIS_IN_INITIALIZER_LIST(show_menu_task_factory_(this)) { - SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); - - if (profile_->GetExtensionsService()) { - model_ = profile_->GetExtensionsService()->toolbar_model(); - model_->AddObserver(this); - } - - resize_animation_.reset(new SlideAnimation(this)); - resize_area_ = new views::ResizeArea(this); - resize_area_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_SEPARATOR)); - AddChildView(resize_area_); - - chevron_ = new views::MenuButton(NULL, std::wstring(), this, false); - chevron_->set_border(NULL); - chevron_->EnableCanvasFlippingForRTLUI(true); - chevron_->SetAccessibleName( - l10n_util::GetString(IDS_ACCNAME_EXTENSIONS_CHEVRON)); - chevron_->SetVisible(false); - AddChildView(chevron_); - - SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_EXTENSIONS)); -} - -BrowserActionsContainer::~BrowserActionsContainer() { - if (model_) - model_->RemoveObserver(this); - StopShowFolderDropMenuTimer(); - HidePopup(); - DeleteBrowserActionViews(); -} - -// Static. -void BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) { - prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0); -} - -void BrowserActionsContainer::Init() { - LoadImages(); - - // We wait to set the container width until now so that the chevron images - // will be loaded. The width calculation needs to know the chevron size. - if (model_ && - !profile_->GetPrefs()->HasPrefPath(prefs::kExtensionToolbarSize)) { - // Migration code to the new VisibleIconCount pref. - // TODO(mpcomplete): remove this after users are upgraded to 5.0. - int predefined_width = - profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth); - if (predefined_width != 0) - model_->SetVisibleIconCount(WidthToIconCount(predefined_width)); - } - if (model_ && model_->extensions_initialized()) - SetContainerWidth(); -} - -int BrowserActionsContainer::GetCurrentTabId() const { - TabContents* tab_contents = browser_->GetSelectedTabContents(); - return tab_contents ? tab_contents->controller().session_id().id() : -1; -} - -BrowserActionView* BrowserActionsContainer::GetBrowserActionView( - ExtensionAction* action) { - for (BrowserActionViews::iterator iter = browser_action_views_.begin(); - iter != browser_action_views_.end(); ++iter) { - if ((*iter)->button()->browser_action() == action) - return *iter; - } - return NULL; -} - -void BrowserActionsContainer::RefreshBrowserActionViews() { - for (size_t i = 0; i < browser_action_views_.size(); ++i) - browser_action_views_[i]->button()->UpdateState(); -} - -void BrowserActionsContainer::CreateBrowserActionViews() { - DCHECK(browser_action_views_.empty()); - if (!model_) - return; - - for (ExtensionList::iterator iter = model_->begin(); iter != model_->end(); - ++iter) { - if (!ShouldDisplayBrowserAction(*iter)) - continue; - - BrowserActionView* view = new BrowserActionView(*iter, this); - browser_action_views_.push_back(view); - AddChildView(view); - } -} - -void BrowserActionsContainer::DeleteBrowserActionViews() { - if (!browser_action_views_.empty()) { - for (size_t i = 0; i < browser_action_views_.size(); ++i) - RemoveChildView(browser_action_views_[i]); - STLDeleteContainerPointers(browser_action_views_.begin(), - browser_action_views_.end()); - browser_action_views_.clear(); - } -} - -void BrowserActionsContainer::OnBrowserActionVisibilityChanged() { - SetVisible(!browser_action_views_.empty()); - owner_view_->Layout(); - owner_view_->SchedulePaint(); -} - -size_t BrowserActionsContainer::VisibleBrowserActions() const { - size_t visible_actions = 0; - for (size_t i = 0; i < browser_action_views_.size(); ++i) { - if (browser_action_views_[i]->IsVisible()) - ++visible_actions; - } - return visible_actions; -} - -void BrowserActionsContainer::OnBrowserActionExecuted( - BrowserActionButton* button, - bool inspect_with_devtools) { - ExtensionAction* browser_action = button->browser_action(); - - // Popups just display. No notification to the extension. - // TODO(erikkay): should there be? - if (!button->IsPopup()) { - ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted( - profile_, browser_action->extension_id(), browser_); - return; - } - - // If we're showing the same popup, just hide it and return. - bool same_showing = popup_ && button == popup_button_; - - // Always hide the current popup, even if it's not the same. - // Only one popup should be visible at a time. - HidePopup(); - - if (same_showing) - return; - - // We can get the execute event for browser actions that are not visible, - // since buttons can be activated from the overflow menu (chevron). In that - // case we show the popup as originating from the chevron. - View* reference_view = button->GetParent()->IsVisible() ? button : chevron_; - gfx::Point origin; - View::ConvertPointToScreen(reference_view, &origin); - gfx::Rect rect = reference_view->bounds(); - rect.set_origin(origin); - - gfx::NativeWindow frame_window = browser_->window()->GetNativeHandle(); - BubbleBorder::ArrowLocation arrow_location = base::i18n::IsRTL() ? - BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT; - - popup_ = ExtensionPopup::Show(button->GetPopupUrl(), browser_, - browser_->profile(), frame_window, rect, arrow_location, true, - inspect_with_devtools, ExtensionPopup::BUBBLE_CHROME, this); - popup_button_ = button; - popup_button_->SetButtonPushed(); -} - -gfx::Size BrowserActionsContainer::GetPreferredSize() { - if (browser_action_views_.empty()) - return gfx::Size(ToolbarView::kStandardSpacing, 0); - - // We calculate the size of the view by taking the current width and - // subtracting resize_amount_ (the latter represents how far the user is - // resizing the view or, if animating the snapping, how far to animate it). - // But we also clamp it to a minimum size and the maximum size, so that the - // container can never shrink too far or take up more space than it needs. In - // other words: ContainerMinSize() < width() - resize < ClampTo(MAX). - int clamped_width = std::min( - std::max(ContainerMinSize(), container_width_ - resize_amount_), - IconCountToWidth(-1, false)); - return gfx::Size(clamped_width, 0); -} - -void BrowserActionsContainer::Layout() { - if (browser_action_views_.empty()) { - SetVisible(false); - return; - } - - SetVisible(true); - resize_area_->SetBounds(0, ToolbarView::kVertSpacing, kItemSpacing, - IconHeight()); - - // If the icons don't all fit, show the chevron (unless suppressed). - int max_x = GetPreferredSize().width(); - if ((IconCountToWidth(-1, false) > max_x) && !suppress_chevron_) { - chevron_->SetVisible(true); - gfx::Size chevron_size(chevron_->GetPreferredSize()); - max_x -= - ToolbarView::kStandardSpacing + chevron_size.width() + kChevronSpacing; - chevron_->SetBounds( - width() - ToolbarView::kStandardSpacing - chevron_size.width(), - ToolbarView::kVertSpacing, chevron_size.width(), chevron_size.height()); - } else { - chevron_->SetVisible(false); - } - - // Now draw the icons for the browser actions in the available space. - int icon_width = IconWidth(false); - for (size_t i = 0; i < browser_action_views_.size(); ++i) { - BrowserActionView* view = browser_action_views_[i]; - int x = ToolbarView::kStandardSpacing + (i * IconWidth(true)); - if (x + icon_width <= max_x) { - view->SetBounds(x, 0, icon_width, height()); - view->SetVisible(true); - } else { - view->SetVisible(false); - } - } -} - -void BrowserActionsContainer::Paint(gfx::Canvas* canvas) { - // TODO(sky/glen): Instead of using a drop indicator, animate the icons while - // dragging (like we do for tab dragging). - if (drop_indicator_position_ > -1) { - // The two-pixel width drop indicator. - static const int kDropIndicatorWidth = 2; - gfx::Rect indicator_bounds( - drop_indicator_position_ - (kDropIndicatorWidth / 2), - ToolbarView::kVertSpacing, kDropIndicatorWidth, IconHeight()); - - // Color of the drop indicator. - static const SkColor kDropIndicatorColor = SK_ColorBLACK; - canvas->FillRectInt(kDropIndicatorColor, indicator_bounds.x(), - indicator_bounds.y(), indicator_bounds.width(), - indicator_bounds.height()); - } -} - -void BrowserActionsContainer::ViewHierarchyChanged(bool is_add, - views::View* parent, - views::View* child) { - // No extensions (e.g., incognito). - if (!model_) - return; - - if (is_add && child == this) { - // Initial toolbar button creation and placement in the widget hierarchy. - // We do this here instead of in the constructor because AddBrowserAction - // calls Layout on the Toolbar, which needs this object to be constructed - // before its Layout function is called. - CreateBrowserActionViews(); - } -} - -bool BrowserActionsContainer::GetDropFormats( - int* formats, - std::set<OSExchangeData::CustomFormat>* custom_formats) { - custom_formats->insert(BrowserActionDragData::GetBrowserActionCustomFormat()); - - return true; -} - -bool BrowserActionsContainer::AreDropTypesRequired() { - return true; -} - -bool BrowserActionsContainer::CanDrop(const OSExchangeData& data) { - BrowserActionDragData drop_data; - return drop_data.Read(data) ? drop_data.IsFromProfile(profile_) : false; -} - -void BrowserActionsContainer::OnDragEntered( - const views::DropTargetEvent& event) { -} - -int BrowserActionsContainer::OnDragUpdated( - const views::DropTargetEvent& event) { - // First check if we are above the chevron (overflow) menu. - if (GetViewForPoint(event.location()) == chevron_) { - if (show_menu_task_factory_.empty() && !overflow_menu_) - StartShowFolderDropMenuTimer(); - return DragDropTypes::DRAG_MOVE; - } - StopShowFolderDropMenuTimer(); - - // Figure out where to display the indicator. This is a complex calculation: - - // First, we figure out how much space is to the left of the icon area, so we - // can calculate the true offset into the icon area. - int width_before_icons = ToolbarView::kStandardSpacing + - (base::i18n::IsRTL() ? - (chevron_->GetPreferredSize().width() + kChevronSpacing) : 0); - int offset_into_icon_area = event.x() - width_before_icons; - - // Next, we determine which icon to place the indicator in front of. We want - // to place the indicator in front of icon n when the cursor is between the - // midpoints of icons (n - 1) and n. To do this we take the offset into the - // icon area and transform it as follows: - // - // Real icon area: - // 0 a * b c - // | | | | - // |[IC|ON] [IC|ON] [IC|ON] - // We want to be before icon 0 for 0 < x <= a, icon 1 for a < x <= b, etc. - // Here the "*" represents the offset into the icon area, and since it's - // between a and b, we want to return "1". - // - // Transformed "icon area": - // 0 a * b c - // | | | | - // |[ICON] |[ICON] |[ICON] | - // If we shift both our offset and our divider points later by half an icon - // plus one spacing unit, then it becomes very easy to calculate how many - // divider points we've passed, because they're the multiples of "one icon - // plus padding". - int before_icon_unclamped = (offset_into_icon_area + (IconWidth(false) / 2) + - kItemSpacing) / IconWidth(true); - - // Because the user can drag outside the container bounds, we need to clamp to - // the valid range. Note that the maximum allowable value is (num icons), not - // (num icons - 1), because we represent the indicator being past the last - // icon as being "before the (last + 1) icon". - int before_icon = std::min(std::max(before_icon_unclamped, 0), - static_cast<int>(VisibleBrowserActions())); - - // Now we convert back to a pixel offset into the container. We want to place - // the center of the drop indicator at the midpoint of the space before our - // chosen icon. - SetDropIndicator(width_before_icons + (before_icon * IconWidth(true)) - - (kItemSpacing / 2)); - - return DragDropTypes::DRAG_MOVE; -} - -void BrowserActionsContainer::OnDragExited() { - StopShowFolderDropMenuTimer(); - drop_indicator_position_ = -1; - SchedulePaint(); -} - -int BrowserActionsContainer::OnPerformDrop( - const views::DropTargetEvent& event) { - BrowserActionDragData data; - if (!data.Read(event.GetData())) - return DragDropTypes::DRAG_NONE; - - // Make sure we have the same view as we started with. - DCHECK_EQ(browser_action_views_[data.index()]->button()->extension()->id(), - data.id()); - DCHECK(model_); - - size_t i = 0; - for (; i < browser_action_views_.size(); ++i) { - int view_x = - browser_action_views_[i]->GetBounds(APPLY_MIRRORING_TRANSFORMATION).x(); - if (!browser_action_views_[i]->IsVisible() || - (base::i18n::IsRTL() ? (view_x < drop_indicator_position_) : - (view_x >= drop_indicator_position_))) { - // We have reached the end of the visible icons or found one that has a - // higher x position than the drop point. - break; - } - } - - // |i| now points to the item to the right of the drop indicator*, which is - // correct when dragging an icon to the left. When dragging to the right, - // however, we want the icon being dragged to get the index of the item to - // the left of the drop indicator, so we subtract one. - // * Well, it can also point to the end, but not when dragging to the left. :) - if (i > data.index()) - --i; - - if (profile_->IsOffTheRecord()) - i = model_->IncognitoIndexToOriginal(i); - - model_->MoveBrowserAction( - browser_action_views_[data.index()]->button()->extension(), i); - - OnDragExited(); // Perform clean up after dragging. - return DragDropTypes::DRAG_MOVE; -} - -void BrowserActionsContainer::OnThemeChanged() { - LoadImages(); -} - -AccessibilityTypes::Role BrowserActionsContainer::GetAccessibleRole() { - return AccessibilityTypes::ROLE_GROUPING; -} - -void BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) { - if (source == chevron_) { - overflow_menu_ = new BrowserActionOverflowMenuController( - this, chevron_, browser_action_views_, VisibleBrowserActions()); - overflow_menu_->set_observer(this); - overflow_menu_->RunMenu(GetWindow()->GetNativeWindow(), false); - } -} - -void BrowserActionsContainer::WriteDragData(View* sender, - const gfx::Point& press_pt, - OSExchangeData* data) { - DCHECK(data); - - for (size_t i = 0; i < browser_action_views_.size(); ++i) { - BrowserActionButton* button = browser_action_views_[i]->button(); - if (button == sender) { - // Set the dragging image for the icon. - scoped_ptr<gfx::Canvas> canvas( - browser_action_views_[i]->GetIconWithBadge()); - drag_utils::SetDragImageOnDataObject(*canvas, button->size(), press_pt, - data); - - // Fill in the remaining info. - BrowserActionDragData drag_data( - browser_action_views_[i]->button()->extension()->id(), i); - drag_data.Write(profile_, data); - break; - } - } -} - -int BrowserActionsContainer::GetDragOperations(View* sender, - const gfx::Point& p) { - return DragDropTypes::DRAG_MOVE; -} - -bool BrowserActionsContainer::CanStartDrag(View* sender, - const gfx::Point& press_pt, - const gfx::Point& p) { - return true; -} - -void BrowserActionsContainer::OnResize(int resize_amount, bool done_resizing) { - if (!done_resizing) { - resize_amount_ = resize_amount; - OnBrowserActionVisibilityChanged(); - return; - } - - // Up until now we've only been modifying the resize_amount, but now it is - // time to set the container size to the size we have resized to, and then - // animate to the nearest icon count size if necessary (which may be 0). - int max_width = IconCountToWidth(-1, false); - container_width_ = - std::min(std::max(0, container_width_ - resize_amount), max_width); - SaveDesiredSizeAndAnimate(Tween::EASE_OUT, - WidthToIconCount(container_width_)); -} - -void BrowserActionsContainer::AnimationProgressed(const Animation* animation) { - DCHECK_EQ(resize_animation_.get(), animation); - resize_amount_ = static_cast<int>(resize_animation_->GetCurrentValue() * - (container_width_ - animation_target_size_)); - OnBrowserActionVisibilityChanged(); -} - -void BrowserActionsContainer::AnimationEnded(const Animation* animation) { - container_width_ = animation_target_size_; - animation_target_size_ = 0; - resize_amount_ = 0; - OnBrowserActionVisibilityChanged(); - suppress_chevron_ = false; -} - -void BrowserActionsContainer::NotifyMenuDeleted( - BrowserActionOverflowMenuController* controller) { - DCHECK(controller == overflow_menu_); - overflow_menu_ = NULL; -} - -void BrowserActionsContainer::InspectPopup(ExtensionAction* action) { - OnBrowserActionExecuted(GetBrowserActionView(action)->button(), true); -} - -void BrowserActionsContainer::ExtensionPopupIsClosing(ExtensionPopup* popup) { - // ExtensionPopup is ref-counted, so we don't need to delete it. - DCHECK_EQ(popup_, popup); - popup_ = NULL; - popup_button_->SetButtonNotPushed(); - popup_button_ = NULL; -} - -void BrowserActionsContainer::MoveBrowserAction(const std::string& extension_id, - size_t new_index) { - ExtensionsService* service = profile_->GetExtensionsService(); - if (service) { - const Extension* extension = service->GetExtensionById(extension_id, false); - model_->MoveBrowserAction(extension, new_index); - SchedulePaint(); - } -} - -void BrowserActionsContainer::HidePopup() { - if (popup_) - popup_->Close(); -} - -void BrowserActionsContainer::TestExecuteBrowserAction(int index) { - BrowserActionButton* button = browser_action_views_[index]->button(); - OnBrowserActionExecuted(button, false); -} - -void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) { - model_->SetVisibleIconCount(icons); - chevron_->SetVisible(icons < browser_action_views_.size()); - container_width_ = IconCountToWidth(icons, chevron_->IsVisible()); - Layout(); - SchedulePaint(); -} - -// static -int BrowserActionsContainer::IconWidth(bool include_padding) { - static bool initialized = false; - static int icon_width = 0; - if (!initialized) { - initialized = true; - icon_width = ResourceBundle::GetSharedInstance().GetBitmapNamed( - IDR_BROWSER_ACTION)->width(); - } - return icon_width + (include_padding ? kItemSpacing : 0); -} - -// static -int BrowserActionsContainer::IconHeight() { - static bool initialized = false; - static int icon_height = 0; - if (!initialized) { - initialized = true; - icon_height = ResourceBundle::GetSharedInstance().GetBitmapNamed( - IDR_BROWSER_ACTION)->height(); - } - return icon_height; -} - -void BrowserActionsContainer::BrowserActionAdded(const Extension* extension, - int index) { -#if defined(DEBUG) - for (size_t i = 0; i < browser_action_views_.size(); ++i) { - DCHECK(browser_action_views_[i]->button()->extension() != extension) << - "Asked to add a browser action view for an extension that already " - "exists."; - } -#endif - CloseOverflowMenu(); - - if (!ShouldDisplayBrowserAction(extension)) - return; - - size_t visible_actions = VisibleBrowserActions(); - - // Add the new browser action to the vector and the view hierarchy. - if (profile_->IsOffTheRecord()) - index = model_->OriginalIndexToIncognito(index); - BrowserActionView* view = new BrowserActionView(extension, this); - browser_action_views_.insert(browser_action_views_.begin() + index, view); - AddChildView(index, view); - - // If we are still initializing the container, don't bother animating. - if (!model_->extensions_initialized()) - return; - - // Enlarge the container if it was already at maximum size and we're not in - // the middle of upgrading. - if ((model_->GetVisibleIconCount() < 0) && - !profile_->GetExtensionsService()->IsBeingUpgraded(extension)) { - suppress_chevron_ = true; - SaveDesiredSizeAndAnimate(Tween::LINEAR, visible_actions + 1); - } else { - // Just redraw the (possibly modified) visible icon set. - OnBrowserActionVisibilityChanged(); - } -} - -void BrowserActionsContainer::BrowserActionRemoved(const Extension* extension) { - CloseOverflowMenu(); - - if (popup_ && popup_->host()->extension() == extension) - HidePopup(); - - size_t visible_actions = VisibleBrowserActions(); - for (BrowserActionViews::iterator iter = browser_action_views_.begin(); - iter != browser_action_views_.end(); ++iter) { - if ((*iter)->button()->extension() == extension) { - RemoveChildView(*iter); - delete *iter; - browser_action_views_.erase(iter); - - // If the extension is being upgraded we don't want the bar to shrink - // because the icon is just going to get re-added to the same location. - if (profile_->GetExtensionsService()->IsBeingUpgraded(extension)) - return; - - if (browser_action_views_.size() > visible_actions) { - // If we have more icons than we can show, then we must not be changing - // the container size (since we either removed an icon from the main - // area and one from the overflow list will have shifted in, or we - // removed an entry directly from the overflow list). - OnBrowserActionVisibilityChanged(); - } else { - // Either we went from overflow to no-overflow, or we shrunk the no- - // overflow container by 1. Either way the size changed, so animate. - chevron_->SetVisible(false); - SaveDesiredSizeAndAnimate(Tween::EASE_OUT, - browser_action_views_.size()); - } - return; - } - } -} - -void BrowserActionsContainer::BrowserActionMoved(const Extension* extension, - int index) { - if (!ShouldDisplayBrowserAction(extension)) - return; - - if (profile_->IsOffTheRecord()) - index = model_->OriginalIndexToIncognito(index); - - DCHECK(index >= 0 && index < static_cast<int>(browser_action_views_.size())); - - DeleteBrowserActionViews(); - CreateBrowserActionViews(); - Layout(); - SchedulePaint(); -} - -void BrowserActionsContainer::ModelLoaded() { - SetContainerWidth(); -} - -void BrowserActionsContainer::LoadImages() { - ThemeProvider* tp = GetThemeProvider(); - chevron_->SetIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW)); - chevron_->SetHoverIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW_H)); - chevron_->SetPushedIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW_P)); -} - -void BrowserActionsContainer::SetContainerWidth() { - int visible_actions = model_->GetVisibleIconCount(); - if (visible_actions < 0) // All icons should be visible. - visible_actions = model_->size(); - chevron_->SetVisible(static_cast<size_t>(visible_actions) < model_->size()); - container_width_ = IconCountToWidth(visible_actions, chevron_->IsVisible()); -} - -void BrowserActionsContainer::CloseOverflowMenu() { - if (overflow_menu_) - overflow_menu_->CancelMenu(); -} - -void BrowserActionsContainer::StopShowFolderDropMenuTimer() { - show_menu_task_factory_.RevokeAll(); -} - -void BrowserActionsContainer::StartShowFolderDropMenuTimer() { - int delay = View::GetMenuShowDelay(); - MessageLoop::current()->PostDelayedTask(FROM_HERE, - show_menu_task_factory_.NewRunnableMethod( - &BrowserActionsContainer::ShowDropFolder), - delay); -} - -void BrowserActionsContainer::ShowDropFolder() { - DCHECK(!overflow_menu_); - SetDropIndicator(-1); - overflow_menu_ = new BrowserActionOverflowMenuController( - this, chevron_, browser_action_views_, VisibleBrowserActions()); - overflow_menu_->set_observer(this); - overflow_menu_->RunMenu(GetWindow()->GetNativeWindow(), true); -} - -void BrowserActionsContainer::SetDropIndicator(int x_pos) { - if (drop_indicator_position_ != x_pos) { - drop_indicator_position_ = x_pos; - SchedulePaint(); - } -} - -int BrowserActionsContainer::IconCountToWidth(int icons, - bool display_chevron) const { - if (icons < 0) - icons = browser_action_views_.size(); - if ((icons == 0) && !display_chevron) - return ToolbarView::kStandardSpacing; - int icons_size = - (icons == 0) ? 0 : ((icons * IconWidth(true)) - kItemSpacing); - int chevron_size = display_chevron ? - (kChevronSpacing + chevron_->GetPreferredSize().width()) : 0; - return ToolbarView::kStandardSpacing + icons_size + chevron_size + - ToolbarView::kStandardSpacing; -} - -size_t BrowserActionsContainer::WidthToIconCount(int pixels) const { - // Check for widths large enough to show the entire icon set. - if (pixels >= IconCountToWidth(-1, false)) - return browser_action_views_.size(); - - // We need to reserve space for the resize area, chevron, and the spacing on - // either side of the chevron. - int available_space = pixels - ToolbarView::kStandardSpacing - - chevron_->GetPreferredSize().width() - kChevronSpacing - - ToolbarView::kStandardSpacing; - // Now we add an extra between-item padding value so the space can be divided - // evenly by (size of icon with padding). - return static_cast<size_t>( - std::max(0, available_space + kItemSpacing) / IconWidth(true)); -} - -int BrowserActionsContainer::ContainerMinSize() const { - return ToolbarView::kStandardSpacing + kChevronSpacing + - chevron_->GetPreferredSize().width() + ToolbarView::kStandardSpacing; -} - -void BrowserActionsContainer::SaveDesiredSizeAndAnimate( - Tween::Type tween_type, - size_t num_visible_icons) { - // Save off the desired number of visible icons. We do this now instead of at - // the end of the animation so that even if the browser is shut down while - // animating, the right value will be restored on next run. - // NOTE: Don't save the icon count in incognito because there may be fewer - // icons in that mode. The result is that the container in a normal window is - // always at least as wide as in an incognito window. - if (!profile_->IsOffTheRecord()) - model_->SetVisibleIconCount(num_visible_icons); - - int target_size = IconCountToWidth(num_visible_icons, - num_visible_icons < browser_action_views_.size()); - if (!disable_animations_during_testing_) { - // Animate! We have to set the animation_target_size_ after calling Reset(), - // because that could end up calling AnimationEnded which clears the value. - resize_animation_->Reset(); - resize_animation_->SetTweenType(tween_type); - animation_target_size_ = target_size; - resize_animation_->Show(); - } else { - animation_target_size_ = target_size; - AnimationEnded(resize_animation_.get()); - } -} - -bool BrowserActionsContainer::ShouldDisplayBrowserAction( - const Extension* extension) { - // Only display incognito-enabled extensions while in incognito mode. - return (!profile_->IsOffTheRecord() || - profile_->GetExtensionsService()->IsIncognitoEnabled(extension)); -} |