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