1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_BAR_VIEW_H_ 6 #define CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_BAR_VIEW_H_ 7 8 #include <memory> 9 #include <set> 10 11 #include "base/compiler_specific.h" 12 #include "base/macros.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/observer_list.h" 15 #include "chrome/browser/ui/bookmarks/bookmark_bar.h" 16 #include "chrome/browser/ui/bookmarks/bookmark_bubble_observer.h" 17 #include "chrome/browser/ui/bookmarks/bookmark_stats.h" 18 #include "chrome/browser/ui/views/bookmarks/bookmark_menu_controller_observer.h" 19 #include "components/bookmarks/browser/bookmark_model_observer.h" 20 #include "components/bookmarks/browser/bookmark_node_data.h" 21 #include "components/prefs/pref_change_registrar.h" 22 #include "ui/gfx/animation/slide_animation.h" 23 #include "ui/views/accessible_pane_view.h" 24 #include "ui/views/animation/animation_delegate_views.h" 25 #include "ui/views/context_menu_controller.h" 26 #include "ui/views/controls/menu/menu_types.h" 27 #include "ui/views/drag_controller.h" 28 29 class BookmarkBarViewObserver; 30 class BookmarkBarViewTestHelper; 31 class BookmarkContextMenu; 32 class Browser; 33 class BrowserView; 34 class Profile; 35 class ReadLaterButton; 36 37 namespace bookmarks { 38 class BookmarkModel; 39 class ManagedBookmarkService; 40 } // namespace bookmarks 41 42 namespace content { 43 class PageNavigator; 44 } 45 46 namespace gfx { 47 class FontList; 48 } 49 50 namespace views { 51 class Button; 52 class MenuButton; 53 class MenuItemView; 54 class LabelButton; 55 } // namespace views 56 57 // BookmarkBarView renders the BookmarkModel. Each starred entry on the 58 // BookmarkBar is rendered as a MenuButton. An additional MenuButton aligned to 59 // the right allows the user to quickly see recently starred entries. 60 // 61 // BookmarkBarView shows the bookmarks from a specific Profile. BookmarkBarView 62 // waits until the HistoryService for the profile has been loaded before 63 // creating the BookmarkModel. 64 class BookmarkBarView : public views::AccessiblePaneView, 65 public bookmarks::BookmarkModelObserver, 66 public views::ContextMenuController, 67 public views::DragController, 68 public views::AnimationDelegateViews, 69 public BookmarkMenuControllerObserver, 70 public bookmarks::BookmarkBubbleObserver { 71 public: 72 // The internal view class name. 73 static const char kViewClassName[]; 74 75 // |browser_view| can be NULL during tests. 76 BookmarkBarView(Browser* browser, BrowserView* browser_view); 77 ~BookmarkBarView() override; 78 79 static void DisableAnimationsForTesting(bool disabled); 80 81 // Returns the current browser. browser()82 Browser* browser() const { return browser_; } 83 84 void AddObserver(BookmarkBarViewObserver* observer); 85 void RemoveObserver(BookmarkBarViewObserver* observer); 86 87 // Sets the PageNavigator that is used when the user selects an entry on 88 // the bookmark bar. 89 void SetPageNavigator(content::PageNavigator* navigator); 90 91 // Sets whether the containing browser is showing an infobar. This affects 92 // layout during animation. 93 void SetInfoBarVisible(bool infobar_visible); 94 95 // Changes the state of the bookmark bar. 96 void SetBookmarkBarState(BookmarkBar::State state, 97 BookmarkBar::AnimateChangeType animate_type); 98 99 // If |loc| is over a bookmark button the node is returned corresponding to 100 // the button and |model_start_index| is set to 0. If a overflow button is 101 // showing and |loc| is over the overflow button, the bookmark bar node is 102 // returned and |model_start_index| is set to the index of the first node 103 // contained in the overflow menu. 104 const bookmarks::BookmarkNode* GetNodeForButtonAtModelIndex( 105 const gfx::Point& loc, 106 size_t* model_start_index); 107 108 // Returns the MenuButton for node. 109 views::MenuButton* GetMenuButtonForNode(const bookmarks::BookmarkNode* node); 110 111 // Returns the position to anchor the menu for |button| at. 112 void GetAnchorPositionForButton(views::MenuButton* button, 113 views::MenuAnchorPosition* anchor); 114 115 // Returns the button responsible for showing bookmarks in the 116 // "Other Bookmarks" folder. other_bookmarks_button()117 views::MenuButton* other_bookmarks_button() const { 118 return other_bookmarks_button_; 119 } 120 121 // Returns the button used when not all the items on the bookmark bar fit. overflow_button()122 views::MenuButton* overflow_button() const { return overflow_button_; } 123 read_later_button()124 ReadLaterButton* read_later_button() const { return read_later_button_; } 125 size_animation()126 const gfx::Animation& size_animation() { return size_animation_; } 127 128 // Returns the active MenuItemView, or NULL if a menu isn't showing. 129 views::MenuItemView* GetMenu(); 130 131 // Returns the context menu, or null if one isn't showing. 132 views::MenuItemView* GetContextMenu(); 133 134 // Returns the drop MenuItemView, or NULL if a menu isn't showing. 135 views::MenuItemView* GetDropMenu(); 136 137 // If a button is currently throbbing, it is stopped. If immediate is true 138 // the throb stops immediately, otherwise it stops after a couple more 139 // throbs. 140 void StopThrobbing(bool immediate); 141 142 // Returns the tooltip text for the specified url and title. The returned 143 // text is clipped to fit |max_tooltip_width|. 144 // 145 // Note that we adjust the direction of both the URL and the title based on 146 // the locale so that pure LTR strings are displayed properly in RTL locales. 147 static base::string16 CreateToolTipForURLAndTitle( 148 int max_tooltip_width, 149 const gfx::FontList& font_list, 150 const GURL& url, 151 const base::string16& title); 152 153 // views::View: 154 gfx::Size CalculatePreferredSize() const override; 155 gfx::Size GetMinimumSize() const override; 156 void Layout() override; 157 void ViewHierarchyChanged( 158 const views::ViewHierarchyChangedDetails& details) override; 159 void PaintChildren(const views::PaintInfo& paint_info) override; 160 bool GetDropFormats(int* formats, 161 std::set<ui::ClipboardFormatType>* format_types) override; 162 bool AreDropTypesRequired() override; 163 bool CanDrop(const ui::OSExchangeData& data) override; 164 void OnDragEntered(const ui::DropTargetEvent& event) override; 165 int OnDragUpdated(const ui::DropTargetEvent& event) override; 166 void OnDragExited() override; 167 int OnPerformDrop(const ui::DropTargetEvent& event) override; 168 void OnThemeChanged() override; 169 const char* GetClassName() const override; 170 void VisibilityChanged(View* starting_from, bool is_visible) override; 171 172 // AccessiblePaneView: 173 void GetAccessibleNodeData(ui::AXNodeData* node_data) override; 174 175 // views::AnimationDelegateViews: 176 void AnimationProgressed(const gfx::Animation* animation) override; 177 void AnimationEnded(const gfx::Animation* animation) override; 178 179 // BookmarkMenuControllerObserver: 180 void BookmarkMenuControllerDeleted( 181 BookmarkMenuController* controller) override; 182 183 // bookmarks::BookmarkBubbleObserver: 184 void OnBookmarkBubbleShown(const bookmarks::BookmarkNode* node) override; 185 void OnBookmarkBubbleHidden() override; 186 187 // bookmarks::BookmarkModelObserver: 188 void BookmarkModelLoaded(bookmarks::BookmarkModel* model, 189 bool ids_reassigned) override; 190 void BookmarkModelBeingDeleted(bookmarks::BookmarkModel* model) override; 191 void BookmarkNodeMoved(bookmarks::BookmarkModel* model, 192 const bookmarks::BookmarkNode* old_parent, 193 size_t old_index, 194 const bookmarks::BookmarkNode* new_parent, 195 size_t new_index) override; 196 void BookmarkNodeAdded(bookmarks::BookmarkModel* model, 197 const bookmarks::BookmarkNode* parent, 198 size_t index) override; 199 void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, 200 const bookmarks::BookmarkNode* parent, 201 size_t old_index, 202 const bookmarks::BookmarkNode* node, 203 const std::set<GURL>& removed_urls) override; 204 void BookmarkAllUserNodesRemoved(bookmarks::BookmarkModel* model, 205 const std::set<GURL>& removed_urls) override; 206 void BookmarkNodeChanged(bookmarks::BookmarkModel* model, 207 const bookmarks::BookmarkNode* node) override; 208 void BookmarkNodeChildrenReordered( 209 bookmarks::BookmarkModel* model, 210 const bookmarks::BookmarkNode* node) override; 211 void BookmarkNodeFaviconChanged(bookmarks::BookmarkModel* model, 212 const bookmarks::BookmarkNode* node) override; 213 214 // views::DragController: 215 void WriteDragDataForView(views::View* sender, 216 const gfx::Point& press_pt, 217 ui::OSExchangeData* data) override; 218 int GetDragOperationsForView(views::View* sender, 219 const gfx::Point& p) override; 220 bool CanStartDragForView(views::View* sender, 221 const gfx::Point& press_pt, 222 const gfx::Point& p) override; 223 224 // views::ContextMenuController: 225 void ShowContextMenuForViewImpl(views::View* source, 226 const gfx::Point& point, 227 ui::MenuSourceType source_type) override; 228 229 private: 230 class ButtonSeparatorView; 231 struct DropInfo; 232 struct DropLocation; 233 234 friend class BookmarkBarViewTestHelper; 235 friend class BookmarkBarViewEventTestBase; 236 237 // Used to identify what the user is dropping onto. 238 enum DropButtonType { DROP_BOOKMARK, DROP_OTHER_FOLDER, DROP_OVERFLOW }; 239 240 // Creates recent bookmark button and when visible button as well as 241 // calculating the preferred height. 242 void Init(); 243 244 void AppsPageShortcutPressed(const ui::Event& event); 245 void OnButtonPressed(const bookmarks::BookmarkNode* node, 246 const ui::Event& event); 247 void OnMenuButtonPressed(const bookmarks::BookmarkNode* node, 248 const ui::Event& event); 249 250 // NOTE: unless otherwise stated all methods that take an index are in terms 251 // of the bookmark bar view. Typically the view index and model index are the 252 // same, but they may differ during animations or drag and drop. 253 // 254 // It's easy to get the mapping wrong. For this reason all these methods are 255 // private. 256 257 // Returns the index of the first hidden bookmark button. If all buttons are 258 // visible, this returns GetBookmarkButtonCount(). 259 size_t GetFirstHiddenNodeIndex(); 260 261 // Creates the button showing the "Other Bookmarks" folder. 262 std::unique_ptr<views::MenuButton> CreateOtherBookmarksButton(); 263 264 // Creates the button showing the "Managed Bookmarks" folder. 265 std::unique_ptr<views::MenuButton> CreateManagedBookmarksButton(); 266 267 // Creates the button used when not all bookmark buttons fit. 268 std::unique_ptr<views::MenuButton> CreateOverflowButton(); 269 270 // Creates the button for rendering the specified bookmark node. 271 std::unique_ptr<views::View> CreateBookmarkButton( 272 const bookmarks::BookmarkNode* node); 273 274 // Creates the button for rendering the apps page shortcut. 275 std::unique_ptr<views::LabelButton> CreateAppsPageShortcutButton(); 276 277 // Configures the button from the specified node. This sets the text, 278 // and icon. 279 void ConfigureButton(const bookmarks::BookmarkNode* node, 280 views::LabelButton* button); 281 282 // Implementation for BookmarkNodeAddedImpl. Returns true if LayoutAndPaint() 283 // is required. 284 bool BookmarkNodeAddedImpl(bookmarks::BookmarkModel* model, 285 const bookmarks::BookmarkNode* parent, 286 size_t index); 287 288 // Implementation for BookmarkNodeRemoved. Returns true if LayoutAndPaint() is 289 // required. 290 bool BookmarkNodeRemovedImpl(bookmarks::BookmarkModel* model, 291 const bookmarks::BookmarkNode* parent, 292 size_t index); 293 294 // If the node is a child of the root node, the button is updated 295 // appropriately. 296 void BookmarkNodeChangedImpl(bookmarks::BookmarkModel* model, 297 const bookmarks::BookmarkNode* node); 298 299 // Shows the menu used during drag and drop for the specified node. 300 void ShowDropFolderForNode(const bookmarks::BookmarkNode* node); 301 302 // Cancels the timer used to show a drop menu. 303 void StopShowFolderDropMenuTimer(); 304 305 // Stars the timer used to show a drop menu for node. 306 void StartShowFolderDropMenuTimer(const bookmarks::BookmarkNode* node); 307 308 // Calculates the location for the drop in |location|. 309 void CalculateDropLocation(const ui::DropTargetEvent& event, 310 const bookmarks::BookmarkNodeData& data, 311 DropLocation* location); 312 313 // Returns the node corresponding to |sender|, which is one of the 314 // |bookmark_buttons_|. 315 const bookmarks::BookmarkNode* GetNodeForSender(View* sender) const; 316 317 // Writes a BookmarkNodeData for node to data. 318 void WriteBookmarkDragData(const bookmarks::BookmarkNode* node, 319 ui::OSExchangeData* data); 320 321 // This determines which view should throb and starts it 322 // throbbing (e.g when the bookmark bubble is showing). 323 // If |overflow_only| is true, start throbbing only if |node| is hidden in 324 // the overflow menu. 325 void StartThrobbing(const bookmarks::BookmarkNode* node, bool overflow_only); 326 327 // Returns the view to throb when a node is removed. |parent| is the parent of 328 // the node that was removed, and |old_index| the index of the node that was 329 // removed. 330 views::Button* DetermineViewToThrobFromRemove( 331 const bookmarks::BookmarkNode* parent, 332 size_t old_index); 333 334 // Sets/updates the colors and icons for all the child objects in the 335 // bookmarks bar. 336 void UpdateAppearanceForTheme(); 337 338 // Updates the visibility of |other_bookmarks_button_| and 339 // |managed_bookmarks_button_|. Also shows or hides the separator if required. 340 // Returns true if something changed and a LayoutAndPaint() is needed. 341 bool UpdateOtherAndManagedButtonsVisibility(); 342 343 // Updates the visibility of |bookmarks_separator_view_|. 344 void UpdateBookmarksSeparatorVisibility(); 345 346 // Updates the visibility of the apps shortcut based on the pref value. 347 void OnAppsPageShortcutVisibilityPrefChanged(); 348 349 void OnShowManagedBookmarksPrefChanged(); 350 LayoutAndPaint()351 void LayoutAndPaint() { 352 Layout(); 353 SchedulePaint(); 354 } 355 356 // Inserts |button| in logical position |index| in the bar, maintaining 357 // correct focus traversal order. 358 void InsertBookmarkButtonAtIndex(std::unique_ptr<views::View> button, 359 size_t index); 360 361 // Returns the model index for the bookmark associated with |button|, 362 // or size_t{-1} if |button| is not a bookmark button from this bar. 363 size_t GetIndexForButton(views::View* button); 364 365 // Needed to react to kShowAppsShortcutInBookmarkBar changes. 366 PrefChangeRegistrar profile_pref_registrar_; 367 368 // Used for opening urls. 369 content::PageNavigator* page_navigator_ = nullptr; 370 371 // BookmarkModel that owns the entries and folders that are shown in this 372 // view. This is owned by the Profile. 373 bookmarks::BookmarkModel* model_ = nullptr; 374 375 // ManagedBookmarkService. This is owned by the Profile. 376 bookmarks::ManagedBookmarkService* managed_ = nullptr; 377 378 // Used to manage showing a Menu, either for the most recently bookmarked 379 // entries, or for the starred folder. 380 BookmarkMenuController* bookmark_menu_ = nullptr; 381 382 // Used when showing a menu for drag and drop. That is, if the user drags 383 // over a folder this becomes non-null and manages the menu showing the 384 // contents of the node. 385 BookmarkMenuController* bookmark_drop_menu_ = nullptr; 386 387 // If non-NULL we're showing a context menu for one of the items on the 388 // bookmark bar. 389 std::unique_ptr<BookmarkContextMenu> context_menu_; 390 391 // Shows the "Other Bookmarks" folder button. 392 views::MenuButton* other_bookmarks_button_ = nullptr; 393 394 // Shows the managed bookmarks entries. 395 views::MenuButton* managed_bookmarks_button_ = nullptr; 396 397 // Shows the Apps page shortcut. 398 views::LabelButton* apps_page_shortcut_ = nullptr; 399 400 // Used to track drops on the bookmark bar view. 401 std::unique_ptr<DropInfo> drop_info_; 402 403 // Visible if not all the bookmark buttons fit. 404 views::MenuButton* overflow_button_ = nullptr; 405 406 // The individual bookmark buttons. 407 std::vector<views::LabelButton*> bookmark_buttons_; 408 409 ButtonSeparatorView* bookmarks_separator_view_ = nullptr; 410 411 ReadLaterButton* read_later_button_ = nullptr; 412 ButtonSeparatorView* read_later_separator_view_ = nullptr; 413 414 Browser* const browser_; 415 BrowserView* browser_view_; 416 417 // True if the owning browser is showing an infobar. 418 bool infobar_visible_ = false; 419 420 // Animation controlling showing and hiding of the bar. 421 gfx::SlideAnimation size_animation_{this}; 422 423 // If the bookmark bubble is showing, this is the visible ancestor of the URL. 424 // The visible ancestor is either the |other_bookmarks_button_|, 425 // |overflow_button_| or a button on the bar. 426 views::Button* throbbing_view_ = nullptr; 427 428 BookmarkBar::State bookmark_bar_state_ = BookmarkBar::SHOW; 429 430 base::ObserverList<BookmarkBarViewObserver>::Unchecked observers_; 431 432 // Factory used to delay showing of the drop menu. 433 base::WeakPtrFactory<BookmarkBarView> show_folder_method_factory_{this}; 434 435 DISALLOW_COPY_AND_ASSIGN(BookmarkBarView); 436 }; 437 438 #endif // CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_BAR_VIEW_H_ 439