Home | History | Annotate | Download | only in bookmarks
      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.
     61   Profile* GetProfile() { return profile_; }
     62 
     63   // Returns the current browser.
     64   Browser* browser() const { return browser_; }
     65 
     66   // Returns the top level 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 
    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