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_GTK_BOOKMARKS_BOOKMARK_BAR_GTK_H_ 6 #define CHROME_BROWSER_UI_GTK_BOOKMARKS_BOOKMARK_BAR_GTK_H_ 7 8 #include <gtk/gtk.h> 9 10 #include <vector> 11 12 #include "base/compiler_specific.h" 13 #include "base/gtest_prod_util.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/weak_ptr.h" 16 #include "base/prefs/pref_member.h" 17 #include "chrome/browser/bookmarks/bookmark_model_observer.h" 18 #include "chrome/browser/bookmarks/bookmark_utils.h" 19 #include "chrome/browser/ui/bookmarks/bookmark_bar.h" 20 #include "chrome/browser/ui/bookmarks/bookmark_bar_instructions_delegate.h" 21 #include "chrome/browser/ui/bookmarks/bookmark_context_menu_controller.h" 22 #include "chrome/browser/ui/gtk/menu_bar_helper.h" 23 #include "content/public/browser/notification_observer.h" 24 #include "content/public/browser/notification_registrar.h" 25 #include "ui/base/animation/animation.h" 26 #include "ui/base/animation/animation_delegate.h" 27 #include "ui/base/animation/slide_animation.h" 28 #include "ui/base/gtk/gtk_signal.h" 29 #include "ui/base/gtk/owned_widget_gtk.h" 30 #include "ui/gfx/point.h" 31 #include "ui/gfx/size.h" 32 33 class BookmarkBarInstructionsGtk; 34 class BookmarkMenuController; 35 class Browser; 36 class BrowserWindowGtk; 37 class GtkThemeService; 38 class MenuGtk; 39 class TabstripOriginProvider; 40 41 namespace content { 42 class PageNavigator; 43 } 44 45 class BookmarkBarGtk : public ui::AnimationDelegate, 46 public BookmarkModelObserver, 47 public MenuBarHelper::Delegate, 48 public content::NotificationObserver, 49 public chrome::BookmarkBarInstructionsDelegate, 50 public BookmarkContextMenuControllerDelegate { 51 public: 52 BookmarkBarGtk(BrowserWindowGtk* window, 53 Browser* browser, 54 TabstripOriginProvider* tabstrip_origin_provider); 55 virtual ~BookmarkBarGtk(); 56 57 // Returns the current browser. 58 Browser* browser() const { return browser_; } 59 60 // Returns the top level widget. 61 GtkWidget* widget() const { return event_box_.get(); } 62 63 // Sets the PageNavigator that is used when the user selects an entry on 64 // the bookmark bar. 65 void SetPageNavigator(content::PageNavigator* navigator); 66 67 // Create the contents of the bookmark bar. 68 void Init(); 69 70 // Changes the state of the bookmark bar. 71 void SetBookmarkBarState(BookmarkBar::State state, 72 BookmarkBar::AnimateChangeType animate_type); 73 74 // Get the current height of the bookmark bar. 75 int GetHeight(); 76 77 // Returns true if the bookmark bar is showing an animation. 78 bool IsAnimating(); 79 80 // ui::AnimationDelegate implementation -------------------------------------- 81 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE; 82 virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE; 83 84 // MenuBarHelper::Delegate implementation ------------------------------------ 85 virtual void PopupForButton(GtkWidget* button) OVERRIDE; 86 virtual void PopupForButtonNextTo(GtkWidget* button, 87 GtkMenuDirectionType dir) OVERRIDE; 88 89 // BookmarkContextMenuController::Delegate implementation -------------------- 90 virtual void CloseMenu() OVERRIDE; 91 92 const ui::Animation* animation() { return &slide_animation_; } 93 94 private: 95 FRIEND_TEST_ALL_PREFIXES(BookmarkBarGtkUnittest, DisplaysHelpMessageOnEmpty); 96 FRIEND_TEST_ALL_PREFIXES(BookmarkBarGtkUnittest, 97 HidesHelpMessageWithBookmark); 98 FRIEND_TEST_ALL_PREFIXES(BookmarkBarGtkUnittest, BuildsButtons); 99 100 // Change the visibility of the bookmarks bar. (Starts out hidden, per GTK's 101 // default behaviour). There are three visiblity states: 102 // 103 // Showing - bookmark bar is fully visible. 104 // Hidden - bookmark bar is hidden except for a few pixels that give 105 // extra padding to the bottom of the toolbar. Buttons are not 106 // clickable. 107 // Fullscreen - bookmark bar is fully hidden. 108 void Show(BookmarkBar::State old_state, 109 BookmarkBar::AnimateChangeType animate_type); 110 void Hide(BookmarkBar::State old_state, 111 BookmarkBar::AnimateChangeType animate_type); 112 113 // Calculate maximum height of bookmark bar. 114 void CalculateMaxHeight(); 115 116 // Helper function which generates GtkToolItems for |bookmark_toolbar_|. 117 void CreateAllBookmarkButtons(); 118 119 // Sets the visibility of the instructional text based on whether there are 120 // any bookmarks in the bookmark bar node. 121 void SetInstructionState(); 122 123 // Sets the visibility of the overflow chevron. 124 void SetChevronState(); 125 126 // Shows or hides the other bookmarks button depending on whether there are 127 // bookmarks in it. 128 void UpdateOtherBookmarksVisibility(); 129 130 // Destroys all the bookmark buttons in the GtkToolbar. 131 void RemoveAllButtons(); 132 133 // Adds the "other bookmarks" and overflow buttons. 134 void AddCoreButtons(); 135 136 // Removes and recreates all buttons in the bar. 137 void ResetButtons(); 138 139 // Returns the number of buttons corresponding to starred urls/folders. This 140 // is equivalent to the number of children the bookmark bar node from the 141 // bookmark bar model has. 142 int GetBookmarkButtonCount(); 143 144 // Returns LAUNCH_DETACHED_BAR or LAUNCH_ATTACHED_BAR based on detached state. 145 bookmark_utils::BookmarkLaunchLocation GetBookmarkLaunchLocation() const; 146 147 // Set the appearance of the overflow button appropriately (either chromium 148 // style or GTK style). 149 void SetOverflowButtonAppearance(); 150 151 // Returns the index of the first bookmark that is not visible on the bar. 152 // Returns -1 if they are all visible. 153 // |extra_space| is how much extra space to give the toolbar during the 154 // calculation (for the purposes of determining if ditching the chevron 155 // would be a good idea). 156 // If non-NULL, |showing_folders| will be packed with all the folders that are 157 // showing on the bar. 158 int GetFirstHiddenBookmark(int extra_space, 159 std::vector<GtkWidget*>* showing_folders); 160 161 // Update the detached state (either enable or disable it, or do nothing). 162 void UpdateDetachedState(BookmarkBar::State old_state); 163 164 // Turns on or off the app_paintable flag on |event_box_|, depending on our 165 // state. 166 void UpdateEventBoxPaintability(); 167 168 // Queue a paint on the event box. 169 void PaintEventBox(); 170 171 // Finds the size of the current web contents, if it exists and sets |size| 172 // to the correct value. Returns false if there isn't a WebContents, a 173 // condition that can happen during testing. 174 bool GetWebContentsSize(gfx::Size* size); 175 176 // Connects to the "size-allocate" signal on the given widget, and causes it 177 // to throb after allocation. This is called when a new item is added to the 178 // bar. We can't call StartThrobbing directly because we don't know if it's 179 // visible or not until after the widget is allocated. 180 void StartThrobbingAfterAllocation(GtkWidget* item); 181 182 // Used by StartThrobbingAfterAllocation. 183 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnItemAllocate, GtkAllocation*); 184 185 // Makes the appropriate widget on the bookmark bar stop throbbing 186 // (a folder, the overflow chevron, or nothing). 187 void StartThrobbing(const BookmarkNode* node); 188 189 // Set |throbbing_widget_| to |widget|. Also makes sure that 190 // |throbbing_widget_| doesn't become stale. 191 void SetThrobbingWidget(GtkWidget* widget); 192 193 // An item has been dragged over the toolbar, update the drag context 194 // and toolbar UI appropriately. 195 gboolean ItemDraggedOverToolbar( 196 GdkDragContext* context, int index, guint time); 197 198 // When dragging in the middle of a folder, assume the user wants to drop 199 // on the folder. Towards the edges, assume the user wants to drop on the 200 // toolbar. This makes it possible to drop between two folders. This function 201 // returns the index on the toolbar the drag should target, or -1 if the 202 // drag should hit the folder. 203 int GetToolbarIndexForDragOverFolder(GtkWidget* button, gint x); 204 205 void ClearToolbarDropHighlighting(); 206 207 // Overridden from BookmarkModelObserver: 208 209 // Invoked when the bookmark model has finished loading. Creates a button 210 // for each of the children of the root node from the model. 211 virtual void Loaded(BookmarkModel* model, bool ids_reassigned) OVERRIDE; 212 213 // Invoked when the model is being deleted. 214 virtual void BookmarkModelBeingDeleted(BookmarkModel* model) OVERRIDE; 215 216 // Invoked when a node has moved. 217 virtual void BookmarkNodeMoved(BookmarkModel* model, 218 const BookmarkNode* old_parent, 219 int old_index, 220 const BookmarkNode* new_parent, 221 int new_index) OVERRIDE; 222 virtual void BookmarkNodeAdded(BookmarkModel* model, 223 const BookmarkNode* parent, 224 int index) OVERRIDE; 225 virtual void BookmarkNodeRemoved(BookmarkModel* model, 226 const BookmarkNode* parent, 227 int old_index, 228 const BookmarkNode* node) OVERRIDE; 229 virtual void BookmarkAllNodesRemoved(BookmarkModel* model) OVERRIDE; 230 virtual void BookmarkNodeChanged(BookmarkModel* model, 231 const BookmarkNode* node) OVERRIDE; 232 // Invoked when a favicon has finished loading. 233 virtual void BookmarkNodeFaviconChanged(BookmarkModel* model, 234 const BookmarkNode* node) OVERRIDE; 235 virtual void BookmarkNodeChildrenReordered(BookmarkModel* model, 236 const BookmarkNode* node) OVERRIDE; 237 238 // Overridden from content::NotificationObserver: 239 virtual void Observe(int type, 240 const content::NotificationSource& source, 241 const content::NotificationDetails& details) OVERRIDE; 242 243 GtkWidget* CreateBookmarkButton(const BookmarkNode* node); 244 GtkToolItem* CreateBookmarkToolItem(const BookmarkNode* node); 245 246 void ConnectFolderButtonEvents(GtkWidget* widget, bool is_tool_item); 247 248 // Finds the BookmarkNode from the model associated with |button|. 249 const BookmarkNode* GetNodeForToolButton(GtkWidget* button); 250 251 // Creates and displays a popup menu for BookmarkNode |node|. 252 void PopupMenuForNode(GtkWidget* sender, const BookmarkNode* node, 253 GdkEventButton* event); 254 255 // GtkButton callbacks. 256 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, gboolean, OnButtonPressed, 257 GdkEventButton*); 258 CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnClicked); 259 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnButtonDragBegin, 260 GdkDragContext*); 261 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnButtonDragEnd, GdkDragContext*); 262 CHROMEGTK_CALLBACK_4(BookmarkBarGtk, void, OnButtonDragGet, 263 GdkDragContext*, GtkSelectionData*, guint, guint); 264 265 // GtkButton callbacks for folder buttons. 266 CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnFolderClicked); 267 268 // GtkButton callback for apps button. 269 CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnAppsButtonClicked); 270 271 // GtkToolbar callbacks. 272 CHROMEGTK_CALLBACK_4(BookmarkBarGtk, gboolean, OnToolbarDragMotion, 273 GdkDragContext*, gint, gint, guint); 274 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnToolbarSizeAllocate, 275 GtkAllocation*); 276 277 // Used for both folder buttons and the toolbar. 278 CHROMEGTK_CALLBACK_6(BookmarkBarGtk, void, OnDragReceived, 279 GdkDragContext*, gint, gint, GtkSelectionData*, 280 guint, guint); 281 CHROMEGTK_CALLBACK_2(BookmarkBarGtk, void, OnDragLeave, 282 GdkDragContext*, guint); 283 284 // Used for folder buttons. 285 CHROMEGTK_CALLBACK_4(BookmarkBarGtk, gboolean, OnFolderDragMotion, 286 GdkDragContext*, gint, gint, guint); 287 288 // GtkEventBox callbacks. 289 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, gboolean, OnEventBoxExpose, 290 GdkEventExpose*); 291 CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnEventBoxDestroy); 292 293 // Callbacks on our parent widget. 294 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnParentSizeAllocate, 295 GtkAllocation*); 296 297 // |throbbing_widget_| callback. 298 CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnThrobbingWidgetDestroy); 299 300 // Overriden from chrome::BookmarkBarInstructionsDelegate: 301 virtual void ShowImportDialog() OVERRIDE; 302 303 // Updates the visibility of the apps shortcut button |apps_shortcut_visible_| 304 // changes. 305 void OnAppsPageShortcutVisibilityChanged(); 306 307 // Updates the drag&drop state when |edit_bookmarks_enabled_| changes. 308 void OnEditBookmarksEnabledChanged(); 309 310 // Used for opening urls. 311 content::PageNavigator* page_navigator_; 312 313 Browser* browser_; 314 BrowserWindowGtk* window_; 315 316 // Provides us with the offset into the background theme image. 317 TabstripOriginProvider* tabstrip_origin_provider_; 318 319 // Model providing details as to the starred entries/folders that should be 320 // shown. This is owned by the Profile. 321 BookmarkModel* model_; 322 323 // Contains |bookmark_hbox_|. Event box exists to prevent leakage of 324 // background color from the toplevel application window's GDK window. 325 ui::OwnedWidgetGtk event_box_; 326 327 // Used to detached the bookmark bar when on the NTP. 328 GtkWidget* ntp_padding_box_; 329 330 // Used to paint the background of the bookmark bar when in detached mode. 331 GtkWidget* paint_box_; 332 333 // Used to position all children. 334 GtkWidget* bookmark_hbox_; 335 336 // Alignment widget that is visible if there are no bookmarks on 337 // the bookmar bar. 338 GtkWidget* instructions_; 339 340 // BookmarkBarInstructionsGtk that holds the label and the link for importing 341 // bookmarks when there are no bookmarks on the bookmark bar. 342 scoped_ptr<BookmarkBarInstructionsGtk> instructions_gtk_; 343 344 // The apps page shortcut button. 345 GtkWidget* apps_shortcut_button_; 346 347 // GtkToolbar which contains all the bookmark buttons. 348 ui::OwnedWidgetGtk bookmark_toolbar_; 349 350 // The button that shows extra bookmarks that don't fit on the bookmark 351 // bar. 352 GtkWidget* overflow_button_; 353 354 // A separator between the main bookmark bar area and 355 // |other_bookmarks_button_|. 356 GtkWidget* other_bookmarks_separator_; 357 358 // The other bookmarks button. 359 GtkWidget* other_bookmarks_button_; 360 361 // Padding for the other bookmarks button. 362 GtkWidget* other_padding_; 363 364 // The BookmarkNode from the model being dragged. NULL when we aren't 365 // dragging. 366 const BookmarkNode* dragged_node_; 367 368 // The visual representation that follows the cursor during drags. 369 GtkWidget* drag_icon_; 370 371 // We create a GtkToolbarItem from |dragged_node_| ;or display. 372 GtkToolItem* toolbar_drop_item_; 373 374 // Theme provider for building buttons. 375 GtkThemeService* theme_service_; 376 377 // Whether we should show the instructional text in the bookmark bar. 378 bool show_instructions_; 379 380 MenuBarHelper menu_bar_helper_; 381 382 // The last displayed right click menu, or NULL if no menus have been 383 // displayed yet. 384 // The controller. 385 scoped_ptr<BookmarkContextMenuController> current_context_menu_controller_; 386 // The view. 387 scoped_ptr<MenuGtk> current_context_menu_; 388 389 // The last displayed left click menu, or NULL if no menus have been 390 // displayed yet. 391 scoped_ptr<BookmarkMenuController> current_menu_; 392 393 ui::SlideAnimation slide_animation_; 394 395 // Used to optimize out |bookmark_toolbar_| size-allocate events we don't 396 // need to respond to. 397 int last_allocation_width_; 398 399 content::NotificationRegistrar registrar_; 400 401 // The size of the web contents last time we forced a paint. We keep track 402 // of this so we don't force too many paints. 403 gfx::Size last_web_contents_size_; 404 405 // The last coordinates recorded by OnButtonPress; used to line up the 406 // drag icon during bookmark drags. 407 gfx::Point last_pressed_coordinates_; 408 409 // The currently throbbing widget. This is NULL if no widget is throbbing. 410 // We track it because we only want to allow one widget to throb at a time. 411 GtkWidget* throbbing_widget_; 412 413 // Tracks whether the apps shortcut button should be shown. 414 BooleanPrefMember apps_shortcut_visible_; 415 416 // Tracks whether bookmarks can be modified. 417 BooleanPrefMember edit_bookmarks_enabled_; 418 419 base::WeakPtrFactory<BookmarkBarGtk> weak_factory_; 420 421 BookmarkBar::State bookmark_bar_state_; 422 423 // Maximum height of the bookmark bar. 424 int max_height_; 425 426 DISALLOW_COPY_AND_ASSIGN(BookmarkBarGtk); 427 }; 428 429 #endif // CHROME_BROWSER_UI_GTK_BOOKMARKS_BOOKMARK_BAR_GTK_H_ 430