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