1 // Copyright (c) 2011 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 #pragma once 8 9 #include <set> 10 11 #include "base/compiler_specific.h" 12 #include "chrome/browser/bookmarks/bookmark_model_observer.h" 13 #include "chrome/browser/bookmarks/bookmark_node_data.h" 14 #include "chrome/browser/sync/profile_sync_service.h" 15 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_instructions_view.h" 16 #include "chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.h" 17 #include "chrome/browser/ui/views/detachable_toolbar_view.h" 18 #include "content/common/notification_registrar.h" 19 #include "ui/base/animation/animation_delegate.h" 20 #include "views/controls/button/button.h" 21 #include "views/controls/menu/view_menu_delegate.h" 22 23 class Browser; 24 class PageNavigator; 25 class PrefService; 26 27 namespace ui { 28 class SlideAnimation; 29 } 30 31 namespace views { 32 class CustomButton; 33 class MenuButton; 34 class MenuItemView; 35 class TextButton; 36 } 37 38 // BookmarkBarView renders the BookmarkModel. Each starred entry on the 39 // BookmarkBar is rendered as a MenuButton. An additional MenuButton aligned to 40 // the right allows the user to quickly see recently starred entries. 41 // 42 // BookmarkBarView shows the bookmarks from a specific Profile. BookmarkBarView 43 // waits until the HistoryService for the profile has been loaded before 44 // creating the BookmarkModel. 45 class BookmarkBarView : public DetachableToolbarView, 46 public ProfileSyncServiceObserver, 47 public BookmarkModelObserver, 48 public views::ViewMenuDelegate, 49 public views::ButtonListener, 50 public NotificationObserver, 51 public views::ContextMenuController, 52 public views::DragController, 53 public ui::AnimationDelegate, 54 public BookmarkMenuController::Observer, 55 public BookmarkBarInstructionsView::Delegate { 56 friend class ShowFolderMenuTask; 57 58 public: 59 // Constants used in Browser View, as well as here. 60 // How inset the bookmarks bar is when displayed on the new tab page. 61 static const int kNewtabHorizontalPadding; 62 static const int kNewtabVerticalPadding; 63 64 // Maximum size of buttons on the bookmark bar. 65 static const int kMaxButtonWidth; 66 67 // Interface implemented by controllers/views that need to be notified any 68 // time the model changes, typically to cancel an operation that is showing 69 // data from the model such as a menu. This isn't intended as a general 70 // way to be notified of changes, rather for cases where a controller/view is 71 // showing data from the model in a modal like setting and needs to cleanly 72 // exit the modal loop if the model changes out from under it. 73 // 74 // A controller/view that needs this notification should install itself as the 75 // ModelChangeListener via the SetModelChangedListener method when shown and 76 // reset the ModelChangeListener of the BookmarkBarView when it closes by way 77 // of either the SetModelChangedListener method or the 78 // ClearModelChangedListenerIfEquals method. 79 class ModelChangedListener { 80 public: ~ModelChangedListener()81 virtual ~ModelChangedListener() {} 82 83 // Invoked when the model changes. Should cancel the edit and close any 84 // dialogs. 85 virtual void ModelChanged() = 0; 86 }; 87 88 static const int kNewtabBarHeight; 89 90 BookmarkBarView(Profile* profile, Browser* browser); 91 virtual ~BookmarkBarView(); 92 93 // Resets the profile. This removes any buttons for the current profile and 94 // recreates the models. 95 void SetProfile(Profile* profile); 96 97 // Returns the current profile. GetProfile()98 Profile* GetProfile() { return profile_; } 99 100 // Returns the current browser. browser()101 Browser* browser() const { return browser_; } 102 103 // Sets the PageNavigator that is used when the user selects an entry on 104 // the bookmark bar. 105 void SetPageNavigator(PageNavigator* navigator); 106 107 // Sets whether the containing browser is showing an infobar. This affects 108 // layout during animation. set_infobar_visible(bool infobar_visible)109 void set_infobar_visible(bool infobar_visible) { 110 infobar_visible_ = infobar_visible; 111 } 112 113 virtual bool IsOnTop() const; 114 115 // DetachableToolbarView methods: 116 virtual bool IsDetached() const OVERRIDE; 117 virtual double GetAnimationValue() const OVERRIDE; 118 virtual int GetToolbarOverlap() const OVERRIDE; 119 120 // View methods: 121 virtual gfx::Size GetPreferredSize() OVERRIDE; 122 virtual gfx::Size GetMinimumSize() OVERRIDE; 123 virtual void Layout() OVERRIDE; 124 virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child) 125 OVERRIDE; 126 virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE; 127 virtual bool GetDropFormats( 128 int* formats, 129 std::set<ui::OSExchangeData::CustomFormat>* custom_formats) OVERRIDE; 130 virtual bool AreDropTypesRequired() OVERRIDE; 131 virtual bool CanDrop(const ui::OSExchangeData& data) OVERRIDE; 132 virtual void OnDragEntered(const views::DropTargetEvent& event) OVERRIDE; 133 virtual int OnDragUpdated(const views::DropTargetEvent& event) OVERRIDE; 134 virtual void OnDragExited() OVERRIDE; 135 virtual int OnPerformDrop(const views::DropTargetEvent& event) OVERRIDE; 136 virtual void ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) 137 OVERRIDE; 138 139 // AccessiblePaneView methods: 140 virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE; 141 142 // ProfileSyncServiceObserver method. 143 virtual void OnStateChanged(); 144 145 // Called when fullscreen mode toggles on or off; this affects our layout. 146 void OnFullscreenToggled(bool fullscreen); 147 148 // Sets the model change listener to listener. SetModelChangedListener(ModelChangedListener * listener)149 void SetModelChangedListener(ModelChangedListener* listener) { 150 model_changed_listener_ = listener; 151 } 152 153 // If the ModelChangedListener is listener, ModelChangeListener is set to 154 // NULL. ClearModelChangedListenerIfEquals(ModelChangedListener * listener)155 void ClearModelChangedListenerIfEquals(ModelChangedListener* listener) { 156 if (model_changed_listener_ == listener) 157 model_changed_listener_ = NULL; 158 } 159 160 // Returns the model change listener. GetModelChangedListener()161 ModelChangedListener* GetModelChangedListener() { 162 return model_changed_listener_; 163 } 164 165 // Returns the page navigator. GetPageNavigator()166 PageNavigator* GetPageNavigator() { return page_navigator_; } 167 168 // Returns the model. GetModel()169 BookmarkModel* GetModel() { return model_; } 170 171 // Returns true if the bookmarks bar preference is set to 'always show'. 172 bool IsAlwaysShown() const; 173 174 // True if we're on a page where the bookmarks bar is always visible. 175 bool OnNewTabPage() const; 176 177 // How much we want the bookmark bar to overlap the toolbar. If |return_max| 178 // is true, we return the maximum overlap rather than the current overlap. 179 int GetToolbarOverlap(bool return_max) const; 180 181 // Whether or not we are animating. 182 bool is_animating(); 183 184 // SlideAnimationDelegate implementation. 185 virtual void AnimationProgressed(const ui::Animation* animation); 186 virtual void AnimationEnded(const ui::Animation* animation); 187 188 // BookmarkMenuController::Observer 189 virtual void BookmarkMenuDeleted(BookmarkMenuController* controller); 190 191 // Returns the button at the specified index. 192 views::TextButton* GetBookmarkButton(int index); 193 194 // Returns the button responsible for showing bookmarks in the other bookmark 195 // folder. other_bookmarked_button()196 views::MenuButton* other_bookmarked_button() const { 197 return other_bookmarked_button_; 198 } 199 200 // Returns the active MenuItemView, or NULL if a menu isn't showing. 201 views::MenuItemView* GetMenu(); 202 203 // Returns the drop MenuItemView, or NULL if a menu isn't showing. 204 views::MenuItemView* GetDropMenu(); 205 206 // Returns the context menu, or null if one isn't showing. 207 views::MenuItemView* GetContextMenu(); 208 209 // Returns the button used when not all the items on the bookmark bar fit. overflow_button()210 views::MenuButton* overflow_button() const { return overflow_button_; } 211 212 // If |loc| is over a bookmark button the node is returned corresponding 213 // to the button and |start_index| is set to 0. If a overflow button is 214 // showing and |loc| is over the overflow button, the bookmark bar node is 215 // returned and |start_index| is set to the index of the first node 216 // contained in the overflow menu. 217 const BookmarkNode* GetNodeForButtonAt(const gfx::Point& loc, 218 int* start_index); 219 220 // Returns the MenuButton for node. 221 views::MenuButton* GetMenuButtonForNode(const BookmarkNode* node); 222 223 // Returns the position to anchor the menu for |button| at, the index of the 224 // first child of the node to build the menu from. 225 void GetAnchorPositionAndStartIndexForButton( 226 views::MenuButton* button, 227 views::MenuItemView::AnchorPosition* anchor, 228 int* start_index); 229 230 // BookmarkBarInstructionsView::Delegate. 231 virtual void ShowImportDialog(); 232 233 // If a button is currently throbbing, it is stopped. If immediate is true 234 // the throb stops immediately, otherwise it stops after a couple more 235 // throbs. 236 void StopThrobbing(bool immediate); 237 238 // Returns the number of buttons corresponding to starred urls/folders. This 239 // is equivalent to the number of children the bookmark bar node from the 240 // bookmark bar model has. 241 int GetBookmarkButtonCount(); 242 243 // Returns the tooltip text for the specified url and title. The returned 244 // text is clipped to fit within the bounds of the monitor. 245 // 246 // Note that we adjust the direction of both the URL and the title based on 247 // the locale so that pure LTR strings are displayed properly in RTL locales. 248 static std::wstring CreateToolTipForURLAndTitle( 249 const gfx::Point& screen_loc, 250 const GURL& url, 251 const std::wstring& title, 252 Profile* profile); 253 254 // If true we're running tests. This short circuits a couple of animations. 255 static bool testing_; 256 257 private: 258 class ButtonSeparatorView; 259 struct DropInfo; 260 261 // Task that invokes ShowDropFolderForNode when run. ShowFolderDropMenuTask 262 // deletes itself once run. 263 class ShowFolderDropMenuTask : public Task { 264 public: ShowFolderDropMenuTask(BookmarkBarView * view,const BookmarkNode * node)265 ShowFolderDropMenuTask(BookmarkBarView* view, const BookmarkNode* node) 266 : view_(view), 267 node_(node) { 268 } 269 Cancel()270 void Cancel() { 271 view_->show_folder_drop_menu_task_ = NULL; 272 view_ = NULL; 273 } 274 Run()275 virtual void Run() { 276 if (view_) { 277 view_->show_folder_drop_menu_task_ = NULL; 278 view_->ShowDropFolderForNode(node_); 279 } 280 // MessageLoop deletes us. 281 } 282 283 private: 284 BookmarkBarView* view_; 285 const BookmarkNode* node_; 286 287 DISALLOW_COPY_AND_ASSIGN(ShowFolderDropMenuTask); 288 }; 289 290 // Creates recent bookmark button and when visible button as well as 291 // calculating the preferred height. 292 void Init(); 293 294 // Creates the button showing the other bookmarked items. 295 views::MenuButton* CreateOtherBookmarkedButton(); 296 297 // Creates the button used when not all bookmark buttons fit. 298 views::MenuButton* CreateOverflowButton(); 299 300 // Invoked when the bookmark bar model has finished loading. Creates a button 301 // for each of the children of the root node from the model. 302 virtual void Loaded(BookmarkModel* model); 303 304 // Invoked when the model is being deleted. 305 virtual void BookmarkModelBeingDeleted(BookmarkModel* model); 306 307 // Invokes added followed by removed. 308 virtual void BookmarkNodeMoved(BookmarkModel* model, 309 const BookmarkNode* old_parent, 310 int old_index, 311 const BookmarkNode* new_parent, 312 int new_index); 313 314 // Notifies ModelChangeListener of change. 315 // If the node was added to the root node, a button is created and added to 316 // this bookmark bar view. 317 virtual void BookmarkNodeAdded(BookmarkModel* model, 318 const BookmarkNode* parent, 319 int index); 320 321 // Implementation for BookmarkNodeAddedImpl. 322 void BookmarkNodeAddedImpl(BookmarkModel* model, 323 const BookmarkNode* parent, 324 int index); 325 326 // Notifies ModelChangeListener of change. 327 // If the node was a child of the root node, the button corresponding to it 328 // is removed. 329 virtual void BookmarkNodeRemoved(BookmarkModel* model, 330 const BookmarkNode* parent, 331 int old_index, 332 const BookmarkNode* node); 333 334 // Implementation for BookmarkNodeRemoved. 335 void BookmarkNodeRemovedImpl(BookmarkModel* model, 336 const BookmarkNode* parent, 337 int index); 338 339 // Notifies ModelChangedListener and invokes BookmarkNodeChangedImpl. 340 virtual void BookmarkNodeChanged(BookmarkModel* model, 341 const BookmarkNode* node); 342 343 // If the node is a child of the root node, the button is updated 344 // appropriately. 345 void BookmarkNodeChangedImpl(BookmarkModel* model, const BookmarkNode* node); 346 347 virtual void BookmarkNodeChildrenReordered(BookmarkModel* model, 348 const BookmarkNode* node); 349 350 // Invoked when the favicon is available. If the node is a child of the 351 // root node, the appropriate button is updated. If a menu is showing, the 352 // call is forwarded to the menu to allow for it to update the icon. 353 virtual void BookmarkNodeFaviconLoaded(BookmarkModel* model, 354 const BookmarkNode* node); 355 356 // DragController method. Determines the node representing sender and invokes 357 // WriteDragData to write the actual data. 358 virtual void WriteDragDataForView(views::View* sender, 359 const gfx::Point& press_pt, 360 ui::OSExchangeData* data) OVERRIDE; 361 362 virtual int GetDragOperationsForView(views::View* sender, 363 const gfx::Point& p) OVERRIDE; 364 365 virtual bool CanStartDragForView(views::View* sender, 366 const gfx::Point& press_pt, 367 const gfx::Point& p) OVERRIDE; 368 369 // Writes a BookmarkNodeData for node to data. 370 void WriteBookmarkDragData(const BookmarkNode* node, 371 ui::OSExchangeData* data); 372 373 // ViewMenuDelegate method. Ends up creating a BookmarkMenuController to 374 // show the menu. 375 virtual void RunMenu(views::View* view, const gfx::Point& pt); 376 377 // Invoked when a star entry corresponding to a URL on the bookmark bar is 378 // pressed. Forwards to the PageNavigator to open the URL. 379 virtual void ButtonPressed(views::Button* sender, const views::Event& event); 380 381 // Invoked for this View, one of the buttons or the 'other' button. Shows the 382 // appropriate context menu. 383 virtual void ShowContextMenuForView(views::View* source, 384 const gfx::Point& p, 385 bool is_mouse_gesture); 386 387 // Creates the button for rendering the specified bookmark node. 388 views::View* CreateBookmarkButton(const BookmarkNode* node); 389 390 // COnfigures the button from the specified node. This sets the text, 391 // and icon. 392 void ConfigureButton(const BookmarkNode* node, views::TextButton* button); 393 394 // Used when showing the menu allowing the user to choose when the bar is 395 // visible. Return value corresponds to the users preference for when the 396 // bar is visible. 397 virtual bool IsItemChecked(int id) const; 398 399 // Used when showing the menu allowing the user to choose when the bar is 400 // visible. Updates the preferences to match the users choice as appropriate. 401 virtual void ExecuteCommand(int id); 402 403 // NotificationService method. 404 virtual void Observe(NotificationType type, 405 const NotificationSource& source, 406 const NotificationDetails& details); 407 408 // Overridden from views::View. 409 virtual void OnThemeChanged(); 410 411 // If the ModelChangedListener is non-null, ModelChanged is invoked on it. 412 void NotifyModelChanged(); 413 414 // Shows the menu used during drag and drop for the specified node. 415 void ShowDropFolderForNode(const BookmarkNode* node); 416 417 // Cancels the timer used to show a drop menu. 418 void StopShowFolderDropMenuTimer(); 419 420 // Stars the timer used to show a drop menu for node. 421 void StartShowFolderDropMenuTimer(const BookmarkNode* node); 422 423 // Returns the drop operation and index for the drop based on the event 424 // and data. Returns ui::DragDropTypes::DRAG_NONE if not a valid location. 425 int CalculateDropOperation(const views::DropTargetEvent& event, 426 const BookmarkNodeData& data, 427 int* index, 428 bool* drop_on, 429 bool* is_over_overflow, 430 bool* is_over_other); 431 432 // Returns the index of the first hidden bookmark button. If all buttons are 433 // visible, this returns GetBookmarkButtonCount(). 434 int GetFirstHiddenNodeIndex(); 435 436 // This determines which view should throb and starts it 437 // throbbing (e.g when the bookmark bubble is showing). 438 // If |overflow_only| is true, start throbbing only if |node| is hidden in 439 // the overflow menu. 440 void StartThrobbing(const BookmarkNode* node, bool overflow_only); 441 442 // Returns the view to throb when a node is removed. |parent| is the parent of 443 // the node that was removed, and |old_index| the index of the node that was 444 // removed. 445 views::CustomButton* DetermineViewToThrobFromRemove( 446 const BookmarkNode* parent, 447 int old_index); 448 449 // Updates the colors for all the child objects in the bookmarks bar. 450 void UpdateColors(); 451 452 // Updates the visibility of |other_bookmarked_button_| and 453 // |bookmarks_separator_view_|. 454 void UpdateOtherBookmarksVisibility(); 455 456 // This method computes the bounds for the bookmark bar items. If 457 // |compute_bounds_only| = TRUE, the bounds for the items are just computed, 458 // but are not set. This mode is used by GetPreferredSize() to obtain the 459 // desired bounds. If |compute_bounds_only| = FALSE, the bounds are set. 460 gfx::Size LayoutItems(bool compute_bounds_only); 461 462 // Creates the sync error button and adds it as a child view. 463 views::TextButton* CreateSyncErrorButton(); 464 465 NotificationRegistrar registrar_; 466 467 Profile* profile_; 468 469 // Used for opening urls. 470 PageNavigator* page_navigator_; 471 472 // Model providing details as to the starred entries/folders that should be 473 // shown. This is owned by the Profile. 474 BookmarkModel* model_; 475 476 // Used to manage showing a Menu, either for the most recently bookmarked 477 // entries, or for the starred folder. 478 BookmarkMenuController* bookmark_menu_; 479 480 // Used when showing a menu for drag and drop. That is, if the user drags 481 // over a folder this becomes non-null and manages the menu showing the 482 // contents of the node. 483 BookmarkMenuController* bookmark_drop_menu_; 484 485 // Shows the other bookmark entries. 486 views::MenuButton* other_bookmarked_button_; 487 488 // ModelChangeListener. 489 ModelChangedListener* model_changed_listener_; 490 491 // Task used to delay showing of the drop menu. 492 ShowFolderDropMenuTask* show_folder_drop_menu_task_; 493 494 // Used to track drops on the bookmark bar view. 495 scoped_ptr<DropInfo> drop_info_; 496 497 // The sync re-login indicator which appears when the user needs to re-enter 498 // credentials in order to continue syncing. 499 views::TextButton* sync_error_button_; 500 501 // A pointer to the ProfileSyncService instance if one exists. 502 ProfileSyncService* sync_service_; 503 504 // Visible if not all the bookmark buttons fit. 505 views::MenuButton* overflow_button_; 506 507 // BookmarkBarInstructionsView that is visible if there are no bookmarks on 508 // the bookmark bar. 509 views::View* instructions_; 510 511 ButtonSeparatorView* bookmarks_separator_view_; 512 513 // Owning browser. This is NULL during testing. 514 Browser* browser_; 515 516 // True if the owning browser is showing an infobar. 517 bool infobar_visible_; 518 519 // Animation controlling showing and hiding of the bar. 520 scoped_ptr<ui::SlideAnimation> size_animation_; 521 522 // If the bookmark bubble is showing, this is the visible ancestor of the URL. 523 // The visible ancestor is either the other_bookmarked_button_, 524 // overflow_button_ or a button on the bar. 525 views::CustomButton* throbbing_view_; 526 527 // Background for extension toolstrips. 528 SkBitmap toolstrip_background_; 529 530 DISALLOW_COPY_AND_ASSIGN(BookmarkBarView); 531 }; 532 533 #endif // CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_BAR_VIEW_H_ 534