// Copyright (c) 2011 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. #ifndef CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_BAR_VIEW_H_ #define CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_BAR_VIEW_H_ #pragma once #include #include "base/compiler_specific.h" #include "chrome/browser/bookmarks/bookmark_model_observer.h" #include "chrome/browser/bookmarks/bookmark_node_data.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/ui/views/bookmarks/bookmark_bar_instructions_view.h" #include "chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.h" #include "chrome/browser/ui/views/detachable_toolbar_view.h" #include "content/common/notification_registrar.h" #include "ui/base/animation/animation_delegate.h" #include "views/controls/button/button.h" #include "views/controls/menu/view_menu_delegate.h" class Browser; class PageNavigator; class PrefService; namespace ui { class SlideAnimation; } namespace views { class CustomButton; class MenuButton; class MenuItemView; class TextButton; } // BookmarkBarView renders the BookmarkModel. Each starred entry on the // BookmarkBar is rendered as a MenuButton. An additional MenuButton aligned to // the right allows the user to quickly see recently starred entries. // // BookmarkBarView shows the bookmarks from a specific Profile. BookmarkBarView // waits until the HistoryService for the profile has been loaded before // creating the BookmarkModel. class BookmarkBarView : public DetachableToolbarView, public ProfileSyncServiceObserver, public BookmarkModelObserver, public views::ViewMenuDelegate, public views::ButtonListener, public NotificationObserver, public views::ContextMenuController, public views::DragController, public ui::AnimationDelegate, public BookmarkMenuController::Observer, public BookmarkBarInstructionsView::Delegate { friend class ShowFolderMenuTask; public: // Constants used in Browser View, as well as here. // How inset the bookmarks bar is when displayed on the new tab page. static const int kNewtabHorizontalPadding; static const int kNewtabVerticalPadding; // Maximum size of buttons on the bookmark bar. static const int kMaxButtonWidth; // Interface implemented by controllers/views that need to be notified any // time the model changes, typically to cancel an operation that is showing // data from the model such as a menu. This isn't intended as a general // way to be notified of changes, rather for cases where a controller/view is // showing data from the model in a modal like setting and needs to cleanly // exit the modal loop if the model changes out from under it. // // A controller/view that needs this notification should install itself as the // ModelChangeListener via the SetModelChangedListener method when shown and // reset the ModelChangeListener of the BookmarkBarView when it closes by way // of either the SetModelChangedListener method or the // ClearModelChangedListenerIfEquals method. class ModelChangedListener { public: virtual ~ModelChangedListener() {} // Invoked when the model changes. Should cancel the edit and close any // dialogs. virtual void ModelChanged() = 0; }; static const int kNewtabBarHeight; BookmarkBarView(Profile* profile, Browser* browser); virtual ~BookmarkBarView(); // Resets the profile. This removes any buttons for the current profile and // recreates the models. void SetProfile(Profile* profile); // Returns the current profile. Profile* GetProfile() { return profile_; } // Returns the current browser. Browser* browser() const { return browser_; } // Sets the PageNavigator that is used when the user selects an entry on // the bookmark bar. void SetPageNavigator(PageNavigator* navigator); // Sets whether the containing browser is showing an infobar. This affects // layout during animation. void set_infobar_visible(bool infobar_visible) { infobar_visible_ = infobar_visible; } virtual bool IsOnTop() const; // DetachableToolbarView methods: virtual bool IsDetached() const OVERRIDE; virtual double GetAnimationValue() const OVERRIDE; virtual int GetToolbarOverlap() const OVERRIDE; // View methods: virtual gfx::Size GetPreferredSize() OVERRIDE; virtual gfx::Size GetMinimumSize() OVERRIDE; virtual void Layout() OVERRIDE; virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child) OVERRIDE; virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE; virtual bool GetDropFormats( int* formats, std::set* custom_formats) OVERRIDE; virtual bool AreDropTypesRequired() OVERRIDE; virtual bool CanDrop(const ui::OSExchangeData& data) OVERRIDE; virtual void OnDragEntered(const views::DropTargetEvent& event) OVERRIDE; virtual int OnDragUpdated(const views::DropTargetEvent& event) OVERRIDE; virtual void OnDragExited() OVERRIDE; virtual int OnPerformDrop(const views::DropTargetEvent& event) OVERRIDE; virtual void ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) OVERRIDE; // AccessiblePaneView methods: virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE; // ProfileSyncServiceObserver method. virtual void OnStateChanged(); // Called when fullscreen mode toggles on or off; this affects our layout. void OnFullscreenToggled(bool fullscreen); // Sets the model change listener to listener. void SetModelChangedListener(ModelChangedListener* listener) { model_changed_listener_ = listener; } // If the ModelChangedListener is listener, ModelChangeListener is set to // NULL. void ClearModelChangedListenerIfEquals(ModelChangedListener* listener) { if (model_changed_listener_ == listener) model_changed_listener_ = NULL; } // Returns the model change listener. ModelChangedListener* GetModelChangedListener() { return model_changed_listener_; } // Returns the page navigator. PageNavigator* GetPageNavigator() { return page_navigator_; } // Returns the model. BookmarkModel* GetModel() { return model_; } // Returns true if the bookmarks bar preference is set to 'always show'. bool IsAlwaysShown() const; // True if we're on a page where the bookmarks bar is always visible. bool OnNewTabPage() const; // How much we want the bookmark bar to overlap the toolbar. If |return_max| // is true, we return the maximum overlap rather than the current overlap. int GetToolbarOverlap(bool return_max) const; // Whether or not we are animating. bool is_animating(); // SlideAnimationDelegate implementation. virtual void AnimationProgressed(const ui::Animation* animation); virtual void AnimationEnded(const ui::Animation* animation); // BookmarkMenuController::Observer virtual void BookmarkMenuDeleted(BookmarkMenuController* controller); // Returns the button at the specified index. views::TextButton* GetBookmarkButton(int index); // Returns the button responsible for showing bookmarks in the other bookmark // folder. views::MenuButton* other_bookmarked_button() const { return other_bookmarked_button_; } // Returns the active MenuItemView, or NULL if a menu isn't showing. views::MenuItemView* GetMenu(); // Returns the drop MenuItemView, or NULL if a menu isn't showing. views::MenuItemView* GetDropMenu(); // Returns the context menu, or null if one isn't showing. views::MenuItemView* GetContextMenu(); // Returns the button used when not all the items on the bookmark bar fit. views::MenuButton* overflow_button() const { return overflow_button_; } // If |loc| is over a bookmark button the node is returned corresponding // to the button and |start_index| is set to 0. If a overflow button is // showing and |loc| is over the overflow button, the bookmark bar node is // returned and |start_index| is set to the index of the first node // contained in the overflow menu. const BookmarkNode* GetNodeForButtonAt(const gfx::Point& loc, int* start_index); // Returns the MenuButton for node. views::MenuButton* GetMenuButtonForNode(const BookmarkNode* node); // Returns the position to anchor the menu for |button| at, the index of the // first child of the node to build the menu from. void GetAnchorPositionAndStartIndexForButton( views::MenuButton* button, views::MenuItemView::AnchorPosition* anchor, int* start_index); // BookmarkBarInstructionsView::Delegate. virtual void ShowImportDialog(); // If a button is currently throbbing, it is stopped. If immediate is true // the throb stops immediately, otherwise it stops after a couple more // throbs. void StopThrobbing(bool immediate); // Returns the number of buttons corresponding to starred urls/folders. This // is equivalent to the number of children the bookmark bar node from the // bookmark bar model has. int GetBookmarkButtonCount(); // Returns the tooltip text for the specified url and title. The returned // text is clipped to fit within the bounds of the monitor. // // Note that we adjust the direction of both the URL and the title based on // the locale so that pure LTR strings are displayed properly in RTL locales. static std::wstring CreateToolTipForURLAndTitle( const gfx::Point& screen_loc, const GURL& url, const std::wstring& title, Profile* profile); // If true we're running tests. This short circuits a couple of animations. static bool testing_; private: class ButtonSeparatorView; struct DropInfo; // Task that invokes ShowDropFolderForNode when run. ShowFolderDropMenuTask // deletes itself once run. class ShowFolderDropMenuTask : public Task { public: ShowFolderDropMenuTask(BookmarkBarView* view, const BookmarkNode* node) : view_(view), node_(node) { } void Cancel() { view_->show_folder_drop_menu_task_ = NULL; view_ = NULL; } virtual void Run() { if (view_) { view_->show_folder_drop_menu_task_ = NULL; view_->ShowDropFolderForNode(node_); } // MessageLoop deletes us. } private: BookmarkBarView* view_; const BookmarkNode* node_; DISALLOW_COPY_AND_ASSIGN(ShowFolderDropMenuTask); }; // Creates recent bookmark button and when visible button as well as // calculating the preferred height. void Init(); // Creates the button showing the other bookmarked items. views::MenuButton* CreateOtherBookmarkedButton(); // Creates the button used when not all bookmark buttons fit. views::MenuButton* CreateOverflowButton(); // Invoked when the bookmark bar model has finished loading. Creates a button // for each of the children of the root node from the model. virtual void Loaded(BookmarkModel* model); // Invoked when the model is being deleted. virtual void BookmarkModelBeingDeleted(BookmarkModel* model); // Invokes added followed by removed. virtual void BookmarkNodeMoved(BookmarkModel* model, const BookmarkNode* old_parent, int old_index, const BookmarkNode* new_parent, int new_index); // Notifies ModelChangeListener of change. // If the node was added to the root node, a button is created and added to // this bookmark bar view. virtual void BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, int index); // Implementation for BookmarkNodeAddedImpl. void BookmarkNodeAddedImpl(BookmarkModel* model, const BookmarkNode* parent, int index); // Notifies ModelChangeListener of change. // If the node was a child of the root node, the button corresponding to it // is removed. virtual void BookmarkNodeRemoved(BookmarkModel* model, const BookmarkNode* parent, int old_index, const BookmarkNode* node); // Implementation for BookmarkNodeRemoved. void BookmarkNodeRemovedImpl(BookmarkModel* model, const BookmarkNode* parent, int index); // Notifies ModelChangedListener and invokes BookmarkNodeChangedImpl. virtual void BookmarkNodeChanged(BookmarkModel* model, const BookmarkNode* node); // If the node is a child of the root node, the button is updated // appropriately. void BookmarkNodeChangedImpl(BookmarkModel* model, const BookmarkNode* node); virtual void BookmarkNodeChildrenReordered(BookmarkModel* model, const BookmarkNode* node); // Invoked when the favicon is available. If the node is a child of the // root node, the appropriate button is updated. If a menu is showing, the // call is forwarded to the menu to allow for it to update the icon. virtual void BookmarkNodeFaviconLoaded(BookmarkModel* model, const BookmarkNode* node); // DragController method. Determines the node representing sender and invokes // WriteDragData to write the actual data. virtual void WriteDragDataForView(views::View* sender, const gfx::Point& press_pt, ui::OSExchangeData* data) OVERRIDE; virtual int GetDragOperationsForView(views::View* sender, const gfx::Point& p) OVERRIDE; virtual bool CanStartDragForView(views::View* sender, const gfx::Point& press_pt, const gfx::Point& p) OVERRIDE; // Writes a BookmarkNodeData for node to data. void WriteBookmarkDragData(const BookmarkNode* node, ui::OSExchangeData* data); // ViewMenuDelegate method. Ends up creating a BookmarkMenuController to // show the menu. virtual void RunMenu(views::View* view, const gfx::Point& pt); // Invoked when a star entry corresponding to a URL on the bookmark bar is // pressed. Forwards to the PageNavigator to open the URL. virtual void ButtonPressed(views::Button* sender, const views::Event& event); // Invoked for this View, one of the buttons or the 'other' button. Shows the // appropriate context menu. virtual void ShowContextMenuForView(views::View* source, const gfx::Point& p, bool is_mouse_gesture); // Creates the button for rendering the specified bookmark node. views::View* CreateBookmarkButton(const BookmarkNode* node); // COnfigures the button from the specified node. This sets the text, // and icon. void ConfigureButton(const BookmarkNode* node, views::TextButton* button); // Used when showing the menu allowing the user to choose when the bar is // visible. Return value corresponds to the users preference for when the // bar is visible. virtual bool IsItemChecked(int id) const; // Used when showing the menu allowing the user to choose when the bar is // visible. Updates the preferences to match the users choice as appropriate. virtual void ExecuteCommand(int id); // NotificationService method. virtual void Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details); // Overridden from views::View. virtual void OnThemeChanged(); // If the ModelChangedListener is non-null, ModelChanged is invoked on it. void NotifyModelChanged(); // Shows the menu used during drag and drop for the specified node. void ShowDropFolderForNode(const BookmarkNode* node); // Cancels the timer used to show a drop menu. void StopShowFolderDropMenuTimer(); // Stars the timer used to show a drop menu for node. void StartShowFolderDropMenuTimer(const BookmarkNode* node); // Returns the drop operation and index for the drop based on the event // and data. Returns ui::DragDropTypes::DRAG_NONE if not a valid location. int CalculateDropOperation(const views::DropTargetEvent& event, const BookmarkNodeData& data, int* index, bool* drop_on, bool* is_over_overflow, bool* is_over_other); // Returns the index of the first hidden bookmark button. If all buttons are // visible, this returns GetBookmarkButtonCount(). int GetFirstHiddenNodeIndex(); // This determines which view should throb and starts it // throbbing (e.g when the bookmark bubble is showing). // If |overflow_only| is true, start throbbing only if |node| is hidden in // the overflow menu. void StartThrobbing(const BookmarkNode* node, bool overflow_only); // Returns the view to throb when a node is removed. |parent| is the parent of // the node that was removed, and |old_index| the index of the node that was // removed. views::CustomButton* DetermineViewToThrobFromRemove( const BookmarkNode* parent, int old_index); // Updates the colors for all the child objects in the bookmarks bar. void UpdateColors(); // Updates the visibility of |other_bookmarked_button_| and // |bookmarks_separator_view_|. void UpdateOtherBookmarksVisibility(); // This method computes the bounds for the bookmark bar items. If // |compute_bounds_only| = TRUE, the bounds for the items are just computed, // but are not set. This mode is used by GetPreferredSize() to obtain the // desired bounds. If |compute_bounds_only| = FALSE, the bounds are set. gfx::Size LayoutItems(bool compute_bounds_only); // Creates the sync error button and adds it as a child view. views::TextButton* CreateSyncErrorButton(); NotificationRegistrar registrar_; Profile* profile_; // Used for opening urls. PageNavigator* page_navigator_; // Model providing details as to the starred entries/folders that should be // shown. This is owned by the Profile. BookmarkModel* model_; // Used to manage showing a Menu, either for the most recently bookmarked // entries, or for the starred folder. BookmarkMenuController* bookmark_menu_; // Used when showing a menu for drag and drop. That is, if the user drags // over a folder this becomes non-null and manages the menu showing the // contents of the node. BookmarkMenuController* bookmark_drop_menu_; // Shows the other bookmark entries. views::MenuButton* other_bookmarked_button_; // ModelChangeListener. ModelChangedListener* model_changed_listener_; // Task used to delay showing of the drop menu. ShowFolderDropMenuTask* show_folder_drop_menu_task_; // Used to track drops on the bookmark bar view. scoped_ptr drop_info_; // The sync re-login indicator which appears when the user needs to re-enter // credentials in order to continue syncing. views::TextButton* sync_error_button_; // A pointer to the ProfileSyncService instance if one exists. ProfileSyncService* sync_service_; // Visible if not all the bookmark buttons fit. views::MenuButton* overflow_button_; // BookmarkBarInstructionsView that is visible if there are no bookmarks on // the bookmark bar. views::View* instructions_; ButtonSeparatorView* bookmarks_separator_view_; // Owning browser. This is NULL during testing. Browser* browser_; // True if the owning browser is showing an infobar. bool infobar_visible_; // Animation controlling showing and hiding of the bar. scoped_ptr size_animation_; // If the bookmark bubble is showing, this is the visible ancestor of the URL. // The visible ancestor is either the other_bookmarked_button_, // overflow_button_ or a button on the bar. views::CustomButton* throbbing_view_; // Background for extension toolstrips. SkBitmap toolstrip_background_; DISALLOW_COPY_AND_ASSIGN(BookmarkBarView); }; #endif // CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_BAR_VIEW_H_